这两年我团队里最大的变化,不是换了多少工具,而是 AI 辅助开发的范式整体转了一圈:从把大模型当“一次性便签”,到如今把 Memory 工程当成一等公民。我见过太多项目明明已经接入了 AI 编程助手,却一直在原地打转——同一条业务规则,上午刚让模型改完,下午新会话又要从头讲一遍;同一个模块的历史决策,换个对话窗口就全部失效。问题本质就一句话:无状态模型本身不是错,错在没人替它做记忆工程。
所谓的“范式转换”,核心就是从“无状态模型”走向“有上下文的编码代理”,而 AGENTS.md 这种声明式配置文件,正是当前最容易落地、性价比最高的一层记忆载体。它把项目应该被模型知道的信息,固化成仓库根目录下的规格文件,让 AI 在每次新会话里都能稳定看到同一张“图纸”,而不是靠开发者反复讲、模型反复猜。这篇文章我会先从无状态模型的痛点讲起,再拆 Memory 工程的具体形态,最后用一整份可直接抄走的 AGENTS.md 结构收尾,适合正在做 AI 编码工具落地的开发者、技术负责人,也适合想搞清楚“AI 怎么才能记住我项目”的独立开发者。
1. 为什么“无状态”成了 AI 编码路上的隐形天花板
1.1 上下文窗口只是一次性缓存,不是业务记忆
几乎所有主流大模型在设计上都基于无状态推理:每一次生成请求都是独立的,模型只能依靠当前输入和上下文窗口里的内容来给出回答。上下文窗口看起来很大,动辄几万甚至几十万 token,但它本质上是一块“用完即弃”的便利贴板。会话一关、窗口一换,前面发生过的一切就跟没发生过一样。
这就带来一个非常反直觉的现实:AI 编码助手的能力上限,不取决于模型本身有多强,而取决于每次会话你愿意塞多少上下文给它。窗口塞得越多,模型越容易被无关信息干扰;窗口塞得越少,它对项目的理解就越浅。早期我们用 AI 改小文件、写单点函数感觉特别爽,是因为这些问题不需要太多项目背景。可一旦进入多文件重构、跨模块联调、老系统维护这类工作,无状态模型的短板立刻暴露——它记不住你三天前拍板的架构方向,也记不住上个月刚定下的技术选型。
我常用一个类比给团队解释:这就像你每天请一位新来的实习生帮忙,这位实习生非常聪明,但每天早上都要你把公司的规章制度、项目背景、代码规范从头讲一遍。你讲得越细,他干得越像样;你不讲,他就按自己的通用常识瞎发挥。而 Memory 工程要解决的,正是“让他自己去看那份永远存在着的员工手册”。
1.2 我在迭代中反复踩到的三个具体场景
场景一:跨会话的决策漂移。A 同学在周一把某个模块从单体函数重构成策略模式,跟 AI 助手讨论得很细,当时模型完全理解了意图。周二新开一个会话,让 AI 给这个模块加一个新分支,它却基于自己的“通用最佳实践”提出要引入插件机制,差点把周一的方案推翻。类似的问题不是一次两次,而是每一轮大规模迭代都会出现。
场景二:同一段背景知识被重复解释。项目里用了一套自研的配置加载框架,每次让 AI 改相关代码,都得先把框架的加载顺序、权限模型、常见坑位写进提示词。同一个解释,我可能在十个会话里写了十遍,效率损耗极大。更糟的是,不同会话里解释的详细程度还不一样,今天少讲一个细节,明天模型就会交出完全不同的实现。
场景三:大型代码库里的定位成本飙升。代码量一上来,AI 在无状态模式下会频繁“迷路”。它不知道哪个文件是核心入口、哪些目录已经废弃、哪几条公共方法是被全局引用的。你让它“找到订单状态的流转逻辑”,它可能从控制器翻到工具类,最后给出一个看似合理但根本没被调用的修改点。不是模型笨,是它真的不知道项目地图长什么样。
这三个场景指向同一个结论:AI 编码的下一个瓶颈不再是大模型的推理能力,而是它对项目的持续理解能力。谁先把这段“长期记忆”建起来,谁就能在 AI 辅助开发里拉开差距。
2. Memory 工程的基本盘:AI 到底要记住什么、怎么记
2.1 记忆不是把聊天记录粗暴地塞进上下文
一说要给 AI 加记忆,很多人第一反应是“把历史对话保存下来,下次继续传”。这个做法在小型个人项目里勉强能用,工程上却问题重重:历史对话里充斥着试错、废话和被否决的旧方案,直接塞回上下文不但浪费 token,还会把模型带偏。真正的 Memory 工程,要做的是把“发生过的事情”提炼成“应该长期成立的约束”,然后按需、分层地喂给模型。
我的经验是:先把记忆分成三类,再分别设计存储与检索方式。否则很容易陷入“什么都想记,最后跟没记一样”的窘境。
2.2 三类记忆形态:场景记忆、决策记忆、结构记忆
这三类记忆各有各的载体和使用时机,放一起对比如下:
| 记忆类型 | 内容举例 | 推荐载体 | 注入时机 |
|---|---|---|---|
| 场景记忆 | 项目语言、框架版本、启动命令、测试命令、部署方式 | AGENTS.md、README 约定 | 每次会话开始固定注入 |
| 决策记忆 | 技术选型原因、架构红线、禁止改动区域、已否决方案 | 决策记录文档 + 向量索引 | 遇到相关模块时检索注入 |
| 结构记忆 | 目录职责、关键文件职责、模块之间的依赖方向 | 文件头注释 + 自动生成的索引 | 涉及具体文件修改时局部注入 |
我实际踩过的坑是:很多人只做场景记忆,觉得“只要 AI 知道怎么跑起来就够了”。但真正决定代码质量的其实是决策记忆和结构记忆。比如“为什么当时没有用消息队列”“库存扣减为什么不允许先更新再锁”,这些隐藏知识一旦丢失,模型就会按通用套路重新设计,轻则风格不一致,重则直接违反系统在极端场景下才暴露的约束。
2.3 向量检索与语义检索:海量上下文里的拾取器
当项目文档超过一定体量,把所有内容都塞进上下文窗口就不现实了。这时候需要引入向量检索:把结构化文档、代码片段、历史决策记录切成小块,做向量化后存入向量库;新会话开始时,把当前用户需求和代码变更信息也向量化,通过相似度匹配,只把最相关的几块记忆拉进上下文。
听上去很玄,但本质上就是一个“语义版 grep”。你问“订单状态机在哪里”,它不会傻傻地匹配关键词“订单”,而是能把“状态流转”“支付回调”“取消流程”这些语义相关的代码块都捞出来。配合上层的 AGENTS.md 这类强声明文件,静态记忆负责“约定”,向量检索负责“发现”,两者互不冲突。
这里要特别提醒:向量检索召回的结果不是永远可信。它可能搜到一段已经废弃的旧实现,也可能因为语义相近把两个不同模块的代码混在一起。所以在设计上,静态的 AGENTS.md 规则优先级一定要高于动态检索结果,冲突时以静态声明为准。没有这层仲裁机制,检索式记忆反而会引入新噪声。
3. AGENTS.md 的定位:从“每次现问”到“宣告即事实”
3.1 根目录下的声明式规格,意味着什么
AGENTS.md 这个名字是近几年在 AI 编程社区逐步标准化出来的约定:在代码仓库根目录放一个名为 AGENTS.md 的纯文本格式文件,AI 编程助手打开项目时会自动读取它,并把它作为理解项目的最高优先级上下文。你可以把它理解为项目给 AI 看的“入职手册”。
关键在“声明式”三个字。文件里写的不是“请帮我做某事”,而是“这个项目是什么、有哪些必须遵守的规则”。AI 每次进入项目都先读这份文件,相当于每次新会话都自动加载了同一个项目世界观。不管是碰过这个项目的开发者,还是第一次接触仓库的 AI,看到的都是同一套事实。这从根本上消解了我前面说的决策漂移问题——不是靠人记得去交代,而是靠文件永远戳在那里。
3.2 AGENTS.md 与普通文档、提示词文件的本质区别
很多人问:这不就是写个说明文档吗?还真不是。普通 README 面向人类阅读,强调叙事性和可读性,AI 读起来反而不够“可执行”。而临时提示词文件面向某一次特定任务,不具备持久效力。
| 对比维度 | README 文档 | 临时提示词文件 | AGENTS.md 声明式配置 |
|---|---|---|---|
| 主要读者 | 人类开发者 | AI + 当前任务 | AI 代理(人类也可读) |
| 生命周期 | 长期存在但不严格 | 单次对话 | 长期且自动加载 |
| 内容密度 | 介绍性、叙述性 | 高密度任务指令 | 高密度约束与事实 |
| 被 AI 利用方式 | 需要人主动提供 | 当前会话有效 | 每次进入项目自动读取,优先遵循 |
这里有个容易被忽略的技术细节:AGENTS.md 之所以比普通文档管用,除了内容设计之外,还在于工具链会把它识别为“指令文件”,在构建上下文时给予特殊权重。同样的内容放进一个随便叫 notes.txt 的文件里,AI 不一定会把它当必须遵守的规则。所以文件名和文件位置本身就是一种协议,不建议自作主张换成别的名字。
3.3 设计原理:声明式优于命令式
命令式配置长这样:“先打开 src/order 目录,然后找到 Service 文件,把第 80 行的逻辑改为异步,再执行测试命令。”这套指令只对当下这次修改有效,如果代码结构与描述不符,模型就会卡死。而且这类指令本身就是一种“代码”,需要随着项目变化频繁改,维护成本极高。
声明式配置则不关心完成路径,只关心边界和事实。它写的是:“订单模块的库存操作必须走库存服务,视图层不允许直接改库存表。”至于模型具体怎么组织函数、拆几个类,那是它自己的事。把“方法”放给模型,把“约束”留给自己,这才是 AGENTS.md 的正确使用姿势。
4. 从零搭一块自己的 AGENTS.md:结构与落盘细节
4.1 目录位置与配套文件的摆放
核心文件一定放在仓库根目录,命名精确为 AGENTS.md。子目录里也可以放局部规则,做法是对应模块目录下放 AGENTS.md,只描述该子模块的约定。这种做法在处理大型 monorepo 时特别有效:根文件描述全局命令和整体架构,子目录文件描述各自领域细节,二者形成树状记忆结构。
我目前的推荐布局:
- 根目录 AGENTS.md:全局命令、技术栈、编码红线、跨模块约束
- services/order/AGENTS.md:订单领域专用规则、关键实体、不允许破坏的事务边界
- docs/decisions/:每个重大技术决策一个文件,作为决策记忆主载体
- scripts/build_index/:负责生成代码结构索引,供检索式记忆使用
4.2 一份可直接改用的 AGENTS.md 核心模板
下面是我在模拟项目 X 里实际用过的骨架,字段不多,但每一项都经过了实战检验:
# AGENTS.md ## 项目一句话目标 B2C 订单与库存管理系统,核心目标是保证订单状态与库存扣减的一致性。 ## 运行环境与技术栈 - 后端:Go 1.22 + PostgreSQL 16 + Redis 7 - 前端:Vue 3 + Vite - 基础设施:单机 Docker Compose 起步,禁止引入未评估的额外中间件 ## 常用命令 - 启动后端:make dev - 运行全部测试:make test - 数据库迁移:make migrate-up - 代码检查:make lint ## 目录结构与职责边界 - cmd/ 只放进程入口,不允许放业务逻辑 - internal/order 订单领域,支持库依赖只向内 - internal/infra 底层基础设施,不允许反向依赖业务包 - pkg/ 对外可复用能力,必须保持无业务语义 ## 编码红线(违反即打回) 1. 库存预占必须与订单创建在同一数据库事务内 2. 视图层/接口层禁止直接访问 Redis 与数据表 3. 所有对外消息必须走统一的消息封装,禁止裸发 JSON 4. 已写入 docs/decisions 的架构决策,修改前必须先讨论 ## 对外接缝 - 订单创建成功后发布 OrderCreated 事件,由消息队列消费 - 库存回滚与订单取消必须可重入,事件消费端要做幂等 ## 模型交互建议 - 涉及多文件改动时,先 README + AGENTS.md,再打开具体文件 - 修改公共接口时,先搜索调用方再动签名4.3 常见反模式与自检清单
写法上的坑比很多人想的多。我至少踩过这几类:
第一种是写成了“代码生成器说明书”。比如“把 controller 拆分得更细”“多用设计模式”,这种抽象要求只会让 AI 自由发挥,产出风格极不稳定。正确做法是给可判断的标准:“函数超过 60 行必须拆解”“禁止在 service 层暴露原始 DB 连接”。
第二种是信息过时。AGENTS.md 里写的命令和目录结构,一旦项目升级后没有同步更新,模型就会拿着一份过期地图干活。我现在的做法是把“命令同步维护”列为代码审查的必检项,改依赖、改目录时同步改 AGENTS.md。
第三种是规则太多,互相矛盾。几十条红线堆在一起,模型要么顾此失彼,要么干脆选择性失明。建议核心红线控制在 5 到 8 条之间,能合并的语义尽量合并,让每一条都是真正会被违反且代价高昂的约束。
自检清单我一般用四条:第一,这份文件能否让完全不了解项目的人,在 5 分钟内恢复大部分上下文;第二,是否每条规则都是可验证、可通过代码或现象观测的;第三,删除其中任意一条,是否会对 AI 输出质量造成明显影响;第四,文件里的命令和目录结构,当前是否都是真实存在的。
5. 让记忆“活”起来:静态配置文件之外的检索与索引
5.1 静态文件覆盖不了 10 万行代码
AGENTS.md 在中小型项目里是“主记忆”,但到大型系统里,再详细的声明式文件也没办法把每个业务模块的细节都写进去。这时候就需要引入第二层记忆——检索式记忆增强。把核心业务代码的头注释、关键函数说明、已归档的架构决策文档统一做向量化,建立项目专属的知识库。
我习惯把这一层叫“记忆的缓存层”。它不追求全量记忆,只追求“模型遇到具体问题时,能把最相关的记忆捞进来”。比如用户问“支付回调失败怎么处理”,检索层返回的不只是文件路径,而是那几个和支付状态流转相关的函数的注释与历史决策,让模型在动手前先看到上下文。
5.2 动态上下文注入与分层采样策略
动态注入不是把所有检索结果一股脑塞给模型,那样会撑爆窗口且引入大量噪声。我的采样策略是按四个优先级执行:
- 第一优先级:AGENTS.md 根配置与对应子模块配置,强制注入
- 第二优先级:用户本次会话里明确提及的文件和符号,直接注入
- 第三优先级:向量检索召回的相似代码块与决策记录,按 top-K 截断
- 第四优先级:通用框架知识、第三方库文档,只在出错时补充
这种分层设计的效果是:静态记忆给出边界,自动检索补充细节,用户需求决定方向。三者合起来,模型看到的上下文量不大,但每一段都是“当前任务真正用得上”的。
5.3 记忆一致性:配置文件与检索结果的冲突仲裁
动态检索最危险的场景,是检索出来的旧代码和 AGENTS.md 里的新规则打架。比如 AGENTS.md 明确规定“订单模块不允许直接访问库存表”,但向量库里还躺着一份旧代码注释写着“库存扣减可在订单服务内完成”,模型万一采信了后者就会越界。
我在实践里定了一条硬规则:静态声明优先级永远高于检索结果。一旦出现冲突,模型必须按 AGENTS.md 执行,并在回复里明示“检查到检索结果与项目红线不一致,已忽略检索信息”。同时,检索索引要定期跟随代码变更重建,最好在 CI 里增加一步索引更新检查,确保向量库里不积累过期的“僵尸记忆”。
6. 团队落地:把 AGENTS.md 当代码资产管理
6.1 让 AGENTS.md 参与代码评审与 CI 检查
很多团队把 AGENTS.md 写完就丢在仓库里不管了,这跟“配了代码规范但没人执行”没什么区别。更靠谱的做法,是把它当成一份正式代码资产来治理。AGENTS.md 的任何改动都要走 MR/PR 评审,评审重点不是语法,而是“规则语义是否准确反映当前架构”。什么时候改依赖、改目录、改核心流程,就要同步审视改不改 AGENTS.md。
如果团队对规则一致性要求更高,还可以在 CI 里加一份轻量校验脚本:检查 AGENTS.md 中提及的路径是否真实存在、命令是否能被 make 识别、引用文档是否未失效。这套检查不需要多复杂,一个几百行的脚本就能把“过期地图”的问题拦截在合入之前。
6.2 从“个人习惯”到“团队约定”的推进顺序
我在团队里推广 AGENTS.md 时,没有一上来就号召所有人写文件,而是分了三步走。第一步,我自己在负责的模块里建好文件,让模型的改动质量明显提升;第二步,拉着合作最密切的两三个人,把约定暴露成“公开规则”,提交信息里引用对应条目;第三步,在全组会里展示一组对比案例——同一需求,有 AGENTS.md 的模块一次通过,没配置的模块来回跑了四人轮。数据比任何宣讲都有说服力。
推进过程中要特别警惕“为写而写”。如果团队的业务模块还不稳定、代码结构天天在变,强行写一堆精细规则很容易天天维护。我的建议是:先写稳定不变的底层事实,架构红线等真正稳定后再沉淀,激进地把临时结论写进 AGENTS.md 只会让配置本身成为一个新负担。
6.3 我实测后的一些边界条件和经验心得
聊点实操维度的心得。第一,AGENTS.md 的密度要克制,最好控制在 100 到 200 行之内的信息量,太长之后模型对每条规则的注意力会明显衰减,核心红线的“优先级权重”反而被稀释。第二,子模块级 AGENTS.md 比根级配置更有惊喜,因为业务规则越靠近源代码,模型执行越准确。第三,不要试图在 AGENTS.md 里写“禁止做某些事却不说替代方案”,模型需要知道“不这样做,那应该怎样”。
另外一个容易被忽略的细节:AGENTS.md 开头几句话非常关键。模型的注意力在加载文件时往往是线性扫描,前面几条规则更容易被严格遵守。所以我会把最重要的红线放在前 20 行内,让“仓库认知”最重的地基先进模型视野。我目前实测下来,配合向量检索这批工程手段,团队内的 AI 编码会话里重复解释项目的次数减少了大约七八成,多文件改动被要求返工的比例也有了明显下降。
说到底,从无状态模型到 AGENTS.md 声明式配置,本质上是在做同一件事:把散落在人脑、聊天记录里的隐性项目知识,转成机器可自动加载的显性结构。这份配置文件写得越精准,AI 与项目的贴合度就越高,而人类要做的,只是守住那些真正值得固化的边界。