Agent Skills:给 AI 编程补上工程纪律
一位资深工程师的工作,大部分是那些不会体现在代码对比(diff)中的部分:需求规格(Specs)、测试、代码审查、范围纪律、以及拒绝发布无法被验证的东西。而 AI 编程智能体(Coding Agents)默认会跳过这些部分。Agent Skills(智能体技能)就是我试图让这些部分变得“不可或缺”的尝试。
任何 AI 编程智能体的默认行为,都是选择到达“完成”的最短路径。你要求一个功能,它就写出这个功能。它不会问你是否有规格说明,不会在实现之前先写测试,不会考虑这个变更是否跨越了信任边界,也不会检查这个 PR(Pull Request)在审查者眼里会是什么样。它只会产出代码,宣布胜利,然后继续下一个任务。
这与每一位资深工程师在职业生涯中努力学习去避免的失败模式如出一辙。任何任务的“资深版本”都包含那些不会在代码 diff 中显示出来的工作:明确假设、编写规格说明、将工作拆分成可审查的块、选择朴实无华的设计、留下结果正确的证据、以及控制变更规模以便人类能够真正进行审查。正是这些步骤,区分了那些能在大规模下交付可靠软件的工程师,和那些提交会把系统搞崩的代码的人。
智能体跳过这些步骤的原因,和任何初级工程师一样:因为这些步骤是无形的。系统的奖励信号指向的是“任务完成”,而不是“任务完成且设计文档存在”。因此,我们必须把“资深工程师”的脚手架重新搭建起来。
Agent Skills 就是我为搭建这套脚手架所做的尝试。它刚刚突破了 2.6 万个 Star,所以显然并非只有我一个人有这个需求。这篇文章将探讨 README 中没有完全涵盖的部分:为什么会有这些设计选择,它们如何映射到标准的软件开发生命周期(SDLC)以及 Google 公开的工程实践,以及哪怕你一个技能都不安装,你也可以从这个项目中“偷”走些什么。
“技能(Skill)”到底是什么
在 Claude Code / Anthropic 的词汇表中,“技能”这个词承载了很多含义,我们需要对它进行精确的定义。一个“技能”就是一个带有前言(frontmatter)的 Markdown 文件,当情况需要时,它会被注入到智能体的上下文中。它介于系统提示词片段和运维手册(runbook)之间。
技能不是参考文档。它不是“关于测试你应该知道的一切”。它是一个工作流(workflow):智能体遵循的一系列步骤,带有产出证据的检查点,并以一个明确的退出标准(exit criterion)结束。
这个区别是整个游戏的关键。如果你把一篇 2000 字的关于测试最佳实践的文章放进智能体的上下文中,智能体读完后,会生成一段看起来很合理的文本,然后直接跳过实际的测试过程。但如果你放进去的是一个工作流(先写一个注定失败的测试,运行它,看着它失败,编写最少的代码让它通过,看着它通过,最后重构),智能体就有了具体要做的事,而你也有了可以验证的东西。
流程重于长篇大论(Process over prose)。工作流重于参考资料。带有退出标准的步骤重于没有退出标准的文章。 就是这一个区别,区分了一个有用的技能和一个漂亮的 Markdown 文件。这也解释了为什么那么多打着“AI 规则”旗号的代码库,在实践中根本毫无用处。因为那些规则只是一篇篇文章。
技能编码的 SDLC(软件开发生命周期)
代码库中的 20 个技能围绕着 6 个生命周期阶段组织,并在顶层提供了 7 个斜杠命令。定义(/spec)是你决定到底要构建什么的地方。计划(/plan)将工作进行拆解。构建(/build)以垂直切片的方式实现功能。验证(/test)证明它能工作。审查(/review)捕捉漏网之鱼。发布(/ship)将其安全地交付给用户。/code-simplify(代码简化)则贯穿于整个过程的底层。
这并非巧合。这正是每一个正常运转的工程组织都在运行的 SDLC,只是用了不同的词汇。Google 称之为:设计文档 → 审查 → 实现 → 可读性审查 → 发布清单。Amazon 称之为:逆向工作备忘录(working-backwards memo)和抬高标准者(bar raiser)。每一个健康的团队都有这个循环的某种变体。
AI 编程智能体带来的新情况是:大多数智能体默认会跳过这些阶段中的绝大部分。你要求一个功能,你得到了一个实现代码,而规格说明、计划、测试、审查和发布清单全都没有发生。技能的作用就是强迫智能体经历资深工程师强迫自己经历的相同阶段,因为如果不经历这些就发布代码,你就是在制造生产事故。
一个复杂的功能可能会按顺序激活 11 个技能。一个小小的 Bug 修复可能只会用到 3 个。路由器(using-agent-skills)决定应用哪些技能。关键在于,工作流是根据实际的任务范围来缩放的,而不是根据假设的范围。
正在发挥作用的五项原则
项目中有五个承重级的设计决策。系统的其余部分都是由它们衍生而来的。
1. 流程重于长篇大论 (Process over prose)
刚才已经讲过。工作流是智能体可执行的;文章则不是。对于人类团队来说也是如此。如果你的团队手册有 200 页,在时间紧迫的情况下没人会去读它。如果它是一组带有检查点的小型工作流,人们才会真正去执行。
2. 反合理化表格 (Anti-rationalization tables)
这是项目中最具特色的设计决策,也是我最希望其他团队能“偷”走的一点。
每个技能都包含一个表格,列出了智能体(或疲惫的工程师)可能用来跳过该工作流的常见借口,并配有书面的反驳。这里有几个接近原版的例子:
- “这个任务太简单了,不需要规格说明。” → 验收标准依然适用。写五行可以。零行不行。
- “我晚点再写测试。” → “晚点”是这里的承重词。没有“晚点”。先写出必定失败的测试。
- “测试通过了,发布吧。” → 测试通过只是证据,不是绝对的证明。你检查过运行时状态了吗?你验证过用户可见的行为吗?有人类读过代码 diff 吗?
这套机制之所以有效,是因为大语言模型(LLM)非常擅长“合理化(rationalisation)”。它们会生成一段听起来非常有道理的话,解释为什么这个特定的任务不需要规格说明,或者为什么这个特定的变更不经审查直接合并也没问题。反合理化表格,就是为智能体尚未说出口的谎言提前写好的反驳词。
这个模式对人类团队同样适用。大多数工程质量的衰退,并不是因为有人故意要做糟糕的工作。而是因为人们接受了那些听起来很有道理的借口,从而跳过了那些他们不想做的部分。一个把“反合理化借口”写下来的团队,这种借口就会少得多。
3. 验证是不可谈判的 (Verification is non-negotiable)
每一个技能都必须以具体的证据作为终结。测试通过。构建输出无报错。运行时追踪显示了预期的行为。审查者签字同意。“看起来是对的” 永远不够。
正是这一原则使得 Anthropic 的测试框架能够从失败中恢复,使得 Cursor 的 planner/worker/judge 拆分能够真正捕捉到 Bug,使得任何长时间运行的智能体具备可恢复性。智能体是一个生成器(generator)。你需要一个独立的信号来证明工作已经完成。技能将这种信号固化到了每一个工作流中。
4. 渐进式暴露 (Progressive disclosure)
不要在会话开始时就把全部 20 个技能都加载到上下文中。应该根据所处的阶段来激活它们。一个名为 using-agent-skills 的小型元技能充当路由器,决定哪个技能适用于当前的任务。
这是在技能粒度上应用的外壳框架工程(harness engineering)经验。加载到上下文中的每一个 token 都会在某个地方降低性能,所以你只加载相关的部分,把其余的留在磁盘上。渐进式暴露,就是让你能把一个包含 20 个技能的库塞进 5K token 的槽位里,而不会污染整个上下文池的方法。
5. 范围纪律 (Scope discipline)
元技能中编码了一条不可谈判的原则,如果可以的话,我希望能把它钉死在每一个智能体身上:“只碰你被要求碰的东西。” 不要去重构相邻的系统。不要删除你不完全理解的代码。不要只是因为碰巧看到一个 TODO 注释,就决定重写整个文件。
这听起来像是一句废话,直到你亲眼看到一个智能体决定:为了修复一个 Bug,需要顺便把三个毫不相关的文件“现代化”一下。范围纪律,是决定一个智能体的 PR 能否被合并、还是必须被撤销的最大决定因素。 这也是最清晰地映射到 Google 代码审查规范的原则,在 Google,如果一个 PR 做了不止一件事,审查者就会阻止它。
Google 的 DNA
这些技能中渗透着来自《Google 软件工程》和 Google 公开工程文化的实践。这是有意为之的。让 Google 规模的软件能够运转起来的绝大部分方法都是公开且有文档记录的,而这正是智能体最容易跳过的部分。
以下是部分技能与其实践的映射:
- **海勒姆定律(Hyrum’s Law)**体现在
api-and-interface-design(API 与接口设计)中。你的 API 的每一个可观察行为,最终都会被某人依赖,所以在设计时要把这一点铭记在心。 - **测试金字塔(~80/15/5)和碧昂丝法则(Beyoncé Rule)**体现在
test-driven-development(测试驱动开发)中。“如果你喜欢它,你就应该给它戴上戒指(加个测试)。” 基础设施的变更捕捉不到 Bug;测试才能。 - 在测试中,DAMP(描述性且有意义的短语)优于 DRY(不要重复自己)。 Google 的测试哲学明确指出,测试代码读起来应该像一份规范说明,哪怕代价是产生一些重复代码。过度抽象的测试是一种已知的反模式。
- ~100 行的 PR 规模控制,以及 Critical(致命) / Nit(挑刺) / Optional(可选) / FYI(供参考)的严重程度标签体现在
code-review-and-quality(代码审查与质量)中。这直接出自 Google 的代码审查规范。大型的 PR 根本得不到真正的审查;它们只会得到一个“盖章通过”。 - **切斯特顿的栅栏(Chesterton’s Fence)**体现在
code-simplification(代码简化)中。在没有弄明白为什么某个东西会被放在那里之前,千万不要去拆除它。 - **基于主干的开发(Trunk-based development)和原子提交(atomic commits)**体现在
git-workflow-and-versioning(Git 工作流与版本控制)中。 - **左移(Shift Left)和特性开关(feature flags)**体现在
ci-cd-and-automation(CI/CD 与自动化)中。尽可能早地捕捉问题,将部署(deploy)与发布(release)解耦。 - **代码即负债(Code-as-liability)**体现在
deprecation-and-migration(废弃与迁移)中。你保留的每一行代码都是你必须永远维护的,所以要偏爱更小的表面积。
这些都不是什么新想法。关键在于,默认情况下它们都不在智能体的脑子里。 一个前沿模型可能在它的训练数据里读到过“海勒姆定律”这个词,但当它在凌晨 3 点为你设计 API 时,它并不会主动去应用海勒姆定律。技能,就是你确保它会去应用的手段。
如何实际使用它
有三种模式,投入程度大致依次递增。
模式 1:通过插件市场安装。 如果你在使用 Claude Code:
/plugin marketplace add addyosmani/agent-skills
/plugin install agent-skills@addy-agent-skills
你将获得这些斜杠命令(/spec, /plan, /build, /test, /review, /ship, /code-simplify),而且智能体会根据上下文自动激活相关的技能。这是我推荐大多数人开始尝试的路径。
模式 2:将 Markdown 文件丢进你常用的工具中。 这些技能就是带有前言的纯 Markdown 文件。Cursor 用户可以把它们放进 .cursor/rules/ 目录下。Gemini CLI 有自己的安装路径。Codex、Aider、Windsurf、OpenCode……任何接受系统提示词的工具都能读取它们。工具本身不重要,重要的是底层的这套工作流。
模式 3:将它们作为规范说明来阅读。 哪怕你什么都不安装,这些技能本身就是一份*“记录了与 AI 智能体合作进行优秀工程实践应该长什么样”的文档*。阅读 code-review-and-quality.md,并将它的五轴框架应用到你们团队的审查流程中。阅读 test-driven-development.md,用它来平息下次与初级工程师关于“我们是否需要先写测试”的争论。阅读元技能,把那五个不可谈判的原则“偷”走,放到你们自己的 AGENTS.md 文件里。
这第三种模式才是我实际推荐开始的地方。挑选四到五个与你们当前痛点最接近的技能。决定你想要强制执行哪些工作流。然后再安装运行时(runtime)或自己开发一个来实现强制执行。
哪怕你不安装也应该“偷走”的东西
无论你是否使用 AI 编程智能体,我都建议你从这个项目中“偷走”以下几个模式:
将“反合理化”作为一种团队实践。 把你们团队自欺欺人的谎言写下来。“我们上线后再去修测试。”“这个变更太小了,不需要写设计文档。”“没关系的,我们有监控。” 为每一条谎言配上反驳词。把它们放在你们的 AGENTS.md 或工程 Wiki 里。这会帮你们省去很多争论,并且能拦截住下一个在疲惫的周五下午试图走捷径的行为。
对于内部编写的任何东西,流程重于长篇大论。 如果你发现自己正在写一篇 2000 字、标题为“我们如何处理 X”的文档,那你其实是在写参考资料。把它转换成一个带有检查点的工作流。文档会缩减到 400 字,而且人们才会真正去执行它。这不仅适用于智能体技能,同样适用于新人入职指南和运维手册。
将验证作为硬性的退出标准。 把“产出证据”作为每一项任务的退出步骤。无论是对智能体、对工程师,还是对你自己。证据可以是任何能证明工作已完成的东西:绿色的测试运行结果、一张截图、一段日志、或者审查通过的签字。没有证据,任务就没有完成。“看起来是对的” 永远不能作为闭环的终点。
对任何规则手册使用渐进式暴露。 不要写一本 50 页的手册。写一个小型路由器,根据具体情况指向正确的小章节。对于 AGENTS.md、运维手册、事故处理手册,以及任何人在时间紧迫的情况下需要阅读的东西来说,这都是适用的。
我明天就会放进任何 AGENTS.md 文件里的五条不可谈判的原则(提取自元技能):
- 在构建之前明确假设。保持沉默的错误假设是最常见的失败模式。
- 当需求冲突时,停下来询问。不要瞎猜。
- 在必要时进行反驳。智能体(或工程师)不是一台只会说“Yes”的机器。
- 偏爱朴实无华、显而易见的解决方案。小聪明往往代价昂贵。
- 只碰你被要求碰的东西。
这短短五行字就构成了一种有价值的工程文化,而且你不需要安装任何东西就能采纳它。
这在框架体系中处于什么位置
从更宏观的视角来看,技能是智能体外壳框架工程(agent harness engineering)的其中一层。外壳框架(harness)是指模型加上你围绕它构建的所有东西;而技能是可重用的工作流块,它们被渐进式地暴露并注入到系统提示词中。它们与 AGENTS.md(滚动更新的规则手册)、钩子(确定性的强制执行层)、工具(智能体可以采取的行动)和会话日志(持久的记忆)并列存在。每一层都有其特定的工作。而技能所负责的,就是扮演“资深工程师流程”的角色。
对于长时间运行的智能体(long-running agents)来说,技能比对聊天式智能体更为重要,因为长时间的运行会放大每一次偷懒走捷径的后果。一个在 10 分钟会话中跳过测试的智能体会产生一个 Bug。而一个在 30 小时会话中跳过测试的智能体,会在运行结束时交给你一个堪比考古发掘的调试项目,那时已经没人记得最初的意图是什么了。运行的时间越长,“资深工程师”的脚手架就越需要被强制执行,而不仅仅是建议。
技能格式的便携性也很重要。同一个 SKILL.md 文件可以在 Claude Code、Cursor(通过 rules)、Gemini CLI、Codex 以及任何接受系统提示词内容的外壳框架中工作。工作流只需编写一次,运行时会自动强制执行它。这就是“带前言的 Markdown”这种格式能为你带来的好处,而这是定制化的提示词工程所无法提供的。
结语
相比于技能本身,我最希望人们从这个项目中带走的,是这种思维框架。
AI 编程智能体能力极强,但它们就像是没有直觉的初级工程师,根本不知道这份工作中那些不会体现在代码 diff 里的部分有多重要。资深工程师的工作(明确假设、控制变更规模、编写规格说明、留下证据、拒绝合并无法审查的代码),恰恰是智能体会默认跳过的,除非你让它不可能跳过。因此,我们日益重要的工作,就是将这种纪律编码成智能体无法自己找借口逃避的东西。
技能就是这种纪律的一种形态。反合理化表格。渐进式暴露。流程重于长篇大论。将验证作为承重级的退出标准。以及将那些在 Google 已经被证明行之有效的实践,变得可移植化。
你可以安装我的版本。你也可以自己开发一套。无论哪种方式,核心教训是不变的:即使工程师是一个 AI 模型,这份工作中属于资深工程师的那部分,也绝不再是可有可无的选项。
项目代码库位于 github.com/addyosmani/agent-skills (MIT 开源协议)。关于更宏观的脚手架体系,请参阅 智能体外壳框架工程 (Agent Harness Engineering) 和 长时间运行的智能体 (Long-running Agents)。