一个月给 Claude Code 烧了 1.5 万美金,我才搞懂 skill 到底该怎么写
公众号名称:吴师兄学大模型
作者名称:吴师兄
发布时间:2026-06-20 17:24
大家好,我是吴师兄。
先甩个让我肉疼的数据,上个月我做 AlgoMooc 这个算法网站,光 Claude Code 和 Codex 的账单就跑到了 14,942 美金,比五月份的 994 翻了快 15 倍,一个月烧掉十几万人民币的 token。

你可能以为这钱是花在”装备精良”上的。我前后给 Claude Code 写了十几个 skill,自我感觉武装到了牙齿。直到有一天我顺手在脚本入口加了行日志,把每个 skill 的调用次数打出来,才发现头三个月写的那批,加起来被 Claude 主动调用的次数,一只手数得过来,剩下时间它们就安静躺在目录里,跟我没写过一样。
钱烧得飞起,自以为精良的装备却大半在吃灰。这俩数字摆在一起,我才意识到自己根本没把 skill 用明白。
为什么提这个?因为上周一个学员面字节的 Agent 岗,被问到的就是这件事的另一面。
面试官让他现场讲一个自己写过的 skill。他讲得挺顺,把目录结构、操作步骤都说清楚了。面试官听完没评价,反而问了句:你这个 skill,前后改过几版?他说,没改过啊,一次写好就放进去了,挺好用的。
面试官笑了一下,说:那它大概率没被真正用起来。一个 skill 一次就写对、之后再没动过,往往说明它根本没经过 Claude 的实战检验。好的 skill 不是你写出来的,是你和 Claude 一起喂出来的。
学员后面就有点接不住了。
这句话戳到我了,因为我自己就是花了大半年才咂摸明白这个道理的。skill 这东西,认知门槛低,真正用好的门槛高。Anthropic 内部活跃的 skill 有几百个,他们最近把这几百个攒下来的经验写成了一篇博客,我又顺着 Claude Code 的源码扒了一圈实现细节。
但这篇我不想照着官方的目录给你复述一遍,那样你看完还是不会写。我想换个讲法:把我做 AlgoMooc 时,skill 从废柴长成主力的四个阶段,一段段摆给你看,每个阶段卡在哪、官方的哪条经验把我捞出来的。

skill 从一份文档喂养成一个工作系统的演化
一、第一阶段:我的 skill 是个谁都不理的 markdown
我最早写 skill,就是把”怎么给一道算法题生成动画题解”这套流程,老老实实写成一份 markdown,扔进 skill 目录。我以为这就齐活了,Claude 该用的时候自然会去读。
结果它几乎从不主动用。我说”给两数之和做个动画”,它自己吭哧吭哧从零开始写,把我 skill 里早就定好的那套舞台规范、配色、分步逻辑全无视了。我得每次手动点它名字,它才肯翻开那份文档照着做。
我一度怀疑是机制不行。后来去翻源码才搞明白,是我对 Claude 怎么”挑” skill 的理解整个错了。
很多人下意识以为,Claude 每次会把所有 skill 的全文都读一遍,再挑个合适的。真这样的话,你装十几个 skill,光这些文档就把 context 撑爆了。实际机制要省得多:会话一启动,Claude Code 只把每个 skill 的名字和那行 description 拿出来,拼成一张清单塞进 context。Claude 平时眼里就只有这张目录,正文一个字都没加载。等它觉得某个任务跟某条目录对上了,才会去调用,这时 SKILL.md 的全文才进对话。
官方给这套机制起了个名,叫渐进式披露(Progressive Disclosure),平时只露目录,用到了才露正文。
想通这一层,我那个 skill 没人理的原因就藏不住了:Claude 判断要不要用它,从头到尾就盯着那一行 description。它压根没读过我正文里写得多细致。而我当时的 description 写的是什么呢,“一个强大、灵活、支持多种算法的可视化生成助手”,一句正经的使用场景都没有,全是形容词。
我去源码里求证,发现这事比我想的还要苛刻。这张 skill 清单是有硬预算的:
export const SKILL_BUDGET_CONTEXT_PERCENT = 0.01
export const MAX_LISTING_DESC_CHARS = 250
这两个常量在 src/tools/SkillTool/prompt.ts 里。翻成人话就是:整张清单顶天只能占 context 窗口的百分之一,而且每个 skill 在清单里的描述,最多 250 个字符。超了怎么办?同一个文件里写得很干脆:
return desc.length > MAX_LISTING_DESC_CHARS
? desc.slice(0, MAX_LISTING_DESC_CHARS - 1) + '…'
: desc
超过 250 的部分直接截断,补个省略号。你要是把关键的触发场景写在第三百个字符上,那段话 Claude 这辈子都不会看见。
知道了这个,我把 description 重写了。形容词一个不留,改成大白话的场景描述:“当用户要给某道算法题生成动画题解、或者直接用 /anim 命令时,调用我。“就这么一改,效果立竿见影。我拿同一句”给两数之和做个动画”,连开五次全新会话去测,改之前五次零触发,改之后五次里中了四次。
所以 description 根本不是写给人看的简介,它是写给模型看的判断条件。你要把它当成一句 if 来写:满足什么情况,就该用我。形容词堆得再漂亮,模型也不为所动,它只认场景。

Claude 启动时只读到 skill 的目录清单,正文懒加载
这一阶段我还顺带踩明白一件事:skill 真不是越多越好。那百分之一的预算是全局共享的,你目录里每多一个 skill,清单里就多挤一行,所有 skill 能分到的描述空间就被压薄一点。装到一定程度,Claude Code 会先把所有 description 按比例压缩,再装不下就干脆只留名字、描述全砍。这就是为什么很多人感觉”装得越多越没人触发”。我后来清过一次目录,把那几个三个月没被调用过的直接删了,剩下的反而触发得更利索。

description 从形容词堆砌改成场景判断条件的前后对比
二、第二阶段:它肯干活了,可交上来的全是黑屏
description 治好了触发,新麻烦马上接上。Claude 终于肯用我的动画 skill 了,但它生成完,跟我说一句”动画已完成”,我点开一看,黑屏。
而且不是偶尔。题解动画这东西最阴的地方在于,代码跑完不报错,跟动画真的播出来了,完全是两码事。可能是数据没绑上,可能是第一帧就卡死,也可能是某个组件根本没挂载。但 Claude 看不到画面,它只看到自己的代码顺利执行完了,于是心安理得给我报了个”完成”。
有一次我上线前不放心,把它前一晚报绿的二十个动画页一个个手动点开看,结果二十个里有七个是黑屏。它一个都没漏报,全给我打了勾。那一刻我才真正明白,Claude 写代码的能力其实已经很强了,真正缺的是另一件事:它没法确认自己写的东西到底对不对。没有这个能力,它给你的每一个”完成”,都只是”我觉得应该没问题”。
这正好撞上官方那批经验里我体会最深的一条。他们把内部几百个 skill 归过类,结论是:在所有类型里,教 Claude 验证自己工作成果的那一类,对输出质量的提升最明显。原话夸张到什么程度,说这值得专门派一个工程师,啥别的都不干,花整整一周就把验证类 skill 打磨到极致。
我信这句话,因为我自己就是被那七个黑屏教育的。后来我给动画 skill 加了一道死规矩:它不许凭空喊”完成”。在交活之前,必须真的把页面跑起来,沿着播放路径走一遍,在不同时间点抓多帧截图,每帧都给图加个缓存戳证明不是拿旧图糊弄我,最后还要断言关键数据真的渲染到了画面上。这道关卡上线之后,“假完成”基本绝迹了。

上线前抽查:20 个报绿的动画页有 7 个其实是黑屏
一个会自己验收的 Claude,跟一个只会把活扔给你的 Claude,根本是两种东西。前者你能放手让它批量干,后者你得在它身后一张张图地查。这道验证关卡,是我整套 AlgoMooc skill 里回报最高的一笔投入,没有之一。如果你现在只有精力打磨一个 skill,别犹豫,就打磨”让 Claude 自己验收”这一件事。

验证关卡:跑起来→走播放路径→多帧截图加缓存戳→断言数据
三、第三阶段:活儿能看了,但它总在同一个坑里翻车
动画能正常播了,日子清净了一阵。可很快我发现,Claude 会反复栽在同几个坑里,今天填了,过两天换个会话它又踩。
问题出在我对 skill 正文的理解上。我一开始写正文,写得特别勤快,恨不得把每一步都交代清楚,连”写完要测一下""注意代码规范”这种话都写进去。后来才知道,这些全是废话。Claude 本来就会写代码、本来就会测,你把它默认就会的事再写一遍,等于往它脑子里灌噪音,半点增量都没有。
官方有个判断标准我觉得特别准:如果你的 skill 是在传授知识,那就只写能把 Claude 从默认行为上掰过来的内容。换句话说,只写它猜不到的,删掉它本来就会的。他们自己有个例子很传神,官方那个前端设计 skill,通篇没教 Claude 怎么写 CSS,因为它会,而是列了一堆”别这么干”:别张口就用某个烂大街的字体,别动不动上紫色渐变,全冲着模型的默认审美去纠偏。
那 skill 正文里最该写的是什么?是坑点。是那些光读代码永远读不出来、只有真摔过跟头的人才知道的东西。
我那个动画 skill 的坑点清单,是整份文档里最长的一节,从最早三条,一路被 Claude 喂到了二十多条。随便举几个真实的:
第一条,截图必须等动画播到第三十帧以后再抓。因为开头那十几帧画面还在初始化,全是白的,Claude 要是第零帧就截,截到一张白图还以为大功告成。
第二条,题解页发到 CDN 之后,得主动调一次刷新缓存的接口。不然你打开看到的还是上一版,改了半天没生效,你以为是代码逻辑错了,对着代码查半天,其实是缓存没刷。这个坑我自己都中过两回。
第三条,配色不能让它自由发挥,必须从 assets 里那套 token 取。它一自由发挥,红绿对比度就不够,色弱用户根本看不清哪个是当前比较的元素。
你看这几条的共同点:没有一条是 Claude 能靠读我代码推断出来的,全是它当着我面翻过车、我才补进去的。这就是坑点清单含金量最高的原因,每补一条,就等于提前帮它拆掉一颗它早晚要踩的雷。

坑点清单:从 3 条被 Claude 一次次喂到 22 条
但这里有个反方向的度要把握。官方专门提醒过,别把 Claude 锁死在轨道上。它对指令的服从度很高,你要是把每一步都写得死死的,它一碰到你没覆盖到的情况,就容易僵在原地按错误的轨道硬开,明明该随机应变的地方也不敢变。所以正确的姿势是:把它需要知道的信息给足,但具体怎么走,留出余地让它自己判断。信息要满,指令要松。
四、第四阶段:skill 多了,它们开始互相抢资源
写到第四个、第五个 skill 的时候,我才真正理解了开头那句话,skill 根本不是文件,是文件夹。
这是官方点名的头号误解,我也是踩进去之后才信的。一个像样的 skill,除了那份必需的 SKILL.md,还能带一整套家当。我那个动画 skill 后来长成了这样:
algomooc-animator/
├── SKILL.md # 唯一必需:何时用我 + 操作指引 + 坑点清单
├── references/ # 已上线的优质题解页,给它学风格
├── assets/ # 配色 token、动画组件规范
├── outputs/ # 生成的动画 HTML 页面
└── scripts/
├── render_check.py # 第二阶段那道验证关卡
└── deploy.py # 发布并刷 CDN 缓存
关键在于,这些子文件不会一股脑塞给 Claude。它干到哪一步、需要哪份材料,才拿着根目录地址自己去翻。源码里这个细节我印象很深,skill 被调用时,系统会在 SKILL.md 全文最前面拼一句话,告诉它”你这个 skill 的根目录在这儿”,剩下的 references、scripts 全靠它照着正文的指引自己去读。所以渐进式披露其实是三层:平时只有 description,调用时加载 SKILL.md 全文,正文里点到的参考文件,等它真用到了才去取。一层比一层深。
理解了文件夹这一层,三个让我后来离不开的玩法才打开。
第一个是把脚本喂给它。官方有句话我特别认同,你能给 Claude 最强的工具就是代码。我把取数、渲染、发布这些底层动作全封装成现成脚本放进 scripts,Claude 每个回合就不用再现写一遍样板,而是花在思考”这一步该调哪个脚本”上。我那个 render_check.py 就是这么来的,它不用每次重新发明一遍截图校验,直接调。
第二个是给 skill 装记忆。每次会话都是新开的,Claude 不记得上回干了啥。官方的解法很朴素,让 skill 把状态存进自己的文件夹。我做 AlgoMooc 时就把部署要用的 CDN bucket、刷缓存的接口、预览和正式两套域名,都写进了一个 config.json。第一次配好,之后每次发布它直接读,再没来问过我第二遍。相当于给 skill 配了个”首次使用引导”,问一次,记一辈子。
第三个最容易被忽略,是挂只在 skill 激活期间生效的临时 hook。这种 hook 平时不存在,skill 一被调用才注册,会话一结束就消失。官方有个叫 freeze 的例子,激活后就禁止改指定目录之外的任何文件。我太需要这个了。以前让 Claude 改一个题解页,它经常顺手把旁边无关的页面也动了,我得逐行 review 防它越界。后来我在改单页的时候挂上类似 freeze 的约束,把它死死圈在当前这一页里,越界这毛病当场就好了。
所以一个用满了的 skill,早就不是一份文档了,它是一个带工具、带记忆、还带保险丝的小工作系统。我前三个月写的那批废柴,败就败在只写了文档那一层。

skill 文件夹的全貌:SKILL.md + references + scripts + assets
这套从生成到验证到部署的完整流程,后来成了我做 AlgoMooc 时最依赖的一条流水线。它不是某一天想清楚一口气写出来的,是这四个阶段里,被一个个具体的车祸逼着一点点长出来的。如果你也想搭一套自己的,我把 AlgoMooc 这套 skill 的演化过程和踩坑记录整理在了官网上,可以去翻翻看,少走点我走过的弯路。

脚本、记忆、临时 hook:让 skill 成为带保险丝的工作系统
五、最后一道坎:我怎么知道哪个 skill 真有用?
回到开头那个让我脸红的日志。
skill 攒到十几个,新问题就来了:哪些是主力,哪些是化石?光靠感觉是会骗人的。我一度以为我那个”批量改题解配色”的 skill 会很常用,特意打磨过好几轮。结果日志一拉,它整个月就被调了四次,而那个生成动画页的 skill,同期被调了一百多次。要不是这行日志,我还在惦记着给配色 skill 加新功能,纯属把劲使在了没人走的路上。
这正是官方建议给 skill 做埋点的原因。方法很轻,用一个 PreToolUse hook 监听 skill 工具的每次调用,把谁在什么时候用了哪个 skill 记下来。数据一汇总,两类 skill 立刻现形:一类是高频主力,值得你把那”一周打磨验证 skill”的力气花上去;另一类叫触发不足,你以为它该常用、数据却显示没人碰,这种八成就是第一阶段那个病,description 没写对,模型扫一眼清单根本想不起它。把这种揪出来回去修 description,就形成了闭环。
知道了哪个是主力,我后来就把精力集中砸在动画 skill 上,专门优化它的渲染速度,单页生成从原来的十几秒压到了三四秒。这种优化,砸在一个月被调一百多次的 skill 上才有意义,砸在那个一个月四次的配色 skill 上,纯属自我感动。
不被度量的 skill 目录,迟早变成一个没人敢动、也没人想用的杂物间。
顺带说一句团队层面。我是个人做 AlgoMooc,但如果是在公司里,skill 还能打包成 plugin 放进团队的内部市场,谁用谁装,避免所有人无差别承担那百分之一的预算。官方那边甚至没有专门的审批团队,全靠自然演化,谁写了好用的就先扔进沙盒,用的人多了口碑起来了,再提交进正式市场。好东西是靠口碑长出来的,不是靠评审评出来的。

skill 调用计数:配色 skill 月调 4 次,动画 skill 月调一百多次
面试怎么答 Claude Code Skill?
如果面试官问到 skill,别去背官方那七八个要点,照着”它会怎么坏”这条线答,反而显得你真用过。
第一步,先点破认知(30 秒):skill 不是一份 markdown,是一个文件夹。SKILL.md 是唯一必需的,外加 references、scripts、assets 这些按需加载的家当。只写一份文档,等于这个机制的能力你只用了一成。
第二步,讲清它为什么不触发(1 分钟):核心是渐进式披露,三层。平时只把名字和 description 注进 context,单条上限 250 字符、整张清单只占窗口的百分之一;命中才加载 SKILL.md 全文;正文点到的参考文件,等真需要 Claude 才去读。所以 description 决定生死,要写成”什么场景下用我”的判断条件,不是写给人看的简介。
第三步,讲正文该写什么(30 秒):只写 Claude 推断不出来的,含金量最高的是坑点清单,是那些只有踩过坑才知道的东西;别陈述显而易见的事,也别把步骤写太死把它锁死在轨道上。
第四步,亮一个高阶点(30 秒):skill 还能带封装好的脚本、带跨会话的记忆,甚至挂只在激活期生效的临时 hook 当保险丝;团队里用内部市场分发、用 PreToolUse hook 埋点看哪些 skill 真被用。
能把这四步串成一条”从不触发到被用烂”的线讲下来,面试官立马能听出来,你是真把 skill 喂大过的人,而不是装了几个就来面 Agent 岗的。
写在最后。这篇里所有的坑,都是我做 AlgoMooc 这大半年,被 Claude 一次次当面演车祸演出来的。官方那句话我越想越对,他们内部最好的那批 skill,几乎都是从几行字加一个坑点起步的,然后跟着 Claude 撞上一个个新边界,被人一点点喂大。所以你的第一个 skill 真不用写三千行,先把一个真实的坑写进去,剩下的交给时间和你自己的项目。
我是吴师兄,我们下篇文章见。
内容效果不满意?点此反馈