我把那些反复粘贴的指令,做成了一个 Skill
我这个博客挂着一个小小的工具区——JSON 格式化、Base64、URL 编码、JWT 解码这些纯客户端的小玩意儿,平时手痒了就 vibecoding 顺手加一个。可每加一个,都有一堆只有我自己知道的规矩:新工具一律是 src/pages/tools/<名字>/index.astro 这一个文件,逻辑全塞进内联 <script> 里、不拆外部 JS、不打后端,写完还得回 src/pages/tools/index.astro 的 tools 数组里登记一条,没做完的先挂 available: false;交互和配色也得跟现有那几个对齐,深浅色都不能破。这些规矩没写在任何醒目的地方,散落在我脑子里和已经做好的那几个工具里。
结果就是:每次让 Claude Code 帮我加个新工具,我都得把这套规矩重新交代一遍。交代少了它瞎放文件、忘了登记;交代多了我自己累。我一度把它们堆进项目的 CLAUDE.md,但那东西越堆越长,而且 CLAUDE.md 是每次对话都整篇加载的——我为「加个工具」这件偶尔才做的事,付了全程的上下文成本。
后来我在 Claude Code 文档里读到一句话,大意是:当 CLAUDE.md 里某一段从「事实」长成了「流程」,就该把它挪出去做成一个 skill。 这话正好戳中我,于是我真去做了一个。这篇就记录一下这趟过程,顺带把 Agent Skills 这套东西捋清楚:它到底是什么、那个叫 progressive disclosure 的机制解决了什么、它和我已经在用的几样东西(CLAUDE.md、slash 命令、MCP、子代理)差在哪一层。老规矩,官方说的和我自己试的分开讲。
一、Skill 到底是什么:一个文件夹
剥掉所有包装,一个 skill 就是一个文件夹,里面放一个 SKILL.md。这个文件分两半:上面一段 YAML frontmatter,下面是给 Claude 看的 Markdown 正文。frontmatter 里真正必要的只有一行 description,告诉 Claude「这个 skill 是干嘛的、什么时候该用」;正文则是它被触发后要照着做的步骤。
除了 SKILL.md,文件夹里还可以塞别的:模板、参考文档、能直接执行的脚本。但这些都是可选的,SKILL.md 是唯一的入口。
放在 Claude Code 里,它住在两个地方:
| 范围 | 路径 | 作用于 |
|---|---|---|
| 个人 | ~/.claude/skills/<name>/SKILL.md | 你所有的项目 |
| 项目 | .claude/skills/<name>/SKILL.md | 当前这个仓库 |
文件夹的名字就是你敲的命令——new-tool/ 这个目录会自动变成 /new-tool。这里有个我一开始没反应过来的点:Claude Code 把以前的自定义 slash 命令并进了 skill。 也就是说 .claude/commands/deploy.md 和 .claude/skills/deploy/SKILL.md 是一回事,都给你一个 /deploy,旧的 commands/ 目录照常能用。skill 只是在 slash 命令之上多给了两样东西:可以带一整个文件夹的附属文件,以及——这才是关键——能让 Claude 在合适的时候自己想起来用它,而不只是等你手动敲斜杠。
二、真正的机关在 progressive disclosure
如果只看上面那段,你会觉得 skill 不就是「把一段提示词存成文件」嘛,和我往 CLAUDE.md 里堆有什么本质区别。区别不在「存不存」,在「什么时候加载」。这套机制官方叫 progressive disclosure(渐进式披露),我觉得是整件事里最值得理解的地方。
它分三层,一层比一层晚加载:
- 第一层:只有 skill 的名字和那一句
description,启动时就预载进系统提示。哪怕你装了几十个 skill,这一层也只占几十个 token 的量级。Claude 靠这一层来判断「眼下这个活儿,要不要翻开某个 skill」。 - 第二层:当任务匹配上某个
description,Claude 才把那一篇SKILL.md的正文完整读进来。没用上的 skill,正文一个字都不进上下文。 - 第三层:正文里引用到的脚本、参考文档、模板,要用到时才逐个打开。更妙的是脚本——Claude 可以直接跑它、只看输出,而不必把整段源码读进上下文。
Anthropic 给的比喻我觉得挺到位:做一个 skill,像是给新人写一份入职手册;而 progressive disclosure 就像一本编排好的手册——先翻目录,需要哪章读哪章,附录留到真要查的时候再翻。你不会上班第一天就把整本手册背下来。
对照我之前往 CLAUDE.md 里堆指令的做法,差别一下就清楚了:CLAUDE.md 是整篇常驻,我为偶尔一用的「加工具流程」付的是全天候的上下文租金;skill 是平时只露一句描述,真用上了才展开。省下来的不是磁盘,是上下文——而上下文对我这种按 token 付费的人来说,就是钱和注意力。
三、它和我已经在用的几样东西,差在哪一层
我手里这几样能「教 Claude 干活」的东西,一度在我脑子里是糊在一起的。真正把它们分开,靠两个问题就够了:这东西是一直待在上下文里,还是按需加载?它给的是「做法」,还是「能力」?
CLAUDE.md给的是知识,而且常驻。适合放「事实」——这个项目用什么技术栈、规范叫什么、绝对不能碰哪些文件。一句话能说清、且每次都可能用到的,放这儿。- Skill 给的也是知识,但按需。适合放「流程」——一套有步骤、偶尔才走一遍的做法。我那个加工具的流程就是典型:不是每次对话都用,但用的时候希望它一步不漏。判断标准很朴素:一条事实写进
CLAUDE.md,一套流程做成 skill。 - MCP 给的是能力,不是知识。它替 Claude 接上一个外部系统——一个数据库、一个内部 API、一个第三方服务,让 Claude 多出几个能调用的工具。skill 是教 Claude「怎么用它已经有的工具把事做对」,MCP 是给它「本来没有的工具」。两件事,两层。
- 内置工具(
Read、Bash、Edit这些)是常驻的能力,开箱就在,不用你操心。
至于子代理和 workflow,它们压根不在这张图的两个轴上——那是另一个维度的事:决定一件活儿「在哪个上下文里、并行几路」去跑,而不是给它知识或能力。一个子代理在干活时,照样可以加载某个 skill。它们是配合关系,不是替代关系。
想明白这一层,我对「该把东西放哪」就不纠结了:事实进 CLAUDE.md,流程做成 skill,缺工具上 MCP,要并行交给 workflow。
四、我真给博客写了一个 Skill
回到开头那个加工具的活儿。我做的 skill 叫 new-tool,SKILL.md 删繁就简大概长这样:
---
name: new-tool
description: 在本博客的工具区新增一个纯客户端小工具。当用户说「加一个
…工具 / 做一个 … 转换器」「在 tools 里再开一个」时使用。
allowed-tools: Read Write Edit
---
## 新增流程
1. 在 `src/pages/tools/<名字>/index.astro` 新建文件,逻辑全部写进
内联 `<script>`,不拆外部 JS,不打后端。
2. 回到 `src/pages/tools/index.astro`,往 `tools` 数组里登记一条;
还没做完的先挂 `available: false`。
3. 交互和配色参考 references/conventions.md:纯客户端、深浅色都不破,
和现有的 JSON / Base64 那几个工具对齐。
4. 写完跑一遍 references/checklist.md 自查。
正文我故意写得短,把「配色和交互的细则」「自查清单」这种长东西拆进了 references/ 里——按第三层的规则,它们只在真要用时才被读进来。
真正让我多花时间的,反倒是 description 那一行。它是整个机制里最关键、也最容易写砸的地方:写得太泛(比如只写「写个页面」),Claude 要么想不起来用、要么在我只是随手改别的页面时也硬要触发;写得够具体、带上几个我真会说的触发语,它才会在对的时候自己冒出来。我在那一行上来回改的次数,比改正文还多。
效果是实打实的:现在我不用再复述那套规矩了。我说一句「帮我在 tools 里加个 X 转换器」,它自己就翻开了 new-tool,文件放对了位置、逻辑全在内联 <script> 里、tools 数组那条登记也没忘。当然,写这个 skill 本身也是成本——只有当一件事你确定会反复做,这笔前期投入才划算。一次性的活儿,老老实实直接说就行,犯不上为它做个 skill。
顺带一提,这套格式现在不只是 Claude 的私货了。Anthropic 把 Agent Skills 开放成了一个跨工具的标准,同一个 SKILL.md 文件夹据说已经能被一票不同厂商的工具识别。我没逐一验证,就当个方向记下:我写的这个 new-tool,理论上不会因为哪天换了工具就作废。
五、碎碎念
description 决定生死,但它不是魔法咒语。 它能让 Claude「想起来」用某个 skill,可它判断得准不准,仍然取决于你这句话写得清不清楚、和当前任务像不像。我遇到过描述太含糊、它压根不触发的情况。这一行要当成正经文案来写,不是填个空。另外它有长度上限,别想把整篇说明塞进描述里——那是第二层正文该干的事。
不是 skill 越多越好。 每个 skill 的那句描述,是常驻在上下文里的。装三五个无所谓,装上几十上百个,光这些描述就开始占地方,还会稀释 Claude 的判断——它要在一大堆相似的描述里挑,反而容易挑错。我的做法是只为「确实反复做、且步骤值得固化」的事建 skill,其余的克制住。
它不会让模型变聪明,只是在对的时刻喂对的指令。 skill 解决的是「Claude 知不知道我这儿的规矩」,不解决「Claude 会不会写代码」。流程写得烂,它就按烂的流程一丝不苟地执行给你看。garbage in,garbage out 这条老规矩,在这儿一点没变。
跨工具标准是好事,但 Claude Code 的那些扩展字段未必通用。 allowed-tools、disable-model-invocation 这类 frontmatter,是 Claude Code 在标准之上加的料。description 和正文大概能跨工具搬,可一旦用上这些专属字段,可移植性就得打个问号。我暂时不会为了「通用」去回避它们——好用优先,但心里有数。
最后兜底的还是我。 这个 skill 把我的规矩交给了 Claude,但工具上线后是挂在我域名下、出 bug 由我背的。它写得再顺,代码我该读的还是要读、该测的还是要测。这点和我用 workflow 搭 MVP 时的结论是一样的:工具能把活儿做快,给成品兜底的永远是人。
小结
说穿了,一个 skill 就是一个装着指令的文件夹,聪明之处在于 progressive disclosure——平时只露一句描述,相关了才展开正文,要用到才打开附件,让你只在需要时才付那份上下文。对我这种被「重复交代规矩」拖着的独立开发者,这是我目前找到的最干净的解法:把散在脑子里的流程沉淀成文件,让 Claude 在对的时候自己想起来。
它不神,省的是上下文和我的口舌,不省我对成品该负的责任。
想看一手信息的,官方的工程博客把设计思路讲得最透:Equipping agents for the real world with Agent Skills;具体到 Claude Code 怎么建、怎么管,看官方文档的 skills 章节;想直接抄现成例子,anthropics/skills 这个仓库里有一堆官方写好的 skill 可以拆开看。等我攒下更多自己写的 skill、踩过更多坑,再回来更新这篇。