像大多数团队一样,我们第一次听说 AGENTS.md 时,都以为它只是又一份“给 AI 看的 README”。真正意识到这件事没那么简单,是在一次 Agent Context 治理把我们折磨得够呛之后——上下文动不动就溢出、AI 反复犯同一个低级错误、规则写了等于没写。回头看,AGENTS.md 根本不是普通文档,它是一个项目在 AI 时代最核心的上下文基线。这篇文章不聊概念,只讲我们在一个真实项目里怎么把 AGENTS.md 从“摆设”变成“约束系统”的全过程,包括踩过的坑、改过的话术、以及让规则真正生效的实操细节。适合正在用 AI 辅助写代码、又对上下文管理一头雾水的团队和个人。
1. 从“给 AI 看的 README”到上下文基线
1.1 为什么普通文档救不了 Agent
你打开一个陌生仓库的 README,通常会看到“项目简介”“安装步骤”“快速开始”这类内容,那是写给人类看的。人会主动跳过已知信息,也能靠目录快速定位到自己需要的段落。但 AI Agent 不太一样,它在一个新会话里面对整个代码库时,几乎没有“常识”可言——它不知道你的技术栈选型是什么、不知道哪些目录是生成产物不能乱碰、更不知道团队内部约定要优先遵循。
一开始我们也天真地以为,只要仓库文档齐全,AI 就能表现良好。结果一测就露馅。它经常自信满满地改了不该改的配置文件,或者在错误目录下新建了看似合理实际上完全脱离架构的模块。原因很简单:文档存在并不等于文档进了模型的上下文。普通 README 不会在每次会话开始时被自动加载,就算加载了,它也不是为了“告诉 AI 什么能做、什么不能做”而设计的。
AGENTS.md 解决的是另一个问题:它要在对话真正开始之前,成为唯一确定进入上下文的东西。它不是文档库里的一个可选项,而是 AI 对项目建立初始认知的默认起点。我们后来把它称为“项目的意识基线”,因为整个会话里的决策质量,很大程度取决于开头这几屏内容。
注意:别再拿 README 改个名就充数。AGENTS.md 的写作逻辑和 README 完全相反,它要的是操作指令,不是项目介绍。
1.2 Context 治理的本质是筛选信息,不是压缩信息
“Agent Context 治理”这个说法看起来高大上,其实就是回答一个问题:在有限的上下文窗口里,什么东西值得被优先放进去?很多人一听说上下文不够用,第一反应是压缩——把所有信息搞成一段摘要,让 AGENTS.md 尽量短。这是方向性错误。
上下文治理的本质是筛选。你要决定的是哪 10% 的信息必须百分百出现在模型面前,哪 90% 的信息该放在仓库其他位置,等模型真正需要时再去读。AGENTS.md 该承载的是那些“你没说模型就一定会猜错”的关键信息,而不是把项目的边边角角都塞进去。
我拿 README 和 AGENTS.md 做过一个对比,两者定位差异挺明显的:
| 维度 | README | AGENTS.md |
|---|---|---|
| 读者 | 人类开发者 | AI Agent |
| 核心目的 | 让人理解项目、跑起来 | 让 AI 遵守边界、按规则操作 |
| 语气 | 描述、解释 | 命令、约束 |
| 内容偏好 | 功能特性、使用场景 | 技术栈、目录边界、硬性规则 |
| 维护节奏 | 按版本迭代 | 跟着每个翻车现场不断更新 |
| 失效判定 | 人看着别扭 | AI 开始做蠢事 |
理解了这个差异,你才会明白为什么 AGENTS.md 值得单独存在。它不是 README 的补充,不是 .github 模板,而是 AI 辅助开发时代项目里的独立基础设施。
2. 真实项目里的混乱现场:我们为什么开始治理
2.1 项目背景:一个逼着我们正视问题的模拟项目
先说项目背景。我们小组维护一个数据可视化平台,顺手起个代号“模拟项目X”,技术栈大概是 Vue 3 + TypeScript 做前端,Python 负责数据处理接口,再加几个跑定时任务的独立模块。代码量不算巨大,但目录结构复杂,内部还有一套自定义的数据接入规范。
组里七个人都在重度使用 AI 编程助手,日常写页面、改接口、修 bug 都会让 AI 代劳。最初的体验确实爽,但随着项目越来越复杂,AI 表现开始明显下滑。最让人崩溃的是,同一个错误反复出现,这周改了,下周换个会话又给你犯一遍。
我们当时以为问题是“AI 太笨”,后来才慢慢发现,问题出在我们自己身上——我们从没给 AI 提供一个稳定、高质量的项目认知起点。每次它都靠猜来起步,那它每次跑偏的地方也都差不多。
2.2 三个典型的翻车现场
这里记录几个真实发生过的场景,很多团队估计都有类似经历。
第一个翻车现场:AI 改错配置文件。平台有好几个环境配置入口,真正生效的配置文件集中在deploy/config下,而根目录也有一个.env.example,只是一个模板。AI 收到“修改超时时间”的需求后,没有看任何说明,直接改了.env.example里的值,然后信誓旦旦地告诉你已经完成。代码评审的时候才发现,真正的配置一点没动。
第二个翻车现场:在错误的目录里实现功能。当时我们让 AI 在 service 层加一个数据导出的接口函数。正常来说,这个函数应该放在src/services/export/下,结果 AI 一通搜索后,在src/utils/里新建了一个文件,把导出逻辑写在“通用工具”里。功能倒是跑得通,但代码归属完全混乱,后续维护成本直线上升。
第三个翻车现场:忽略团队内部既有工具。项目里其实已经封装了一个内部时间处理函数,专门处理数据平台的时间格式。AI 在实现时间范围筛选时,却自己引入了date-fns,没用内部封装。这个问题在代码评审里被拎出来的时候,AI 还振振有词,觉得自己引入标准库更合理。
这三个场景都指向同一个本质:当 AI 没有接收到项目特有的规则和边界信息时,它会用自己的“平均先验”来补全。而项目恰恰是那个充满特有约定的地方,平均先验必然翻车。
2.3 把问题归类:信息缺失、规则模糊、上下文膨胀
复盘多了之后,我们把问题归成了三类。
第一类是信息缺失。AI 不知道项目的技术栈边界、不知道配置入口在哪、不知道内部工具已经存在。不是它能力不行,是我们从来没给它讲清楚。
第二类是规则模糊。很多团队约定只存在于口头交流、PR 评论或者某个群聊里。人可以靠社交记忆遵守这些约定,AI 完全没有渠道知道。你不写进它肯定能看到的文件,它就只能靠猜。
第三类是上下文膨胀。长会话场景下,对话轮次一多,模型注意力会被各种无关信息稀释。它一开始可能还记得你的约束,聊到后面就彻底忘了。我们后来发现,AGENTS.md 能在一定程度缓解这个问题,因为在长会话里,它相当于一个随时可以回去“重新对齐”的基准点。
这三类问题单独看都不致命,合在一起就会让 AI 辅助开发的效率变得极不稳定。我们决定动手治理,第一步就是从根目录放一个 AGENTS.md 开始。
3. 从文档到基线:AGENTS.md 的内容拆解与编写实操
3.1 我们的第一版:最小可用模型
动手之前我们定了一个原则:不求全,求最小可用。第一版 AGENTS.md 被刻意控制在 80 行以内,能少写就少写。以下是我们当时最终定稿的大纲,现在看依然有参考价值:
# AGENTS.md ## 项目一句话 模拟项目X:数据可视化平台,负责指标接入、报表展示和定时导出。 ## 技术栈白名单 - 前端:Vue 3 + TypeScript + Pinia - 后端:Python + FastAPI - 禁止引入未在 package.json / requirements.txt 中出现过的新库,必须先讨论。 ## 目录地图 - `src/services/`:所有业务接口实现,新增接口函数必须放这里。 - `src/utils/`:仅放与业务无关的通用纯函数,禁止放业务逻辑。 - `deploy/config/`:运行时配置真正读取的目录,修改配置优先看这里。 - 根目录 `.env.example`:只是模板,修改它不会影响任何环境。 ## 常用命令 - 开发:npm run dev - 测试:npm run test - 格式检查:npm run lint - 生成接口文档:npm run gen:docs ## 硬性约束 - 时间处理必须使用 `src/utils/datetime.ts` 内的封装,禁止直接引入第三方日期库。 - 所有外部数据接入必须走 `src/services/ingestion/` 统一的入口。 - 定时任务必须通过调度器注册,禁止在业务代码里自行创建循环线程。 - 新增配置项必须同步修改 `deploy/config` 下对应环境的默认值。 ## 常见陷阱 - 图表联动统一走 store 里的 chart 模块,不要在各页面组件里各自拉取数据。 - 现有接口返回结构里 status 字段是字符串枚举,不是数字,避免类型误判。 - 导出文件名需要遵循既有命名规则:`report_YYYYMMDD_<枚举>.csv`。 ## 工作流提示 - 修改代码前先找到对应目录,确认修改范围。 - 涉及多个模块的改动,先在 AGENTS.md 对应的章节里验证自己的理解。这一版虽然不完美,但已经解决了 80% 的“AI 乱猜”问题。它把项目里最常见的认知盲区一次性摊开,让 AI 第一次具备了相对准确的项目心智。
3.2 每个板块为什么要存在
很多团队写 AGENTS.md 时容易堆砌,写出一堆 AI 根本用不上的废话。我们每个板块都经历了实际验证,留下来的都有明确作用。
技术栈白名单的作用是“防污染”。AI 模型训练数据里充满了各种技术方案,你如果不声明边界,它非常倾向于用自己最熟悉的方案,而不是你这个项目实际使用的方案。在代码评审里看到模型私自引库,基本都是没写白名单。
目录地图的作用是“定边界”。AI 对文件路径的理解纯粹来自上下文里的线索。你不告诉它src/utils不能放业务逻辑,它就真的会把业务代码写进去。这个板块是最直接的防呆设计,建议用显式的“允许/禁止”句式,不要用“建议”“应该”这类软性词。
硬性约束板是全部规则里优先级最高的一档。我们故意和前面的目录地图分开,因为有些规则跨越目录边界,比如时间处理统一封装这件事,它影响任何模块。当 AI 在多个任务之间切换时,这栏内容就是那个“不管什么时候都不能破”的底线。
常见陷阱板是效率利器。里面每一条都来自真实的翻车现场,相当于我们提前把踩坑经验喂给 AI,省得它每次都从头开始试错。后期迭代时,这一栏增长得最快。
实操心得:如果你不确定某条规则该不该写进 AGENTS.md,就问自己一句话:如果我不写,AI 会不会大概率做错?会,就写。不会,就别写,省点上下文空间。
3.3 编写语言:命令式、可验证、不留模糊地带
这部分是最大的坑。一开始我们写“请保持代码清晰”“不要破坏既有结构”,结果一点用都没有。原因也很简单,这些说法根本没有可验证的边界,AI 无法判断自己什么时候算“清晰”,什么时候算“破坏”。
后来我们摸索出一套写法,核心就三个要点。第一,用命令式语气,直接给指令。“必须”“禁止”“唯一入口”这类词汇可以放开用,它们不会冒犯 AI,只会让规则更清晰。
第二,让规则能落地验证。比如我们不写“保持良好架构”,而是写“新增业务接口函数必须放在 src/services 对应模块下”。AI 写代码时很容易检查自己有没有遵守这条规则,约束力自然就强。
第三,不给模糊地带留空间。如果某个选择你们已经定了,直接写死。之前我们在缓存方案上举棋不定,AGENTS.md 里写了一堆“可以考虑用 XXX 或 YYY”,结果 AI 每次选得都不一样,还自以为做了技术选型。后来改成“缓存统一使用 Redis,键规范为 projectX:模块:业务键”,世界安静了。
我们后来整理了一份正反例对照,这里分享几个最典型的:
| 错误写法(模糊) | 正确写法(可验证) |
|---|---|
| 请保持项目整洁 | 新增功能代码必须放到 src/services 对应模块,禁止堆在 utils |
| 尽量使用现有组件 | UI 组件优先使用 src/components/ui 下的封装,禁止在页面里直接引第三方组件库 |
| 注意处理异常 | 所有对外接口必须捕获异常并返回标准结构{code, message, data} |
| 性能要好 | 列表页数据超过 500 条时,必须走分页查询,禁止一次性拉全量 |
这套话术,基本可以用到所有 AGENTS.md 里,区别只是具体约束内容不同。
4. 让 AGENTS.md 真正生效的四个迭代技巧
4.1 让规则可被验证,而不是可被感受
第一部分提到了可验证原则,这里展开讲一个具体做法:给规则配备“检查动作”。每条规则最好都能对应到一次搜索、一次命令或一次代码定位,AI 可以先执行检查动作,再判断当前操作是否合规。
举个例子。我们有一条规则是“所有数据接入必须走 ingestion 统一入口”,为了让 AI 更容易验证,我们补了一句:“新增接入时,先搜索register_ingestion确认入口函数签名”。这句话不是规则本身,而是给 AI 一条自查路径,它照着做就不容易出错。
还有一条是“禁止手动创建循环线程执行定时任务”。为了让 AI 能验证,我们写了:“定时任务必须通过src/scheduler/中的注册函数添加,修改前先查看scheduler/README.md”。AI 找到 README 后自然能看到正确用法。
这就是我们后来总结的一个原则:AGENTS.md 里的规则,要让 AI 有办法“执行前自查”,而不是只凭感觉干活。规则越具体,AI 越不容易假装自己懂了。
4.2 守住上下文预算:AGENTS.md 本身不能太长
AGENTS.md 存在的作用是管理上下文,但它自己也在消费上下文。如果一份 AGENTS.md 写了两千行,模型要么来不及读完,要么读到一半就忘了前面,反而制造新的信息干扰。
我们给自己定了一个很朴素的预算:AGENTS.md 主文件控制在 80 到 120 行之间。超过这个范围,就会触发我们的“内容迁移流程”,把某个板块细拆到独立文件里,在主文件里只留一句“如需深入,先读 docs/agents/xxx.md”。
我们的预算分配经验大致是这样:
- 全局硬性约束:25% 篇幅,这部分最重要,必须留在主文件。
- 目录地图与边界:20% 篇幅,防止 AI 乱跑。
- 常用命令与工作流:15% 篇幅,保证基本操作正确。
- 常见陷阱与内部约定:25% 篇幅,提前避坑。
- 其他说明与链接:15% 篇幅,作为补充索引。
这个比例不是严格的,但思路是对的:把所有内容分成“必须在主文件”和“可以外链”两类,别让主文件变成信息垃圾桶。上下文是一种稀缺资源,你在 AGENTS.md 里多写一行废话,AI 在处理真实任务时就多一分分心的可能。
4.3 像维护代码一样维护 AGENTS.md
AGENTS.md 是活文档,但它不能“活得太随意”。我们接手项目三个月后,AGENTS.md 已经积累了不少过时内容,最典型的是技术栈白名单里写着“暂不使用状态管理库”,可项目早就引入了 Pinia。AI 基于过时信息干活,效果比没有 AGENTS.md 还糟糕。
从那以后,我们把 AGENTS.md 纳入严格的版本管理。具体做法很简单:所有修改都走 PR,和普通代码一起评审。改动说明必须写明原因,是哪个翻车场景推动了这次修改。废弃的规则直接删除,不保留什么“历史说明”区块。旧版本信息留在 git 历史里就够了,没必要在文档里继续占空间。
这个习惯带来的额外好处是,代码评审时大家会顺便看看 AGENTS.md 的变化,团队共识因此不断被强化。以前约定只存在于某个人的脑子里,现在所有规则都有一份明确的集体快照。
4.4 用会话日志反推改写:从哪里找规则素材
AGENTS.md 最大的素材来源,其实是你和 AI 的纠偏对话。每次你在对话里纠正 AI,说“不对,这里应该走 XXX”,那都是一条潜在的 AGENTS.md 规则。
我们后来养成了一个习惯:周一早上花二十分钟,把上一周 AI 会话里所有“纠偏”记录下来。不看技术细节,只看重复出现的类型。如果某个纠正出现了三次以上,它就不再是偶然问题,而是系统缺陷,必须写进 AGENTS.md。
举例来说,项目里的空值处理一度反复出问题。AI 经常默认字段一定有值,导致统计数据异常。我们第一次发现后修了 bug,第二次又犯,第三次还在犯。有一次 PR 评审里有人扔了一句“空值处理必须先看 schema 默认值”,这句话后来被我们原封不动地写进了 AGENTS.md 的常见陷阱区。从那以后,这个问题基本绝迹。
这个方法的关键是把“人的口头纠正”变成“机器的默认前提”。你的团队越依赖 AI,越该建立这个反馈闭环。
5. 常见问题与排查技巧实录
5.1 常见问题速查表
下面是我们团队在实践过程中整理的一份速查表,适用于大多数已经引入 AI 辅助开发的项目:
| 问题现象 | 可能原因 | 排查思路与解决动作 |
|---|---|---|
| AI 完全不理会 AGENTS.md 里的规则 | 工具版本不支持,或文件位置不对 | 确认工具文档支持哪个文件名,大多数情况要求放在仓库根目录;检查文件大小是否超过读取限制 |
| 上下文窗口依然容易溢出 | 会话里贴了太多代码全文 | 把“贴代码”改成“引路径+问题描述”;并检查 AGENTS.md 是否塞入了可外链的冗余内容 |
| 新旧规则冲突,AI 行为飘忽 | 规则增删没有清理旧描述 | 打开 AGENTS.md 通读一遍,删除所有互相矛盾的表述;约定冲突时必须保留最新且最强约束 |
| AGENTS.md 写了不生效,AI 自己另搞一套 | 规则表述过于模糊 | 把“应该”“尽量”改成“必须”“禁止”;给每条规则配上检查动作 |
| AI 改 A 模块时受 B 模块规则干扰 | 主文件上下文太杂 | 拆分局部规则到子目录的 AGENTS.md,主文件只留跨模块的全局约束 |
| 多语言/多端项目,规则相互打架 | 目录归属混乱 | 按模块拆分 docs/agents/,并明确“改前端代码前只读前端相关章节” |
这张表不是一次性整理完的,每一条背后都有过一次真实的痛苦经历。建议团队在落地 AGENTS.md 时,把“问题台账”顺手维护起来,比临时回忆靠谱得多。
5.2 一次真实调试过程:从翻车到规则落地
拿我们前面提到过的图表联动问题来复盘一下。当时的任务是:给平台某个报表页的图表增加联动筛选功能。合理范围是只改一个页面组件和对应 store 模块,两三个文件就够。
AI 第一次动手时,直接跑去把所有 page 目录下的数据获取逻辑都改了一遍,因为它“推测”联动应该全局生效。结果几个不相关的页面全被牵扯,代码评审直接红了脸。我们第一反应是骂工具不行,冷静下来后,发现真正的问题是 AI 根本不知道“图表联动统一走 store 的 chart 模块”这个约定。
这个约定此前只存在于一次会议讨论中,没有任何文档记录。于是我们做了一次标准动作。第一步,打开 AGENTS.md,在“常见陷阱”区加了一条:图表联动统一走 store 里的 chart 模块,不要在页面组件里各自拉取数据。第二步,在目录地图里标出src/store/chart.ts,注明这是图表状态的唯一入口。第三步,加了一个可验证提示:接手图表相关任务时,先搜索useChartStore确认当前状态管理方式。
改完后我们做了同样的任务测试。AI 这次的改动范围收敛到了两个模块:store 更新一个文件,页面组件调整一个文件,和我们预期完全一致。同类任务后续连续测试几次,都没有再复发这个问题。这个案例给我的启发是:很多“AI 能力不行”的结论,其实都是“项目上下文缺失”的误判。
5.3 排查时要有的心态
AGENTS.md 的维护不是一次性能做完的,它像一个规则搜索引擎,需要持续收录新的边界和新陷阱。我们在排查过程中最大的切身体会就是:别指望一次改到位,特别是团队较大、AI 使用场景较杂时,每两周固定做一次“规则体检”是合理频率。
另外,规则加多了之后,评估机制也要跟上。我们后来每季度会做一次小测试:随机挑三四个常见任务,让 AI 从零开始做一遍,观察它是否主动遵守 AGENTS.md 里的约束。这个测试成本很低,但能帮你发现哪些规则已经被 AI 内化,哪些规则只是躺在文件里当摆设。
6. 更进一步:分治、分工与 AGENTS.md 的边界
6.1 用 docs/agents/ 做内容分治
当项目规模变大,单一 AGENTS.md 支撑不住所有信息时,不需要硬撑。我们的做法是在仓库里建一个docs/agents/目录,按模块拆分布局规则。
根目录 AGENTS.md 只保留全局约定:技术栈基线、跨模块硬性约束、全局命令和工作流提示。每个重点模块各放一个独立 AGENTS.md,比如:
docs/agents/ frontend.md # 前端模块规则,UI 组件边界 backend.md # 服务端规则,接口规范 ingestion.md # 数据接入规则 deploy.md # 部署与配置规则根目录 AGENTS.md 负责“路由”,写清楚类似这样的句子:“当你需要修改前端页面时,先读 docs/agents/frontend.md;当你处理数据接入时,先读 docs/agents/ingestion.md”。这样 AI 在打开会话时,先建立全局框架,等到具体任务时再按需加载对应子规则。
这种分治的核心价值,是让上下文更贴近任务本身。一个专门改前端页面的 AI 会话,不需要知道部署模块的完整细节。信息越聚焦,AI 的决策质量越高。实测下来,同样的任务在分治前后,回答的稳定性差距非常明显。
6.2 和其他项目文档的分工协作
很多人问 AGENTS.md 和 README、CONTRIBUTING 的关系。我们的分工原则是:README 对外讲故事,说明项目为什么存在、能解决什么问题;CONTRIBUTING 面向人类贡献者,说明提交流程和代码评审规范;AGENTS.md 面向 AI,说明操作边界和硬性约束。
三者会有少量重叠,但定位必须清晰。如果一份文档既想当 README 又想当 AGENTS.md,往往两个角色都当不好。AI 会花大量上下文去理解项目历史和愿景,却没记住最该遵守的边界规则。
要特别注意,AGENTS.md 不要写“历史上我们曾经……”,也不要写“未来我们打算……”。它只关心一个问题:此刻,在这个仓库里,AI 该怎么正确地工作。凡是不能直接指导当前操作的句子,都属于多余内容。
6.3 一个诚实的提醒:AGENTS.md 不是银弹
写了这么多实操,我得诚实说一句:AGENTS.md 不是银弹,它有自己的边界。
它解决的是“信息缺失”问题,但解决不了“模型遵循能力不足”的问题。如果AI工具本身不读取这个文件,或者模型对长文指令的理解能力有限,AGENTS.md 写得再好也是白搭。好在我们用的主流 AI 编程工具基本都兼容这个约定,而且会持续支持,在这个生态里投入是值得的。
另一个边界是:规则过时会带歪 Agent,甚至比没有规则更危险。我们踩过一次,技术栈白名单里旧条目没清理,AI 坚持使用一个我们早就废弃的库,因为它认为“AGENTS.md 说的”就是权威。从那以后,我们把 AGENTS.md 的定期清理看成和写代码一样重要的任务。
总结下来,AGENTS.md 的本质,是把团队的隐性知识显性化,再把它放到 AI 的视野内。这是一个持续投入、持续修正的过程,不需要一次性做到完美,但一定要开始做,并且持续做下去。
最后说一点我个人在实际操作里的感受。AGENTS.md 没有改变我们团队使用 AI 的方式,但它改变了我们对“上下文”的理解。以前我担心的是会话太长、模型太笨,现在我会换一个角度想问题:如果明天这个会话从零开始,它还能不能做出和今天一样的决定?如果能,说明项目上下文已经被治理好了;如果不能,那就把那条缺失的规则写进 AGENTS.md。每多写一条,AI 就少一次自由发挥,项目就多一分稳定。如果你读完也想试试,建议只做一个小动作:挑一个最常让 AI 出错的目录,写五行动态规则放进去。你会发现,同样的任务,AI 的表现会有非常直接的改变。