1. 无状态模型的真实困境:AI 的"金鱼记忆"早就该治了
AI 编程助手每次开新会话都像失忆的病人——昨天刚跟它讲好的分层规则,今天它又直接在 handler 里写数据库查询。你早晚会意识到,这轮"AI 编程范式转换"的胜负手不在模型参数,而在记忆。无状态模型天生记不住项目,于是 Memory 工程成了一门正经手艺,而 AGENTS.md 声明式配置正是这条路上最值得先掌握的一环。
大概半年前我接手了一个维护三年的后端仓库,提交规范极其严格,分层约定写满了整整三页评审清单。我把这些规则一点点"喂"给 AI 编程助手,结果它在同一段代码里一边用优雅的链式调用、一边用最原始的循环过滤,注释一会儿中文一会儿英文。我不停地打断它、纠正它,一个下午改一个模块,效率还不如自己上手。
那段时间我把问题归咎于"模型不够聪明"。后来才慢慢反应过来:这和聪明不聪明关系不大,它每开一个新会话都是"失忆"的,我们面临的是一个典型的工程问题——记忆管理问题。想明白了这一点,后来的很多方案都顺了。
1.1 为什么模型天生"记不住":无状态的底层含义
大模型本质上是一个条件概率生成器。每一次回答,都是从你当前输入的上下文(prompt 加历史对话)出发做一次独立推理。上一次会话里发生的所有事情——约定、结论、你纠正过的错误——在模型内部都没有任何残留痕迹。
这就是"无状态模型"的含义:状态完全由外部提供。你往上下文里塞得越多,它这一刻就"记得"越多;你不塞,它一无所知。所谓的"多轮对话记忆",其实只是把聊天记录原封不动地拼接进下一次请求里,本质上是一种极其粗糙的外部缓存,随时可能被截断、被压缩、被遗忘。
这个机制在闲聊场景没什么问题,在写代码场景就彻底露馅了。代码项目本身就是一棵巨大的信息树:架构选型、依赖关系、目录约定、代码风格、领域术语、历史踩坑……这些信息如果每次都要靠聊天记录临时传递,既塞不满,也塞不全。上下文窗口那么贵,不可能把整个仓库都放进去。
1.2 项目失控的真实表现:风格漂移与反复纠错
我观察到的失控症状很有规律,基本可以列成一张表来对照:
| 症状 | 典型表现 | 造成的隐性成本 |
|---|---|---|
| 风格漂移 | 新生成的代码和旧代码像两个人写的,命名、错误处理、日志格式全不一致 | 评审成本上升,维护者需要额外解释 |
| 重复踩坑 | 上一轮明确说"不要改 xx 目录",新会话它又改了 | 返工,信任度下降 |
| 上下文浪费 | 为了让它记住一条约定,你得重新陈述一遍,同样的话反复出现 | 有效信息被稀释,推理质量下滑 |
| 修复引入新错 | 改 A 处的问题,却顺着引用链动了 B 处的逻辑 | 范围失控,线上事故风险 |
这四条单独看都不致命,凑在一起就是慢性失血。每个开发者被迫扮演"AI 监督员",把本该花在业务逻辑上的注意力,全耗在和助手的重复沟通上。真正折损的是开发的连续心流。
当时我自己也试过各种补丁:在每次会话开头贴一段长指令、写一份个人级的规则文件、靠快捷回复把常用约定一次性注入……都有效果,但都很脆。直到我把思路从"每次注入"翻转为"让项目自己携带约定",事情才真正开始变得不一样。
2. Memory 工程:把记忆从对话搬进项目本身
"Memory 工程"这个词听起来玄,本质就一句话:把 AI 编程助手需要知道的东西,从易失的会话里,搬运到持久、可更新、可版本管理的载体上去。
你可以把它理解成给 AI 助手做一套"项目档案"。真人新入职一个团队,靠的不是面试官多叮嘱几句,而是团队的制度文档、代码评审规范、可读的代码库。AI 助手也是一样,它需要的是一份"入职培训材料",而不是一整吨临时叮嘱。想通了这一层,你就不会再指望靠聊天把它"调教"好。
2.1 记忆的分层:全局、项目与会话
我习惯把记忆工程拆成三层来理解。
第一层是全局记忆,属于个人偏好或通用规则。比如"新代码一律用函数式组件""日志统一用结构化 JSON""提交信息禁止出现临时标记"。这层只和写代码的人有关,和具体项目无关,适合放在个人配置里,跟着账号走。
第二层是项目记忆,属于某个仓库独有的东西:目录约定、构建命令、分层规则、历史遗留的特殊约束。这层必须跟着项目走,进版本库,任何人检出来都有。
第三层是会话记忆,只服务于当下这个任务,比如"这次只重构 xx 文件,不要动测试""这个 bug 在 xx 处,目标是保持对外接口不变"。这层适合放在对话里,用完即走。
我之前犯的错误,就是把这层的边界搞混。把项目级的约定放在个人全局配置里,导致换了仓库照样被错误规则约束;又把全局规则塞进项目文件里,导致不同项目互相污染。分层清楚了,记忆工程的地基才算打对。
2.2 为什么声明式配置优于"每次多叮嘱两句"
这里有一个关键选择:用声明式配置文件,还是用更强的手动 prompt(每次对话前贴一大段说明)?我的结论是,声明式配置在三个维度上完胜。
第一,声明式配置受版本控制。你改了约定会走评审、留历史,出错可以 diff,可以回归。靠聊天注入的说明,改完就没了,版本之间没法对比。第二,声明式配置是被动加载的。助手自己会去读,不需要你每次都记得贴出来。人的记忆力不可靠,流程才可靠。第三,声明式配置是可测试的。你把规则写成固定文件后,可以开一个新会话、用一个标准问题去验证它是否生效。prompt 没法自动化测试,文件可以。
当然这里有个前提:你得先把上下文设计得足够有信息量。声明式配置解决的只是"怎么存",存什么、怎么组织,仍然需要你自己下功夫。我把常见做法的利弊放在下面这张表里,方便你对照自己现在的处境:
| 做法 | 存储位置 | 生命周期 | 优点 | 典型缺点 |
|---|---|---|---|---|
| 会话内反复说明 | 对话历史 | 本次会话 | 灵活、即时生效 | 易失、占上下文、不可审计 |
| 个人全局规则 | 用户配置 | 长期 | 覆盖所有项目 | 无法按项目区分,容易误伤 |
| 项目级规则文件(AGENTS.md) | 仓库内 | 长期,随仓库演进 | 版本可控、可评审、跨会话生效 | 需要维护,存在过期风险 |
| 动态检索注入 | 外部索引 | 随任务变化 | 精细、省上下文 | 实现成本高,依赖基础设施 |
抛开最后一种需要对基础设施投入较多的方案,项目级规则文件是目前性价比最高的起点。它不需要额外服务,不需要学习新工具,只需要一个 Markdown 文件加一套维护习惯。
3. AGENTS.md 的定位:给 AI 看的项目制度文件
3.1 AGENTS.md 不是提示词,而是项目约束
现在主流的方向,是把对 AI 的约束从"prompt"转化为"约定文件名"。AGENTS.md 就是这种思潮下的产物。它的核心思想其实很简单:在仓库根目录放一个名为 AGENTS.md 的普通文本文件,里面用平实的语言描述这个项目对 AI 助手的一切工作要求。兼容这个约定的编程助手,在进入项目工作前会主动读取它,把它作为行为准则的一部分。人看着不碍眼,AI 看得懂,两边共用一套。
这和传统意义上的 README 有本质区别。README 是给人看的入门介绍,经常写"这是一个 Web 服务,基于某框架"。AGENTS.md 是给助手看的约束文件,写的是"这个仓库的命令是什么、代码应该怎么写、哪些地方严禁改动、遇到模棱两可时按什么优先级决策"。
它更像一本执法手册或者 SOP,而不是一份介绍资料。很多人第一次写 AGENTS.md 时容易把它写成技术博客,这是第一个坑。记住:AGENTS.md 的目标读者是一个对项目一无所知、但执行力非常强的实习生,你要做的不是让它理解项目有多好,而是让它在动手前就知道边界在哪。
3.2 一份可执行的 AGENTS.md 长什么样
我直接给一份经过简化的真实示例(模拟项目 X),你可以对照着感受一下密度:
# 项目 X:内部数据看板服务 ## 概述 - 用途:为运营团队提供实时指标看板,服务端 + 管理后台两个应用。 - 技术栈:服务端 Go 1.22 + PostgreSQL;前端 React + TypeScript + Vite。 - 关键目录:monorepo 布局,apps/server 与 apps/web 各自独立。 ## 常用命令 - 启动服务:`make dev` - 跑测试:`make test`(服务端) / `cd apps/web && pnpm test` - 代码检查:`make lint` - 数据库迁移:`cd apps/server && make migrate-up` ## 代码约定 - 所有 HTTP 接口遵从现有路由文件的路由前缀,禁止自行新增 meta 路由。 - service 层是业务入口;handler 层只做参数校验与响应封装,禁止在 handler 中直接查询数据库。 - 错误处理统一用 fmt.Errorf 包装并附带上下文;禁止吞掉错误日志。 - 前端组件遵循目录内现有组件规范,优先使用已有设计系统组件。 ## 严禁事项 - 不要修改 migrations 目录下的历史迁移文件。 - 不要改动生产环境的部署脚本;涉及部署变更先写出方案再交人评审。 - 不要自动升级依赖版本;依赖变更属于独立 PR。 ## 工作方式 - 所有代码变更默认附带新增/更新的测试。 - 提交信息使用 conventional commits(feat/fix/refactor/test/chore)。 - 如果任务描述与以上规则冲突,先停下来向用户说明冲突点,等待确认。这份文件满打满算不到四十行,但复用价值极高。你可以试想一下:新会话一旦加载了它,它会主动遵守错误包装、目录边界、路由前缀、提交格式,这些在过去要靠我不厌其烦地重复,现在全部变成了"配置项"。
因为规则是声明式的,助手在行动之前就知道边界在哪里,而不是边做边被你纠正。这个体验差别,就像让新手开工前先读一遍员工手册,和边干活边被主管骂之间的差别,完全不在一个数量级。
4. 落地实操:写出一份真正能用的 AGENTS.md
4.1 三条铁律:简短、指令化、可验证
写 AGENTS.md 最容易犯的错,是把它当成文档来写。我踩完坑以后,总结出三条铁律。
第一,简短。一份 AGENTS.md 控制在 100 到 200 行为佳。太长的文件有两个副作用:一是占用上下文窗口,挤占了真正处理代码的空间;二是助手在超长文本里抓重点的能力有限,信息密度一低,约束就会被稀释。宁可只写 20 条最重要的,也不要写 200 条次重要的。
第二,指令化。用祈使句,直接告诉助手做什么、不做什么。不要说"一般来说建议使用责任链模式,这样更清晰",要说"新增校验逻辑一律放入 middleware/validate.go 中,禁止在 handler 内联写校验条件"。模糊表达等于没表达。
第三,可验证。每条规则都得能通过行为被检查。比如"所有新增模块都必须有测试"是可验证的;"代码要保持整洁"就是不可验证的废话。写完后可以拿一个具体的新任务去试,看助手的行为是否符合每一条。测不出来的规则,干脆别写。
4.2 多级配置:根目录与子目录的分工
小项目一个根文件就够,但稍微大一点的 monorepo,单层文件就不够精细了。我现在的做法是"根目录给总纲,子目录给细则"。
根目录的 AGENTS.md 只写全局层面的硬性约束:命令、总体架构、跨应用依赖、通用编码规范。子目录里再放各自的 AGENTS.md,覆盖该模块特有的细节,比如某个服务的限流规则、某个包依赖的文件组织方式。
需要注意的是,根文件的优先级应该最高。我见过子目录配置和根目录配置互相矛盾的仓库,助手直接无所适从。解决方式是在所有子目录文件头部加一行说明:"仅适用于本目录;与仓库根目录规则冲突时,以根目录为准。"
多级配置的价值在于:助手在不同目录工作时,加载的细则不同,既能享受全局稳定,又能获得局部敏感。这比把所有内容都塞进一个根文件要高效得多,也符合人类团队的管理直觉——公司制度手册不可能细致到每个团队的日报格式,同样的逻辑放到 AI 约束文件上也成立。
4.3 维护机制:像代码一样评审和迭代
AGENTS.md 不是写一次就完事的静态文件,它需要持续演进。我的做法是把它纳入每次代码评审的范畴:谁改了架构、谁改了目录规范、谁在约束上踩了坑,顺手改 AGENTS.md,一起提 PR。
关键维护场景大概是这些:
- 目录重构后,同步更新架构说明。
- 新成员(人或 AI)连续两次在同一个地方出错,说明该处规则缺失或表述不清,补一条。
- 发现某条规则在真实任务中导致助手过度僵化,降低优先级或删除。
- 工具链升级后,命令变化了,务必同步命令部分。
最怕的是"手上的规则文件早已过期"。过期规则比没有规则更糟,因为它会建立一种虚假的安全感,而且助手会忠实执行已经废弃的路径。我之前就吃过这个亏:迁移脚本早换成了新工具,AGENTS.md 里还写着旧命令,助手就用错误命令操作数据库环境,差点出事故。
所以请把 AGENTS.md 当成一等公民来维护。它跟代码一样会腐化、要重构、需要被测试。指望写好一份就能一劳永逸,是很多 Memory 工程落地失败的根本原因。
5. 踩坑与边界:Memory 工程不是银弹
5.1 最常见的翻车场景:内容过期、冲突、过度约束
Memory 工程落地一段时间后,我遇到的最典型的三个坑,逐个说。
第一是内容过期。前面已经提到了,解决方案是定期审计,最好每两到三个迭代就打开文件通读一遍,也可以把"核查 AGENTS.md"设成固定的团队节奏项。不要等出事再回头翻文件。
第二是规则冲突。最常见的是项目内配置文件之间的冲突,其次是全局配置和项目配置之间的冲突。比如全局说"禁止使用任何第三方图表库",项目里又明确引用了图表库,助手就会无所适从。解决的关键是建立优先级顺序,并且把顺序写进配置里,让助手在冲突时有明确的决策路径,而不是每次都要来问人。
第三是过度约束。把规则写得过死,助手做每件事都要逐条对照规则,思考成本急剧上升,代码反而变得不自然。比如你规定"所有函数必须带注释、每行不超过 80 字符、所有循环必须用 lambda",这样的助手生成的代码会像机器人写的,可读性奇差。规则要约束"边界",不要规定"每一笔"。给助手留出合理的自主裁量空间,它的产出才会更像一个合格工程师,而不是一台复印机。
5.2 信息安全:AGENTS.md 里绝对不能写的东西
这个坑,我建议每个人第一次写之前就记住:AGENTS.md 是跟着仓库走的,会进入版本库、会同步给其他人、也会被助手读取。
所以绝对不要在里面写任何敏感信息。举几个反例:
- 真实的数据库连接串或者 API Key。
- 尚未公开的内部服务地址。
- 包含个人隐私的偏好描述。
- 超出必要范围的复盘、绩效类内容。
AGENTS.md 应该是"公开可读的信息压缩包",是你在毫不设防的情况下也愿意给别人看的内容。任何需要保密的信息,都应该通过更安全的外部机制提供,而不是写进项目文件里等着出事。
5.3 工具兼容与规则优先级:不同助手的读取差异
目前各家 AI 编程助手对这类配置文件的支持度不完全一样。有的生态优先读取自己专属命名的规则文件,有的生态把 AGENTS.md 作为默认读取项。这意味着你写了 AGENTS.md 之后,不一定所有助手都会自动遵守。
我的经验是,以 AGENTS.md 为项目主配置,然后按工具差异做一层"适配层":如果有某个助手只认自己的专门文件,就写一个很小的桥接文件,内容核心指向项目内的 AGENTS.md。做法也很简单,就是在这个专属文件里写上一句"本项目的完整约定见仓库根目录 AGENTS.md",再补充该工具特有的执行参数。
这样既保持项目内单一事实来源,又兼顾不同工具的加载机制。切忌每个工具维护一套独立规则——那迟早会演变成多份规则互相矛盾的局面,维护成本直接爆炸。
6. 从个人习惯到团队协作:范式转换的下一步
6.1 AI 助手的"入职培训",本质是记忆资产的沉淀
写到这里你会发现,Memory 工程真正改变的不只是个人工作流,而是团队的工作方式。一个新人工程师入职,要读 README、架构文档、代码规范,加上两周的熟悉期。现在 AI 助手入职只需读一个 AGENTS.md,几秒钟后就能按团队规范工作。
这带来一个很有意思的推论:项目里的 AGENTS.md 就是团队的"AI 入职培训材料",它跟着项目走、被所有人维护、被版本管理。当它足够完善时,团队相当于投资了一项可继承的 AI 协作资产。新人也好,新工具也好,进入项目就能立刻获得团队的隐性知识,不用再从零探索。
在这个过程中,我强烈建议团队把 AGENTS.md 的维护责任落实到具体的人。它不该是某个热心工程师的私人物品,而应像架构文档一样,由负责架构的同事牵头、全体成员参与评审。没有责任人的规则文件,三个月后就变成一纸空文。
6.2 记忆的下一步:检索、代码图谱与动态上下文
AGENTS.md 这类静态声明文件解决的是"稳定约束"。但还有很多记忆是动态的:过去修过哪个 bug、某个模块最近引入了什么依赖、代码库中与当前任务相关的函数分布。这些信息靠静态文件表达不清,更适合通过检索或结构化索引来提供。
我现在比较看好的方向有两个。一是把项目文档、历史提交记录、甚至代码注释做成可检索的索引,在任务开始时动态拉取与任务相关度最高的片段注入上下文。二是让助手在完成任务后回写一份"工作日志"式的记忆文件,沉淀新的结论和踩坑点,在下一次任务里复用。
这两条路并不冲突。AGENTS.md 相当于"宪法",检索索引相当于"图书馆",回写记忆相当于"个人笔记"。一个项目如果能把这三层都建立起来,AI 编程助手从"每次都是新人"进化成"越用越懂这个项目",只是时间问题。
6.3 我踩过这些坑之后的体会
如果让我给刚开始尝试的人一句实用建议,我会说:从最小的 AGENTS.md 开始,先用一个仓库试跑两周,观察助手在哪些环节上反复犯同样的错,再一条一条补规则。不要一开始就追求大而全,更不要照搬别人的模板。
在真实项目里,默认它会在第一周内失效,因为项目在变、工具在变、需求在变。真正的工程能力不只是写好这份配置,而是养成一个持续校准它的习惯。我个人的迭代节奏是:每当同一类纠正连续出现两次,我就把它沉淀成一条规则;每当一条规则连续两周没有被用到,我就问自己是否该删掉。
说到底,从无状态模型到 AGENTS.md 声明式配置,这个转换的本质是把"和 AI 对话"变成"和项目对话"。对话内容是易失的,项目文件是持久的。谁先把记忆沉淀进项目,谁就先享受到越用越顺手的 AI 协作体验。我现在已经离不开这套机制了,写完这份梳理之后,下一个动作就是去检查仓库里现有配置有没有该更新但还没更新的部分。