ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AGENTS.md:给AI编程建一份项目记忆说明书

AGENTS.md:给AI编程建一份项目记忆说明书

不跟你绕圈子,这篇文章的出发点是我这段时间反复踩到的一个问题:我把同一个项目背景跟AI编程工具讲了不下十遍,每次新建会话它都像第一天上班一样,对我的代码库一无所知。模型的对话窗口装得下上下文,但它记住的东西在你关掉窗口那一刻就清零了——这就是无状态模型最别扭的地方。后来我试着把项目的关键约定、命令、架构边界写进一个叫 AGENTS.md 的文件,放进仓库根目录,让工具在每次会话开始时自动读取,效果是立竿见影的。现在我把这套思路完整梳理一遍,从无状态模型的底层逻辑讲到 Memory 工程的实现路线,再落到 AGENTS.md 的实际写法,希望能帮到那些还在靠复制粘贴提示词撑场面的同学。

1. 无状态模型的工作方式:每次对话都是从零开始

1.1 上下文窗口与令牌:模型的"瞬时记忆"

要理解 AI 编程里的记忆问题,先得说清楚大模型的工作机制。你每次跟模型说的话,会被切成若干个令牌,一块一块喂进模型里。模型只在这一轮交互中看着这些令牌做出预测,下一轮重新开始——严格来说,你的上一句话并不存在于模型的"脑子"里,它只是被临时拼接到了当前对话窗口里,让它"看起来像是记得"。你可以把大模型想象成一个记忆力极差但理解力极强的新同事:你跟他说完需求转身就走,他听懂了你说的每句话,但走出会议室就把重要细节全忘了。

这个机制带来的直接后果,就是对话窗口里的内容决定了模型能"想起"什么。命令是pnpm build还是npm run build、测试框架用的是 Vitest 还是 Jest、目录里哪个文件夹才是核心业务代码——这些信息如果不出现在当前窗口里,模型就永远猜不到。它只能靠"猜"和"泛化"。猜对有运气成分,猜错就浪费时间。很多人在用 AI 编程工具时觉得"它智商忽高忽低",其实多半不是模型变笨了,而是它在缺少关键上下文的情况下做了太多假设。

1.2 项目场景下的记忆缺失:为什么同一个 Bug 要解释两遍

我在某个模拟项目X(后来被我用来做 AGENTS.md 验证的目标项目)上就遇到了非常典型的情况。这个项目的测试要用pnpm test --filter core,单测涉及 mock 数据库连接,集成测试又依赖本地 Docker 容器。我前面已经跟某个 AI 编程工具解释过三遍,每次它听完都能给出不错的建议,但下一次会话我再让它"总结一下测试策略",它就开始用通用答案糊弄:让我npm test,还让我检查环境变量对不对,就是不知道这项目真正的测试链路长什么样。

这种"重复解释"的浪费看起来好像只是多打了几段字,实际成本很高。你每开一个新会话,都得花时间把项目背景、技术栈、目录结构、常用命令、当前要解决的问题重新叙述一遍。而且人描述一个复杂系统时是很容易遗漏细节的,你忘了说"这个项目里配置文件的优先级是 env 覆盖 yaml",模型就会给你一个在特定环境根本跑不通的临时方案。久而久之,你会开始下意识怀疑:AI 编程是不是只适合那些结构简单、文档齐全的模板项目?

答案当然是否定的。问题不在"AI 能不能记住",而在"谁来负责记住"。既然模型天然无状态,那我们要做的,就是把记忆从模型脑子里挪到文件系统里——用一个模型每次都能自动读到、而人类也能方便维护的地方。这就引出了 Memory 工程的核心思路。

2. Memory 工程的两种路线:检索增强与声明式配置

2.1 检索增强路线:建知识库,让模型主动查资料

Memory 工程这几年发展出两条主流路线。一条是检索增强,也就是我们常说的 RAG。它的做法比较重:把项目文档、代码注释、历史 Issue 信息全部抽取出来,做向量化处理,存进向量数据库。模型每次回答问题之前,先用相似度检索把相关性最高的片段捞出来,拼进当前的上下文里。

RAG 的优势在于扩容性好,你给它塞再多的历史文档它都能检索得动,而且适合处理非结构化的零散信息,比如某个老模块的内部设计文档、某个用户反馈里的历史问题描述。但缺点也很明显:整个链路里牵扯的东西太多,你得维护向量库、选择嵌入模型、设计检索策略,还要处理检索结果不准确带来的误召回。对一个中小型项目来说,这一套基建的运维成本可能比项目本身的复杂度还高。我并不是否定 RAG 的价值,只是觉得项目级记忆的大部分需求其实不需要这么重的方法。

2.2 声明式配置路线:把项目上下文写进仓库

另一条路线是声明式配置,思路和 RAG 完全相反。它不搞向量化,不依赖语义检索,而是直接写一份结构化的项目说明文件放进仓库里,让 AI 工具在每次进入项目时自动读取。这份文件不长,通常一个上百行的 Markdown 就能覆盖项目最核心的约定。工具的加载机制一般是:启动会话时,扫描项目根目录,如果找到类似 AGENTS.md 这类约定文件名,就把它注入到当前上下文窗口里,模型从第一句话开始就"知道"了项目背景。

这个做法的底层逻辑很有意思。你想想,给项目写说明书这件事,传统团队里一点都不陌生——README 就是干这个的。但 AGENTS.md 和 README 的最大区别在于:它服务对象不是人,而是 AI。这意味着它的语言基调、信息组织方式、层次结构都要以"机器读懂、人好维护"为最高优先级,而不是像 README 那样讲究叙事流畅和界面友好。

2.3 两种路线的对比与适用场景

我用一个表格把两种路线放在一起看,会更清楚:

维度检索增强(RAG)声明式配置(AGENTS.md)
信息载体外部向量库、非结构化文档仓库内的 Markdown 文件
加载时机每轮按需检索每次会话开始时自动注入
维护成本需要维护检索基建直接编辑 Markdown
适用规模文档量极大、信息分散的场景中小型项目、团队约定型项目
实现歧义可能出现误召回写什么就是什么
上下文占用按当前问题动态拼装固定占用一定窗口

从实际体验来说,RAG 更适合解决"外部知识怎么找",声明式配置更适合解决"项目内部约定怎么同步"。而 AI 编程场景里,模型面对的绝大多数问题恰恰是项目内部的问题:目录结构是什么、构建命令是什么、哪些文件不能动、测试环境怎么起。这些信息是有限、明确、结构化的,写进一个文件里反而比丢进向量库里更直接、更可靠。AGENTS.md 的价值就在于此:它让项目本身的"姿势"变成可检索、可版本管理、可评审的资产。

3. AGENTS.md 的设计哲学:写给AI看的项目说明书

3.1 文件位置与加载机制:为什么放根目录

AGENTS.md 这个名字虽然是近期才流行的,但它背后的思路在 AI 编程圈里已经发展了很久。约定是:把这份文件放在项目根目录,上游的编程工具在启动一个项目会话时,会主动去查找并读取它。根目录这个位置选得非常巧妙——不会弄丢,不会混淆,是任何开发者进入项目时必然经过的地方。工具加载时采用了一种聪明的机制:在窗口顶端注入这份文件,让它成为模型最先看到的"项目背景板"。

这就像给新入职的同事一份入职手册:他不熟悉你们公司的茶水间在哪、打卡规则是什么、项目代码仓库怎么拉取,但只要在第一天把这些写清楚,之后所有的协作都会顺畅很多。AGENTS.md 的作用就是这份"入职手册"。而且因为它在仓库里,任何修订都走正常的代码评审流程,不会出现"你口头跟 AI 说过的规矩,转身就忘了"的情况。

3.2 字段拆解:一份可复用的 AGENTS.md 模板

下面是我实际在用的一份模板结构,你可以直接拿来做底子,再根据自己的项目增删:

# AGENTS.md ## 项目定位 一句话说明项目是做什么的,目标用户是谁,核心业务场景是什么。 ## 技术栈速览 - 主要语言与框架 - 关键的运行时依赖(可选) - 项目脚手架/初始化方式(可选) ## 目录结构速览 按顶层目录分组说明: - src/:业务代码主目录,应用层逻辑都在这里面 - packages/core/:核心模块,别乱动,依赖关系很复杂 ## 常用命令 - 安装依赖: pnpm install - 本地开发: pnpm dev - 单元测试: pnpm test --filter core - 构建打包: pnpm build ## 代码风格约定 - 禁止在业务代码里出现 console.log - 组件 API 全部用 TypeScript 类型声明 - 提交信息遵循 conventional commits 规范 ## 架构边界说明 - 数据访问层必须走 repository 封装,禁止直接拼 SQL - 领域服务内不要直接调用第三方 HTTP 客户端,通过接口注入(可选) ## 已知陷阱 - 配置文件优先级:env > yaml,改配置前先确认环境变量是否存在 - 内置的 API 网关在某些环境需要额外配置 CORS 头

这份模板的核心点在于每个字段都是"事实描述",不是"操作指令"。比如"数据访问层必须走 repository 封装"——这是在告诉模型项目的架构边界长什么样,而不是叫它现在就去重构某段代码。模型在后续提出建议、生成代码时,会自然地遵守这些边界规则。

3.3 为什么用 Markdown 而不是 YAML 或 JSON

有些人可能会问:既然是给 AI 看的配置,那用 YAML 或者 JSON 不是更结构化吗?我的看法刚好相反——AGENTS.md 最好是 Markdown。

第一,AI 模型对自然语言的理解能力远强于对键值对结构的理解能力。自然语言里可以描述"哪些情况要避免""什么时候不要做 X"这种模糊但重要的规则,代码注释里常见的场景化提醒,用 Markdown 表述起来比 YAML 稀松自然得多。

第二,Markdown 对人类友好。AGENTS.md 不是写完之后就永远封存的机器配置,它是要长期维护的文档。团队里的新成员要读、架构师要评审、普通开发者也可能顺手改一句。你总不能让所有人为了改一行配置去学 YAML 语法。

第三,Markdown 的 diff 结果是可读的。用 Git 管理 AGENTS.md 时,每次修订的差异会清晰地显示出来,哪一行规则变了、谁改的备注也一目了然。YAML 文件虽然也能 diff,但缩进和列表嵌套经常让 diff 变得乱糟糟,不利于 review。

4. 从零散提示词到 AGENTS.md 的实战改造记录

4.1 改造前的痛点:我为什么受够了提示词模板

在给模拟项目X写 AGENTS.md 之前,我用的是另一套土办法:维护一个超长的规则提示词文档,每次要用 AI 帮我改代码的时候,先把那段几百字的内容粘贴进对话里,再继续问问题。这个办法初期有效,但越用越难受。

首先,那段提示词写得太长,每次占用的上下文窗口都不小。模型一进来先读你粘贴的 1500 字项目背景,再回答你的问题,回复质量反而被稀释了。其次,提示词是"一次性的记忆"——它不在项目仓库里,脱离了当前对话就毫无价值。我换了台机器、换了台电脑,提示词不在手边,一切从头再来。更关键的是,提示词没有版本维护,我说改了规则,但旧规则在复制粘贴时往往没删干净,模型经常被前后矛盾的指示搞糊涂。

4.2 改造步骤:盘点、归纳、写入、验证

整个改造流程我总结为四步,非常朴素,但在模拟项目X上验证效果极好。

第一步:盘点项目知识。我先把项目里"只有老人才知道"的信息列出来:启动命令、测试范围、核心模块边界、哪些代码路径禁止绕过既有封装、容易踩坑的环境配置。列的时候有个判断标准——凡是需要跟新人解释两遍以上的内容,都应该进 AGENTS.md。例如"这个项目的核心计算模块在packages/engine/src里,其他模块不要直接 import 它的内部模块,必须走公开 API"——这种内容,你要是只靠口头说,新来的开发者十有八九会漏。

第二步:归纳分类。盘点出来的信息有十几条,不能平铺直叙堆在一个文件里。我按照"项目定位、技术栈、目录结构、命令、风格约定、架构边界、已知陷阱"分了七块,每块只写核心的、不会频繁变动的规则。像"依赖安装用 pnpm"这种,写一次就好;像"某个 API 的响应字段现在改了名字"这种临时信息,就不放进 AGENTS.md,直接在工作对话里说明。

第三步:写入仓库。根目录创建一个AGENTS.md,把整理好的内容填进去。这里我通常会刻意控制篇幅,控制在 120 行以内。因为 AGENTS.md 会被注入到模型上下文的开头,太长了会挤占后续任务指令的空间,反而降低整体回复质量。如果一个项目的信息量实在太大,我建议按目录拆分多份,而不是硬塞进一个超大文件(下一节会讲这个)。

第四步:验证迭代。写好之后我在两个场景里做了验证。第一个场景是新建会话,让 AI"帮我列出这个项目的所有可用测试命令"——它准确回答出了pnpm test --filter core和相关的集成测试脚本,这个结果要是之前靠猜,几乎不可能。第二个场景是让它"基于存在的 repository 封装风格的代码习惯,为某个新模块写一段数据访问代码",结果生成出来的代码确实主动使用了Repository接口,没有直接操作数据库连接。这说明 AGENTS.md 里的架构边界确实被模型读取并遵守了,这比我预想的效果还要好。

4.3 踩过的坑:AGENTS.md 写作的常见失误

写 AGENTS.md 和写文档一样,也会踩坑。我把自己的经验教训总结几条:

坑一:写成了"操作手册"而不是"事实描述"。我第一版里写"请先运行pnpm install",结果模型真的每次都先执行安装——它把这句话理解为必须执行的步骤。把表述改掉,改成"安装依赖使用pnpm install",语气中性,它才会把它当作一条可用知识,而不是一个前置行动指令。AGENTS.md 的核心语法不是"做 X",而是"项目里存在 X"。

坑二:混入一次性信息。当时我把某个临时调试环境变量也写了进去,结果后续会话里模型反复提这个变量,反而干扰了正常开发。临时性的、跟当前任务绑定的信息,留在对话里说就行,别污染项目级的记忆文件。

坑三:和 README 重复。AGENTS.md 不是 README 的复制品。README 面向人类,讲项目是什么、怎么部署、怎么参与贡献;AGENTS.md 面向模型,讲的是"你在这个项目里帮忙时要遵守的规矩"。两者重复的部分可以保留,但立场一定要分开——我会在 README 里写"项目简介",在 AGENTS.md 里写"模型在这个项目里需要注意哪些边界"。

5. AGENTS.md 的边界与未来:记住项目的下一步

5.1 多文件与分层配置:当单文件装不下的时候

AGENTS.md 放在根目录,覆盖的是整个项目的全局约定。但实际项目往往比这复杂:某个子包有自己特殊的构建流程、某个目录有独立的技术栈、某些 Legacy 代码有外人不知道的历史包袱。让根目录的 AGENTS.md 强行描述所有这些细节,文件会迅速膨胀,模型上下文里的噪声也会越来越大。

我的做法是分层配置:根目录放精简版 AGENTS.md,只描述全局约束;然后在需要额外说明的子目录里,比如packages/core/、server/、scripts/,分别放自己的局部说明文件,让模型在专注子模块时能读取到更精准的信息。不同编程工具对这种局部文件的命名约定可能略有差异,但思路是通用的。每一层文件都是"项目状态的事实描述",叠加起来就是一套完整的项目知识图谱。

5.2 与执行工具的联动:记忆不只是"读取"

AGENTS.md 解决的是"模型读得懂项目",但 AI 编程工具真正完成一段代码改动,还需要执行命令、读写文件、检查测试结果。这一系列动作如果能在会话里被自动记录和回溯,就构成了更强的记忆闭环。现在有些工具已经开始把会话内的执行历史、命令记录、文件变更作为"可回溯上下文"注入到后续会话中,AGENTS.md 则可以理解为这种行为的"静态初始值"。

我不太看好让 AGENTS.md 承担实时状态存续的责任——它是声明式文件,是"项目背景版"的快照,不是"当前进度"的日志。如果你希望模型在中断之后还能接着上一次的任务干,正确做法是让工具记录会话摘要,或者在下一次对话里主动提供一个简短的状态描述,而不是反复往 AGENTS.md 里塞"现在正在做 XX"这类临时信息。

5.3 团队协作中的维护体验:让记忆成为团队资产

AGENTS.md 最让我满意的地方,是它把"个人记忆"变成了"团队资产"。以前每个人对项目的理解都藏在自己脑子里,带着各自的偏差。现在项目根目录就有一份公开的、给 AI 看的"项目白皮书"。新人入职时直接读一遍 AGENTS.md,带教成本能低一截。产品迭代时如果改了架构约定,顺手更新 AGENTS.md,代码评审时大家也能看到这个变化,整个团队对项目的理解始终保持一致。

当然,它的维护也需要配套习惯。我的经验是:任何代码评审都顺手看一下 AGENTS.md 是否需要同步更新。如果某个约定改了但你忘了更新,AI 又开始"猜规则",AGENTS.md 就成了一座断桥——看起来在,实际已经失效。这个文件的价值与它的准确性直接挂钩,维护不好比不写还难受。

我在实际使用中最深的体会就是:AI 编程的下一个阶段,拼的不只是模型的聪明程度,更是开发者对项目记忆的工程化管理能力。从无状态模型到 AGENTS.md 声明式配置,本质上是把"让 AI 懂我"这件事,从一次性的提示词对话,变成了一套可版本管理、可团队共享、可持续演化的仓库资产。

如果你现在还被"每次重新解释项目"折磨,我建议你今天就动手,花半小时给自己的主力项目建一份 AGENTS.md。先别追求完美,从最常用的命令和最容易踩的坑开始写。另一个实用的启动技巧是:找个 AI 编程工具,让它根据你的仓库现状自动生成一份初稿,你在此基础上削减和修正——这个过程本身就是一次项目知识的复盘,做完之后你对项目的理解比之前又深了一层。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进