Skip to Content
Claude Code Skill 指南Cognition解剖 skill-creator:创建 Skill 的 Skill

解剖 skill-creator:创建 Skill 的 Skill

这一章深入拆解了 skill-creator 的内部架构。如果你更想先动手写 Skill,可以跳到第 5 章,等读完第 20 章再回来看这里——那时你会对评测体系有切身体验,理解起来更顺畅。

一个自举问题

skill-creator 是 Anthropic 官方发布的一个 Skill,用途是教 Claude 创建其他 Skill。

停下来想一想这件事有多奇怪。这就像用编译器编译编译器自身,或者写一本叫《如何写书》的书。这种自举结构天然存在一个矛盾:它作为 Skill 被加载时,SKILL.md 建议控制在 500 行以内(超过这个长度,AI 对后半部分指令的遵循度会明显下降),但它要指导的流程——从意图捕获、访谈调研、编写测试到迭代改进——复杂度远超 500 行能承载的信息量。

skill-creator 是怎么解决这个矛盾的?它把自己拆成了四层:SKILL.md 只做流程编排,计算逻辑交给 scripts/,评测逻辑交给 agents/,可视化交给 eval-viewer/。每一层各司其职,SKILL.md 就像一个项目经理,自己不写代码,但清楚知道每个阶段该调用谁。

这个架构决策本身就是一堂 Skill 设计课。本章把它拆开看。

五阶段工作流

skill-creator 把创建 Skill 的过程切成五个阶段,每个阶段有明确的输入和输出。不是随便分的——每个阶段的边界都对应着一个”需要人类决策”的节点。

Stage 1:捕获意图

用户说”帮我写一个部署 Skill”,这句话信息量远远不够。skill-creator 的第一件事不是动手写,而是搞清楚三个问题:

  • 做什么:这个 Skill 的职责边界在哪?“部署”是部署到哪?包不包括回滚?
  • 什么时候触发:用户说什么话的时候应该激活这个 Skill?“部署一下”算不算?“上线”算不算?
  • 什么算成功:怎么判断这个 Skill 工作正常?部署完成?还是部署完成且健康检查通过?

这个阶段的输出是一个结构化的意图描述,不是代码。

Stage 2:访谈与研究

拿到意图后,skill-creator 开始主动追问。不是礼貌性地问”还有什么要补充的吗”,而是针对性地挖:

  • 边界情况:如果部署失败怎么办?如果目标环境不存在呢?
  • 格式要求:输出是纯文本还是 Markdown?需要包含时间戳吗?
  • 依赖关系:需要调用什么外部工具?需要什么权限?

同时,它会用子代理并行调研——读项目的现有代码结构、查看已有的 Skill 作为参考、分析用户提到的工具文档。这里的关键词是”并行”。不是串行地一个个查,而是同时派出多个子代理各查各的,然后汇总结果。

Stage 3:编写 SKILL.md

进入实际编写阶段。这里有几个硬约束:

  • SKILL.md 必须控制在 500 行以内
  • frontmatter 必须包含 name 和 description
  • description 要写得”激进”——宁可多匹配一些用户意图,也不要漏掉

为什么 description 要激进?因为 description 决定了 Skill 的触发率。一个 description 写成”部署 Node.js 应用到 AWS ECS”的 Skill,当用户说”帮我把服务上线”时就不会被触发。但如果写成”部署、上线、发布应用到生产环境”,覆盖面就大得多。误触发的代价很低(大不了 Skill 加载后发现不适用),但漏触发的代价是用户根本不知道这个 Skill 存在。

Stage 4:测试与评测

这是整个流程中最复杂的阶段,也是 skill-creator 设计最精巧的部分。

流程是这样的:

  1. 同时启动两组运行:一组带 Skill(with_skill),一组不带(without_skill),用相同的测试用例。两组并行跑,不是串行。
  2. 在等待运行结果的同时写断言。注意这个时序——断言是在看到输出之前写的。为什么?因为看到输出再写断言,你会不自觉地把断言写成”验证输出就是这样的”,而不是”验证输出应该是这样的”。这是事后诸葛亮,测不出真正的问题。
  3. 运行完成后立即捕获 timing 数据。这一步有个陷阱:子代理完成时的通知消息里会带 timing 信息(执行耗时),但这个数据只在通知中出现一次,不会被保存到任何地方。如果你没有在通知到达的那一刻把它抓下来,这个数据就永远丢了。
  4. grader 子代理评分:读 transcript,逐条评判断言是否通过。
  5. aggregate_benchmark.py 汇总统计:把所有评分聚合成可比较的数据。
  6. eval-viewer 呈现结果:生成一个零依赖的 HTML 页面,直接在浏览器里看。

Stage 5:迭代

评测结果不满意?改 SKILL.md,在 iteration-N+1 目录重跑。注意是新建目录,不是覆盖原来的——保留每一轮的完整记录,方便对比”第 3 轮改了什么导致评分下降了”。

架构解析:四层分工

skill-creator/ ├── SKILL.md ← 流程编排(<500行),入口 ├── scripts/ ← 确定性计算,不靠 AI │ ├── run_eval.py 运行评测 │ ├── aggregate_benchmark.py 汇总统计 │ ├── quick_validate.py 快速校验 │ ├── run_loop.py 循环运行 │ ├── improve_description.py 优化描述 │ └── generate_report.py 生成报告 ├── agents/ ← 子代理指令 │ ├── grader.md 双角色评测 │ ├── comparator.md 盲比 │ └── analyzer.md 模式分析 └── eval-viewer/ ← 可视化 ├── generate_review.py └── viewer.html

这四层的分工原则很清晰:

职责执行者为什么这样分
SKILL.md流程编排、原则传达Claude 主线程不超过 500 行,只说做什么,不做计算
scripts/统计、校验、聚合Python 脚本确定性计算让 AI 做是浪费且不可靠
agents/评判、比较、分析Claude 子代理需要理解力和判断力的工作
eval-viewer/结果呈现静态 HTML零依赖,不需要 npm install

关键决策:scripts/ 全用 Python 标准库。不依赖 pandas、不依赖 numpy,连 requests 都不用。为什么?因为 Skill 要在任何环境下都能跑。用户机器上不一定有 Node.js 18+,不一定装了 pip 包,但 Python 标准库是几乎所有开发环境的标配。零依赖意味着零摩擦。

另一个决策:eval-viewer 是一个纯静态的 HTML 文件。不需要启动开发服务器,双击就能打开。generate_review.py 把评测数据嵌入 HTML 文件内的 <script> 标签里,viewer.html 用原生 JavaScript 渲染。没有 React,没有 Vue,没有构建步骤。

这不是偷懒,是刻意的。一个用来创建 Skill 的工具,如果自己就需要复杂的环境配置,那它怎么说服别人”Skill 是轻量的”?

双角色评测:grader 的设计

grader 是 agents/ 目录下最重要的子代理。它的特殊之处在于:它不仅评判输出质量,还评判断言本身的质量。如果你的断言太弱(比如”输出是有效的 JSON”——空 {} 也能通过),grader 会标记出来,防止你被虚高的 pass_rate 误导。

grader 内部有一个 7 步评测流程,从读 transcript、逐条评判断言、到批判断言质量本身,形成完整的双层检验。详细的 7 步流程拆解见第 20 章。

盲比系统:comparator 的设计

改进了一个 Skill 之后,怎么判断是不是真的变好了?直接对比有一个根本问题:你知道哪个是新版本,确认偏差会让你倾向于觉得改过的更好。

comparator 用盲比解决这个问题——两个输出匿名呈现,顺序随机,评完分之后才揭示来源。评分分”内容”和”结构”两个维度,防止出现”正确性提高但格式变差”的此消彼长。详细的评分维度和评判标准见第 20 章。

关键设计决策复盘

把几个最有意思的决策拉出来单独聊。

为什么立即捕获 timing? 子代理完成时,系统会发一条通知消息,里面包含执行耗时。但这条消息是瞬时的——它不会被写入文件,不会被保存到数据库,不会出现在 transcript 里。如果你没有在 SKILL.md 里明确指示”收到通知后立即记录 timing 数据”,这个数据就永远消失了。而 timing 对评测至关重要:一个 Skill 正确但耗时 5 分钟,另一个也正确但耗时 30 秒,你不会选前者。

为什么断言要在运行期间写? 这是反直觉的。大多数人的习惯是:先跑出结果,看看输出长什么样,然后写断言。但这样写出来的断言是”描述现状”而非”定义预期”。你会不自觉地把断言写成刚好能通过当前输出的样子。在运行期间写断言,你只能基于对需求的理解来写——“输出应该包含部署目标环境""输出应该包含回滚步骤”——这才是真正有意义的断言。

为什么 scripts/ 全用 Python 而不是 JavaScript? 不是因为 Python 比 JavaScript 好,而是因为 Python 标准库够用。aggregate_benchmark.py 需要做的事——读 JSON、算均值、算标准差、生成报告——全都用 jsonstatisticspathlib 就能搞定。如果用 JavaScript,你大概率会想用 lodash,然后就需要 npm install,然后就需要 package.json,然后就需要 node_modules。依赖链一旦开始,就很难停下来。

为什么用盲比而不是直接 A/B 对比? 因为你总会觉得自己改过的版本更好。这不是能力问题,是认知偏差。双盲实验是科学界解决这个问题的标准方法。skill-creator 把同样的方法搬到了 Skill 评测里。

从 skill-creator 提炼的 10 条设计原则

  1. 流程交给 SKILL.md,计算交给 scripts/——AI 擅长理解和判断,不擅长精确计算。让每个角色做它擅长的事。
  2. 解释 why,不要命令 must——写”因为 timing 数据只出现一次所以要立即捕获”,不要写”你必须立即捕获 timing 数据”。前者让 AI 理解意图,后者只是一条可能被忽略的指令。
  3. 读 transcript,不要只看输出——最终输出可能碰巧正确,但推理过程一塌糊涂。评测要看过程,不只看结果。
  4. 看到重复工作就抽脚本——如果 SKILL.md 里有任何”计算 X 的均值”之类的描述,它应该是一个 Python 函数,不应该让 AI 每次都重新算。
  5. 为百万次调用设计,不为测试用例优化——你的 Skill 可能被成千上万个用户在各种奇怪的场景下调用。不要为了让测试通过而写 hack。
  6. Description 要激进,宁可多触发——误触发的代价是多加载一次 SKILL.md(几百行文本),漏触发的代价是用户完全不知道这个 Skill 的存在。
  7. 断言要在看到输出之前写——先定义预期,再验证结果。反过来做就是事后诸葛亮。
  8. 评测输出,也评测断言本身——弱断言比没有断言更危险,因为它给你虚假的安全感。
  9. 用盲比消除自我偏差——不要相信自己能客观评价自己的改进。
  10. 立即捕获一次性数据——任何只出现一次的信息(timing、中间状态、临时通知),要么当场记录,要么永远丢失。

这 10 条不是从理论推导出来的,是从 skill-creator 的实际架构中逆向提炼的。每一条背后都有一个”不这样做就会踩坑”的真实故事。后面的章节会反复引用它们。

Last updated on