我在日常使用 Claude Code 时,最头疼的事情就是同一个项目反复交代类似的规则。今天让 AI 按团队风格写提交信息,明天提醒它别动测试文件,后天又得教它怎么跑本地构建。CLAUDE.md 越写越长,提示词越堆越重,但换个项目、换台机器,或者想把这些“经验”分享给同事时,全都得从头再来。
后来我把这些内容沉淀成了 Skills,工作方式立刻就不一样了。简单说,Skills 就是给 Claude Code 安装的一套“专业技能包”:一个 Skill 对应一类具体任务,里面有清晰的触发条件、操作流程、判断标准和可复用的资源文件。它让 AI 在“该出手时自动出手”,而且不需要你每次把背景知识重新讲一遍。官方在文档里专门给过一整套最佳实践,总结出来其实可以浓缩成一句话:设计 Skill 的核心不是“写一份说明书”,而是“设计一套能在合适时机自动触发、且稳定产出好结果的工作流”。
这篇文章主要面向已经在用 Claude Code、想把重复劳动沉淀成资产的开发者。不管你是想让 AI 更懂某个框架的代码风格,还是想让团队共享统一的审查规范,看完你都能按一套可落地的步骤去设计自己的 Skill。
1. 先想清楚:Skills 到底解决什么问题
1.1 从“反复解释”到“一次封装”
先说个我自己的例子。早前我维护一个前端仓库,每次让 Claude 改样式都得费半天劲:先告诉它项目用什么 CSS 方案,再说是 BEM 命名习惯,接着强调禁止内联样式,最后还得叮嘱它提交前跑 lint。这些指令每次都一样,每次都得重新敲一遍,或者从旧对话里翻出来粘贴。后来我把这些整理成两个 Skill:一个负责“按项目规范生成样式代码”,另一个负责“提交前检查代码风格”。从那以后,Claude 读代码上下文时就会自动判断该不该启用这些技能,整个过程我几乎不用额外说什么。
官方给 Skills 的定位,其实就是“让 Claude 在恰当的时候自动调用你预先封装好的知识或流程”。它和普通提示词最大的区别在于“自动触发”和“结构化”——你不需要在每次对话里明确说“请使用某某技能”,只要描述写得好,Claude 会在需要时自己找上门来。这个机制带来的直接好处是:人的注意力被释放了,AI 的行为变得稳定可预期,团队协作时经验也能直接复用。
1.2 Skills 与 CLAUDE.md、MCP 的分工
很多新手会混淆这三者的关系,我做一个简单但重要的区分:
- CLAUDE.md 是“全局背景知识”,告诉 Claude 项目是什么、技术栈是什么、常用命令、代码风格。它回答“你是谁、你在哪儿、有什么规矩”。
- Skills 是“专项工作能力”,解决“遇到某类任务时,如何高质量完成”。它回答“这件事具体怎么做、按什么步骤做、达到什么标准才算好”。
- MCP 是“外部工具接入”,让 Claude 能访问数据库、浏览器、第三方 API。它回答“还能调用什么资源”。
用生活里的话来讲:CLAUDE.md 像入职手册,Skills 像岗位 SOP,MCP 像办公系统接口。入职手册告诉你公司情况,但具体怎么处理客诉、怎么写周报,靠的是 SOP;要查客户资料、发邮件,则要打开对应系统。
常见的误区是把所有东西都塞进 CLAUDE.md。一旦内容超过几十行,模型的注意力会被稀释,真正重要的规矩反而容易被忽略。这时候就该考虑把“业务规则”留在 CLAUDE.md,把“任务执行方法”挪到 Skill 里。我见过不少团队把几百行的规范全部塞进 CLAUDE.md,结果模型在长上下文中丢失重点,该守的规矩反而守不住。
2. 官方最佳实践第一课:结构设计决定成败
2.1 目录放哪:用户级、项目级还是插件级
Skills 按作用范围分成几层,很多人在第一步就放错了位置:
| 位置 | 作用范围 | 适用场景 |
|---|---|---|
用户级~/.claude/skills/ | 所有项目 | 个人通用技能,如代码审查、提交信息规范 |
项目级.claude/skills/ | 单个仓库 | 项目专属规则,如某框架的代码生成习惯 |
| 插件级(插件包内 skills 目录) | 随插件分发 | 团队共享,通过插件分发到不同机器 |
按照官方最佳实践的组织方式,单个 Skill 就是一个独立目录,目录名就是 Skill 名,用短横线连接的小写单词,比如fix-lint-errors、write-rust-tests。目录内至少要有一份SKILL.md,这是入口文件,其余可以放脚本模板、示例代码等。
我建议普通用户按这个顺序试验:先在项目级放一两个最常用的,跑通了再沉淀到用户级。不要一上来就建一大堆全局技能,维护成本高不说,还容易在不同项目里互相干扰。一个很实际的例子:某前端项目的“禁止使用内联样式”规则,放到另一个用 CSS-in-JS 的项目里就完全没意义,如果放在用户级,反而会给那个项目添乱。
2.2 前言 YAML:这部分是“触发器”不是“名片”
SKILL.md顶部有一小段 YAML 前言,很多人的前言写得像论文摘要,结果导致技能完全不触发。前言里最关键的不是name,而是description。官方最佳实践明确强调:description 要写“何时使用这个技能”,而不是“这个技能是什么”。
举个例子,假设你想写一个“修复 lint 错误”的技能。错误的 description 是:
这个技能用于修复 JavaScript 代码中的 lint 错误。
正确的 description 应该是:
当代码中存在 lint 错误,或用户要求检查代码风格、修复 eslint 报错时使用。尤其适合在提交前、CI 失败后或代码审查阶段调用。
区别在于:前者只能靠用户提到“lint 错误”时才会被想起,后者则把各种可能触发的情境都覆盖到了。Claude 会不会用你的技能,很大程度上取决于它从 description 里能不能联想到“现在就是该用这个技能的时刻”。
我自己的经验是:写 description 时,多列几个“用户可能怎么说、什么场景下会用到”,越具体越好。测试时如果技能没触发,八成不是正文写得不好,而是 description 写得不够“招人”。描述不是写给人看的,是写给模型做场景匹配用的,这个思维转变很关键。
2.3 正文三层结构:渐进式披露是核心原则
官方最佳实践反复强调“渐进式披露”这个原则,说白了就是“别让 AI 一口气读完全部细节”。SKILL.md的正文建议按三层组织:
- 概述层:一段话说清楚这个技能是做什么的、什么时候用、最终达到什么效果。
- 流程层:用步骤列表列出核心工作流程,每个步骤一句话,让 Claude 先建立全貌。
- 细节层:把每个步骤的细节、判断标准、注意事项放在后文,或者在需要时引导 Claude 去查看子文件。
为什么这么做?因为 Claude 每轮对话的上下文窗口是有限的。如果你在一个 Skill 里堆了 5000 字的细节,即使它能在某些情况下全部读完,也会占用大量上下文空间,挤占真正的代码内容。三层结构让 Claude 只需要读概述就能判断用不用,决定用了再按需深入,省下大量 token 不说,响应质量也更稳定。
我见过不少写得特别详细的 Skill,事无巨细列了上百条规则,结果模型反而抓不住重点。克制一点,反而更可靠。这不是懒,是设计。最理想的状态是:概述层一两段能读完,流程层五六个步骤能扫完,细节则完全按需展开。
2.4 别忘了版本管理:Skill 也是代码
既然 Skills 是“沉淀下来的资产”,就应该像代码一样管理。我自己会把整个.claude/skills/目录放进 Git 仓库,每次修改都有记录,方便回滚。这个习惯救过我一次:有一次我优化某个技能的正文结构,改完后发现它在某个场景下反而不触发了,靠着 Git 历史直接 diff 定位到是 description 的改动导致场景匹配变了,马上回退,前后不到五分钟。
如果团队协作,我还会在仓库里加一个简单的README.md,说明每个 Skill 的用途、维护人和更新历史。配合依赖管理工具做插件分发时,这种规范尤其重要。技能包不像普通代码,它不会在编译期报错,出问题都是运行时才暴露,所以变更记录和回滚手段比你想的更值钱。
3. 亲手写一个技能包:代码审查 Skill 实战
3.1 场景设定与目录规划
下面我用一个真实用过的场景——“代码审查”——来完整演示怎么写。目标:让 Claude Code 在收到审查请求时,不是东一榔头西一棒子地随便看,而是按照统一规范输出结构化审查结果。
先建目录结构:
.claude/skills/code-review/ ├── SKILL.md ├── checklists/ │ ├── frontend.md │ └── backend.md └── templates/ └── review-report.md目录名叫code-review,小写加短横线。SKILL.md是总入口,checklists放不同技术栈的检查清单,templates放输出报告模板。为什么要把 checklists 拆成前端和后端?因为一个仓库里通常只有一种主要技术栈,如果我把两套检查项都写进主文件,Claude 审查前端代码时也会读到后端的检查项,这些无关信息会干扰判断。拆开之后,它按需读取,干净利落。
3.2 SKILL.md 完整示范与逐段拆解
下面是一个简化但完整的SKILL.md:
--- name: code-review description: 当用户要求"帮我看看代码是否有问题"、"做一次代码审查"、"Review一下这个PR",或提交变更前希望检查潜在Bug和安全隐患时使用。适用于前端、后端、脚本等各类代码。 --- # 代码审查 这个技能用于执行一次结构化的代码审查,输出按"严重程度"分类的问题清单,并附上可执行的修复建议。适用于合并请求提交前、代码交付前的自检阶段。 ## 执行流程 1. 确认范围:如果用户没有明确指定,先找出最近的变更文件(git diff 或用户提供的文件列表),明确审查边界。 2. 逐文件审查:按下述"审查维度"逐项检查每个变更文件,记录问题。 3. 风险分级:把每个问题标记为阻塞级、建议级或风格级。 4. 生成报告:使用 `review-report.md` 模板输出,包含问题清单、严重程度、定位行号和修复建议。 5. 复查验证:再次确认所有"阻塞级"问题均已列出,没有遗漏。 ## 审查维度 - 正确性:空值、边界条件、异步时序、异常处理是否完整。 - 安全性:输入校验、鉴权判断、危险函数使用是否安全。 - 性能:是否有明显不必要的循环、重复查询、无记忆化计算。 - 可维护性:命名、函数长度、模块拆分是否符合常规范式。 详细的分技术栈检查项,参考 checklists/ 目录下对应文件;如果涉及前端仓库,阅读 frontend.md;涉及后端,阅读 backend.md。 ## 输出格式 严格按 `templates/review-report.md` 组织,不要遗漏严重程度列。如果某个维度没有发现任何问题,也要写"未发现异常",避免阅读者误以为检查跳过。你把描述部分写得特别长,是因为它是整个技能能否触发的关键。前面已经讲过 description 的设计原则,这里再强调一句:让 Claude 自己推理何时用这个技能,比给它一些花哨的关键词更有用。流程部分拆成 5 步,每步都是可执行动作,而不是抽象建议。官方特别强调要用“行动导向”的语言,比如“执行流程”里写“找出最近的变更文件”,而不是“确保审查范围清晰”。前者是可操作步骤,后者像个口号,模型执行起来没抓手。
还有一个小细节:我在“审查维度”里没有把所有规则铺开,而是写道“详细检查项见 checklists 目录”。这就是渐进式披露的实际操作——把容易膨胀的细节拆到子文件,让主文件保持在易读的范围。这样当 Claude 遇到前端代码时,它会主动去读frontend.md;遇到后端代码时读backend.md,避免无关文件的信息干扰。
3.3 渐进式披露与子文件:checklists 到底怎么放
checklists/frontend.md里我一般放这类内容:组件拆分是否合理、状态管理是否有明显反模式、样式是否遵循项目约定、有无遗留的 console 和调试代码、事件监听有没有清理。backend.md则关注:接口有无鉴权、SQL 是否存在 N+1 查询、异常有没有被吞掉、敏感信息有没有硬编码。
每个子文件不需要写成非常正式的文档,用列表就足够。关键是条目要具体、可检查。一个可靠的 checklist 条目是“检查所有catch块,是否存在空 catch 导致错误被静默吞掉”,而不是“妥善处理异常”。前者是一个可以执行、可以判断通过与否的动作,后者是一句正确的废话。
在子文件的设计里,我还习惯给每个条目加一个“严重级别建议”,因为不同团队对同一问题的容忍度不一样。比如“缺少输入校验”在内部工具里可能是建议级,在对外 API 里就必须是阻塞级。这样 Claude 在生成报告时就有了分级依据,而不是自己拍脑袋。我建议你在自己的子文件里也尝试这个思路,让规则更贴合团队实际情况。
3.4 验收清单与迭代流程
Skill 不是写完就完事,最好按下面的清单过一遍:
| 检查项 | 通过标准 |
|---|---|
| 触发验证 | 在 3 种不同表述的对话里,Claude 均能自动启用该技能 |
| 上下文占用 | 主文件读完后,约占用不超过 1000 个 token(可通过对话日志估算) |
| 结果一致性 | 同一份代码连续审查 3 次,问题清单差异不大 |
| 可运维性 | 子文件中的检查项能被团队成员独立修改,不影响主流程 |
我建议把“触发验证”做成一个小脚本,把几种典型用户提问记下来,反复测试。这样每次改完 description,几分钟就能回归一遍。有一次我就是靠这个习惯,发现了新改的 description 反而让技能在某个场景下不再触发了,赶紧回退。触发问题不是“改了就完事”,而是要持续回归,尤其是在技能逐渐变多之后。
迭代的时候记住一个顺序:如果 Skill 没有被触发,优先检查 description 的场景枚举;如果触发了但结果不达标,再回来优化正文流程。这个“先调触发器、再调执行器”的顺序,我踩过不少坑才总结出来。很多人一上来就改正文,改了半小时发现问题根本不在这里,白白浪费时间。
4. 常见问题与排查经验
4.1 技能总是不触发,怎么办
不触发是最常见的问题,90% 的情况出在 description。可以按这个顺序排查:
- 是不是 description 只写了“是什么”没写“何时用”?补上具体场景。
- 是不是场景描述太窄?比如你只写了“修复 eslint 错误”,但用户可能说的是“帮我把这行缩进调一下”。
- 是不是项目级和用户级放混了?确认技能确实在当前项目可访问的路径下。
- 是不是正文第一步就让 Claude 犹豫了?有些技能正文开头要求用户先提供信息,但如果上下文里已经有这些信息,Claude 可能判断“还缺东西”而放弃调用。
测试时有一种取巧的办法:直接在对话里说“请使用 code-review 技能”,如果这样它都不读SKILL.md,那多半是文件本身放错位置或格式错误;如果能读但不会主动用,问题就在 description。这个二分法能帮你快速缩小排查范围,不用瞎猜。
4.2 技能被触发后,结果全是套话
这种情况通常是正文写得“太原则”,缺少强制性的输出约束。解决思路是加几条硬性规则,比如规定报告必须包含定位行号、问题必须按三级分类、每条建议必须给出可直接落地的代码片段。
我之前写过一份审查技能的早期版本,流程写得挺全,但输出格式没约束,结果 Claude 经常给出一堆“建议加强代码健壮性”之类的废话。后来我把输出模板改成表格,并且规定“没有行号的问题一律不接受”,质量立刻上来了。模板不是形式主义,它是一种很好的“强制格式校验”。框架性约束越多,模型的自由度越低,反而越稳定。
4.3 多技能互相抢任务,行为不稳定
当你有多个 Skill 时,可能出现“两个技能都想接管同一类任务”的情况,这时 Claude 的行为会变得不稳定。我的处理办法是给每个 Skill 划清边界:在 description 里明确写“如果涉及部署操作,请改用 deploy-check 技能”,或者反过来写“本技能只处理前端代码,不处理后端”。
另一种办法是刻意让技能粒度更小。官方也建议单个技能聚焦一类任务,而不是做成一个“全能工具箱”。一个技能搞定所有事情,听起来省事,实际维护时会让你怀疑人生——因为它太多分支、太多特例,逐步变得不可预测。拆分到每个技能对应一个明确场景,行为反而更可控。我见过最典型的反面教材是一个“项目助手”技能,里面既有代码规范又有部署流程还有数据库操作建议,结果什么都做,什么都不精。
4.4 实战排查速查表
| 现象 | 可能原因 | 处理办法 |
|---|---|---|
| 完全不触发 | description 场景不足或放错目录 | 扩充场景枚举,检查目录层级 |
| 触发率时好时坏 | 多个技能 description 描述重叠 | 在描述中标明边界,收敛场景 |
| 输出不符合预期 | 正文缺少流程与验收标准 | 补流程步骤、输出模板、质量标准 |
| 上下文大量浪费 | 正文太详细、未做渐进式披露 | 细节下沉到子文件,主文件保持概览 |
| 结果不稳定 | 规则过多且互相冲突 | 精简规则,突出 3~5 条核心硬性约束 |
我个人还有一个习惯:每星期抽时间看看 Claude 和 Skill 的交互记录,挑一两条它没做好或者执行得反常的记录,反推是哪一句话让它跑偏了。这比起凭空重写整个文件要高效得多。排查技能问题时,别光靠“感觉”,尽量从实际日志和对话记录里找证据,这样定位问题的速度会快非常多。
根据自己的几个项目经验,最值得投入的 Skills 是那种“你会反复做、且每次做完都感觉像第一次做”的任务。把这些任务沉淀成技能包,省下来的不只是敲提示词的时间,更是一种“团队经验显性化”的过程。新同事拿到项目仓库,跑一次代码审查技能,基本就能摸清团队对代码的期待,比读半年文档都管用。
最后再分享一个小技巧:如果你实在不知道从哪个 Skill 开始写,就盯着自己最近十次让 AI 改代码的对话,把重复出现的那些要求挑出来——比如“记得跑测试”“用项目现有的工具函数”“不要动公共接口”。把这几句话整理成一个最小的 Skill,立刻就能感受到差距。别追求一次写完美,先交付一个“70 分的能用版本”,在真实使用中迭代到 90 分,远比关起门来打磨大而全的方案要靠谱得多。