最早看到 AGENTS.md 这个概念时,我的第一反应是:项目里已经有 README 了,这玩意儿是不是重复造轮子?但被 AI 编码助手连续坑了几次之后,我彻底改了想法。你让一个 agent 在完全不熟悉的老项目里加功能,它表现好与坏,很多时候就差一份“写给 AI 看的操作说明”。AGENTS.md 干的就是这件事——用极短篇幅告诉 AI:项目结构是怎么组织的、哪些命令是权威的、哪些目录绝对不能碰、代码风格和提交流程是什么。这篇文章我来讲讲 AGENTS.md 的写法参考,包括一份可以直接改来用的模板、三个我踩过坑才总结出的底层原则,以及实测下来最容易掉进去的坑。适合两类人:被 AI 改代码改到脑溢血的个人开发者,以及想给团队建立 AI 协作规范的技术负责人。
1. 为什么要写 AGENTS.md:先弄明白它解决什么问题
1.1 没有规则约束时,AI agent 的表现有多飘
我自己最早遇到的问题是“AI 每次都能把任务做完,但每次都用不同的方式做完”。比如在一个用 pnpm workspace 搭起来的 monorepo 里,AI 可能跑出npm install,然后把 lockfile 搞乱;它能找到测试文件,却用全局 jest 命令去执行,结果跑了半天报一堆环境错误;更离谱的是,它在改一个核心模块时,顺手把生成目录里的文件也重构了一遍,那些文件下次生成时瞬间被覆盖,改动全部白费。其实模型本身的能力并不差,问题在于它缺少“项目上下文”,只能靠猜。你人在团队里待久了,会自然知道“这个仓库的测试统一走pnpm test”“那个src/pkg/legacy是历史包袱不要动”,但 AI 不知道,因为没有任何地方把这些默契写下来。
后来我在项目根目录放了一份 AGENTS.md,把这类“我以为大家都知道”的约束写进去。效果非常直接:AI 第一次跑命令就是pnpm test,不会再自己发明一个;它生成的 PR 描述里也明确写了“未修改 generated 目录”。项目里少了以前那种“看起来合理、实际上违反约定”的改动。所以 AGENTS.md 不是给人看的文档,而是给 agent 的“入职手册”。与其反复在 prompt 里交代项目背景,不如把它沉淀成文件,让每一次新会话都能拿到同样的上下文。你写一次,所有未来的对话都受益,这是投入产出比非常高的一件事。
1.2 它和 README、CLAUDE.md、.cursorrules 的区别
很多人问:README 和 AGENTS.md 能不能合并?我的建议是最好不要。两者读者和写作逻辑完全不同。README 是给别人看的,讲究项目介绍、安装方式、API 示例,它要回答“这是什么”;AGENTS.md 是给模型看的,讲究作业规则、操作边界、执行流程,它要回答“在这里干活要注意什么”。人类读 README 能忍受大量背景介绍,模型读冗余文档时反而容易被稀释重点。你把一堆技术栈历史和设计缘起塞给 AI,它可能记不住最关键的几条操作指令。
如果你在 AI 相关工具链里待过,还会看到 CLAUDE.md、.cursorrules 之类的名字。严格来说,这些文件各有归属:CLAUDE.md 是 Claude Code 默认会读的项目指令文件,.cursorrules 是早期 Cursor 常用的一种规则文件。而 AGENTS.md 更像是社区慢慢形成的一个通用约定:越来越多的工具会把根目录下叫 AGENTS.md 的文件塞进上下文,位置和作用类似.gitignore之于 git。我在自己的仓库里是这么处理的:保留完整 README 给人类,在根目录放 AGENTS.md,然后再放一份很短的 CLAUDE.md,内容只写一句“请先看根目录 AGENTS.md”。这样无论 agent 优先认哪个文件,都不会迷路。
1.3 什么时候写最划算
这个问题我踩过坑,答案是“越早越好,但任何时候补都值得”。新项目在首日写,大概 20 分钟就能完成,之后每个成员和每个 AI 会话都自动继承这些约定;老项目补写则像是给过去的事故做复盘。你先想一想近三个月里,AI 或新手同事在哪些地方最常出错,把那些“坑”直接变成规则。比如“不要改动src/db/migrations目录下的历史迁移文件”“修改 API 前先更新相关 OpenAPI 文档”,这类规则只有经历过问题才知道价值,写下来比口头强调管用得多。
另外,如果你的仓库规模很小、只有一两个文件,AGENTS.md 的意义确实不大;但如果项目有几十个文件、有特殊构建脚本、或者你同时会用好几个 AI 工具,那就非常值得写。我现在的判断标准很简单:如果过去一周里,我至少有一次因为 AI 乱跑命令或者改错文件而浪费时间,我就该把对应的教训写进 AGENTS.md。文件不是摆设,它是你和 AI 之间的“协作契约”。
2. 我写 AGENTS.md 遵守的三条底层原则
2.1 用“任务视角”而不是“文档视角”写
刚开始写 AGENTS.md 时,我犯过一个典型错误:把它写成了 README 的精简版——“本项目是一个订单系统,使用 React + Node.js,目录结构如下……”AI 读了当然没坏处,但也没多大帮助。真正起作用的写法是任务视角,也就是每条都直接告诉模型:当你做什么事时,必须怎样做,禁止怎样做。比如:
当你要新增一个 API 接口时,必须先运行
pnpm gen:api生成类型,再编写实现代码;禁止手写src/api/generated里的文件。
这句话里包含触发条件、操作顺序、禁止事项,模型不需要再推理。反观“请保持良好的代码风格”这种话,没有任何可执行性。我的经验是:每写一条规则前,问自己两个问题——这条规则能防止什么具体错误?模型在什么场景下会触发它?如果答不上来,就不要写。规则写得越贴近真实任务,模型遵守的概率越高。
为什么任务视角这么重要?因为大模型对“指令性语言”的遵循程度远好于“描述性语言”。描述说“项目里有一些生成文件,在 public/generated 下”,模型可能并不会意识到“不能改”;指令说“永远不要修改 public/generated 下的文件,它是构建脚本自动生成的”,模型则容易把这句话内化成一个硬编码约束。同一个意思,换一种说法,效果完全不一样。所以 AGENTS.md 里应该尽量充斥着“当…时”“必须…”“禁止…”,而不是“该项目…”“可以看到…”。
2.2 命令和文件路径永远写具体,不要给模型留太多自由发挥余地
第二个原则来自我的血泪教训:命令必须给到“在项目根目录执行pnpm test -- --watch=false”,而不是“运行测试”。文件路径最好精确到文件名或目录名,而不是“服务端代码在 server 目录”。原因很简单:模型不是人,它不会因为大概知道目录结构就真的去验证;它会基于 token 概率生成一个“看起来正确”的命令。你用npm test还是pnpm test,它没法从代码里直接悟出来,尤其是在 lockfile 和脚本写得比较随意的项目里。
具体命令还能防止另一类问题:AI 自作主张安装新依赖。我见过它为了一个很小的功能,顺手装了 moment.js,只因为它“觉得方便”。如果 AGENTS.md 里有一句“新增第三方依赖前必须停下来询问用户,并且说明替代方案”,这类事情基本可以杜绝。路径同理:写清“业务代码在src/modules,不要改src/legacy”,模型就不会把你十年前的老代码一起重构了。
注意,命令写具体也并不意味着永远不变。package.json 里的脚本改了,AGENTS.md 也要跟着改,所以我在文件头部放了“最后更新日期”,并在代码审查时留意规则是否已经过期。你可以把 AGENTS.md 当成一段需要持续维护的配置代码,而不只是一篇写一次就完事的文章。
2.3 每条规则要能被“打勾”,少用形容词,多用清单
最后一条原则和写测试很像:能验证的规则才是有用的规则。AGENTS.md 里的每一句话,最好都能被人工或脚本判断“遵守了 / 违反了”,而不是靠感觉。比如:
- 不要写“代码要整洁”,要写“新增的组件必须放在
src/components/ui/下,并在src/components/index.ts中导出”。 - 不要写“注意性能”,要写“在
orders这类高频接口中,禁止在循环内调用await”。 - 不要写“测试要覆盖全面”,要写“任何修改
src/services的 PR,必须附带对应单元测试,运行pnpm test -- src/services通过”。
这种用肯定清单和否定清单组织的规则,模型理解成本最低,也方便你检查它有没有照做。我在文件末尾专门放了一个 “Definition of Done” 小节,列出了 PR 提交前必须跑的命令和必须满足的条件。AI 每次完成一个任务后,会自己对照这个清单检查一遍,相当于给模型装了一个内置的自检程序。规则就是给模型划的边界,边界越清晰,它越不会在“觉得差不多”的时候偷懒。
3. 手把手拆解一份可以直接用的 AGENTS.md 模板
3.1 文件头部:让 agent 知道“这是你的操作手册”
一份合格的 AGENTS.md 不需要太长,但头部一定要清楚。我习惯在最开始用 front matter 式的几行元信息:项目名、项目一句话简介、适用 agent 范围、版本号和最后更新时间。这样模型即使只读到前半段,也能立刻知道这个文件的定位。头部之后,紧跟着一句强指令:“在开始任何代码修改前,阅读本文件并务必遵守。” 这句话不是摆设,很多模型只有在被明确要求“先读”时,才会把文件内容当成最高优先级。
实际模板头部长这样:
--- name: myapp description: 订单中台服务,提供 REST API 和后台管理界面 scope: all agents version: 2025.06.01 --- # AGENTS.md 在开始任何代码修改前,你必须先完成以下两件事: 1. 阅读本文件全部内容 2. 在你的回答开头列出本次遵守的关键规则,再开始实现 若本文件与 README 或其他文档冲突,一切以本文件为准。别小看最后一行“冲突时以本文件为准”,实测非常有用。模型同时读到 README 和 AGENTS.md 时,经常会把 README 里已经过时的命令当成准则;加上这一句后,它的偏好会明显转向 AGENTS.md。如果你们仓库里还有 CLAUDE.md,可以让 CLAUDE.md 只写一行“按根目录 AGENTS.md 执行”,避免两套规则互相打架。
3.2 项目速览与目录导航:用 10 行内建立“地图”
这部分不需要长篇大论,你的目标是让 agent 拿到一个“目录地图”,尤其要标出哪些目录是核心、哪些是生成品、哪些禁止改动。很多老项目的目录结构并不直观,AI 进去往往会迷失,比如分不清src/client和src/admin到底哪个是哪个。我会这样写:
## 项目结构 - `src/api`:REST API 路由和校验逻辑,新增接口必须到这里注册 - `src/services`:业务核心,修改必须带单元测试 - `src/db`:数据库访问层;`src/db/migrations` 是历史迁移文件,禁止修改 - `web/`:前端管理台,内部包含 `src/components/ui` 基础组件 - `scripts/`:运维脚本,不可被业务代码直接调用 - `generated/`:由代码生成器产出,**任何情况下不要手工修改**好的地图不是把所有目录都列出来,而是只列“模型最可能搞错”的目录。所以请克制,一般 5 到 10 行就够。再长的项目结构,可以单独写进docs/architecture.md,在 AGENTS.md 里放一个链接就行。你要记住,AGENTS.md 是操作手册,不是架构文档。
3.3 命令与工具约定:把“实际执行的命令”钉死
这一节是避免认知差异的核心。我曾见过 AI 在 monorepo 里用错了包管理器,把整个 workspace 状态搞坏,最后只能重新 clone。所以项目里用哪些命令,必须清清楚楚列出来:
## 常用命令 所有命令请在仓库根目录执行: - 安装依赖:`pnpm install`(首次克隆后执行) - 启动开发服务:`pnpm dev` - 构建:`pnpm build` - 测试:`pnpm test`(禁止使用 `npm test` 或 `yarn test`) - 单测指定模块:`pnpm test -- src/services/order` - 类型检查:`pnpm typecheck` - Lint:`pnpm lint` - API 类型生成:`pnpm gen:api` 新增依赖时:优先使用 `pnpm add`,不要直接修改 package.json;在添加任何新的第三方依赖前,先向用户说明理由并等待确认。这一节能显著减少 AI 的“工具幻觉”。另外,如果项目里有一些特殊流程,比如“修改接口前先跑 mock 服务”“提交前必须更新 changelog”,也在这里写清楚,避免每次都在 prompt 里重复交代。给 AI 的命令越固定,它的产出就越一致,这是团队协作里最值钱的东西。
3.4 编码规范与架构约束:把团队规则翻译成模型能执行的条款
编码规范不要从零开始抄大厂的 style guide,那毫无意义。你只需要提炼项目里真正“易于违反且后果严重”的规范,用条款形式列出来。以下是我一个中型 Node.js 项目里的示例片段:
## 编码与架构约束 - 文件命名:组件文件 `PascalCase.tsx`,工具函数文件 `camelCase.ts` - 导入顺序:内置模块 -> 第三方依赖 -> `@/` 别名 -> 相对路径,每组之间空一行 - 禁止使用 `any`;如果必须使用,请用 `unknown` 并在 20 行内收窄类型 - 所有对外 API 必须先用 `zod` 定义 schema,再通过 `createHandler` 注册;禁止直接用 `req.body` 取数据 - 业务逻辑只允许放在 `src/services`,路由文件里不允许写具体业务处理 - 组件样式统一用 Tailwind 原子类;需要复用的颜色一律走 `theme.ts`,禁止硬编码色值 - 新增文件必须导出并在对应 `index.ts` 里补充,禁止让模块成为不可达代码 - 错误统一通过 `AppError` 抛出,禁止在中间件里捕获后“假装成功”这些条款看起来很细,但每条背后基本都有一次线上事故或一次 code review 冲突。如果你一次性写 50 条,模型记不住,团队也维护不过来;我建议起步时只挑最重要、最容易出错的 8 到 12 条,运行一段时间后根据实际问题再加。规范不是越多越好,而是越准越好。
3.5 工作流协议:从“收到任务”到“提交 PR”的标准动作
最后也是我觉得最容易被忽略的部分,是定义完整的工作流。没有工作流,AI 往往会直接上手改代码,改完就跑,既不搜索现有实现,也不跑测试。你需要给它一个可执行的流程:
## 工作流 1. 接到需求后,先阅读相关模块的 README / 设计文档,并在回答中概括你的理解 2. 在仓库中全局搜索现有实现,复用已有代码;禁止复制粘贴其他文件中的功能重造新文件 3. 实现前先运行 `pnpm test`,确认基准测试是绿的 4. 按“小步提交”原则修改代码,每次改动增量尽量小 5. 实现完成后运行 `pnpm lint`、`pnpm typecheck`、`pnpm test` 6. 需要更新文档时,同步更新 README 和 AGENTS.md 相关描述 7. 提交信息格式:`<type>(<scope>): <subject>`,例如 `feat(order): add batch query API`这个流程的价值在于,它把“负责任工程师”的默认行为写成了显式协议。你不需要每轮对话都重新解释一遍,agent 自己就会照着走。我在实际使用中,配合“回答开头列出关键规则”的要求,基本能保证它在动手前先想清楚,而不是急着输出代码。工作流就是让 AI 的行为变得可预测,你越早给它框架,它越少给你“惊喜”。
4. 实测中的高频问题与排查心得
4.1 为什么 AI 总是不读 AGENTS.md
如果你发现写了 AGENTS.md 但 AI 根本不鸟你,先别怪模型,大概率是这几个原因:工具没有把根目录 AGENTS.md 自动加载进上下文;或者文件太长,被模型的上下文窗口截断了;又或者你的 prompt 里有和 AGENTS.md 冲突的指令,模型更倾向于听临时的指令。
排查顺序我建议这样走。第一步,查看你用的工具的规则加载机制。不同工具偏好不同,有些默认读 CLAUDE.md,有些读 .cursorrules,有些读 AGENTS.md;最稳妥的办法是搞一个“入口文件”策略,比如在 CLAUDE.md 里写“阅读根目录 AGENTS.md”,在 Cursor 的 User Rules 里也加同样一句。第二步,看文件长度。我把超过 300 行的 AGENTS.md 拆掉之后,模型遵守率明显提高。第三步,修改开场指令,第一句就变成“先读根目录 AGENTS.md 并遵守,这是最高优先级”。
有一个我自测有效的小技巧:在每个任务 prompt 结尾加一句“在动手前,先列出你将从 AGENTS.md 应用的 3 条规则”。这样模型会主动去翻文件,而且你能从它的回答里判断它到底读没读。如果它列出的三条和文件内容完全不沾边,那就是加载机制出了问题,赶紧去查工具的 rule 配置,别在 prompt 里一条条重复项目背景。
4.2 规则冲突时,AI 为什么总是选老路走
第二种高频问题是:AGENTS.md 里明明写了“禁止修改 generated”,AI 还是改了;或者更新了规则后,它仍旧用旧规则。这里有两个原因:一是模型上下文中可能存在多个版本的指令,临时 prompt 的优先级往往高于静态文件,所以需要把 AGENTS.md 的规则也写进工具层的全局规则,保证一致性;二是新旧信息打架时,模型有时会依据训练记忆中的常见模式行动,而不是依据你文件里个性化的说明。
解决冲突,我惯用的办法是“显式宣告优先级”。在 AGENTS.md 开头写清楚“若本文件与其他文档冲突,以本文件为准;若子目录规则与本文件冲突,更具体的文件优先。”同时,给文件加版本号。遇到 AI 仍用旧规则,我会直接追问一句“AGENTS.md 当前版本是 2025.06.01,你遵守了其中哪几条?”它往往会重新读取版本信息,很多情况下问题当场消失。别小看这种“逼它自证”的提问,这比反复强调规则内容更有效。
4.3 文件越来越长,最后变成没人看的“摆设”
AGENTS.md 最大的风险是膨胀。一开始你觉得每条规则都很重要,往里越塞越多,半年后几百行,模型读不进去,人也懒得维护。我自己的处理办法是“每条规则必须有事故或 review 记录背书”。新规则想进来,必须能回答:过去三个月里,模型或人在哪里因为缺少这条规则而犯了错?答不上来就不写。定期大约每季度过一遍,删掉那些已经内化成常识的规则,比如“禁止直接 push 到 main”这种不需要告诉 AI 也大概率不会犯的。
另外,规则要分层。长篇幅的背景知识、架构设计、代码规范细则,不应该占用 AGENTS.md 的篇幅,可以放到docs/ai/下,由 AGENTS.md 给出链接。模型需要的时候会去查,而不是每次都把几百行加载进来。这个思路和“头部只放最紧急指令”的做法一脉相承:AGENTS.md 是操作手册,不是百科全书。文件一旦超过 250 行,我就开始怀疑它是不是该拆了。
5. 进阶玩法:多文件拆分、自动化校验与团队协作
5.1 全局规则与局部规则如何搭配
项目复杂后,一个根目录 AGENTS.md 可能不够用。我常用的做法是:根文件放通用规则,子目录再放局部 AGENTS.md,只描述该目录的专属约束。比如src/legacy/AGENTS.md里写“这个目录是旧系统迁移代码,禁止重构,只允许做 bugfix”,而src/api/AGENTS.md里写“所有新接口必须附带 OpenAPI schema 注释”。模型进入对应目录时会读取更具体的规则,相当于把上下文按需喂给它,比什么都塞在根文件里高效得多。
需要注意的是,子目录规则不能和根文件冲突。如果根文件说“统一使用 pnpm”,子目录就不能写“这个目录请用 npm”,否则模型会陷入矛盾。我在子目录文件里会主动声明“本文件是根 AGENTS.md 的补充,未提及的内容遵循根文件”。这种分层约定一开始可能觉得麻烦,但项目维护时间一长,你会发现它帮你省掉了大量“为什么 AI 在这里用了另一套风格”的困惑。
5.2 让 AGENTS.md 可以被脚本校验
既然 AGENTS.md 是给模型强约束的规则文件,它自己最好也能被校验,免得语句和实际命令脱节。我现在会在 CI 里加一个很轻量的脚本,检查三类事情:文件里出现的命令是否存在于 package.json 的 scripts 中;文件里提到的目录是否真实存在;文件是否超过建议的长度。脚本逻辑很简单,比如用 Node.js 读文件,正则提取pnpm [a-z:-]+,去 package.json 的 scripts 里匹配;再统计文件行数,超过 250 行就报警。这个检查不阻塞发布,只是给维护者一个提醒,避免 AGENTS.md 慢慢“腐烂”。
如果你不想在 CI 里加脚本,还有一个更轻量的替代方案:在文件头部手动维护“更新日期”和“适用版本”,每次改 package.json 脚本后,顺手搜索 AGENTS.md 里的对应命令,全局替换并更新日期。习惯一旦养成,文件的生命力会强很多。我一直觉得,AGENTS.md 和代码一样,需要“编译期检查”和“运行时维护”,只写不维护,三个月后就是一堆没人信的废话。
5.3 团队协作:把 AGENTS.md 当成一等公民来 review
最后一个建议,是把 AGENTS.md 当作代码一样看待,而不是“顺便改改的文档”。我所在的团队现在要求:任何修改 AGENTS.md 的 PR,必须有至少一个同事 review,并且描述里写清楚“这条规则是为了解决什么问题”。刚开始会被吐槽“过于仪式化”,但真实执行下来,反而帮大家统一了对项目边界的认知。新同事入职时,我直接把 AGENTS.md 丢给他,比讲半小时文档还有效。
版本管理方面,我用 git 历史就够了;AGENTS.md 的变更记录不追求花哨,只要每次 commit message 写清楚“rules: forbid modifying generated files”之类的描述即可。另外,如果你同时维护多个仓库,可以把公共规范抽成一份 base 文件,用“include”的方式引用;但我个人更推荐先复制到各仓库里,等规范稳定后再做统一维护,否则模型读取 include 文件时往往没有本地文件那么可靠。毕竟对模型来说,你放在它手边的文件才是它最愿意读的文件。
我个人在实际操作中的体会是,AGENTS.md 的写法并没有标准答案,它更像是一份活的“项目协作协议”。你写它的过程,同时也是在替团队梳理那些“说了很多遍但没人记下来”的规矩。即使未来 AI 工具换了又换,只要这份文件还在,新工具也能很快融入你的项目节奏。如果今天你只做一个动作,我建议花 30 分钟把“常用命令 + 不能碰的目录 + 提交流程”这三样写进根目录的 AGENTS.md,然后随便找个小任务让 agent 跑一遍。你会立刻发现,以前那些灵异操作,瞬间少了很多。