我们在用 AI 写代码时,为什么建议要好好维护 AGENTS.md 呢?

前言

现在很多公司都全面推行使用 ai 辅助开发项目了,我们公司现在就是全员 ai 辅助开发。公司给了每个月固定的额度来让我们使用。

但是我发现很多同事在使用 ai 工具比如 codex进行开发的过程中,基本上都是这两种方式:

要么是直接打开对话框,进入裸对话模式提需求。 或者有一定 ai 了解的,会用下内置命令 /init 做项目初始化,但也就到此为止了,就好像只是给项目写了个 README 项目说明文档一样。

然后开发过程中就很容易遇到各种问题:

比如 agent 不按规范设计,总是忘测试验证步骤,甚至会随意修改文件、删除文件。有些重复性的提示,每次都得重新说一遍,然后导致上下文窗口越来越臃肿。结果做出来不仅 bug 多,还得返工修改导致每个月公司给的 token 额度根本不够用。

很多同事觉得是因为使用的模型不对导致的原因。 虽然说模型选择确实有一定的影响,但我觉得很大一部分原因是没有把 AGENTS.md 这个文件真正去合理运用管理起来。

所以这里我按自己个人的使用理解,把这几个问题简单说明一下,AGENTS.md 到底是干嘛的,它怎么被 agent 用起来,/init 又解决了哪些问题,以及为什么生成以后我们还要继续维护。


首先AGENTS.md 到底是什么呢?

在讲 /init 之前,我还是要先把 AGENTS.md 再简单理解一下。

AGENTS.md 是个开放标准 这里我们看官方的介绍就知道了 AGENTS.md

简单来说我们可以把AGENTS.md 视为代理的 README:一个专门的、可预测的地方,用于提供上下文和说明,以帮助 AI 编码代理在我们的项目中工作。

它支持的工具包括 OpenAI Codex、GitHub Copilot、Cursor、Aider、Zed、JetBrains、Claude Code 等等。

可以说一份文件,我们就可以在多个 Agent 里面通用。

一个非常简单的 AGENTS.md 大概是这样的

go 复制代码
`# 项目规则`

`## 构建和测试`
`- 构建:npm run build`
`- 测试:npm test`
`- 格式化:npm run lint`

`## 编码规范`
`- api 入参统一用 XxxParams 命名`
`- 响应统一用 XxxResponse 包装`
`- 不要用 console.log,统一用 logger`

`## 禁止事项`
`- 不要手动修改 generated/ 目录`
`- 不要提交 .env 文件`
`- 不要往 packages/core 添加新依赖`

`## 联动规则`
`- 改了 api 接口,同步更新 docs/api.md 和对应测试`
`- 改了命令入口,同步 src/cli.ts + 测试 + README`

虽然不多,但是基本上是够用了。

所以我们先对AGENTS.md 的大概先理解下,等后面我们讲 /init 和维护规则就好理解了。


但是我发现很多人都不怎么用或者只是把它当成 README 文件来使用。 但是其实它跟我们常见的README.md根本不是一个东西哦。

虽然都是 md 类型的 markdown 文件 但是用法完全不一样。

首先 README.md 是给人看的 比如一个新的开发者进入项目,打开 README.md,就可以知道这是个什么系统、技术栈是啥、本地环境怎么搭、代码仓库在哪。一目了然,比如我自己项目的README.md 是这样的

所以我们看README.md是为了快速去理解项目、快速上手、找到入口这些。

但是 AGENTS.md 不一样,它是给 agent 看的,比如 agent 加载项目后,打开 AGENTS.md,就能很清晰快速的知道构建命令是什么、测试怎么跑、哪些规范必须遵守、代码改完要做哪些验证等等,比如我项目的AGENTS.md是这样写的:

所以agent 看AGENTS.md是为了按规矩做事、减少出错、保持交付质量。

这里我用一个图片简单总结一下:


那么AGENTS.md 是怎么被加载的呢?

在我们上面大概了解了AGENTS.md是什么之后 那我们还需要简单去了解下 AGENTS.md是怎么被 agent 加载的,为什么这个 md 文件写了以后,agent 会更容易按规则做事呢?

简单来理解的话,在 agent 启动、进入项目或者新开会话时,工具会把 AGENTS.md 的内容作为上下文的一部分带进去。

虽然说不同工具的实现细节不完全一样,但大方向是一致的:

规则越靠近当前处理的项目或目录,通常就越具体。

因为我现在使用 codex 工具用来开发项目比较多,所以这里我主要以 Codex 为例讲讲大概的加载逻辑。

我们先看看Codex 官方文档是怎么解释的。

Codex 官方有一份关于 AGENTS.md 的说明文档:developers.openai.com/codex/guide...

这里我简单总结下,文档里面其实主要讲了这几点:

  1. Codex 如何发现指导
  • 启动时会构建指令链

  • 先读全局作用域(~/.codex

  • 再从项目根目录向下遍历到当前工作目录

  • 每个目录查找 AGENTS.override.mdAGENTS.md → fallback 文件名

  1. 制定全局指导方针
  • 可以在 Codex 主目录创建全局默认设置

  • 创建 ~/.codex/AGENTS.md 放通用规则

  • 临时覆盖全局规则时用 AGENTS.override.md

  1. 仓库项目说明
  • 仓库根目录放 AGENTS.md 覆盖基本设置

  • 特定团队需要不同规则时,可以在嵌套目录中添加覆盖规则

  1. 自定义 fallback 文件名
  • 如果项目已经用了其他文件名(比如 TEAM_GUIDE.md

  • 可以在 ~/.codex/config.toml 里配置 project_doc_fallback_filenames

  1. 大小限制
  • Codex 会跳过空文件,并在文件总大小达到限制(project_doc_max_bytes,默认 32 KiB)后停止添加文件
  • 超过限制可以提高上限或将覆盖文件放在专门工作的地方附近

简单来说 Codex 的加载顺序其实就是这样的:

首先Codex 每次启动时会构建一个指令链的,加载顺序是这样的:

全局配置 → 项目根目录 → 当前工作目录。

每一层的 AGENTS.md 会逐层拼接在一起,后面的优先级高于前面的。

举个例子,假设我们的项目结构是这样的:

perl 复制代码
my-monorepo/`
├── AGENTS.md              # 全局项目规则`
├── frontend/`
│   └── AGENTS.md          # React 相关规则`
├── backend/`
│   └── AGENTS.md          # Java/Spring 相关规则`
└── infra/`
    └── AGENTS.md          # 部署相关规则`

我们在 frontend/ 目录下启动 Codex,它会先读全局的 ~/.codex/AGENTS.md,再读 my-monorepo/AGENTS.md,最后读 my-monorepo/frontend/AGENTS.md

如果我们在 backend/ 启动的话,那就会读 ~/.codex/AGENTS.md + my-monorepo/AGENTS.md + my-monorepo/backend/AGENTS.md

最终三份文件的内容拼接在一起。

然后官方文档里还提到,Codex 默认限制是 32 KiB,所有文件拼起来超了会被截断。

怎么理解呢,比如我之前就遇到过一次,在 AGENTS.md里面写了很多规则,结果发现 Codex 好像没按规则做事。后来才发现是超限制了,后面的规则被截断了。

虽然按照文档上面说我们可以在 ~/.codex/config.tomlproject_doc_max_bytes 调大,但我觉得没必要。

毕竟规则写太多的话,agent 也记不住。我更觉得精简规则,比调大限制更有用。

当然有个地方也需要我们注意下,AGENTS.md 不是实时配置中心哦。

也就是说不是说我们刚改了一行规则,当前对话里就立刻全局生效的,Codex 是在启动时构建指令链,运行中不会再动态加载的。 所以更稳妥的方式是我们改完以后新开会话窗口加载。


如果我们用 Claude Code,还可以用 AGENTS.md 吗?

因为 claude code 我也在用,可能很多佬也都是结合使用的 所以这里我也简单解释一下,因为可能有很多人可能觉得 AGENTS.md 只是 Codex 的,Claude Code 有自己的CLAUDE.md 就够了。

其实不是这样的哦。

AGENTS.md 不是 Codex 专属的。我们前面讲过,它是一个开放式协议规则,多个 agent 都可以用。Claude Code 也可以。只不过 Claude Code有自己的一套体系,所以用法稍微不一样哦。

虽然说不同工具的实现细节不完全一样,但可以先按这个方向来理解:

全局规则管个人习惯,项目规则管理当前仓库,子目录规则通常更加具体。 Codex侧通常围绕 AGENTS.md 管项目指令,Claude Code 侧通常围绕 CLAUDE.md 管项目指令。 规则越靠近当前处理的项目或目录,通常越是应该具体一些。

那AGENTS.mdCLAUDE.md 到底有啥区别呢?

上面我们说过了AGENTS.md 是开放标准,多工具都通用的。写在这里面的规则,不管用 Codex、Cursor、Aider,还是 Claude Code,都能读到的。比较适合放通用的项目规则,比如构建命令、测试命令、编码规范、禁止事项、联动规则等等。

而CLAUDE.md 则是 Claude Code 的专属格式,只有 Claude Code 自己认的。写在这里面的内容,只有 Claude Code 能读到。适合放 Claude Code 特有的配置,比如用了哪些 skills(比如 /lark-base/verify)、配置了哪些 hooks(比如改代码后自动跑 prettier)、Memory 相关的说明等等。

那如果我们在开发中同时使用 claude code和 codex,那我们的规则应该怎么放呢?

我个人建议这样理解:

通用规则放 AGENTS.md,Claude Code 通过 CLAUDE.md 去复用它。

还有个最简单好用的方式,就是在项目的 CLAUDE.md 里显式引入 @AGENTS.md,然后下面只补 Claude Code 专属的东西。

比如我们可以在 CLAUDE.md 里写一行 @AGENTS.md,Claude Code 就会自动加载 AGENTS.md 的内容

当然这里我也要简单解释一下:@file 这种引用语法是 Claude Code 的能力,不是 AGENTS.md 本身的通用能力哦,所以不要反过来指望在 AGENTS.md 里面去写一堆 @xxx.md,让所有工具都能理解。通用文件里还是尽量写通用内容的好。

就比如我有个项目就是这样规划的:

AGENTS.md 放通用规则:构建命令 npm run build、测试命令 npm test、编码规范(api 入参用 XxxParams,响应用XxxResponse)、禁止事项(不要手动改 generated/,不要提交 .env)、联动规则(改了接口同步更新文档和测试)。

这些规则不管用 Codex 还是 Claude Code,都需要去遵守的。

CLAUDE.md 则只需要补充 Claude Code 才用得上的:skills(/lark-base 操作飞书多维表格)、hooks(改代码后自动跑 prettier)、memory 提示这些。

这样设计规则的好处是:

通用规则只维护一份,Claude Code 通过 @ 导入,不用重复写。其他工具直接读 AGENTS.md。不管用什么工具,项目规则都是一致的。

其实还有一种方法是这样的,我们也可以在全局的 ~/.claude/CLAUDE.md 里面去放一条约定,比如我看其他佬之前是这样分享的:

遵循并维护/创建最近的 AGENTS.md 文件。它是给 AI 代理使用的项目说明,包含项目上下文和工作指令。

原帖在这里: linux.do/t/topic/103...

这样 Claude Code 进入项目后,就会更加倾向于主动围绕项目里的 AGENTS.md 工作的。

不过呢,我个人更推荐把团队项目的规则显式放在仓库里。因为全局配置只在自己本地生效,别人拉项目下来未必知道本地配了什么。团队一起协作时,项目内就可以CLAUDE.md + @AGENTS.md 这种方式回更清楚,也更容易被团队一起维护。


还有一个地方,Claude Code 还有个 Memory 机制

除了 AGENTS.mdCLAUDE.md,Claude Code 其实还有第三个东西:Memory。

Memory 存在 ~/.claude/projects/<项目hash>/memory/MEMORY.md下面的,每条记录是一个独立的md文件,MEMORY.md 是索引文件,跟前两个的区别是这样的

AGENTS.mdCLAUDE.md 都是项目规则,提交到 git,团队共享。而Memory 是协作过程中的经验记录,只在本地,不提交。

比如我们最近遇到的问题、临时的一些规则约定、还有一些没提炼成规则的经验,都会先记到 Memory 里。每次启动新会话时,Memory 的前 200 行会自动加载进上下窗口中。

所以这里我觉得我们可以没事就去看下 Memroy里面的内容,如果发现有些指令或者规则我们反复提示好几次了,那其实就可以把它提炼到 AGENTS.md 里了。提炼之后,Memory 里这条就可以删了。这样的话我们开发效率和规则约束会更加的好一些。

其实Codex 也有类似的 Memory 机制(存在 ~/.codex/memories/ 下),可以跨 thread携带上下文。详细的配置和使用方式可以可以参考官方文档相关说明: developers.openai.com/codex/memor...


那/init 解决哪些问题,又是什么时候去用呢?

我们上面去理解了 AGENTS.md 的作用以后,再来看 /init 命令就简单多了。

在我个人看来/init 是非常有价值的一个内置命令。

简单来说就是帮 agent 先扫一遍项目,让它知道我们的这个项目大概是什么样的架构体系。比如项目目录怎么分、技术栈是什么、启动命令在哪里、测试命令是什么、README 里有没有写注意事项。

如果这些信息如果不先整理出来,那agent 第一次进项目时就只能边做边猜。完全不了解我们的项目架构信息,虽然它也可以自己去搜文件、读代码,但这会消耗上下文,而且很容易漏掉一些项目约定,所以我才说/init 是非常有价值的。

比如我们使用 codex 在项目根目录运行命令之后通常会生成一个 AGENTS.md 文件。

在生成之前,这个命令一般会去做这些事:

  • 扫描项目结构,比如目录和文件
  • 分析依赖,比如 package.jsonpom.xmlrequirements.txt
  • README.md,找启动命令和测试命令
  • 生成一份基础项目说明

听起来很简单快捷对吧?但问题也在这里:它只能生成起点,看到的更多是项目表面信息。相当于只是对项目做了一个简单梳理初始化。

那我们应该什么时候才去使用/init 命令呢?

这里我需要说明一下:如果是全新的空项目,刚开始写代码,我不太建议马上 /init

因为这个时候项目目录、依赖、启动脚本、测试方式都还没稳定,生成出来的内容大概率会很泛,甚至过几天项目结构变了,那这份文件马上就会过期了。

其实 /init 命令更适合在我们的项目已经有一定代码量、目录结构基本稳定之后使用。

这个时候它扫出来的东西才更接近真实项目,后面也更容易在这个初稿上继续维护才行的哦。


回到我们开头的问题:为什么 /init 之后还需要继续维护呢?

到这里其实就能回答一个问题了:为什么跑了 /init 还远远不够呢?

其实是因为 /init 只是帮我们生成了一个初始文件,但是它并不知道我们团队平常是怎么开发的,也不知道这个项目历史上出现过哪些问题,以及踩过哪些坑。

比如我在用 AI Coding 的时候,也经常是哪里出问题了,就在 prompt 里补一句用来矫正 ai 的执行流程和规则。比如每次都不经过我同意就提交 git,那我就总是在需求里面说明一下:改完记得要先等我审核没问题后再提交 git 这样的。

短期看,这样当然能用。但用久了其实就会发现几个问题:

  • 每次新开会话,都要把同样的话重新说一遍
  • prompt 越写越长,上下文越来越臃肿
  • 忘提醒一次,agent 就可能又按自己的理解去做
  • 团队里每个人提醒的方式不一样,agent 拿到的规则也不一致

所以这时候我们就需要去维护 AGENTS.md,不是为了再写一份项目说明文档。更准确地说,是需要把这些高频、长期、容易出错的规则,提前放进项目上下文里。

这些规则要求指令靠 /init 很难一次性知道,也不适合每次都塞进 prompt 里的,因为它们不是这一次任务才需要的,而是这个项目长期都需要的。

当我们把这些规则要求都写进 AGENTS.md 以后,agent 进入项目时更容易拿到这些规则,不用每次 prompt 里重复解释了,然后上下文也省了,重复提醒也少了,agent 做错事的概率也会降下来。


那又遇到一个问题:AGENTS.md 是不是写得越多越好呢?

可能我们会觉得是不是把所有规则都写进去,agent 就能完全按要求做事了?

其实也不是的哦, 指令太多,agent 反而记不住。 就像我们同时给一个人 100 条要求,他肯定顾不过来,只能记住前面几条一的道理。

这里我们可以参考这个测评:LLM一次可以执行多少条指令?

所以回到我们的 AGENTS.md,本来工具的系统提示本身就带了很多内置指令了(权限控制、工具使用、安全约束、代码风格),这些已经占了相当多的指令位了,我们写的 AGENTS.md 其实是叠加在这些之上的。所以留给我们的有效空间,真的没想象得那么多哦,所以 AGENTS.md 不是写得越多越好,而是要写最关键的、agent 自己推断不出来的那些。


那如果是这样的话, 到底什么规则该写,什么规则不该写呢?

其实这个我觉得很简单,也很好判断,只要是我们觉得需要长期遵守的 或者多次提醒的就可以写入到规则里面,这里我举几个简单的例子:

但是有些人可能不懂怎么写才是一个正确的规则指令,比如我们这样写是不行的:

  • 保持代码优雅
  • 注意可维护性
  • 遵循最佳实践

其实我们应该这样去明确规则指令,比如需要明确动作,像这样的:

  • 改前端组件后需要运行下 pnpm lint
  • 不要手动去修改 generated/目录
  • api入参统一使用 XxxParams 命名方式
  • 改接口后需要补对应测试

比如就像我开头我项目的截图这样的:

简单来说,能从代码里看出来的,不用写。 只在这次任务里需要的,也不用写。 真正值得沉淀进去的,是那些反复影响交付质量的项目规则。


那再补充一点:怎么从Prompt 到 AGENTS.md

这点其实我们前面已经简单说过了, 判断标准其实很简单:第二次重复提醒,就该考虑沉淀了。

这里有个点, 如果用 Claude Code,流程会则多一层哦

因为我们前面说过,Claude Code 是有 Memory 机制的,所以流程应该是这样的:

Prompt → Memory → AGENTS.md

前面我们已经提到过, Memory 存在 ~/.claude/projects/<项目hash>/memory/MEMORY.md,就像一个草稿本历史记录,可以的话就可以没事定期去 review 一下看看是否有需要提炼的规则指令。

如果用的是其他工具,我们就可以直接从 Prompt 沉淀到 AGENTS.md里面,或者我们还看看对应工具有没有类似的中间层机制。

然后就这样慢慢积累沉淀,其实分工就很明确了:

  • AGENTS.md 是项目规则,提交到 git,团队共享
  • Memory(仅 Claude Code)是个人草稿本,本地存储
  • Prompt 只处理临时的、一次性的提醒

就先扯到这里吧,再强调一下哈,AGENTS.md 不是写得越多越好,而是去写 agent 推断不出来、长期都要遵守、能写成明确动作的规则哈。

相关推荐
PBitW1 小时前
GPT训练我的第三天,明白了应该咋说满分回答!😕😕😕
前端·javascript·面试
leeyi4 小时前
Callback 系统:给 Agent 管道装上“监听器“
aigc·agent·ai编程
凌奕4 小时前
别用文档约束你的 Agent:聊聊 Agent 开发流程的思想
llm·github·agent
猪猪拆迁队6 小时前
给虚拟工厂装一个 Agent:对话与批量双编排、自描述工具、可控写入的架构设计
agent
ZzT7 小时前
让 AI 少写一半代码:拆解爆火的 ponytail
ai编程·claude
自由路飞7 小时前
RAG 混合检索深挖:BM25 和向量分数为什么不能直接相加?
面试
老梁agent8 小时前
MCP 协议实战:用标准化方式让 Agent 调用工业工具
物联网·agent·mcp
未秃头的程序猿8 小时前
告别"if-else地狱"!Java 21模式匹配,代码优雅了10倍
java·后端·面试