AGENTS.md 与 Memory 工程:让 AI 编程从无状态走向有状态
1. 从无状态到有状态AI 编程范式转换的底层逻辑1.1 为什么传统 AI 编程方式正在失效过去两年大多数人使用 AI 编程的方式非常简单打开对话框输入需求复制代码粘贴到项目里。这种方式在写一个独立函数、生成一段正则表达式、或者解释一段报错信息时确实够用。但一旦项目规模上去问题就暴露得非常明显。我试过在一个中等规模的前端项目里连续用这种方式推进两周结果到了第三周AI 开始频繁给出与项目已有架构冲突的方案。比如项目里已经封装了一套统一的请求层AI 却还在建议我直接调fetch项目用的是某种特定的状态管理约定AI 却按它自己的习惯生成另一套写法。每次都要在提示词里重新解释一遍项目结构解释完它记住了下一个新对话又忘了。这就是无状态模型的根本问题每一次对话都是独立的模型不记得你上次说过什么不记得你的项目约定不记得你踩过哪些坑。你付出的沟通成本在每次新对话中都要重新支付一遍。1.2 Memory 工程到底在解决什么问题Memory 工程这个词听起来很玄但拆开看其实很朴素。它要解决的核心问题只有一个如何让 AI 在多次交互之间保持对项目上下文的一致认知。传统做法是在每次对话时手动粘贴项目说明或者维护一个超长的系统提示词。这两种方式都有明显缺陷。手动粘贴效率极低而且容易遗漏超长系统提示词则会占用大量上下文窗口导致真正需要 AI 处理的代码内容被挤压。Memory 工程的思路是把项目知识从“每次对话临时提供”转变为“持久化声明”。就像你给一个新加入团队的开发者准备一份项目 README 一样你给 AI 也准备一份它每次都会读取的“项目须知”。这份须知不需要很长但必须精准覆盖 AI 做决策时需要用到的关键信息。1.3 AGENTS.md 为什么成为这个范式的代表AGENTS.md 这个概念的流行不是偶然的。它本质上是一个放在项目根目录的 Markdown 文件用自然语言声明这个项目的技术栈、目录结构、编码约定、禁止事项、常用命令等信息。AI 工具在开始工作前会先读取这个文件从而获得项目的“长期记忆”。它的优势在于三点。第一是声明式你只需要描述“是什么”和“要什么”不需要写复杂的配置逻辑。第二是可版本控制它就是一个普通文件可以跟着代码一起提交、一起 review、一起回滚。第三是跨工具通用不管用的是哪种 AI 编程助手只要它支持读取项目根目录的约定文件就能受益。注意AGENTS.md 不是某个特定工具的专属格式它更像是一种社区约定。不同工具可能支持不同的文件名但核心思路是一致的——把项目上下文持久化到文件里。2. AGENTS.md 的核心结构与编写要点2.1 一份合格的 AGENTS.md 应该包含哪些模块我前后改过十几版 AGENTS.md最终稳定下来的结构大概包含以下几个部分。你可以根据项目实际情况增减但核心模块建议保留。模块作用是否必需项目概述一句话说明项目是什么、给谁用必需技术栈列出语言、框架、关键依赖及版本必需目录结构说明核心目录的职责划分必需编码约定命名规范、文件组织、导入顺序等必需禁止事项明确 AI 不能做的事强烈建议常用命令安装、启动、测试、构建命令强烈建议已知问题当前存在的坑和临时方案可选项目概述不需要长两三句话足够。我见过有人在里面写了一大段产品背景结果 AI 每次都要花上下文去读这些与编码无关的内容。技术栈部分要具体到版本比如“React 18 TypeScript 5.3 Vite 5”而不是只写“React”。版本信息直接影响 AI 生成的代码写法比如 React 18 的并发特性和 React 17 差异很大。2.2 编码约定怎么写才能让 AI 真正遵守这是最容易写砸的部分。很多人写编码约定时喜欢写“代码要清晰”“命名要规范”这种正确的废话AI 读了等于没读。有效的编码约定必须是可判定的。举个例子不要写“组件命名要规范”而要写“组件文件使用 PascalCase工具函数文件使用 camelCase常量文件使用 UPPER_SNAKE_CASE”。不要写“注意代码风格”而要写“使用 2 空格缩进字符串统一用单引号语句末尾不加分号”。再比如导入顺序可以明确写成先导入第三方库再导入项目内绝对路径模块最后导入相对路径模块每组之间空一行。这种规则 AI 执行起来毫无歧义。我自己的经验是编码约定部分控制在 15 条以内效果最好。超过 20 条之后AI 的遵守率会明显下降因为它能分配给每条规则的注意力被稀释了。如果确实有很多约定优先保留那些“AI 最容易搞错”的其他靠代码 review 兜底。2.3 禁止事项比“要做什么”更重要的是“不要做什么”这一块是我踩坑最多的地方。早期我只写“要做什么”结果 AI 经常自作主张引入新依赖、修改不该改的文件、或者用一些项目里已经废弃的写法。禁止事项要写得非常具体。比如不要引入新的第三方依赖如需引入必须先说明理由不要修改config/目录下的任何文件不要使用any类型如确实需要请用unknown加类型守卫不要删除已有的测试用例不要修改数据库 schema 文件这些规则看起来琐碎但每一条背后都是我真实踩过的坑。比如有一次 AI 为了图方便把一个原本用项目内工具函数实现的逻辑改成了直接调某个库结果那个库在项目里根本没装构建直接挂了。提示禁止事项建议用“不要 具体动作 原因”的格式写。加上原因之后AI 在遇到边界情况时能更好地判断意图而不是死板执行。2.4 常用命令与已知问题让 AI 能自己验证常用命令部分看似简单但作用很大。当 AI 知道你用pnpm test跑测试、用pnpm lint检查代码风格时它在给出修改建议后可以主动提醒你运行这些命令验证。已知问题部分则是给 AI 打预防针。比如“当前测试环境缺少某个 mock 数据运行集成测试时会有 3 个用例失败这是预期内的”写上这一句AI 就不会在遇到这些失败时大惊小怪也不会试图去“修复”这些本来就不该它管的问题。3. 实操从零搭建一套 Memory 工程工作流3.1 第一步梳理项目现状并生成初版 AGENTS.md不要一上来就手写 AGENTS.md效率太低。我的做法是先让 AI 帮我生成初版然后人工修正。具体操作是把项目的package.json、目录树用tree -L 2或类似命令输出、以及几个代表性源文件一起提供给 AI让它根据这些信息生成一份 AGENTS.md 草稿。提示词可以这样写请根据我提供的项目信息生成一份 AGENTS.md 文件。 要求包含项目概述、技术栈含版本、目录结构说明、编码约定、禁止事项、常用命令。 编码约定要具体可判定不要写“代码要清晰”这类模糊表述。 禁止事项要针对这个项目的特点不要写通用套话。生成之后逐条检查。重点看技术栈版本是否准确、目录结构说明是否与实际一致、编码约定是否覆盖了项目里真实存在的约定。这一步大概花 20 分钟但能省下后面无数次的重复沟通。3.2 第二步把 AGENTS.md 接入日常工作流生成好文件之后关键是让它真正被用起来。不同工具的接入方式不同但核心逻辑是一样的确保 AI 在开始处理任务前会读取这个文件。有些工具会自动读取项目根目录的约定文件你只需要把文件放对位置就行。有些工具则需要你在提示词里显式引用比如“请先阅读 AGENTS.md然后按照其中的约定完成以下任务”。我自己的习惯是在每次新对话的第一条消息里固定加上一句“请先读取 AGENTS.md”。虽然多打几个字但能确保 AI 不会漏掉。实测下来加了这一句之后AI 违反项目约定的概率大概能降低七成以上。3.3 第三步持续迭代把踩过的坑写进去AGENTS.md 不是一次写完就完事的。每次你发现 AI 犯了某个重复性错误就应该把对应的规则补进去。比如我发现 AI 总是忘记在新增 API 路由时同步更新路由注册文件我就在禁止事项里加了一条“新增路由后必须同步更新routes/index.ts中的注册”。再比如 AI 总是把日期格式化写成某种特定写法而项目里统一用的是另一套工具函数我就在编码约定里明确写“日期格式化统一使用utils/date.ts中的formatDate函数”。这个过程有点像给新员工写工作手册一开始只能写个大概随着他犯的错越来越多手册越来越厚他犯错的频率也越来越低。区别在于 AI 不会觉得你烦你写多少它读多少。3.4 一个完整的 AGENTS.md 示例下面是我在一个模拟项目中实际使用的 AGENTS.md 精简版供参考# AGENTS.md ## 项目概述 这是一个内部使用的数据看板项目面向运营团队提供实时数据展示和导出功能。 ## 技术栈 - React 18.2 TypeScript 5.3 - Vite 5.0 构建 - Zustand 4.5 状态管理 - TanStack Query 5.x 数据请求 - Tailwind CSS 3.4 样式方案 ## 目录结构 - src/components/ 通用组件按功能分子目录 - src/pages/ 页面组件与路由一一对应 - src/hooks/ 自定义 hooks - src/utils/ 工具函数 - src/api/ 接口定义与请求封装 - src/stores/ Zustand store 定义 ## 编码约定 1. 组件文件用 PascalCase工具函数文件用 camelCase 2. 使用 2 空格缩进字符串用单引号语句末尾不加分号 3. 导入顺序第三方库 → 项目绝对路径 → 相对路径组间空一行 4. 所有 API 请求必须通过 src/api/ 中的封装不直接调 fetch 5. 日期格式化统一使用 utils/date.ts 中的 formatDate 6. 样式优先使用 Tailwind 类名不写独立 CSS 文件 ## 禁止事项 - 不要引入新的第三方依赖如需引入必须先说明理由 - 不要修改 config/ 目录下的任何文件 - 不要使用 any 类型用 unknown 加类型守卫替代 - 不要删除已有的测试用例 - 新增路由后必须同步更新 routes/index.ts ## 常用命令 - 安装依赖pnpm install - 启动开发pnpm dev - 运行测试pnpm test - 代码检查pnpm lint - 构建pnpm build ## 已知问题 - 集成测试中有 3 个用例因缺少 mock 数据而失败属预期内 - 导出功能在 Safari 下有兼容性问题暂未修复这份文件大概 60 行放在项目根目录每次 AI 开始工作前读一遍基本能覆盖 80% 的常见决策场景。4. 常见问题与排查技巧实录4.1 AI 不读 AGENTS.md 怎么办这是最常见的问题。首先要确认你的工具是否支持自动读取。如果不支持就需要在提示词里显式引用。我试过几种引用方式效果最好的是在对话开头用明确的指令“请先读取项目根目录的 AGENTS.md 文件理解项目约定后再开始任务。”如果工具支持文件引用但 AI 仍然忽略可能是文件路径不对或者文件内容太长导致 AI 只读了开头。这时候可以把 AGENTS.md 拆成两个文件一个核心约定文件短小精悍一个详细说明文件按需读取。4.2 AGENTS.md 写多长合适我的经验是控制在 100 行以内。超过 100 行之后AI 的遵守率会下降而且维护成本也上去了。如果内容确实多优先保留“禁止事项”和“编码约定”其他部分可以精简。另一个技巧是把不常用的规则放到单独的文档里在 AGENTS.md 中用一行引用说明。比如“详细的 API 设计规范见 docs/api-conventions.md”AI 在需要时可以去读不需要时不占用上下文。4.3 规则冲突了怎么处理有时候 AGENTS.md 里的规则会和用户当次的具体指令冲突。比如 AGENTS.md 说“不要引入新依赖”但用户这次明确要求“用某个库实现某个功能”。这种情况下AI 应该以用户当次指令为准但需要提醒用户这与项目约定冲突。为了避免混乱可以在 AGENTS.md 里加一条元规则“当用户指令与本文档冲突时以用户指令为准但需在回复中说明冲突点。”这样 AI 的行为就有了明确指引。4.4 多人协作时 AGENTS.md 怎么维护AGENTS.md 应该像代码一样走 review 流程。每次有人发现 AI 犯了新的重复性错误就提一个 PR 把对应规则加进去。这样规则库是集体智慧的结晶而不是某一个人的经验。另外建议在 AGENTS.md 顶部加一个变更记录简单记录每次修改的内容和原因。这样新人加入时能快速理解每条规则背后的故事而不是面对一堆不知道为什么存在的约束。常见问题排查思路解决方法AI 不读文件确认工具支持性、路径正确性显式引用、拆分文件规则太长被忽略检查文件行数精简到 100 行以内规则冲突确认冲突来源加元规则明确优先级多人维护混乱检查是否有 review 流程走 PR 流程、加变更记录AI 遵守率下降检查规则数量和具体性减少模糊表述、优先保留高频规则4.5 一个容易被忽略的细节文件编码和格式AGENTS.md 是 Markdown 文件但不同工具对 Markdown 的解析能力不同。我遇到过某个工具无法正确解析嵌套列表的情况导致规则被截断。后来我把所有规则都改成平铺的一级列表问题就解决了。另外建议用 UTF-8 编码保存避免中文注释出现乱码。虽然这是基础操作但确实有人在这上面栽过跟头。5. 从 AGENTS.md 延伸出去的 Memory 工程实践5.1 分层记忆把不同稳定性的信息分开存放AGENTS.md 解决的是项目级长期记忆但实际工作中还有更细粒度的记忆需求。比如某次重构的临时约定、某个功能的特殊处理方式这些信息不适合放进 AGENTS.md但每次对话都解释一遍又太累。我的做法是建一个docs/ai-notes/目录按主题存放临时性的 AI 协作笔记。比如docs/ai-notes/refactor-auth.md记录认证模块重构期间的临时约定。在 AGENTS.md 里加一行“重构相关任务请先阅读 docs/ai-notes/ 下对应文件”这样既保持了 AGENTS.md 的精简又不丢失细节。5.2 用示例代替描述few-shot 在 Memory 工程中的应用有些约定很难用文字描述清楚比如“组件的写法风格”。这时候与其写一堆形容词不如直接放一个示例文件。我通常会在 AGENTS.md 里写“组件写法参考 src/components/ExampleCard/index.tsx”然后确保那个示例文件是项目里最规范的写法。AI 读了示例之后生成的代码风格会明显更贴近项目实际。这个技巧在处理样式方案、测试写法、API 封装模式时特别有效。文字描述一百遍不如给一个例子。5.3 定期清理Memory 也会过期项目在演进AGENTS.md 里的规则也会过时。比如项目从 Webpack 迁移到了 Vite但 AGENTS.md 里还写着 Webpack 相关的约定AI 读了之后就会给出错误的建议。我的习惯是每个 sprint 结束时花 10 分钟过一遍 AGENTS.md把过时的规则删掉把新出现的约定加进去。这个投入产出比非常高10 分钟的维护能避免后面大量的返工。5.4 效果评估怎么知道 Memory 工程真的有用最直观的指标是“重复沟通次数”。在引入 AGENTS.md 之前我每天大概要花 20 分钟在提示词里重复解释项目约定。引入之后这个时间降到了 5 分钟以内。另一个指标是“AI 生成代码的一次通过率”。以前 AI 生成的代码经常因为风格不符或用了禁止的写法被打回现在这种情况明显减少。虽然没法精确统计但体感上至少提升了一半以上。如果你刚开始尝试建议先记录一周的基线数据引入 AGENTS.md 后再记录一周对比一下就能看到效果。数据比感觉更有说服力。5.5 工具选型不要被工具绑定AGENTS.md 的核心价值在于“声明式配置”这个思路而不是某个特定工具的实现。不同工具可能用不同的文件名、不同的读取时机但只要你理解了“把项目上下文持久化到文件里”这个本质换工具时迁移成本很低。我自己的做法是把核心约定写在 AGENTS.md 里然后针对不同工具做一层薄薄的适配。比如某个工具需要.cursorrules文件我就在那个文件里写一行“请读取 AGENTS.md 并遵循其中的约定”。这样核心知识只有一份适配层随时可以替换。提示不要把所有约定都写进工具专属的配置文件里。一旦换工具这些约定就全部失效了。保持核心知识的工具无关性是 Memory 工程长期可维护的关键。这套方法我用了大半年从最初的手忙脚乱到现在的流程化操作最大的体会是AI 编程的效率瓶颈往往不在模型能力而在你能否把项目上下文有效地传递给它。AGENTS.md 和 Memory 工程解决的正是这个传递问题。把这件事做好AI 才能真正从一个“偶尔帮忙的助手”变成“了解项目的协作者”。