🛠️ 第6章 AGENTS.md:给 Agent 的项目说明书
📄 一句话概括

AGENTS.md 只答三个问题:东西在哪儿、怎么跑、什么不能碰。 每一段都有「能不能拿来判」的硬要求,写在里头的话必须可判定。 Demo 里三段各查一遍:地图一个目录写错、入口三条真跑、禁区拦两条放一条。

📝 本章和前面几章的关系

从这一篇开始进第二部分:Harness 四件套。第一件是 AGENTS.md——给 Agent 看的项目说明书。 它不是给人看的文档。 人读文档会跳读、会猜、会问;Agent 不会,它按写的执行,没写的就当不存在。 这个差别决定了写法:少写「我们注重质量」这种话,多写「改完跑 python tasks.py test」。 Demo 造了一份真仓库和三段真说明书, 然后逐段检查:地图里的目录在不在、入口的命令跑不跑得动、禁区拦不拦得住。 结果是「三个目录在、一个不在」「三条入口都跑得动」「三条改动拦两条」。

一、三段结构

三段,顺序也有讲究:先说在哪儿,再说怎么动,最后说别碰什么。

段 回答的问题 典型条数
项目地图 东西在哪儿 三到六条
关键入口 怎么跑、怎么验 两条到四条
禁区 什么绝对不能碰 两条到五条

为什么这个顺序?因为它对应 Agent 的动作顺序: 先找文件、再跑命令、中途判断「这一步能不能做」。 你按它的动作顺序写,它读一遍就能用。 别写成一篇介绍。 「本项目是一个基于情绪识别的聊天应用,采用分层架构」—— 这句话你知道有用,它读着也没错,但它不知道拿这句干什么。 换成「src/api/ 是后端,src/web/ 是前端」,它就能去找文件了。

二、关键入口怎么写

入口要写成「一条能粘进终端的命令」,不是「大概这样跑」。 区别在于:前者它照抄就能跑,后者它得翻译。 翻译就会翻错。

不要这么写 要这么写
用测试框架跑一下测试 python tasks.py test
启动开发服务器 python tasks.py run
检查代码风格 python tasks.py lint

Demo 里三条入口都真跑了一遍,全过。 这个「真跑一遍」值得当成习惯—— 入口写错是最亏的错:它照着跑、报错、然后自己换一条命令,接下来所有的失败你都会归因错。 还有一条建议:入口不超过四条。 跑、验、加一条「只跑一个文件」,就够了。 列十几条命令的说明书,它记不住,你也不维护。

三、禁区要写死

禁区的要求只有一个:能拿来判。 「注意数据安全」判不了——它不知道什么算安全。 「data/ 下一个字都不许改」能判:路径匹配就拦。 Demo 里拿三个改动去撞: data/stopwords.txt 拦住、package-lock.json 拦住、src/emo.py 放行。 三条拦两条,是因为禁区写成了「路径匹配」的形状。 写禁区的三个常见维度: 不能改的目录(线上导出、历史包袱)、不能碰的文件(锁文件、密钥)、不能做的动作(不许加依赖、 不许改表结构)。 最后一条最容易漏:动作类禁区。 「不许新增第三方依赖」这一条,能挡掉很多「顺手装个库」的行为。 而这些行为往往是最难回滚的——装进去的包,你怎么知道它有没有被用上?

四、动手 Demo:三段结构:地图、入口、禁区,各查一遍

这个 Demo 造一份真仓库、写一份三段式 AGENTS.md,然后逐段验证。 地图查「目录真不真在」、入口查「命令跑不跑得动」、禁区拿三个改动去撞。 全部真跑,没有任何一项是摆样子。

secs = _sections(AGENTS_1)          # 按二级标题切段

for it in secs[u"项目地图"]:          # 地图:目录在不在
    d = re.search(r"`([^`]+/)`", it).group(1).rstrip(u"/")
    ok = os.path.isdir(os.path.join(base, d))

for it in secs[u"关键入口"]:          # 入口:真跑一遍
    cmd = re.search(r"`([^`]+)`", it).group(1)
    code, out = py(base, parts[1], args=parts[2:])

实跑输出:

--------------------------------------------------------------------
三段结构:地图、入口、禁区,各查一遍
--------------------------------------------------------------------


  ① 先写一份 AGENTS.md,三段
  --------------------------------------------------------------------
  ## 项目地图(4 条)
  ## 关键入口(3 条)
  ## 禁区(3 条)
  三段加起来十二行。它不解释「为什么」,只写「是什么、在哪儿、不许碰什么」。

  ② 地图:写的目录是不是真在
  --------------------------------------------------------------------
  [在] src
  [在] tests
  [在] docs
  [不在] services
  三个在、一个不在。写错的那个目录会让它去翻一个不存在的地方,翻不到就自己猜。
  ! 地图最常见的问题不是写少,是写旧。
  目录改了名、合了并,文件没人更新——而 Agent 会当真,按旧名字找地方。

  ③ 入口:写的命令跑不跑得动
  --------------------------------------------------------------------
  [能跑] python tasks.py run        -> 退出码 0 | 听你这么说我也高兴
  [能跑] python tasks.py test       -> 退出码 0 | 通过 3 / 失败 0
  [能跑] python tests/test_main.py  -> 退出码 0
  三条入口都真跑了一遍。
  入口写错是最亏的:它照着跑、报错、然后自己换一条命令——你后面看到的失败,全是这一条引起的。

  ④ 禁区:拿三个改动去撞
  --------------------------------------------------------------------
  [拦住] data/stopwords.txt      落在 data/ 禁区
  [放行] src/emo.py              不在禁区里
  [拦住] package-lock.json       lock 文件不许手改
  三条里拦住两条。禁区的写法有个要求:要能拿来判,不能只表态度。
  ! 「注意数据安全」这种写法没法判——它不知道什么算安全。
  「data/ 下一个字都不许改」能判:路径匹配就拦。禁区的每条都要写成这种形状,否则等于没写。

  ⑤ 三段各答一个问题
  --------------------------------------------------------------------
| 段 | 回答的问题 | 写不好会怎样 |
|---|---|---|
| 项目地图 | 东西在哪儿 | 它去翻不存在的地方 |
| 关键入口 | 怎么跑、怎么验 | 它自己发明命令,失败归因全乱 |
| 禁区 | 什么绝对不能碰 | 它顺手改了线上导出的数据 |

地图四条,三个在、一个不在。 不在的那个是 services/——目录改了名,说明书没跟着改。 这是地图最常见的问题:不是写少,是写旧。 三条入口全跑通。 注意第三条「只跑一个文件」也验了一遍——它是最容易被写错的一条, 因为大家只记得住「跑全部」那条。 禁区三条拦两条。 package-lock.json 那条能拦住,是因为禁区写的是「任何锁文件不许手改」, 而不是「注意依赖版本」。 后一种写法拦不住任何东西。 最后那张表是这一篇的全部内容:三段各答一个问题,每段写不好都对应一类事故。 这三段加起来十二行,但它决定了后面所有任务对不对。

30 秒实验

  1. 给你的项目写三段,每段先写三条。 写完拿地图那三条去目录里对着看——大概率有一条已经过时了。
  2. 把你常用的命令粘成一行一行的。 粘完自己跑一遍,跑不通的就是写错的。
  3. 写三条禁区,都用「路径匹配」或「动作」的形状。 写不出来「能判」的,就别写。

常见误区

  1. 「AGENTS.md 是给人看的文档。」 人读文档会猜,Agent 不会。 没写的它当不存在——所以「注意质量」这种话对它等于零。
  2. 「写得越全面越好。」 全面等于没人维护。 十二行能维护,四十行三个月后就过期了。
  3. 「禁区写「注意安全」就够了,它应该懂。」 它不懂。 「注意安全」没有边界,它只能按自己的理解来——而它的理解跟你的不一样。
自测三问(点开对答案) 1. 三段为什么按「地图、入口、禁区」这个顺序? —— **因为它对应 Agent 的动作顺序:先找文件、再跑命令、途中判断能不能做。** **按它的动作顺序写,它读一遍就能用。** 2. 什么样的禁区写法算「能判」? —— **路径匹配或动作匹配。** **「`data/` 下不许改」「不许新增依赖」能判;「注意数据安全」判不了。** 3. 为什么入口要写成能直接粘的命令? —— **因为它不会「翻译」。** **写「用测试框架跑一下」,它得猜是哪个框架、哪条命令**——猜错就换一条, **然后你的失败归因全乱。**

下一篇 6.2 讲分层:根目录和子目录谁覆盖谁,以及为什么「子只能加、不能减」。

相关笔记