ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

AGENTS.md:为AI编程代理打造的项目上下文治理手册

AGENTS.md:为AI编程代理打造的项目上下文治理手册

1. 先搞清楚:AGENTS.md 到底解决了什么问题

1.1 从一场失控的“AI结对编程”说起

前阵子我在维护一个内部的数据处理项目,代码量不算大,三万行出头,模块边界也算清晰。但团队里接入了 AI 编程助手之后,原本还算稳的代码库开始变得“陌生”了——新提交的代码里频繁出现风格不一致的函数命名,某个本该沉淀在存储层的逻辑被直接写进了接口层,更头疼的是,AI 每次开工都要花大量时间四处翻文件才能找到入口文件,有时甚至翻错了版本。

一开始我以为是模型能力的问题,换了好几个工具,效果有改善但没根治。直到有一天,我发现 AI 在一次会话里连续打开了十几个文件,只为了确认一个配置项应该放在哪个目录——那一刻我意识到,问题不在模型,在于我压根没告诉它“这个项目长什么样、该怎么干活”。这就是我今天想聊的:AGENTS.md 不是普通文档,它是给 AI 协作工具体系里那位看不见的同事看的“入职手册”。

所谓 AGENTS.md,简单来说就是一份放在仓库根目录里、专门写给 AI 编程代理(Agent)看的说明文件。它告诉 Agent 项目的代码结构、技术栈、命令约定、变更规范,避免它在每次对话里靠“猜”来理解你的项目。我在这类文件上的投入,让 AI 生成的代码被直接采纳的比例从大概三成提到了七成左右,这件事值得展开讲讲。

1.2 Agent 上下文失控的三类典型症状

先说症状,方便你对号入座。如果你也在用 AI 编程工具,且遇到下面这三种情况,大概率不是模型问题,而是项目上下文治理没做好。

第一类是“地图迷失”。AI 不知道代码在哪,问你“定时任务的入口在哪里”,它先打开main.py找,再翻utils/,最后跑去tests/里碰运气。小项目还好,几千个文件的工程里,这种行为会浪费大量 token,而且经常答非所问。

第二类是“风格漂移”。团队约定变量用 snake_case,Promise 链式调用优先,错误必须先包装再抛出,但 AI 每次生成的代码都在“猜”这些约定。这次对了,下次又错了,代码评审时满屏都是格式类修改,真正该看的逻辑反而被淹没。

第三类是“破坏性操作”。AI 在改一个模块时不小心动到了公共依赖,或者在重构时遗漏了配套的测试更新。它其实没有恶意,只是不知道“哪些文件是核心资产”“哪些操作需要额外小心”。你怪它也没用,因为没人告诉过它。

这三类症状有一个共同的根因:Agent 的上下文里缺少结构化、可执行的项目规则。它手里只有代码库和对话历史,而代码库本身不会说话。AGENTS.md 就是用来补上这张嘴的。

1.3 为什么 README 顶不住:它是给人看的,不是给 Agent 用的

有人会说,我们仓库里有 README,写得挺详细的,还不够吗?我的回答是:README 是给人看的说明书,AGENTS.md 是给 Agent 用的操作手册,两者目标不同,表达方式也不同。

README 的读者是“路过的开发者”,它要回答的是“这个项目是干什么的、怎么跑起来”。所以它会有大段的背景介绍、功能截图、架构图,甚至团队文化。这些内容对 Agent 来说是噪音——它一目十行地扫过去,很难从中提取出“修改src/services/report_service.py时必须同步更新tests/unit/test_report_service.py”这样精确的操作指令。

更关键的是,Agent 不擅长从长篇散文里做“信息检索”,它更擅长按照清单和规则来执行。一份好的 AGENTS.md 应该像机场的地面标识线:清晰、简短、直接指向动作。比如:

## Commands - Build: `pnpm build` - Test: `pnpm test:unit` - Lint: `pnpm lint:es`

这种格式 README 里很少见,但 Agent 读起来效率极高。它不需要理解“为什么用 pnpm”,只需要知道“要跑测试就执行这一条”。

2. 真实项目里的 AGENTS.md 设计思路

2.1 项目背景与治理目标

我先交代一下当时那个项目的实际情况,方便你理解后面的设计决策。项目代号我暂且叫它“某数据清洗与报表服务”,是一个典型的内部业务系统,技术栈为 Python + FastAPI 做后端接口,Vue 3 + TypeScript 做前端控制台,PostgreSQL 存数据,Redis 做缓存。仓库结构大概是backend/、frontend/、shared/、docs/、scripts/五个一级目录,其中backend下又按业务模块拆了十几个子包。

当时团队一共六个人,三位写后端,两位写前端,我兼着做架构和 Code Review。AI 编程助手接入后,最大的痛点不是“它不会写”,而是“它写出来的东西不像是我们团队写的”。比如后端的异常处理,我们约定所有业务异常必须继承自定义的BizError,由全局异常处理器统一兜底;但 AI 经常自作主张抛ValueError,理由也许是对的,但风格和现有代码完全不在一个频道上。

所以这个 AGENTS.md 的治理目标非常明确:不是教 AI“怎么写代码”(那是模型的事),而是告诉它“在这个仓库里,按什么规则写代码才算合格”。具体拆成四层目标:

  • 让 AI 在动手前能快速定位相关代码,减少无效翻找
  • 让 AI 生成的代码符合团队约定,减少评审时的风格纠偏
  • 让 AI 知道哪些操作是危险的,避免它动到不该动的东西
  • 让 AI 在任何一次会话里都能快速恢复上下文,而不是从头开始摸索

带着这四个目标,我开始搭 AGENTS.md 的骨架。

2.2 我最终定下的目录骨架

初版 AGENTS.md 我写了两千多字,塞满了各种“应该怎么做”,结果 AI 反而不听话了——上下文一长,它像是在读论文,抓不住重点。后来我参照一些成熟的开源项目做法,把内容压缩重组,最终形成了五段结构,每段一个小标题:

# Project Overview # Repository Map # Development Workflow # Code Style Guide # Danger Zones

这个骨架不是拍脑袋定的,它对应 Agent 干活时需要依次回答的五个问题:这是什么项目?代码在哪里?怎么构建和测试?写出来的代码该长什么样?有哪些事绝对不能碰?

关键是每个部分都要精简:概览部分只写项目定位和核心技术栈,不超过十行;代码地图部分按目录逐个说明职责,每行一条;工作流部分是命令清单,直接复制可用;风格指南挑团队最在意的十条约,不搞大而全;危险区列出会导致线上事故或代码腐化的操作,用“禁止”句式。

2.3 每条规则背后的“为什么”

这里我想特别强调一个容易被忽略的点:AGENTS.md 里的每一条规则,都应该有对应的“踩坑经历”在里面,哪怕文件里不写原因,你心里得清楚为什么要有这条。

比如我在“禁止直接修改数据库迁移脚本”这条规则背后,是因为我们真出过一次事故——某次 AI 在修复数据字段类型时,直接把已经应用过的迁移文件改掉了,导致同事拉代码后迁移校验失败,整整排查了半天。所以这一类规则,本质上不是审美偏好,而是用真金白银换来的教训。

另一条“新增公共依赖必须先在讨论区确认”,背后是依赖冲突引发的连环问题。规则不需要解释来龙去脉,但每条规则都得有它的分量,AI 才会在决策时真正把这条当作硬约束,而不是可选的风格建议。我通常的做法是:写规则的同时在文件外的团队 Wiki 里记录具体事故案例,AGENTS.md 只保留规则本身,避免文件过长稀释注意力。

3. 逐段解析:一份可复用的 AGENTS.md 实例

3.1 文件头部:角色声明与上下文总览

很多人写 AGENTS.md 一上来就铺目录结构,我建议先加一小段角色声明,告诉 Agent “你是谁、你在哪、你要干什么”。这段看着虚,实际很有用——它相当于给 Agent 一个心理锚点,避免它在处理具体任务时把自己当成普通聊天机器人。

我当时的写法大致是:

# Project Overview You are working in the "Data Cleaning & Reporting Service" repository. This is an internal data platform for transforming raw data into business reports. The primary language is Python 3.11 (backend) and TypeScript 5.2 (frontend). Follow the repository conventions below unless a task explicitly requires otherwise. If you are uncertain about a repository-wide change, ask before acting.

这段信息量不大,但它做了三件事:亮明项目身份、确认技术栈基线、设定“不确定就先问”的行为基调。后两点对 AI 后续行为的影响非常直接。我对比过同一模型在有无这段声明时的表现,有声明时 AI 更倾向于在动手前总结自己对任务的理解,而不是直接开写。

概览部分还有一个容易被忽略的细节:写明项目的“非目标”。比如我们这个服务明确不做实时数据流处理,这就避免了 AI 在某些任务里引入 Kafka 或者 Flink 这类完全不对路的方案。

3.2 代码导航:告诉 Agent 地图怎么画

代码地图是这个文件里我最看重的部分。它的作用等同于给 Agent 一张标注了建筑物用途的城市地图——哪里是商场、哪里是地铁站、哪里是禁行区,一眼就能看懂。

我的写法是按一级目录逐条列出职责,并顺手标注最常见的操作入口:

# Repository Map - `backend/app/api/` — REST API 路由层。每个业务模块一个子目录, 路由函数只做参数解析与响应封装,业务逻辑一律下沉到 service 层。 - `backend/app/service/` — 业务逻辑层。事务边界在这里控制, 禁止在 route 层直接写数据库查询。 - `backend/app/models/` — SQLAlchemy ORM 模型。新增字段时必须配套 编写 Alembic 迁移脚本,不直接改动已发布的迁移历史。 - `backend/app/common/` — 跨模块工具函数与通用组件。 包含统一异常类、分页组件、鉴权依赖等。修改此目录前先确认影响面。 - `frontend/src/api/` — 后端接口封装层。所有 HTTP 请求统一走 该目录下生成的 client 模块,不在组件里裸写 fetch。 - `frontend/src/views/` — 页面级组件。路由对应的顶层页面, 原则上只做组合与状态编排,业务计算放入 `composables/`。 - `shared/` — 前后端共享的 TypeScript 类型定义与常量表。 修改时注意两端同步发布。 - `scripts/` — 本地开发脚本。数据库种子、代码生成器等, 已在 package.json / Makefile 中暴露命令,优先复用现有入口。

这一段看起来只是目录说明,但每个目录后面的那句“注释”才是真正的价值所在。Agent 读完之后,至少能达成三个效果:第一,拿到需求后能直接定位应该动哪个目录;第二,知道跨层调用的“红线”在哪里,不会再把 SQL 写在路由里;第三,修改公共目录时会多一分谨慎。

如果你用的是支持“文件引用语法”的 AI 编程工具,还可以在代码地图里直接写相对路径引用,让它能点击跳转。不过可读性是第一位,别为了炫技把文件撑得太长。

3.3 命令与验证:把“怎么做”写死

这一段的思路很简单:Agent 不需要猜怎么跑测试、怎么跑 lint,直接把命令列出来,它照着执行就行。但有一点要提醒,命令部分不能只列“完美路径”,还要告诉 Agent 遇到失败时怎么排查。

我当时写的是:

# Development Workflow ## Backend (conda active env: py311) - Run dev server: `uvicorn app.main:app --reload` - Run unit tests: `pytest tests/unit -x -q` - Run integration tests: `pytest tests/integration -x -q` - Run linter: `ruff check app tests` - Run formatter: `ruff format --check app tests` ## Frontend - Install deps: `pnpm install` - Run dev server: `pnpm dev` - Run unit tests: `vitest run --reporter=verbose` - Run linter: `eslint src --ext .ts,.vue` - Type-check: `vue-tsc --noEmit`

在命令后面我补了一段“自动化验证”说明,核心思想是:任何改动,在提交前必须让 Agent 自己能跑通的检查都跑一遍。这句话太重要了。我见过很多 AI 生成的代码,逻辑看着合理,结果一跑测试就挂——因为 AI 写代码时根本不跑测试,它只是在“生成文本”。你在 AGENTS.md 里写清命令和验证要求,实际上是在把 AI 的行为从“写代码”纠正为“开发代码”,这是质的区别。

有一个实操细节:命令部分要写绝对命令,别用“用包管理器安装依赖”这种模糊表述。AI 如果觉得项目用 npm 而实际上用了 pnpm,后面所有操作都会错位。把命令写死,就省了它猜的环节。

3.4 变更流程:约束 Agent 的“手”

如果说前面几段是在教 Agent“怎么做对”,那这段就是在教它“怎么避免做错”。我管它叫“变更流程约束”,但实际内容更像一个分支条件和触发器清单。

我的写法是用条件判断句式:

# Danger Zones - If you are about to modify files under `backend/app/models/`, you MUST create a matching Alembic migration script. - If you change a public function signature in `shared/`, you MUST update all call sites in both `backend/` and `frontend/`. - If you add a new third-party dependency, you MUST NOT commit it directly. Add it to the proposal in the repo report file instead. - If you are going to delete or rename an existing API endpoint, you MUST check the frontend callers first and update them together. - You MUST NOT edit migration files under `backend/alembic/versions/` after they have been merged to the main branch.

有条件句式的规则对 Agent 特别有效,因为它在生成代码时本质上是在做“下一个 token 的概率预测”,条件句给了它清晰的触发器。相比之下,像“注意保持代码整洁”这种模糊指令,根本进不了它的决策层。

另外我建议在变更流程里加一条针对“大改动”的兜底规则:如果改动预计影响超过五个文件,或者涉及数据库表结构变更,先输出一份改动计划和影响清单,再开始动代码。这条让 AI 从“闷头写代码”变成“先想后写”,对多人协作的代码库来说非常救命。

4. 实操中的坑与排查实录

4.1 问题一:上下文过长,Agent 反而变笨

刚开始我踩过一个大坑:AGENTS.md 越写越长,总觉得规则加得越多越安全。结果第一版上线之后,AI 的表现反而变差了——它开始频繁“忘记”后面的规则,或者在前面几条上过分纠结,整体行为非常刻板。

后来我想明白了:Agent 的上下文窗口是有限的,文件越长,每条规则分到的“注意力权重”就越低。这就好比给新同事发了一本三百页的员工手册,他不可能每条都记住,反而会抓不住重点。

解决办法是分层:AGENTS.md 只留最核心的、影响“代码能否被接受”的规则,大概二三十条;更细的规范放到子目录的局部说明文件里,比如backend/AGENTS.md只讲后端相关的约定,frontend/AGENTS.md只讲前端约定。这样根目录文件瘦身到八百字左右,AI 处理时轻快很多,而且局部规则更容易命中。

4.2 问题二:规则定义模糊,AI 理解偏离

还有一次,我在风格指南里写了“错误处理要统一”,结果 AI 生成的代码里全是对try...except的滥用——它把普通的返回值校验也包成了异常处理,看着规范,实则画蛇添足。

问题出在“统一”这个词,它含义太泛了。AI 没有我们团队那种“约定俗成”的语境,只有字面理解。后来我把这条改成了带正反例的说明:

- Error handling: business errors MUST be raised as `BizError` with a stable error code. Do NOT catch `Exception` at the route layer unless you are adding observability. Do NOT use `assert` for runtime business validation.

改完之后效果立竿见影,AI 生成的错误处理代码基本能直接用。这让我意识到一个原则:写规则时不要用形容词,要用动词和反例。每一条规则都应该是“可判定的”,既让 AI 能执行,也让人类评审时有据可依。

4.3 问题三:文档与代码脱节,规则失效

AGENTS.md 最大的风险不是写不好,而是写完之后没人维护。代码库天天在变,三个月后新增了workers/目录,但 AGENTS.md 里的代码地图还是旧的,AI 就会基于错误地图做决策,比没有地图还糟糕。

我在实践里定了一个硬规矩:凡是 PR 里新增了一级目录或迁移了关键模块,必须同步更新 AGENTS.md。这事一开始要靠人肉提醒,后来我在代码审查清单里加了一条“Change Log Check”,让检查项变成流程的一部分,坚持几周就变成了团队肌肉记忆。

另外我还会定期做一次“文档体检”:随便挑一个重构类任务,给 AI 设定成“只读模式”——只让它依据 AGENTS.md 输出改动方案,不看实际代码。如果方案里出现了明显偏离实际结构的内容,说明文档该更新了。

4.4 附:我常用的审查清单

这里分享我每次给 AGENTS.md 做迭代时的自检清单,你可以直接抄走:

检查项说明
是否有项目概览一句话说明项目是做什么的,技术栈是什么
代码地图是否准确每个一级目录的职责描述和实际代码一致
命令是否可直接复制构建、测试、lint 命令是否能在全新环境跑通
风格规则是否可判定每条规则是否具体到能判断对错,而非模糊的“要优雅”
危险操作是否列出是否覆盖迁移脚本、公共接口、依赖变更、端到端破坏性改动
是否设置了“不确定时先问”AI 在重大改动前有确认机制,而不是闷头执行
文件长度是否克制根目录文件尽量保持在一屏到两屏内,细节下沉到子目录文档

这七项我每次都会过一遍,基本能做到“文档不拖后腿”。

我个人在实际操作中的体会是:AGENTS.md 这种文件,本质上是在人和 AI 之间建立一份“可执行的默契”。它不需要多华丽,也不需要覆盖所有边界,但它必须精确、真话、有优先级。当这份默契建立起来之后,AI 从“会写代码的实习生”变成“懂规矩的协作者”,那种体验非常微妙——你不再需要逐行盯它的输出,只需要在它给出方案时做决策就够了。

这大概是 Agent Context 治理最迷人的地方:不只是省 token、提效率,而是让人和工具之间的协作边界变得更清晰、更舒适。

RELATED READING

延伸阅读

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