目录概要
- 从按钮到工具——视角切换
- Skill 是一个"文件夹"
- 13 字段 frontmatter:跟 Command 的异同
- 描述字段的"触发哲学"
- 渐进式揭露——Anthropic 把几百 token 砍掉的办法
- Anthropic 内部把 skill 分成的 9 类
- 写好 skill 的 9 条经验(Thariq 版)
- 两种 skill 调用模式回顾
- On-demand hooks:为什么
/careful这种设计值得抄 - 如何度量你的 skill 值不值得留
- 踩过的坑:写得太细、拿不出手的 description、文件放错地方
1. 从按钮到工具——视角切换
上一篇把 Command 拆成了"会自动抓现场的按钮"。这一篇换个主角——Skill。
按钮和工具最大的区别在于谁决定什么时候用它:
graph LR
subgraph Cmd[Command 按钮]
U1[用户] -->|主动按| C1[/ 触发]
end
subgraph Skl[Skill 工具]
U2[用户描述需求] --> Claude[Claude 扫描工具箱]
Claude -->|识别到对应工具| S1[拿出来用]
end
style C1 fill:#afa
style S1 fill:#aaf
按钮只会在"按下去那一刻"工作。工具不一样——工具自己会喊"这活儿我来"。工具箱里摆着十几把工具,Claude 开工前扫一眼工具箱,觉得某一把能用就拿出来。
这就是 Skill 最核心的心智模型。这篇就按"工具"这个视角展开——它长什么样、模型怎么找到它、怎么确保它被挑中、怎么让它好用。
2. Skill 是一个"文件夹"
很多人用了一周 Skill 还以为它是"单个 markdown 文件"。这是最常见的误解。
Anthropic 内部做 skills 的同学 Thariq 原话:
A common misconception is that skills are "just markdown files", but the most interesting part is that they're folders that can include scripts, assets, data, etc. — things the agent can discover, explore, and manipulate.
Skill 的磁盘布局:
.claude/skills/my-skill/
├── SKILL.md ← frontmatter + 简述 + "看什么时候用"
├── references/
│ ├── api.md ← 详细 API 文档
│ └── schema.md ← 数据结构
├── scripts/
│ ├── validate.py ← 可执行脚本
│ └── export.sh
├── examples/
│ ├── case_01.md
│ └── case_02.md
├── assets/
│ └── template.svg
└── config.json ← skill 自己的配置(可选)
这不是一个 prompt 文件,这是一个带代码、带资产、带样例的小包。
SKILL.md 只是这个包的"索引页"。模型最开始只看到索引页——真要用的时候再去读 references/、跑 scripts/、参考 examples/。
为什么这样设计?马上讲。但先看它的 frontmatter。
3. 13 字段 frontmatter:跟 Command 的异同
Skill 的 frontmatter 也是 13 个字段——这个数字跟 Command 一样,是刻意的。Anthropic 把两者做到"字段级一致",只有几个字段的默认值和语义不同。
---
name: my-skill
description: Do X when user asks for Y
argument-hint: [file-path]
disable-model-invocation: false
user-invocable: true
allowed-tools: Read, Grep, Glob
model: sonnet
effort: medium
context: fork
agent: general-purpose
hooks:
PreToolUse: [...]
paths: "src/**/*.py"
shell: bash
---
跟 Command 的字段清单放一起对比:
| 字段 | Command | Skill | 差异 |
|---|---|---|---|
name | 缺省取文件名 | 缺省取目录名 | Skill 是文件夹,name 来自目录 |
description | 可选但强烈推荐 | 关键——模型扫描用 | 决定 skill 能否被模型选中 |
argument-hint | 一致 | 一致 | — |
disable-model-invocation | 默认 false | 默认 false | — |
user-invocable | 默认 true | 预加载 skill 常设为 false | 见第 8 节 |
allowed-tools | 激活时的本地白名单 | 同 | — |
model | 运行时模型 | 同 | — |
effort | 同 | 同 | — |
context | fork 切子上下文 | 同 | — |
agent | 同 | 同 | — |
hooks | 仅 command 生命周期 | 仅 skill 会话周期 | on-demand hooks(见第 9 节) |
paths | glob 激活 | glob 自动激活(无需用户输入) | Skill 的 paths 是自动找工具的触发点 |
shell | bash/powershell | 同 | — |
字段一致是好事——你学 Command 付出的学习成本,到 Skill 继续用。只有几处语义不同要小心:
user-invocable: false—— Command 里很少用(藏起来没意义),Skill 里很常见(agent-preloaded skill 都这样)paths—— Command 只是"在补全里出现",Skill 是"自动被选中"(后者更强的触发力)
4. 描述字段的"触发哲学"
Skill 的 description 跟 Command 的表面上一样,但职责重得多。Thariq 在 Tip 6 里讲得很直白:
The description field is not a summary — it's a description of when to trigger this skill. Write it for the model.
意思是:description 不是写给用户看的"这个 skill 是干啥的",是写给模型看的"什么情况下该用这个 skill"。
4.1 一个对比
反例:
description: A skill for formatting release notes
这是在写"我是谁"。模型扫到这段没有关键触发点——它只能靠 "release notes" 几个词被动匹配。
正例(03 篇里 release-notes-formatter 的真实 description):
description: Formats categorized commit data into a polished
RELEASE_NOTES_<version>.md following the project's house style. Writes
to release-notes/RELEASE_NOTES_<version>.md and release-notes/output.md.
差别是什么?正例在告诉模型:
- 触发场景:有分桶好的 commit 数据要排版时
- 具体产出:RELEASE_NOTES 文件 + output.md 文件
- 路径决定性:写到
release-notes/RELEASE_NOTES_<version>.md
模型扫到这段,看到用户说"给我排一份 release notes"——match;看到用户说"把 commit 列表整理成发布日志"——match;看到当前对话里已经有 feat/fix 分桶数据——更强 match。
4.2 一条实用经验
写 description 时的套路:
动词 + 触发条件 + 产出 [+ 边界说明]
-
❌ "Formats Python code"
-
✅ "Formats Python code with Black configuration from pyproject.toml when user asks for formatting or before committing"
-
❌ "Database query helper"
-
✅ "Runs read-only SQL queries against the analytics warehouse. Use when user asks for metrics, counts, or data aggregations. Does not run DDL or writes."
第二种写法的好处:模型不仅知道能用这个 skill,还知道什么时候不该用("Does not run DDL" 是负面触发条件,避免滥用)。
5. 渐进式揭露——Anthropic 把几百 token 砍掉的办法
回到"为什么 Skill 是文件夹"这个问题。
Claude Code 启动时做一件事:把所有 skill 的 SKILL.md 扫一遍,把 description 塞到系统 prompt 里。只有 description,不是全部内容。
graph TB
Start[Claude Code 启动] --> Scan[扫描所有 .claude/skills/*/SKILL.md]
Scan --> Desc[只读取每个 skill 的 description]
Desc --> Sys[注入系统 prompt<br/>'你有这些 skill 可用:<br/> - skill-a: 描述<br/> - skill-b: 描述']
Use[模型决定用 skill-a] --> Full[读 skill-a 的完整 SKILL.md]
Full --> Ref{需要更多信息?}
Ref -->|需要 API 细节| R1[读 references/api.md]
Ref -->|需要跑脚本| R2[exec scripts/validate.py]
Ref -->|参考样例| R3[读 examples/case_01.md]
style Sys fill:#afa
style Full fill:#ff9
style R1 fill:#aaf
style R2 fill:#aaf
style R3 fill:#aaf
这套机制叫 Progressive Disclosure——渐进式揭露。
5.1 数学账
假设你有 50 个 skills,每个 skill 平均 2000 token。把全部内容都塞进系统 prompt,起步就 10 万 token 消耗。
用渐进式揭露:
- 启动时:50 个 description × 每个 50 token ≈ 2500 token
- 用到某个 skill:+ 2000 token 完整 SKILL.md
- 用到某个 reference:+ ? token
节省 95% 以上。而且随着你 skill 数量的增长,这个比例只会越来越好。
5.2 三层揭露
03 篇里 release-notes-formatter 的目录是典型范例:
.claude/skills/release-notes-formatter/
├── SKILL.md ← 总是加载(其实只有 description 加载,正文待唤醒)
├── reference.md ← 需要 Markdown 模板时才读
└── examples.md ← 需要对照 OSS 样例时才读
SKILL.md 正文里引用了这两个文件:
## Additional resources
- For Markdown template, category headers, and tone examples, see [reference.md]
- For example input/output pairs, see [examples.md]
模型看到 SKILL.md 再决定"我需要 Markdown 模板吗?"——需要就读 reference.md。不需要的话这部分 token 永远不花。
5.3 跟 Commands 的对比
Command 为什么不用这套机制?因为 Command 是用户主动按的——用户按下 /xxx 的那一刻就肯定要用,token 该花就花,没必要搞分层。
Skill 是模型自主挑的——它只看 description 就要做决定,决定前不该让整个 skill 占满上下文。所以 Skill 有目录结构,Command 只有单文件。
这是一个典型的设计权衡——选择机制决定了成本模型。按钮是"只有按下才扫描",工具是"先扫描再决定按",扫描过程必须足够廉价。
6. Anthropic 内部把 skill 分成的 9 类
如果只看官方默认的 5 个 skill(simplify batch debug loop claude-api),你没法理解 Skill 的真正能力上限。Anthropic 内部用了几百个 skill 之后,Thariq 把它们归纳成 9 个大类:
mindmap
root((9 种 skill 类型))
1 Library & API Reference
billing-lib
internal-platform-cli
frontend-design
2 Product Verification
signup-flow-driver
checkout-verifier
tmux-cli-driver
3 Data Fetching & Analysis
funnel-query
cohort-compare
grafana
4 Business Process
standup-post
create-ticket
weekly-recap
5 Code Scaffolding
new-workflow
new-migration
create-app
6 Code Quality & Review
adversarial-review
code-style
testing-practices
7 CI CD Deployment
babysit-pr
deploy-service
cherry-pick-prod
8 Runbooks
service-debugging
oncall-runner
log-correlator
9 Infrastructure Ops
resource-orphans
dependency-management
cost-investigation
九类里真正值得十年以上经验的架构师先投入的是哪几类?我的排序:
| 优先 | 类型 | 为什么值得先做 |
|---|---|---|
| 1 | Library & API Reference | Claude 在陌生 API 上容易瞎编,一个 skill 能立刻止血 |
| 2 | Product Verification | 花一周时间让 skill 会自动验证产出——Thariq 说这个 ROI 最高 |
| 3 | Runbooks | 把线上值班的"第一步、第二步、第三步"交给 skill,减少人肉查 wiki |
| 4 | Code Quality & Review | 结合 hooks 自动跑,团队质量门禁 |
| 5 | Infrastructure Ops | 危险操作带 guardrail,新人误操作率大降 |
最被低估的是 Runbooks——传统团队都有 wiki / confluence / notion 写 runbook,但人真去 oncall 时要么懒得翻要么翻错。Skill 的优势是主动匹配——报警一到,Claude 直接选中对应 runbook skill,人只需要审 Claude 的判断,不需要自己查文档。
7. 写好 skill 的 9 条经验(Thariq 版)
Thariq 同一份公开分享里给了 9 条 skill 编写经验。这里把每条配上"十年经验架构师视角的翻译"——哪些是"废话常识"、哪些是"非做不可"。
7.1 不要写废话
Don't State the Obvious
Claude 已经知道怎么写 React 组件、怎么用 Python pandas、怎么写 SQL。你的 skill 如果只是重复这些,负价值——既占 token 又稀释描述的信号度。
值得写进 skill 的:
- 内部库 / 私有 CLI 的用法
- 跟"行业默认做法"相反的团队约定("我们不用 Inter 字体,不要紫色渐变")
- Claude 经常犯错的边界条件
7.2 Gotchas 是全 skill 信号密度最高的段落
Build a Gotchas Section
Gotchas / 踩坑 / 注意事项——放在 skill 末尾。内容不是凭空想的,是实际用 Claude 时它反复踩的点。
迭代逻辑:
Claude 用 skill 出错 → 人工看原因 → 把这个原因加进 Gotchas → 下次不再踩
这是 skill 从 "v1 能跑" 到 "v10 真好用" 的核心路径。
7.3 用文件系统做渐进式揭露
第 5 节讲过了。要点重复一次:SKILL.md 简短、细节拆到子文件、模型按需读。
7.4 不要给 Claude 写死步骤
Avoid Railroading Claude
新手最容易踩——写 skill 时担心 Claude 不按规矩来,就把"第 1 步、第 2 步、第 3 步"写得死死的。结果是:
- 场景稍微变化,Claude 僵硬套模板
- Skill 复用性急剧下降
对比两种写法:
# 写法一(railroading,不推荐)
## Instructions
1. Read `config.yaml`
2. Extract the `database_url` field
3. Call `psql $database_url -c "SELECT * FROM users"`
4. Parse the output
5. Print as JSON
# 写法二(goal + constraints,推荐)
## Goal
给定 config.yaml,查 users 表并返回 JSON。
## Constraints
- 数据库 URL 在 config.yaml 的 `database_url` 字段
- 只读查询,不做 DDL
- 输出 JSON schema:`{users: [{id, email, created_at}]}`
## Useful tools
- `scripts/run_query.sh` —— 带连接重试的查询脚本
写法二让 Claude 有判断余地——config 格式变了它能跟着调整;JSON 出错它能排查。这是 skill 可持续的关键。
7.5 Setup 要先想清楚
Think through the Setup
有些 skill 需要用户配置才能跑(数据库地址、API key、dashboard ID)。配置存哪里?
Anthropic 的推荐:skill 目录下的 config.json,不存在时用 AskUserQuestion 工具让用户填一遍。
skill/
├── SKILL.md
├── config.json ← 存 setup 结果
└── references/...
SKILL.md 里写:
## Setup
If config.json does not exist, use AskUserQuestion to gather:
- database_url
- default_schema
Then write to config.json and confirm with user.
第一次用 skill 触发 setup,之后永远不用重配。
7.6 description 是写给模型看的
第 4 节展开过。
7.7 Skill 可以自己存记忆
skill 可以自己维护数据文件——append-only log、JSON、甚至 SQLite。但直接存在 skill 目录里会被升级覆盖。
正确做法:用 ${CLAUDE_PLUGIN_DATA} 环境变量指向稳定目录:
## Memory
Append a line to `${CLAUDE_PLUGIN_DATA}/runs.log` every time this skill completes:
`timestamp\tuser\toperation\tresult`
下次启动还能看到历史,skill 升级也不会丢。
7.8 把代码塞进 skill
Store Scripts & Generate Code
这是 Skill 相比 prompt-only 扩展最爆炸的能力。
LLM 擅长"组合、决策、解释",不擅长"重复生成复杂模板代码"。Skill 目录里放 shell / python 脚本,Claude 去调用它们、组合它们,而不是自己写一份。
例子——一个数据查询 skill:
data-query/
├── SKILL.md
├── scripts/
│ ├── run_query.py ← 带 auth、带 retry、带 timeout 的查询封装
│ ├── format_csv.py ← 标准化 CSV 输出
│ └── format_markdown.py ← 转 markdown 表格
└── references/
└── schema.md
SKILL.md 告诉 Claude:
用户要查数据时:
1. 看 references/schema.md 找对表
2. 组合 scripts/run_query.py 的参数
3. 根据用户想要 csv 还是 markdown,pipe 到对应 format_* 脚本
Claude 的工作变成"组装 pipeline",不是"从 0 写查询"。稳定性、速度、token 消耗都好一个量级。
7.9 On-demand hooks
第 9 节展开。
8. 两种 skill 调用模式回顾
第 03 篇讲过 release-notes 生成器同时用了两种 skill 调用方式。这里从 Skill 自己的视角再说一遍,因为这是"什么时候该设 user-invocable: false"的判断依据。
| 模式 | 例子 | 触发 | user-invocable | 何时用 |
|---|---|---|---|---|
| Agent Skill(预加载) | git-log-reader | Agent 启动时读入 | false 隐藏 | skill 是某个 agent 的"必备知识",不独立存在 |
| Direct Skill(直接调用) | release-notes-formatter | Skill 工具 / /name / 模型自动选 | true 或省略 | skill 是"可复用的独立操作" |
判定是否要 preload 的一个硬标准:
如果少了这个 skill,这个 agent 就彻底没法工作 → preload 如果 skill 能在多个 agent 间复用 → 直接调用
git-log-reader 是"怎么解析 conventional commits"——只有 release-notes-agent 用得到,没有它 agent 就瞎了,preload。
release-notes-formatter 是"把分桶数据排版成 Markdown"——以后做 changelog agent、做 monthly digest agent 都能用这个 skill,直接调用。
8.1 跨 skill 调用
Skill 还能引用另一个 skill:
用
file-uploadskill 把这份 CSV 上传到 S3。
模型看到这行,知道去找 file-upload skill 并执行。没有 native 的依赖管理——靠的是 skill 名字自然语言引用。
这种自由度带来的风险是:名字改了引用就断。所以实战里我们会在 SKILL.md 顶部列一段 "Dependencies":
## Dependencies (skills this skill calls)
- `file-upload` — needed to push final CSV to S3
- `data-query` — needed to fetch source data
肉眼能看到依赖,改名时可以 grep 出来。
9. On-demand hooks:为什么 /careful 这种设计值得抄
Skill 的 hooks 字段跟 Command 的 hooks 字段看起来一样,但生效时机不同:
- Command 的 hooks:command 激活期间生效
- Skill 的 hooks:skill 被调用开始直到会话结束都生效
这个区别催生了 Anthropic 内部最好玩的两个 skill:
9.1 /careful——临时穿上防护服
---
name: careful
description: Enable careful mode — blocks destructive operations for this session
---
When invoked, register PreToolUse hooks that block:
- rm -rf commands
- DROP TABLE / DROP DATABASE in SQL
- git push --force / --force-with-lease
- kubectl delete
- terraform destroy
用户说 "/careful" 之后,整个会话都处于"禁毁模式"。会话结束 hook 消失。
为什么不把这个变成默认 hook?因为平时做 dev 没必要阻挡 rm -rf build/——它会频繁报错。/careful 是显式切入的更严格模式,类似 "sudo -i 进了 root 就要小心模式"。
9.2 /freeze——写入范围冻结
---
name: freeze
description: Freeze file writes to a specific directory for this session
---
When invoked, prompt user for allowed directory (e.g., "src/api/").
Register PreToolUse hook on Edit/Write that blocks any path outside that directory.
用途:正在改某个模块,不想让 Claude "顺手也动一下" 其他地方。/freeze src/api/ 之后它就被关在笼子里了。
9.3 这个设计模式的通用性
On-demand hooks 的本质是:用户声明模式,模式改变工具行为。这跟 Vim 的 normal/insert/visual 模式、IDE 的"只读模式"是一个路数。
架构师可以借鉴的场景:
/prod-debug—— 在生产调试时自动加 audit log/review-mode—— 禁止任何 Edit/Write,只能 Read/Grep/deploy-window—— 只在工作时间允许 deploy 类工具
这些都不需要改全局 settings,一个 skill 解决。下一篇讲 subagents 时会看到 subagent 也有 hooks 字段,能做更精细的 per-role 限制。
10. 如何度量你的 skill 值不值得留
写了 20 个 skill,怎么知道哪些被用、哪些是僵尸?
Thariq 分享了 Anthropic 内部做法:用 PreToolUse hook 给 skill 埋点。
# .claude/settings.json
hooks:
PreToolUse:
- matcher: "Skill"
hooks:
- type: command
command: python3 .claude/hooks/log_skill_use.py
log_skill_use.py 记录:
- 时间戳
- 用户
- 被调用的 skill 名
- 调用上下文摘要
- 执行时长
- 最终是否成功
积累一两周之后看数据:
- 高频 + 高成功率 → 明星 skill,值得继续投入
- 高频 + 低成功率 → 需要迭代(加 Gotchas、换 description、拆目录)
- 低频 → 要么 description 写得没辨识度、要么这个场景根本不常见
- 零调用 → 删掉或进存档
这是 skill 生态从"个人玩具"走向"团队基础设施"的关键步骤——没有度量就没有迭代。
11. 踩过的坑
坑 1:description 写成功能描述而不是触发条件
前面展开过。再贴一条反例:
- ❌
description: Git commit helper - ✅
description: Creates conventional commits from staged changes. Invoke when user asks to commit, when changes are staged without a commit message, or before a PR.
坑 2:SKILL.md 写了 500 行
很常见——想"把能说的全说了"。结果每次 skill 被激活都吃 2000 token。
正确做法:SKILL.md 保持在 100 行以内,其他都拆到 references/。
坑 3:references/ 里放的 markdown 跟 SKILL.md 重复
SKILL.md 写"API 用法见 references/api.md";翻开 references/api.md,发现前一半又抄了 SKILL.md 的简述。纯浪费。
references/ 的内容只应该是 SKILL.md 没写的细节,不要解释"这个 skill 是干啥的"。
坑 4:把 scripts/ 写成 "pseudo-code"
skill 的脚本是要执行的,不是写给人读的伪代码。遇到过把 validate.py 写成注释比代码还多、最后不 runnable 的。
验证办法:python3 .claude/skills/my-skill/scripts/validate.py 能直接跑通才合格。
坑 5:paths 写成正则
- ❌
paths: "\\.py$" - ✅
paths: "**/*.py"
paths 接收的是 glob,不是 regex。踩这坑的人意外多。
坑 6:混用 skills: 和 Skill 工具触发
Agent 里写了 skills: [git-log-reader](预加载),结果 command 里又写 Skill(skill: "git-log-reader") 想"再调一次"。会搞乱——agent 已经把 skill 内化为知识,不是一个可调用工具。
规则:同一个 skill,要么 preload 要么 direct,不要两条路都用。
把工具放回柜子
Skill 的完整图景比 Command 大一个量级——它不是"另一个按钮",是"一个会被模型主动挑选、带着脚本资产、能做渐进式揭露的工具包"。
三个最该记住的点:
- 文件夹不是文件 —— SKILL.md 是索引页,其他文件按需读
- description 是触发说明书,不是功能介绍 —— 写给模型看
- Gotchas 是 skill 的质量标尺 —— 真踩过的坑比理论上的注意事项值钱 100 倍
顺着"按钮 → 工具"的类比,下一个该拆的就是"员工"——Subagent。如果 Skill 是"一把等你来拿的工具",Subagent 就是"有独立人格、自己拿工具干活、带记忆的人"。下一篇把 Subagent 的 frontmatter 15+ 字段、memory 三种作用域、isolation 的几种模式摊开讲。