AI编程——Skill原理

cuixiaogang

Skill 是一个带 YAML frontmatter 的 Markdown 文件,靠 frontmatter 三字段决定”叫什么名、何时自动触发、是否只能手动调”,正文是工程纪律的步骤化沉淀——本质是用确定性指令驯化 LLM 的随机性。

简介

在 AI 编码 agent 的语境里,Skill 是一种把”工程纪律”固化成 agent 可读、可触发指令的机制。它不教模型写代码,而是给模型套上一层操作规程:什么时候该走 TDD、什么时候该先盘问对齐、审查 diff 时按哪几条轴走。

这套机制最知名的公开实践是 Matt Pocock 开源的 mattpocock/skills(MIT 协议),副标题”Skills for Real Engineers. Straight from my .agents directory.”——把他自己日常用的 .agents 目录抽出来开源。本文以它为范例讲清 skill 的原理与写法。

skill 的总目标是用确定性去驯化随机系统(原文:wrangle determinism out of a stochastic system)。LLM 是概率模型,同一个输入可能给不同输出;skill 用”触发判据+步骤化正文+反模式清单”把其中需要稳定的那部分钉死。

文件结构

每个 skill 是 <目录>/<名字>/SKILL.md,外加可选的同目录引用文件(如 GLOSSARY.mdtests.md)。SKILL.md 本质就是一个带 YAML frontmatter 的 Markdown:

1
2
3
4
5
6
7
8
9
---
name: tdd
description: Test-driven development... 用在用户想 red-green-refactor / 集成测试时
disable-model-invocation: false
---

# Test-Driven Development

正文:步骤、规则、反模式……

frontmatter 三个字段决定了 skill 的一切行为:

字段 作用
name skill 标识符,也是 /命令 的名字(tdd/tdd
description 模型自动触发的判据——模型读这行判断”当前任务要不要自动加载这个 skill”。写得极讲究:前置触发词、每个分支一个触发条件、不重复正文已有信息
disable-model-invocation true = 只能用户手动 /xxx 调用;false 或省略 = 模型可自动触发

两条触发路径

  • 用户触发(user-invoked):你敲 /grill-me,对应 skill 全文被注入上下文,agent 按里面的步骤执行。它是”编排器”,可以再调别的 model-invoked skill,但不能调另一个 user-invoked skill,防止编排器互相套娃。
  • 模型触发(model-invoked):你不需要点名,模型读到自己 description 命中当前任务时,自动加载并遵循。比如你让它”修个 bug”,它自己命中 diagnosing-bugs 的 description,就走上那套”复现→最小化→假设→插桩→修→回归测试”的纪律。

两条路径的分工:user-invoked 负责”编排工作流”,model-invoked 负责”沉淀可复用的工程纪律”。

skill触发路径
skill触发路径

图里两条路径最终都汇到 MI(model-invoked skill):左边敲 /命令 走 user-invoked,把 skill 全文注入上下文后按步骤执行工作流,期间可下调 model-invoked 但不能套另一个 user-invoked;右边普通任务由模型扫描各 skill 的 description,命中就自动加载对应的 model-invoked,没命中则无约束自由发挥。一句话——user-invoked 是你主动拉来的编排器,model-invoked 是模型按需自动戴上的纪律。

信息分层

正文不是一坨,而是分三层控制上下文成本,这是”渐进披露(progressive disclosure)”原则:

  • in-skill steps:核心步骤,写在正文里,每次必读;
  • in-skill reference:同目录的 tests.md/mocking.md 等,按需读;
  • external reference:链接出去的外部文档,仅在需要时取。

分层的意义:LLM 上下文是稀缺资源,把每次必读的核心步骤和”只在某分支才需要”的细节分开装,避免无关内容吃掉 token。

写作纪律

写 skill 不是写文档,而是写”给模型看的操作规程”。mattpocock/skills 里有个专门的元 skill writing-great-skills 沉淀了这套写法,核心几条如下。

写 description

description 是自动触发的判据,写它有三条规矩:

  • 前置触发词:把最关键的动作词放最前面,让模型扫一眼就命中;
  • 一个分支一个触发:每个触发条件对应一种任务分支,别把多种场景揉成一句;
  • 不重复正文:description 只说”何时触发”,正文里已经讲清的细节不抄进来。

何时拆分

skill 膨胀时要拆,有两种拆法:

  • 按调用方式拆(by invocation):一个步骤该由用户主动发起、还是该由模型自动触发,分属 user-invoked 和 model-invoked,别混在一个文件里。
  • 按序列拆(by sequence):一段流程里前后顺序明确的步骤,拆成可串起来的多个 skill,让编排器按顺序调。

剪枝与 no-op 测试

每段都要过 no-op 测试:删了这句,skill 还能正常工作吗?能就删。所以 skill 写得极简,每句都有用。剪枝时遵循”单一真源”——一个规则只在一处定义,别在多处复述。

leading words

正文里用加粗的术语(如 completion criterionseam)锚定行为,这些是”预训练概念”的浓缩:一个术语背后挂着一整套模型已经懂的知识,用一个词就能调起,省掉大段复述。

六种失败模式

写 skill 会踩六种坑,writing-great-skills 把它们点出名:

失败模式 含义
premature completion(过早完成) 还没把决策树问完就草草收场,该盘问的没问到位
duplication(重复) 同一规则在多处复述,维护时易漂移,违反单一真源
sediment(沉淀) 老内容不再有用却没清掉,像淤泥占着上下文
sprawl(蔓延) skill 越写越大、什么都往里塞,失去焦点
no-op(空操作) 某段删了不影响执行——剪枝漏网
negation(否定式表述) 用”不要做 X”而非”要做 Y”来约束,模型对否定式遵循更差

其中 no-opduplication 是剪枝的主要猎物,negation 是写法上的反模式——尽量用正向指令替代”禁止做某事”。

样例:tdd

tdd 展开一个 skill 的真实写法,因为它最能体现”用 skill 沉淀纪律”的思路。

frontmatter:name: tdddescription 命中”red-green-refactor / 集成测试”等触发词,disable-model-invocation: false(可被模型自动触发)。

正文要点:

  • 好测试:通过公共接口验行为、读起来像规约、扛得住重构。
  • Seam(缝):只在”预先约定并和用户确认过”的公共边界测,不测未确认 seam;任何测试动手前先写下 seam 并与用户确认。
  • 三大反模式
    1. 实现耦合——mock 内部协作者或测私有方法,特征是”重构即崩但行为没变”;
    2. 同义反复——断言把代码逻辑重算一遍,永远不可能挂,期望值必须来自独立真值源;
    3. 横切——先写全测试再写全实现。正确做法是垂直切片:一条测试→一段最小实现→重复,每条测试都是示踪子弹
  • 循环三规:先红后绿(只写够过测试的代码,不投机)、一切一片、重构在循环内(归 code-review)。

可见 tdd 把教科书里的 TDD 纪律,拆成了”触发判据+可执行步骤+反模式清单”,agent 读到就照着走,而不是自由发挥。

与本仓库的关系

这套机制和本仓库 .claude/skills/ 下的 knowledge-splitknowledge-learntech-blog同一套 Agent Skills 标准(都是 Claude Code 的 skill 机制)。理解了本文的原理,自己那几个 skill 的运作方式也就通了:它们的 frontmatter 同样决定触发方式,正文同样按”分步骤+可按需引用”组织。相关 skill 清单与速查,详见 MattPocock学习及Skills速查.md

小结

要点 记住
本体 一个带 frontmatter 的 SKILL.md
三字段 name(命令名)、description(自动触发判据)、disable-model-invocation(是否只能手动调)
两路径 user-invoked 编排工作流、model-invoked 沉淀纪律
三层信息 in-skill steps / in-skill reference / external reference
收紧原则 no-op 测试——删了不影响工作就删
写法禁忌 六种失败模式,尤其 negation(用正向指令替代否定式)

延伸方向:想看 skill 的全集清单与安装使用,读 MattPocock学习及Skills速查.md;想自己写 skill,直接读仓库里的 writing-great-skills 那个元 skill,它是这套规范的源头。