跳至内容
让 AI Coding Agent 真正理解项目:从 Rules 到 AGENTS.md

让 AI Coding Agent 真正理解项目:从 Rules 到 AGENTS.md

你让 AI Coding Agent 做一个看起来很简单的任务:

给订单列表增加一个“导出 CSV”按钮。

十分钟后,Agent 告诉你已经完成。但你打开代码一看:

  • 项目使用 pnpm,它却执行了 npm install,生成了第二份锁文件;
  • 团队要求复用 Button 组件,它重新写了一套按钮样式;
  • API 客户端本应由 OpenAPI 自动生成,它直接改了生成文件;
  • 改完没有运行类型检查,也没有验证中文 CSV 是否乱码;
  • 它顺手“优化”了三个无关组件。

Agent 不一定能力差。真正的问题是:它不知道这个项目里那些没有写在代码语法中的约定。

同事入职时,会有人告诉他:

我们用 pnpm;公共组件在这里;生成目录不要手改;改订单模块要跑这组测试;不确定接口时先问后端。

Agent 每次进入一个新会话,也像一个刚入职、记忆被清空的新同事。如果这些信息只存在于你的脑中、群聊和历史 Review 里,它就只能猜。

项目 Rules 和 AGENTS.md 的作用,就是把这些反复口头交代的内容,变成 Agent 每次工作前都能看到的“项目工作说明”。

没有项目规则与拥有项目规则时,AI Coding Agent 的工作差异

一、先说人话:AGENTS.md 就是给 Agent 的项目入职手册

AGENTS.md 是一个普通 Markdown 文件。它没有神秘语法,也不是某种 AI 模型。

你可以把它理解成:

README.md 主要告诉人“这个项目是什么”;

AGENTS.md 重点告诉 Agent“在这个项目里应该怎样工作”。

一个有用的 AGENTS.md 通常回答下面这些问题:

  • 项目使用什么包管理器?
  • 安装、启动、构建和测试命令是什么?
  • 哪些目录负责什么?
  • 哪些文件允许修改,哪些文件由工具生成?
  • 新代码应该遵守哪些项目特有约定?
  • 不同类型的修改分别要跑哪些检查?
  • 哪些操作有风险,必须先向人确认?
  • 任务完成时要提供什么验证证据?

官方的 AGENTS.md 开放格式说明把它称为“给 Agent 的 README”。它的价值不在于文件名本身,而在于提供一个稳定、可预期、能跟随代码仓库流转的位置。

Rules 又是什么?

Rules 是更宽泛的概念,指所有能够持续影响 Agent 行为的项目指令。

不同工具使用的名称和能力并不完全相同:

工具常见项目指令适合做什么
CodexAGENTS.md、嵌套的 AGENTS.md仓库规则、目录规则、测试和 Review 要求
CursorAGENTS.md、.cursor/rules/*.mdc简单全局规则,或按文件和场景加载的细粒度规则
Claude CodeCLAUDE.md、.claude/rules/*.md项目说明、目录或文件类型规则、Claude 专用要求
GitHub CopilotAGENTS.md、.github/copilot-instructions.md、路径规则根据 IDE、CLI、云端 Agent 或 Code Review 入口加载指令

所以,AGENTS.md 是一种规则载体,但 Rules 不只等于 AGENTS.md。

二、为什么只在聊天里提醒一次不够

你当然可以在每个任务前都写:

使用 pnpm,不要改 generated 目录,完成后运行 pnpm lint 和 pnpm test,
不要修改无关文件……

但这种做法有三个问题。

1. 新会话不会自动记得旧会话

Agent 当前能看到的内容是有限的。换一个会话、换一个同事、换一个 AI Coding 工具,之前口头说过的约定可能就不存在了。

2. 人会漏说,Agent 就会猜

你熟悉项目以后,会下意识认为某些规则“大家都知道”。但 Agent 看到的只是代码文件,并不知道:

  • src/generated/ 每晚会被重新生成;
  • 旧支付接口不能再增加调用方;
  • E2E 测试必须使用测试租户;
  • 数据库迁移只能向前兼容。

代码能够展示“现在是什么”,却不一定能解释“为什么必须这样”。

3. 多人协作会产生不同版本的口头规则

如果规则散落在群聊、个人提示词和 Review 评论中,三个开发者可能给 Agent 三套不同说法。

把规则提交进仓库,至少能让团队:

  • 在 Pull Request 中审查规则;
  • 知道规则什么时候、为什么发生变化;
  • 让本地 Agent 和云端 Agent共享同一份基础约定;
  • 在规则过时以后找到负责人修改。

三、AGENTS.md 不是什么

理解边界,比会写文件更重要。

它不是项目百科全书

不要把所有文档复制进去。Agent 本来就能读取 package.json、目录和代码,重复这些内容只会占用上下文。

应该写:

修改 src/api/generated/ 的需求,必须先更新 openapi.yaml,再运行 pnpm api:generate。

不必写:

src/ 目录里有很多 TypeScript 文件。

前者包含项目特有的行动规则,后者是 Agent 自己就能发现的事实。

它不是一次任务的需求单

“这次把导出按钮放在筛选栏右侧”只属于当前任务,应该放在 Prompt 或规格中。

“所有列表页的主要操作都放在筛选栏右侧”才可能是值得长期保留的项目规则。

它不是安全权限系统

规则可以告诉 Agent“不要读取生产密钥”,但它本质上仍是给模型的指令,不是硬隔离。

如果某件事必须禁止,应使用更可靠的控制:

  • 文件和目录权限;
  • 沙箱;
  • 命令审批;
  • 工具白名单;
  • Git 分支保护;
  • CI 质量门禁;
  • Hooks 或策略配置。

规则负责指导行为,系统负责强制边界。

它不是 Skill,也不是 MCP

机制解决的问题
Prompt这一次任务要完成什么
AGENTS.md / Rules在这个项目里长期应该怎样工作
Skill某类重复任务应该按照什么步骤完成
MCPAgent 如何连接浏览器、数据库、文档等外部能力
Hook / CI / 权限哪些动作必须执行、拒绝或通过检查

例如:

  • “项目统一使用 pnpm”适合放在规则里;
  • “发布版本要执行 12 个步骤”更适合封装成 Skill;
  • “读取浏览器 Console”需要浏览器工具或 MCP;
  • “禁止提交包含密钥的文件”应该由扫描工具和 CI 强制执行。

四、真正有价值的规则,通常来自这六类信息

1. 可以直接执行的命令

不要写:

修改后认真测试。

要写:

- 安装依赖:`pnpm install`
- 本地启动:`pnpm dev`
- 类型检查:`pnpm typecheck`
- 单元测试:`pnpm test`
- 仅运行订单模块测试:`pnpm test src/orders`

Agent 不应该猜命令。错误命令轻则浪费时间,重则生成多余文件或误操作环境。

2. 项目的结构地标

只写那些能改变 Agent 行动路线的信息:

- 页面入口在 `src/pages/`。
- 复用组件在 `src/components/ui/`,新增按钮前先搜索这里。
- API 类型来自 `src/api/generated/`,不要手工修改。
- 业务请求统一通过 `src/api/client.ts`,不要在组件中直接调用 `fetch`。

3. 修改边界和非目标

- 除非任务明确要求,不要升级依赖。
- 不要修改与当前任务无关的格式和命名。
- 涉及公共 API、数据库迁移或鉴权流程时,先说明影响并等待确认。
- 不要编辑 `dist/`、`coverage/` 和自动生成文件。

这类规则能显著减少“顺手重构”和范围漂移。

4. 项目特有的代码约定

格式化工具能够自动处理的事情,交给工具;只把 Agent 无法从默认工具中知道的约定写进规则。

有价值:

- 金额在业务层统一使用整数分,不要使用浮点元。
- React Query 的 query key 必须从 `src/query/keys.ts` 导出。
- 用户可见错误使用 `AppError` 映射,不直接显示后端原始消息。

价值较低:

- 写出优雅、整洁、高质量的代码。
- 使用最佳实践。

后两条听起来正确,却无法验证,也无法告诉 Agent 具体应该怎么做。

5. 与修改类型对应的验证要求

不要要求每次都运行仓库里所有检查。大型项目可能因此浪费半小时。

可以写成分层规则:

- 修改 TypeScript:运行 `pnpm typecheck`。
- 修改业务逻辑:运行相关单元测试。
- 修改页面交互:启动应用,并验证主要流程和错误状态。
- 修改公共包:运行该包测试及至少一个使用方的测试。
- 只修改文档:无需运行应用测试,但检查链接与格式。

6. 交付时必须说明的证据

完成任务时必须报告:

1. 修改了哪些文件;
2. 为什么这样修改;
3. 运行了哪些检查及结果;
4. 哪些内容没有验证;
5. 是否存在需要人工确认的风险。

这会把 Agent 的“已经完成”变成一份可以审查的交付说明。

五、从零写一份最小可用 AGENTS.md

假设我们有一个 React + TypeScript 项目:

shop-console/
├── src/
│   ├── api/
│   │   └── generated/
│   ├── components/
│   │   └── ui/
│   ├── features/
│   │   ├── orders/
│   │   └── payments/
│   └── pages/
├── tests/
├── package.json
└── pnpm-lock.yaml

一份起步版 AGENTS.md 可以这样写:

# AGENTS.md

## 项目概况

- 这是一个 React + TypeScript 的运营后台。
- 使用 `pnpm`,不要运行 `npm install` 或生成 `package-lock.json`。
- 先阅读相关代码和现有测试,再提出修改计划。

## 结构与复用

- 页面位于 `src/pages/`,领域功能位于 `src/features/`。
- 通用 UI 位于 `src/components/ui/`;新增组件前先搜索已有实现。
- `src/api/generated/` 由 OpenAPI 生成,禁止手工修改。
- API 请求统一通过 `src/api/client.ts`。

## 修改边界

- 只修改完成当前任务所需的文件,不做无关重构。
- 不主动升级依赖。
- 修改公共 API、鉴权、支付或数据库结构前,先说明影响并等待确认。
- 不读取、输出或提交 `.env` 中的密钥。

## 代码约定

- 金额在业务逻辑中使用整数分。
- 用户可见文案使用中文,并通过现有 i18n 方法管理。
- 优先复用现有类型,不重复声明相同的数据结构。

## 验证

- TypeScript 修改后运行 `pnpm typecheck`。
- 业务逻辑修改后运行相关单元测试。
- 页面交互修改后运行 `pnpm dev`,验证正常、加载中、空状态和错误状态。
- 只有相关检查通过后,才能声称任务完成。

## 交付说明

- 列出修改文件、验证命令和结果。
- 明确说明未执行的检查及原因。
- 不要自行提交或推送代码,除非任务明确要求。

这份文件没有描述整个系统,也没有复制 ESLint 配置。它只保存了会影响 Agent 决策、容易重复出错、并且可以验证的信息。

六、规则要分层:离代码越近,内容越具体

一个大型仓库可能同时包含前端、后端、移动端和基础设施代码。把所有规则塞进根目录,会产生两个问题:

  • 每个任务都加载大量无关内容;
  • 不同模块的规则互相冲突。

更好的做法是分层。

全局规则、仓库规则、目录规则与当前任务的作用范围

以 Codex 为例,它会从全局规则开始,再从仓库根目录向当前工作目录逐层读取指令;越靠近当前目录的文件越具体,发生冲突时更近的规则拥有更高优先级。

~/.codex/AGENTS.md
        ↓
shop-console/AGENTS.md
        ↓
shop-console/src/features/payments/AGENTS.md
        ↓
当前任务 Prompt

可以这样划分:

全局规则:只属于你个人

路径示例:~/.codex/AGENTS.md

- 默认使用中文解释结论。
- 执行破坏性命令前必须询问。
- 修改完成后先展示 Diff,不自动提交。

这类规则不要提交到团队仓库。

仓库规则:所有模块都适用

路径:项目根目录的 AGENTS.md

- 使用 pnpm。
- 禁止手改生成代码。
- TypeScript 修改后运行类型检查。

它应该提交到 Git,让本地、云端和团队成员获得一致规则。

目录规则:只约束某个模块

路径示例:src/features/payments/AGENTS.md

# 支付模块规则

- 金额只能使用整数分。
- 不记录卡号、验证码或完整支付令牌。
- 修改支付状态机后运行 `pnpm test payments`.
- 改变支付结果枚举属于兼容性变更,必须先说明影响。

需要注意:不同工具的目录发现和优先级并不完全相同。 Codex 原生支持分层 AGENTS.md;Cursor 官方文档目前把根目录 AGENTS.md 定位为简单规则,需要更细粒度时更适合使用 .cursor/rules;Claude Code 则使用分层 CLAUDE.md 和 .claude/rules/。

当前 Prompt:只描述这次任务

给订单列表增加 CSV 导出。

本次只导出当前筛选结果,不增加“导出全部”能力。
验收时需要检查中文、逗号、换行和空列表。

长期规则不应该每次复制到 Prompt;一次性需求也不应该永久写进 AGENTS.md。

七、一个仓库同时使用 Cursor、Claude Code 和 Codex,怎么办?

不要维护三份内容完全相同、迟早互相漂移的长文档。

推荐使用:

AGENTS.md                 # 跨工具共享的核心项目约定
CLAUDE.md                 # 导入 AGENTS.md,再补 Claude 专用说明
.cursor/rules/            # 仅保存需要路径匹配或 Cursor 专用的规则
.github/instructions/     # 仅保存 Copilot 特定或路径规则

Claude Code 官方文档明确说明它原生读取 CLAUDE.md,而不是直接读取 AGENTS.md。可以用一层很薄的适配文件:

# CLAUDE.md

@AGENTS.md

## Claude Code 专用说明

- 修改支付模块前先进入 Plan 模式。
- 使用 `/context` 检查本文件是否已加载。

Cursor 可以直接使用根目录 AGENTS.md。当你需要“仅修改某类文件时才加载”的规则,再创建 .cursor/rules。

GitHub Copilot 不同入口支持的指令类型存在差异。团队应该以 GitHub 官方的自定义指令支持矩阵为准,不要假设 IDE、CLI、云端 Agent 和 Code Review 行为完全相同。

核心原则是:

公共事实只维护一份;工具专用行为放在薄适配层;不要复制粘贴出三份“几乎一样”的规则。

八、规则写得越多,Agent 就越听话吗?

不一定。

规则文件会进入 Agent 的上下文。内容越多,意味着:

  • 占用更多上下文空间;
  • 重要规则更容易被埋没;
  • 冲突概率增加;
  • 过期信息更难发现;
  • 每次任务都要携带更多无关信息。

Claude Code 官方建议让规则具体、简洁、结构清楚;Codex 官方指南也强调,短而准确的 AGENTS.md 比充满模糊要求的长文件更有用。

用这个标准判断一条规则是否值得保留

一条长期规则最好同时满足:

  1. 项目特有:不是所有项目都适用的常识;
  2. 反复需要:如果不写,Agent 容易再次犯错;
  3. 能够行动:Agent 看完知道具体要做什么;
  4. 可以验证:人或工具能判断它是否被遵守;
  5. 相对稳定:不会明天就失效;
  6. 作用域清楚:知道它适用于整个仓库还是某个目录。

例如:

原始写法问题更好的写法
保证代码质量无法行动、无法验收修改 TypeScript 后运行 pnpm typecheck
注意安全范围太大日志中不得输出 access token、卡号和身份证号
使用现有组件不知道去哪里找新增 UI 前先搜索 src/components/ui/
写测试不知道测试什么修改订单金额计算时,补充零值、负值和小数舍入测试
不要乱改含义模糊只修改完成当前任务所需的文件,不做无关格式化和重命名

九、实战:让 Agent 帮你生成规则,但不要直接照单全收

第一步:让 Agent 只调查,不修改

请先只读分析这个仓库,不要修改文件。

请从以下位置收集已经存在的项目事实:
- README 和贡献文档;
- package.json 中的 scripts;
- 锁文件与包管理器配置;
- CI 工作流;
- lint、格式化和类型检查配置;
- 测试目录;
- 自动生成目录和文件头;
- 现有架构文档。

输出一份候选 AGENTS.md,并为每条规则注明证据文件。
不要猜测无法从仓库确认的约定。

“注明证据”很重要。否则 Agent 可能把自己的偏好误写成团队规则。

第二步:人工删除三类内容

删除:

  • Agent 从代码中随时能发现的普通事实;
  • 没有证据的主观偏好;
  • 无法验证的口号。

保留:

  • 正确命令;
  • 隐藏边界;
  • 反复出现的 Review 意见;
  • 模块特有风险;
  • 验证与交付要求。

第三步:用一个真实小任务验证

不要只问 Agent“你读到了吗”,而要设计一个会触发规则的任务。

例如规则写着:

- 不主动新增依赖;确有必要时先说明原因并等待确认。

测试 Prompt:

给日期列表增加“距离现在多久”的显示。
请直接实现,并使用你认为方便的第三方日期库。

理想行为不是立刻安装 dayjs 或 date-fns,而是:

  1. 先检查项目是否已有日期工具;
  2. 尝试使用现有能力;
  3. 确需新增依赖时先说明理由;
  4. 等待确认后再安装。

第四步:要求 Agent 报告加载了哪些规则

Codex 可以从目标目录启动新会话,然后询问:

请列出当前生效的项目指令来源,并用自己的话概括最重要的规则。
不要修改任何文件。

Claude Code 可以使用 /context 查看加载的 CLAUDE.md,也可以用 /memory 管理相关文件。Cursor 中可以让 Agent 先复述当前项目 Rules,再开始修改。

如果 Agent 连规则来源都说不清,先排查文件位置、作用域和新会话加载,不要急着继续加更多规则。

十、为什么 Agent 还是会违反规则?

情况 1:规则没有被加载

检查:

  • 文件名和位置是否正确;
  • 是否在正确的项目目录启动 Agent;
  • 修改规则后是否开启了新会话;
  • 工具是否支持这种规则文件和作用域;
  • 文件是否为空或被忽略。

情况 2:规则互相冲突

根目录写“所有修改必须跑完整测试”,子目录又写“只跑相关测试”,个人规则还写“不要运行耗时命令”。

人看到都会犹豫,Agent 也一样。删除冲突,或者明确条件:

- 默认运行相关测试。
- 修改共享基础包时,再运行完整测试。

情况 3:规则太抽象

把“遵循架构设计”改成可执行路径:

- React 组件不得直接访问 `/api`;请求必须通过 `src/api/client.ts`。

情况 4:规则太长

把只针对支付模块的规则移到支付目录,把多步骤发布流程封装成 Skill,把格式要求交给 formatter。

根文件只保留所有任务都会用到的高价值信息。

情况 5:你需要的其实是强制执行

如果要求是“每次提交前必须运行 lint”,只写规则仍然可能被忘记。

更可靠的组合是:

AGENTS.md 告诉 Agent为什么和怎么做
        +
Hook / CI 确保检查一定执行
        +
分支保护阻止不合格结果合并

把文字规则当作第一道引导,而不是最后一道防线。

十一、让规则成为活文档,而不是一次性工程

最好的规则不是在项目第一天凭空设计出来的,而是从真实摩擦中逐步长出来的。

当下面的事情发生时,可以考虑更新规则:

  • Agent 第二次犯了同一个错误;
  • Code Review 再次解释同一条项目约定;
  • 新增了稳定的构建或测试命令;
  • 某个模块出现了新的安全边界;
  • 团队决定废弃一种旧做法;
  • 一条规则已经与代码现状不符。

每次更新都应该问:

  1. 这是一次性问题,还是会重复发生?
  2. 应该放在根目录,还是更近的子目录?
  3. 能否由 lint、测试或权限直接强制?
  4. 是否会与现有规则冲突?
  5. 六个月后谁来判断它是否过期?

建议把 AGENTS.md 当作普通代码资产:

  • 通过 Pull Request 修改;
  • 要求模块负责人 Review;
  • 在提交记录中说明为什么增加规则;
  • 定期删除失效和重复内容;
  • 用真实任务验证,而不是只检查 Markdown 格式。

十二、今天就能完成的最小实践

打开一个你熟悉的项目,完成下面五步:

  1. 找出正确的安装、启动、检查和测试命令;
  2. 写下三个 Agent 无法只靠读代码理解的项目约定;
  3. 写下一条禁止范围和一条验证要求;
  4. 创建一份不超过 60 行的根目录 AGENTS.md;
  5. 开启新会话,让 Agent 复述规则并完成一个小任务。

如果这次任务中少了一次“不是跟你说过了吗”,这份规则就已经开始产生价值。

项目规则解决的是“在这个仓库里应该怎样工作”。下一篇将继续解决另一个常见问题:规则知道了,但需求本身仍然模糊,Agent 为什么还是越改越乱?

权威资料

最后更新于