AI编程助手无状态困境与AGENTS.md声明式记忆工程实践 1. 从每次都要重新解释一遍说起无状态模型的真实困境如果你最近半年深度用过任何一款 AI 编程助手大概率经历过这样的场景周一早上打开编辑器让模型帮你重构一个模块它给出的方案完全符合项目规范下午换了个会话窗口同样的问题再问一遍它却像失忆了一样把之前约定好的命名风格、目录结构、错误处理方式全部抛在脑后。你不得不把上午那段长长的背景说明再粘贴一遍甚至还要重新解释我们这个项目不用 ORM全部走原生 SQL这种基础设定。这不是模型变笨了而是它的工作方式决定的。当前绝大多数编程类大模型在单次会话内是无状态的——每次请求对它来说都是全新的开始上下文窗口里有什么它就基于什么推理。上下文窗口之外的一切对它而言不存在。这个特性在聊天场景里问题不大但在真实的工程协作里代价极高你花在重复交代背景上的时间可能比模型真正帮你写代码的时间还多。我自己的体感是在一个中等规模的项目里如果不用任何记忆机制每天至少有 30% 的交互轮次是在做上下文重建。这还只是时间成本更隐蔽的是一致性成本同一个项目里A 模块用驼峰命名B 模块用下划线模型每次都要重新猜猜错了你还得改改完下次它又忘了。所以这两年围绕 AI 编程的讨论正在从怎么写出更好的 prompt转向一个更工程化的问题怎么让模型在跨会话、跨任务、跨时间的情况下稳定地记住并遵守项目的约定这就是 Memory 工程要解决的核心命题。而 AGENTS.md 这类声明式配置文件的出现本质上是把记忆从临时的对话上下文里抽出来变成项目仓库里一份可版本管理、可审查、可复用的结构化文档。这篇文章想聊的就是这条演进路径背后的逻辑为什么无状态模型不够用Memory 工程到底在工程什么AGENTS.md 这种声明式配置为什么会被越来越多团队采纳以及在实际落地时哪些坑是文档里不会写、只有踩过才知道的。2. 无状态模型的边界它到底忘了什么2.1 上下文窗口不是记忆是工作台很多人把上下文窗口理解成模型的记忆容量这个类比其实有偏差。更准确的说法是上下文窗口是模型的工作台不是档案柜。工作台上摆着什么它就能处理什么工作台一清空之前摆过的东西就彻底消失了不会自动归档。这个区别很关键。工作台的容量是有限的而且越往后的内容模型对它的注意力权重往往越高这也是为什么很多实践建议把关键指令放在 prompt 末尾。这意味着即使你把项目规范塞进上下文如果它被淹没在几万 token 的代码里模型也可能视而不见。我实测过一个极端情况把一份 800 行的编码规范放在对话开头然后让模型改一个函数它改出来的风格和规范里写的完全相反——因为规范离当前任务太远了注意力早就稀释掉了。所以无状态模型忘的第一件事是跨会话的项目背景。第二件事更隐蔽会话内的注意力衰减。第三件事是隐式约定——那些团队里没人明说、但所有人都默认遵守的规则比如所有对外接口必须加超时日志里不能出现用户手机号。这些规则在人类协作里靠口口相传和 code review 传承但模型完全不知道。2.2 三种失忆对应的三类工程问题把忘拆开看对应的是三类不同的工程问题解决思路也不一样。失忆类型具体表现工程解法方向跨会话失忆新会话不记得项目结构、技术栈、命名规范持久化的项目级配置文件会话内注意力衰减长对话后忽略早期指令指令前置 关键约束重复 分阶段任务隐式约定缺失不知道团队默认规则、安全红线显式声明 可审查的规则文档第一类靠持久化解决第二类靠prompt 结构设计解决第三类靠显式化解决。AGENTS.md 这类文件主要覆盖第一类和第三类第二类则需要配合任务拆分和交互节奏来缓解。理解这个分类后面选型和落地时就不会眉毛胡子一把抓。2.3 为什么把规范写进 prompt不是长久之计有人会说那我每次会话开头把规范粘贴一遍不就行了短期可以长期有三个问题。一是维护成本。规范改了你得同步改所有地方的粘贴内容改漏一处就产生不一致。二是不可审查。粘贴在对话里的规范没有版本记录谁改的、什么时候改的、为什么改全都查不到。三是无法复用。团队里十个人用 AI十个人各自维护一份粘贴内容等于十份可能互相矛盾的事实标准。这三点合起来指向一个结论项目级的 AI 协作约定应该像代码一样被管理——放进仓库、纳入版本控制、走 review 流程。这就是声明式配置文件的立足点。3. Memory 工程到底在工程什么从记住到可治理3.1 记忆的三个层次事实、规则、偏好在动手设计任何 Memory 方案之前先要搞清楚记忆里装的到底是什么。我把它分成三层每层的稳定性和变更频率差别很大。事实层项目是什么技术栈、目录怎么组织、依赖了哪些内部库、部署在什么环境。这层相对稳定几个月才变一次。规则层编码规范、命名约定、错误处理模式、安全红线、测试要求。这层中等稳定可能几周调整一次。偏好层当前任务临时需要的特殊要求比如这次重构先不要动测试文件这个模块暂时保留旧接口兼容。这层变化最快可能每次任务都不同。三层混在一起写是很多团队 Memory 方案失败的第一个原因。事实和规则应该进持久化配置文件偏好应该留在单次会话的 prompt 里。如果把临时偏好也写进 AGENTS.md文件会迅速膨胀成没人愿意读的流水账最后连模型都抓不住重点。3.2 声明式 vs 命令式为什么描述状态比描述步骤更适合记忆AGENTS.md 这类方案的核心特征是声明式——它描述的是项目应该是什么样而不是你应该怎么做。这个区别值得展开说。命令式写法像这样第一步检查 import 顺序第二步如果发现相对导入超过两层改成绝对导入第三步……这种写法的问题是它假设了一个固定的执行流程但真实任务千变万化模型很难把固定流程套到所有场景上。声明式写法像这样本项目统一使用绝对导入禁止超过两层的相对导入。它描述的是一个约束状态模型可以自己判断当前任务是否触及这个约束、怎么在具体场景里满足它。这更接近人类给同事交代事情的方式——你不会告诉同事第一步做什么第二步做什么你会告诉他我们这边的规矩是什么。从工程角度看声明式还有两个好处可组合多条约束可以自由叠加不需要编排顺序和可验证每条约束都是独立的事实陈述容易检查是否被遵守。3.3 记忆的读写分离谁写、谁读、什么时候更新一个健康的 Memory 系统写入和读取应该是分离的而且写入要有明确的触发条件。读取发生在每次 AI 交互开始时模型加载配置文件把里面的约束纳入当前上下文。这一步应该是自动的、无感的。写入则应该是有意识的、低频的。什么时候写当团队达成一个新的约定、当一次 code review 发现某类问题反复出现、当项目结构发生重大变化时。写入应该走类似代码提交的流程有人提议、有人 review、合并进仓库。我见过反面的做法让模型自己在对话结束后总结并写入记忆文件。听起来很智能实际很危险——模型总结的内容可能包含幻觉、可能把临时偏好固化成永久规则、可能用错误的措辞覆盖掉原本准确的约定。记忆文件的写入权应该牢牢握在人手里。4. AGENTS.md 的声明式设计一份文件该写什么、不该写什么4.1 文件结构从给模型看倒推组织方式AGENTS.md 是给模型读的不是给人读的虽然人也要 review。这个定位决定了它的组织方式应该服务于模型能否快速定位到相关约束。我的建议是按约束的作用域分层而不是按重要性或字母顺序。一个可参考的结构# 项目约定 ## 全局约束 - 技术栈、语言版本、包管理器 - 通用命名规范 - 安全红线 ## 目录级约束 ### src/api/ - 接口层只做参数校验和转发不写业务逻辑 ### src/domain/ - 领域逻辑集中在此禁止直接依赖外部 IO ## 任务类型约束 ### 写测试时 - 使用项目统一的测试工具链 - 每个测试用例必须能独立运行这样组织的好处是当模型处理src/api/下的文件时它能快速定位到目录级约束里对应的部分而不是在几千字里大海捞针。4.2 写什么高价值约束的四个特征不是所有约定都值得写进 AGENTS.md。我总结下来值得写的约束通常满足四个特征中的至少两个高频几乎每个任务都会触及。比如命名规范、import 风格。易错模型默认行为容易违反。比如禁止在循环里做数据库查询——模型经常这么写。难发现违反了不会立刻报错但会埋雷。比如所有外部调用必须设超时。有歧义不同人理解不一致需要统一。比如什么算一个大函数。反过来那些模型默认就会做对的事比如代码要有缩进、或者极少触及的事比如每季度更新一次依赖写进去只是噪音。4.3 不写什么三类应该排除的内容临时偏好前面说过这类内容变化太快写进去会污染文件。留在单次会话里。可从代码推断的事实比如本项目用 TypeScript——模型看一眼文件扩展名就知道。写进去浪费空间。但本项目虽然用 TypeScript 但禁止用 any就值得写因为这是模型无法从代码推断的约定。模糊的价值主张比如代码要优雅要保持可维护性。这种话模型无法执行只会让文件显得冗长。约束必须可操作、可判断。4.4 一个容易忽略的细节约束的反例比正例更有信息量写约束时光说要怎么做往往不够加上不要怎么做能显著提升模型的理解准确度。因为模型见过大量代码它的默认倾向可能和你的约定相反只给正例它可能理解偏。比如使用绝对导入这条如果只写这一句模型可能在某些边界情况下犹豫。加上禁止../../这种超过两层的相对导入边界就清晰了。再比如错误处理统一用 Result 类型加上不要抛异常、不要返回 null模型就不会在几种风格之间摇摆。这个技巧我在多个项目里验证过效果比单纯堆正例好很多。代价是文件会长一点但换来的是模型行为的稳定性值得。5. 落地实操把 AGENTS.md 接进真实工作流5.1 起步阶段先写 20 行别追求完整最常见的失败模式是一上来就想写一份完美的项目 AI 协作规范结果写了三天还没写完最后不了了之。正确的做法是增量演进。第一版只写最痛的三五条约束比如命名规范、import 风格、错误处理模式。用一两周观察模型在哪些地方还是反复出错把那些点补进去。每次 code review 发现模型犯的新错误就考虑是不是该加一条约束。我自己的经验是一个项目跑到稳定状态AGENTS.md 大概在 100 到 200 行之间。超过这个量级就要警惕是不是混进了不该写的内容。5.2 与工具链的衔接让加载变成自动的配置文件写得再好如果每次都要手动粘贴用不了几天就会被放弃。关键是让它自动加载。不同工具的支持方式不一样但思路是共通的把文件放在项目根目录用工具约定的文件名AGENTS.md 是当前比较通用的约定之一工具在启动会话时自动读取。如果你的工具不支持自动读取退而求其次的做法是写一个简单的脚本在启动时把文件内容注入到初始 prompt 里。这里有个实操细节注意文件的加载顺序和优先级。如果项目里同时存在全局配置和目录级配置要明确哪个覆盖哪个。我的建议是目录级优先于全局因为目录级更具体。这个规则要写进文件本身让模型也知道。5.3 验证机制怎么知道约束真的生效了写完约束不代表模型就会遵守。需要一套轻量的验证机制。最直接的办法是构造测试任务针对每条关键约束设计一个容易触发它的任务看模型是否遵守。比如针对禁止循环内查询数据库给一个需要批量处理的场景看模型会不会写出 N1 查询。这些测试任务可以攒成一个清单每次大改配置文件后跑一遍。更工程化的做法是把它接进 CI用固定的 prompt 跑一组任务检查输出是否符合约束。这个投入对个人项目可能过重但对团队协作价值很大。5.4 版本管理把配置文件当代码对待AGENTS.md 应该和代码一样走 PR 流程。每次修改都要说明理由最好附上触发这次修改的具体案例比如上周三次 review 都发现模型忘了加超时所以补了这条。这样做有两个好处一是修改有据可查二是新成员能通过阅读修改历史快速理解团队的约定是怎么演进的。我见过一些团队把配置文件的历史当成新人培训材料效果出奇地好。6. 踩过的坑那些文档里不会写的教训6.1 约束写太满模型反而摆烂这是我踩过最深的坑。有一段时间我追求完备把能想到的约束全写进去结果发现模型的表现反而下降了——它开始忽略一些约束或者写出一些为了满足约束而满足约束的奇怪代码。后来想明白了约束太多模型在生成每个 token 时都要同时满足几十条规则注意力被摊薄反而哪条都做不好。这跟人一样你给同事交代二十条注意事项他大概率一条都记不住。解决办法是分层核心约束必须遵守的控制在 10 条以内放在文件最前面次要约束分组放在后面模型有余力时自然会照顾到。实测下来这种分层比平铺的效果好很多。6.2 用自然语言写伪代码约束模型理解更准有些约束用纯自然语言描述容易产生歧义这时候可以借用一点伪代码的形式。比如函数长度这条写函数不要太长很模糊。写成单个函数原则上不超过 50 行超过时考虑拆分就清晰多了。再进一步可以写成类似规则的形式IF 函数行数 50 THEN 考虑拆分为多个职责单一的函数这种半结构化的写法模型理解起来比纯散文准确比真正的代码又灵活。我在几个项目里试过对减少歧义确实有帮助。6.3 别忘了负面清单明确禁止的行为大部分人的配置文件只写要做什么很少写禁止做什么。但负面清单往往价值更高因为模型默认行为里有很多看起来合理但项目里不允许的做法。比如禁止在业务代码里直接console.log、禁止提交带TODO的代码、禁止在测试里依赖真实网络。这些禁止如果不写模型会理所当然地做然后你在 review 时才发现。负面清单的写法要具体最好带上替代方案。比如禁止直接 console.log统一使用项目封装的 logger 模块这样模型知道该用什么替代。6.4 定期瘦身删掉已经内化的约束配置文件不是越厚越好。随着模型能力提升有些以前需要显式声明的约束现在模型默认就会做对。这些约束应该定期清理掉。我一般每季度过一遍配置文件逐条问这条约束最近三个月有没有被违反过如果没有考虑删掉或降级到次要分组。保持文件精简模型对剩余约束的遵守度反而更高。6.5 跨工具兼容别把鸡蛋放一个篮子不同 AI 编程工具对配置文件的格式、文件名、加载方式支持不一样。如果你的团队同时用多个工具最好把核心约束抽成一个中立的格式再为每个工具做一层薄薄的适配。这个投入在团队规模小的时候可能不划算但一旦团队超过五六个人、工具选择开始分化就会体现出价值。核心约束只有一份避免这个工具里写了那条工具里没写的不一致。7. 从声明式配置再往前看Memory 工程的下一步声明式配置文件解决了跨会话记住项目约定的问题但它只是 Memory 工程的一个阶段。再往前看还有几个方向值得关注。一是动态记忆根据当前任务自动加载相关约束而不是每次全量加载。这需要工具支持按任务类型筛选配置内容目前还比较初级但方向是明确的。二是记忆的自动校验不只是加载约束还能在模型生成代码后自动检查是否违反约束违反时给出反馈。这本质上是把 lint 的思路用到 AI 协作上。三是团队级记忆共享目前配置文件是项目级的但很多约定其实是团队级的、跨项目的。怎么在项目级和团队级之间做继承和覆盖是个还没很好解决的问题。不过这些都是后话。对大多数团队来说当下最实际的收益还是先把 AGENTS.md 这类声明式配置用起来把每次都要重新解释一遍的浪费止住。这一步的投入产出比比追任何新概念都高。我个人在实际操作中的体会是Memory 工程听起来很工程但落地时最难的往往不是技术而是克制——克制住把所有东西都写进去的冲动克制住让模型自动写入记忆的诱惑克制住追求完备的执念。一份好的配置文件读起来应该像一位老同事给新人的交代不多但每句都有用。