三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

写给 AI 看的文档,怎么才算写好?Matt Pocock 的六讲拆解

写给 AI 看的文档,怎么才算写好?Matt Pocock 的六讲拆解

Matt Pocock 的 Skills v1.2 更新了一个新技能:不写代码、不跑测试、不查 Bug——它只做一件事,教你写出 Agent 真能读懂的文档。它叫 /writing-for-agents。


怎么用

安装一行命令:

npx skills@latest add mattpocock/skills --skill=writing-for-agents

装好之后,两种触发方式

自动触发。当你创建或修改 skill、编辑AGENTS.mdCLAUDE.md时,Agent 会自动加载这个技能,对照其中的写作规则来检查你的文档。

手动调用。输入/writing-for-agents,然后告诉 Agent 你要写什么:一份 spec、一个 ticket、一段 README、一份 runtime prompt。只要 Agent 会读的东西,都可以用。

Matt 的建议是:写完初稿后,再用这个技能审一遍。Agent 自己写出来的文档通常偏啰嗦:它会花大量篇幅解释模型已知的概念。用/writing-for-agents做一次删减 pass,是这套技能价值最大的使用方式。

判断标准一句话:Agent 会读到这份文档吗?如果是,这套方法论就适用。不管文档怎么进入 Agent 视野:靠指针指名、靠你粘贴、还是本来就躺在仓库里。

下面六讲,是这个技能的核心原理。


一、反向思维:Agent 是读者,不是作者

/writing-for-agents是 Matt Pocock 的 Skills 套装 v1.2 中的第 21 个技能。编号不靠前,但 Matt 把它称为「垫在所有技能底下的那张纸」——套装里每一个 skill、每一份CLAUDE.md、每一个 spec,都是对照这份参考文档写的。

它的前身叫/writing-great-skills,v1.1 时改了名。Matt 的理由很直白:使用者早就不只拿它写 skill 了:AGENTS.mdCLAUDE.md、spec、ticket、README、runtime prompt,只要 Agent 会读的文档,这套方法论全部适用。v1.2 走得更远:把 skill 专属的机制(frontmatter、model-invoked vs user-invoked、router skill)全部拆到了链接引用的SKILL-MECHANICS.md里,主文档只剩通用的写作术。

名字带「writing」,容易踩坑:不是让 Agent 写文档。方向反了:你是作者,Agent 是读者。Matt 在页面里直接怼了这个误解:

"Writing for agents" — so the agent does the writing? The other way round. You are the author; the agent is the reader. That is the whole difficulty of the genre: you are writing for a reader who has already read everything, so explanation is waste and precision is the entire job.
「为 Agent 写作」:所以是 Agent 来写?方向反了。你是作者,Agent 是读者。这就是这个领域的全部难点:你为一个已经读过所有东西的读者写作,所以解释是浪费,精确是全部的工作。

翻译过来:这个读者不需要你解释。它预训练阶段见过了 REST API、React 组件、设计模式、数据库范式。向它解释已知概念,每一行字都是浪费上下文。一行没有改变 Agent 行为的字,就是一个no-op(空操作)。


二、核心框架:两笔账

这个技能的全部逻辑,建立在两个概念上:

Context Load(上下文负载)

Agent 的上下文窗口是有限的。AGENTS.md里的每一行、skill 描述里的每一条规则,都在每一轮对话中占据空间,不管本轮是否用到。Matt 把这叫做「always-loaded material」的代价。

always-loaded material:常驻加载材料——只要在上下文里,每轮都占位,不管用不用。一行代码规范写进CLAUDE.md,Agent 在写 SQL 的时候也要背着它——这就是不必要的 Context Load。

Cognitive Load(认知负载)

这笔账算在人身上。哪些文档存在?什么时候该调用哪个?你是指标:你知道你的项目有 README、有 API docs、有架构决策记录、有 5 个自定义 skill。Agent 不知道,除非你告诉它。这就是 Matt 说的「you are the index」。

you are the index:你就是索引。Agent 不知道什么文档存在——你知道。你不是负担,你是路由。这笔负载不是要最小化的成本——它是人类掌控权的代价。

一旦用这两笔账来思考,大部分写作决策——拆分还是合并?内联还是外链?指路还是灌输?——本质上都是同一个权衡在换场景。


三、五根杠杆

Matt 在技能中定义了五个控制 Agent 文档质量的操作维度。他刻意用「杠杆」(lever)这个词:不是规则,不是模板,是可以调节的控制点。

3.1 Context Pointer(上下文指针)

一段常驻上下文里的文字,指向一份外部材料,并在措辞中编码了「什么时候去读它」。Skill 的描述文字和AGENTS.md里的一句「详见 docs/architecture.md」是同一个东西。关键在于:指针的措辞,而非指针指向的内容,决定了 Agent 会不会真的去读。

比如,下面两种写法效果天差地别:

❌ "See docs/api.md for API guidelines" → 参见 docs/api.md 的 API 规范 (只说了"在哪",没说"什么时候去看") ✅ "Before writing any API endpoint, read docs/api.md for the response shape contract" → 写任何 API 端点之前,先读 docs/api.md 的响应格式约定 (何时触发、为什么读、读后做什么,全有了)

后者告诉 Agent什么时候触发、为什么要读、读完要做什么

3.2 Information Hierarchy(信息层级)

三级阶梯:文件内步骤 → 文件内引用 → 指针背后的外部材料。

渐进式披露(Progressive Disclosure)就是沿着这把梯子往下走,让顶层保持可读。

Progressive Disclosure:渐进披露:最重要的放最前面,细节一层一层往下展开。核心逻辑丢在第一层;细节推到第二层;特定场景的边界情况推到第三层。

一个判断标准:如果你在CLAUDE.md里写了一整段只在「做数据库迁移」时用到的规则,应该把它移到docs/db-migration.md,在CLAUDE.md里只留一个指针。

3.3 Completion Criteria(完成标准)

每一步的「做完条件」的清晰度和苛刻程度。

Matt 把这个杠杆和防止过早完成(premature completion)绑在一起。

premature completion:过早完成——Agent 写到 80% 就宣布「做好了」,因为「差不多」在它看来就是「完成」。Agent 倾向于「差不多就行」:写到 80% 就宣布完成。清晰的完成标准是唯一有效的对抗手段:

❌ "Write tests for the auth module" → 给 auth 模块写测试 (什么叫"写好"?不知道) ✅ "Write tests for the auth module. Every exported function must have at least one success-case and one error-case test. Coverage must be above 80%. Run `npm test -- --coverage` and confirm all pass." → 给 auth 模块写测试。每个导出函数至少一个成功用例和一个错误用例。 覆盖率 80% 以上。跑 npm test -- --coverage 确认全部通过。

后者没有多解释任何概念,只是在「做完」的定义上加了不可模糊的条件。

3.4 Leading Words(引导词)

一个紧凑的概念词,已经在模型预训练数据里出现过,Agent 在执行整份文档时会把它当作思维框架来用。

Matt 举了三个例子:tight(紧凑)、red(红线/不可触碰)、tracer bullet(曳光弹/端到端先走通再打磨)。这些词不需要定义:模型的预训练数据里已经有丰富的使用场景。它们在两个位置起作用:文档正文里驱动执行,指针文字里驱动触发。

Leading Words 的设计是一道翻译题:你心里想的是「不要过度设计」,在 Agent 的语料里那个概念叫YAGNI。用后者,Agent 内部激活的相关文本比你写一百字解释更精确。

YAGNI:You Ain't Gonna Need It——极限编程原则之一,不要实现当前不需要的功能。Agent 预训练数据里有大量 YAGNI 的讨论,用一个词锚定整个设计哲学。

3.5 Pruning(修剪)

单一真相来源、相关性、以及逐句执行的 no-op 测试。对抗三种文档腐化:

  • Duplication(重复)

    :同一件事在两个地方出现。Agent 不知道以哪个为准,或者更糟:读了两个版本,取了一个错误的折中。

  • Sediment(沉积)

    :曾经正确的规则,代码已经变了但文档没更新。Agent 照着做过时的约束。

  • Sprawl(蔓延)

    :文档越长越没人维护,越没人维护越长。死循环。


四、最狠的一招:No-Op 测试

/writing-for-agents有一个默认动作是删除,不是解释。

Matt 的观察很锋利:让 Agent 给另一个 Agent 写操作指南,它会把大量篇幅花在解释模型已知的概念上。这是因为模型在生成时倾向于「完整」:它不知道读者已经知道什么,所以宁可多写也不少写。

但你作为人类作者面对一份 Agent 文档时,可以逐句问一个问题:

删掉这句话,Agent 的行为会变吗?

如果不会:这就是一个 no-op。删掉。

这是行为性测试,不是审美测试。不问「这句话写得好不好」,只问「这句话有没有改变 Agent 接下来会做的事」。

一个真实的例子:

# Before (42 lines) · 改之前 ## API Design Guidelines This document outlines the API design guidelines for our project. APIs are the backbone of modern applications, enabling communication between different services. We use REST because it is widely adopted and well-understood by developers around the world. REST stands for Representational State Transfer... # → 本文档概述项目的 API 设计规范。API 是现代应用的骨干,实现服务间通信。 # 我们采用 REST 因为它被广泛采用并为开发者熟知。REST 全称是表述性状态转移…… # (Agent 不需要你教它 REST 是什么——这就是 42 行的由来) ## Response Format All API responses MUST follow the envelope pattern: { "code": 0, "data": {...}, "message": "ok" }
# After (6 lines) · 改之后 ## API Response Format All endpoints return: { "code": 0, "data": {...}, "message": "ok" } # → 所有端点返回此格式 Error: code != 0, message describes the error. # → 错误时 code 非零,message 描述错误原因

删掉的 36 行全是 no-op:Agent 不需要你告诉它 REST 是什么。剩下的 6 行,每一行都在改变 Agent 的行为。

Matt 在 FAQ 里提到一个关键细节:Agent 被要求「精简」文档时,会按字数优化,因为字数是它唯一能看到的东西。但 no-op 测试是行为性的:删掉一整句话,不是因为太长,是因为它没有改变 Agent 做什么。结果是文档确实变短了,但这是副作用,不是目标。


五、适用边界

创建或修改 skill、编辑AGENTS.mdCLAUDE.md时,Agent 会自动触发这个技能。

Matt 强调,对于 Agent 会读的所有其他文档,应该手动触发:docs、spec、ticket、runtime prompt、AFK prompt。

AFK prompt:Away From Keyboard prompt——离开键盘提示词,你离开电脑前留给 Agent 的最后一段话。

判断标准只有一个问题:

Agent 会读到这份文档吗?

如果是,不管这份文档是怎么进入 Agent 视野的:靠指针指名、靠人粘贴、还是它就在仓库里——这套方法论都适用。

有一个明确的界限:/writing-for-agents管的是文档怎么写,不管文档里写什么。搞清楚代码库里有什么内容、该怎么组织,那是/grill-with-docs的活。前者治文笔,后者治认知。


六、怎样算写好

Matt 给了四条检验标准:

1. 文档越改越短,短到让你意外。每次修改都在删:删重复、删沉积、删 no-op。改三轮还一样长,大概率没真的在改。

2. 一个引导词在不止一个地方生效。如果你挑了tracer bullet这个词,它应该同时出现在 spec(「先用 tracer bullet 走通全链路」)、代码审查清单(「检查 tracer bullet 是否覆盖了所有错误分支」)和 skill 描述(「优先做 tracer bullet 而非逐模块实现」)。一个词在多个位置做功,说明你选对了词。

3. 没有一件事被说了两次。重复是文档从未被测试过的最可靠信号。不是因为「写重了」,是因为没有人跑过这份文档——没有人发现 Agent 读到两次后行为开始扭曲。

4. 只有一条分支需要的参考材料,躲在指针后面而不是躺在主文件里。「某个 skill 只在 Windows 上需要额外配置」,这条配置不该出现在CLAUDE.md里,应该出现在那个 skill 自己的文档里,主文件只留一句指针。

Matt 收尾时说了句有意思的话:这里没有自动化评测。检查方式是手动跑一遍,然后用这套失败模式词汇做诊断工具。当一份文档表现异常时,先说出失败模式的名字,再修。


/writing-for-agents当成「写 skill 的说明书」是对它的低估。

它解决的问题比 skill 更深一层:人和 Agent 之间的信息带宽是有限的,上下文窗口是昂贵的,模糊指令的代价是运行时的行为偏差而非编译时的语法错误。怎么写、怎么删、怎么用词、怎么组织:每一项决策都是一个杠杆,撬动的是 Agent 最终行为的精确度。

回到 Matt 那对概念:Context Load 是你交的硬件税,Cognitive Load 是你交的脑力税。这份技能给的不是免税方案:是把每一 byte 和每一次记忆,精准兑现成 Agent 的正确行为。

Matt 把写作术提炼成了工程术。No-op 测试、Leading Words、Progressive Disclosure:这些概念从写作领域嫁接进 Agent 工程,成为可操作、可验证、可在每次编辑中反复应用的诊断工具,不是一次性清单。

关于 Agent 文档写作,一件事是确定的:好的 Agent 文档不是「写」出来的,是「删」出来的。


Matt Pocock 的 skills 仓库地址:github.com/mattpocock/skills

安装命令:npx skills@latest add mattpocock/skills --skill=writing-for-agents

参考来源:aihero.dev/skills-writing-for-agents

← 返回列表