Skill 规范审计之错误写法
给 Claude Code 写了很多自定义 Skill,用了几个月,直到按官方规范做了一次全面审计,才发现每一个 Skill 的 description 都踩了同一个坑。
这个坑不是语法错误,不是功能缺陷,而是一个认知陷阱:我一直在告诉 Claude “ 我是谁 “,而不是 “ 什么时候该找我 “。
1. Description 是路由条件,不是功能说明
Skills 是上下文工程里一种有效的模式:系统提示只保留索引,完整知识按需加载。
1 | 可用 Skills: |
Claude Code 在每次对话启动时,将所有 Skill 的 name 和 description 注入系统提示词。Claude 扫描这份清单,决定当前任务是否需要加载某个 Skill 的完整内容。有明确匹配时读取 SKILL.md,多个匹配时优先选最具体的,没有匹配就跳过。
整个决策过程可以用一张路由流程图概括:
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart TD
A["对话启动"] --> B["扫描所有 Skill 的 description"]
B --> C{"任务与 description 匹配?"}
C -->|"无匹配"| D["跳过, 不加载任何 Skill"]
C -->|"单个匹配"| E["加载该 Skill 的 SKILL.md"]
C -->|"多个匹配"| F["选最具体的 Skill 加载"]
E --> G["按正文执行"]
F --> G
classDef default fill:#EFF6FF,stroke:#2563EB,color:#1E3A5F
classDef decision fill:#FEF3C7,stroke:#F59E0B,color:#92400E
classDef skip fill:#FEE2E2,stroke:#EF4444,color:#991B1B
classDef load fill:#D1FAE5,stroke:#10B981,color:#065F46
class C decision
class D skip
class E,F,G load所以 description 是路由判断依据,不是功能说明书。每个启用的 Skill 描述符常驻上下文,数量一多,长描述的累积 token 成本很可观:
1 | # 低效(约 45 tokens) |
路由准确率差距不大,但 45 tokens × 20 个 Skill = 900 tokens 常驻开销,9 tokens × 20 = 180 tokens,差 5 倍。
描述太短也有问题。help with backend 会让任何后端工作都触发,路由会乱。有效的描述符应是路由条件:Use when... 说明什么时候该用,Don't use when... 划清边界,再补反例。
测试数据显示:没有反例时路由准确率从基准 73% 掉到 53%,加上反例后升到 85%,响应时间降了 18.1%。反例不是可选项,是描述符正确路由的关键。
但我之前写的 description 全在做自我介绍:
1 | # 原始写法 |
这段 description 有 3 个问题:
- 角色宣言开头:” 顶级战略产品师 “——Claude 不需要知道你自封了什么头衔
- 流程摘要:把 Skill 正文的工作流程压缩到了 description 里
- 缺少触发条件:Claude 读完知道这个 Skill 很厉害,但不知道什么情况下该用它
理解了 description 的路由本质后,接下来看最容易踩的一类错误:在 description 里概括工作流程。
2. 流程摘要是最危险的陷阱
在所有错误中,” 在 description 里概括工作流程 “ 杀伤力最大。
官方规范的测试发现:当 description 写了 “code review between tasks”,Claude 只做了一次 review。但 Skill 正文的流程图明确要求两次——先查规范合规,再查代码质量。
原因是 Claude 把 description 当成了快捷指令,跳过了正文。Description 越详细,Skill 正文越容易被忽略。
我的 code-simplifier 就是典型反面教材。原始 description 长达 300+ 字符,包含功能说明、两种工作模式,甚至内嵌了 example 标签:
1 | # 反面教材:300+ 字符的 description |
Claude 读到这段 description 就已经 “ 知道该怎么做了 “,SKILL.md 正文里精心设计的评估维度、简化策略、代码模式对比?大概率直接跳过。
修正后只保留触发条件:
1 | description: Use when code has excessive complexity, deep nesting, unused |
| 维度 | 修正前 | 修正后 |
|---|---|---|
| 开头 | “ 代码简化与优化专家 “ | “Use when” |
| 内容 | 功能说明 + 模式介绍 + 示例 | 触发场景 |
| 长度 | 300+ 字符 | ~120 字符 |
| Claude 行为 | 按 description 执行,跳过正文 | 匹配后加载正文,按正文执行 |
写完 description 后可以用一条标准检验:如果 Claude 只读 description、不读 SKILL.md 正文,它的行为会和读了正文一样吗?如果答案是 “ 差不多 “,说明 description 泄露了太多信息。好的 description 让 Claude 知道 “ 需要加载这个 Skill”,但不知道 “ 加载后该怎么做 “。
修正了流程摘要问题后,还有 4 类常见的 description 错误模式。
3. 五类 Description 错误模式
审计完 19 个 Skill,错误可以归为 5 类。除了前面展开的流程摘要式,其余 4 类用对比表说明。
3.1 角色宣言式
1 | # ❌ 我是谁 |
“ 顶级 “” 专家 “” 官 “ 这些词对路由判断没有信息量。Claude 不会因为你自称 “ 顶级 “ 就优先加载。
3.2 功能说明式
1 | # ❌ 我能做什么 |
3.3 穷举触发词式
1 | # ❌ 列举所有可能的触发场景 |
穷举 7 个场景 + 7 个关键词,浪费 token,还暗示 “ 不在列表里的场景不要触发 “。
3.4 混合语言堆叠式
1 | # ❌ 中英文混杂 + 关键词堆叠 |
codereview / code review / 代码审查 这种 SEO 式关键词堆叠,在 Claude 的语义理解面前完全多余。
Description 层面的问题修完之后,正文同样需要审查。
4. 正文层面的常见问题
审查正文时发现了 4 类需要处理的问题。
4.1 “ 你是…” 角色扮演
19 个 Skill 里有 10 个以 “ 你是…” 开头:
1 | # ❌ 角色扮演 |
Skill 规范定义很明确:Skills are reusable techniques, patterns, tools, reference guides,不是角色卡。
“ 你是一位资深 Go 架构师 “——Claude 已经知道自己会写 Go。” 你有 15+ 年的产品设计经验 “——虚构的履历对输出质量没有帮助,反而浪费 token,可能干扰模型的能力边界判断。
直接以核心原则开头:
1 | # ✅ 直接切入 |
每个 “ 你是…” 前言占 30-80 个 token,10 个 Skill 累计 300-800 token,每次加载都在消耗上下文预算,换来的只是一段模型会忽略的人格设定。
4.2 超长 Skill 需要拆分
我的 mermaid-generator 有 608 行、1,694 个词——规范建议上限是 500 词。
原因是我把 16 种图表的完整模板全部内联到了 SKILL.md 里。每次用户说 “ 画个流程图 “,Claude 要加载全部 16 种图表模板,包括用不到的桑基图、象限图、Git 图。
规范建议:Heavy reference (100+ lines) 拆到 supporting file。
1 | mermaid-generator/ |
拆分后 SKILL.md 从 1,694 词降到 530 词,模板文件只在 Claude 确认了图表类型后才被引用加载,单次对话节省约 1,100 token 的无效加载。
4.3 相似 Skill 必须划清边界
code-simplifier 做代码简化,code-refactor 做代码重构。听起来不同,但用户说 “ 这段代码太复杂了帮我改改 “ 时,Claude 不知道该加载哪个。两个 Skill 的 description 都能匹配,最终靠运气。
规范的 SKILL.md 结构里有 ## When to Use 章节,要求包含 “When NOT to use”。对于功能相近的 Skill,这是路由正确分流的关键。
修正方式是互相指向对方:
1 | # code-simplifier |
划界的本质是给 Claude 一张路由表:用户意图匹配 A 还是 B,边界条件是什么,歧义时选哪个。没有这张表,Claude 只能猜。
4.4 重复代码需要抽取
7 个内容生成类 Skill 各自实现了一套几乎相同的去重逻辑:读取历史文件 → 查重 → 重试 → 生成 → 追加记录 → FIFO 淘汰。每个 Skill 里这段逻辑占 50-80 词,7 份就是 350-560 词的纯重复。
抽取为通用 supporting file,各 Skill 用两行引用替代:
1 | ## 去重与保存 |
规范里有对应建议:”Use cross-references — Don’t repeat what’s in cross-referenced skills”。同一段逻辑写 7 遍,改一处要改 7 处,还容易漏。
正文问题之外,还有一类容易被忽视的优化:低频 Skill 的触发策略。
5. 低频 Skill 应降级为手动触发
审计还暴露了另一个问题:7 个 “ 每日内容生成器 “ 做成了自动匹配的 Skill。
这些 Skill 每天最多用一次,不辅助编程任务,本质上是固定格式的 Prompt 模板。作为自动匹配 Skill 存在的代价是:每次对话启动时 Claude 都要扫描它们的 description 判断是否需要加载。对于编程助手来说,99% 的对话不需要 “ 每日书籍推荐 “。
解决方案不是删除,而是降级为手动触发:
1 | # 自动匹配模式(Claude 每次都要扫描判断) |
Do NOT auto-trigger 让 Claude 在常规扫描时跳过这个 Skill,用户主动提及触发词时仍然可以加载。成本从 “ 每次对话都扫描 “ 降为 “ 仅在需要时加载 “。
6. Frontmatter 只支持两个字段
规范明确说 frontmatter 只支持 name 和 description。但我有 3 个 Skill 加了 compatibility: opencode——为了兼容另一个 AI 编码工具。Claude Code 会静默忽略它,但它占 token、可能影响解析,属于无效负载。删除即可。
7. 一条检验标准
触发条件归 description,执行逻辑归正文。各司其职。
description 说 “ 什么时候该加载我 “,正文说 “ 加载后怎么做 “。两者职责不同,不应混淆。一旦 description 泄露了执行逻辑,Claude 就会走捷径跳过正文,Skill 里精心设计的流程形同虚设。
8. Autoresearch 优化 Skill
主要使用 :https://github.com/karpathy/autoresearch
- 下载 skill。从这里获取,放进你在 Claude Code 或 Cowork 里的 skills 文件夹。
- 选一个要改进的 skill。 说 “ 对我的 [skill 名称] skill 跑 autoresearch”。选最让你头疼的那个——时好时坏、输出不稳定的那个。
- agent 问你 3 件事。 要优化哪个 skill、用什么测试输入(比如 “ 为一款 AI 生产力工具写落地页文案 “),以及你的 checklist 问题是什么。
- 它跑一遍你的 skill,给出起始分数。这是基准线。我的落地页 skill 起步 56%——标题模糊、流行词泛滥、CTA 软弱。超过一半的检查项都没过。
- 浏览器弹出实时 dashboard。分数曲线、每项 checklist 的通过/失败、每次改动日志。每 10 秒刷新一次。
- 走开。agent 开始循环。找最薄弱的地方,改一点,测试,分数升就留,分数降就撤。然后再来一次。再来一次。一直跑,直到你叫停,或者连续三次超过 95%。
9. 参考资料
- superpowers/writing-skills — superpowers 插件中的 Skill 编写规范,本文所有规范引用的来源
- anthropic-best-practices.md — 同目录下的 Anthropic 官方最佳实践参考文档