返回博客

解剖 Skill:Skill 工程化实战指南(二)

作者 约 6 分钟读完

Skill 是给模型的作业指导书,不是函数调用。四件套(Metadata / allowed-tools / SKILL.md / scripts)+ 三阶段生命周期(注册 → 匹配 → 执行),讲清何时该写、怎么写不跑偏。


解剖 Skill:Skill 工程化实战指南(二)

在上一篇中,我们达成了一个共识:把 Prompt 当工程方案,迟早要出事。要让 AI 真正成为稳定输出的生产力组件,我们需要将其封装为 Skill(技能)。

很多开发者对 Skill 的理解还停留在"稍微高级一点的 Prompt 模板",这就大错特错了。今天,我们拿起"手术刀",划开 Skill 的外皮,看看它内部到底长什么样,以及当你在终端或 IDE 里敲下回车时,底层系统到底经历了怎样的一生。

Skill 的"解剖学":一个标准件的四个单元

不要把 Skill 想象成一段纯文本。在 Claude Code 里,一个标准的 Skill 是一个目录,里面由四类文件各司其职。如果把它比作一个人体,它有四个不可或缺的器官:

.claude/skills/
└── cross-platform-code-review/
    ├── SKILL.md          ← ①②③ 元数据 + 指令骨架
    ├── references/       ← ③ 长参考资料(按需加载)
    │   └── harmonyos-api-compat.md
    └── scripts/          ← ④ 确定性逻辑(交给代码跑)
        └── run_linter.sh

Skill 的四件套:元数据 Frontmatter、权限边界 allowed-tools、核心指令 SKILL.md、确定性脚本 scripts/

① 元数据(Frontmatter):AI 的"简历"

这是最容易被忽视,却决定了 Skill 能否被准确召唤的关键。它写在 SKILL.md 顶部的 YAML frontmatter 里,最关键的两个字段是 name 和 description。

在"手工作坊"时代,你起名字可能叫 prompt_v3_final.txt。但在 Skill 的世界里,description 是写给大模型的"调度路由"看的 —— Claude Code 在会话启动时,只会把每个 Skill 的 name + description 放进可发现列表(这就是所谓的 progressive disclosure),正文要到被命中后才加载。所以 description 写得好不好,直接决定这个 Skill 会不会被用上。

❌ 反面教材: description: 用于检查代码。(太宽泛,AI 根本不知道什么时候该调它)

✅ 工程规范: description: 当用户要求进行跨平台(如 Flutter/HarmonyOS)的 UI 组件代码审查时触发,重点检查状态管理、内存泄漏及平台特定 API 兼容性。

一个完整的 frontmatter 大致长这样:

---
name: cross-platform-code-review
description: 当用户要求进行跨平台(如 Flutter/HarmonyOS)的 UI 组件代码审查时触发,重点检查状态管理、内存泄漏及平台特定 API 兼容性。
allowed-tools: Read, Bash
---

② 权限边界(allowed-tools):真正的"安检门"

这是 Skill 工程化里最实用、也最容易被新手忽略的一个字段。allowed-tools 声明了这个 Skill 被允许使用哪些工具 —— Read / Write / Bash / WebFetch 等等。没写的工具,Skill 就调不到。

告别自然语言模糊性的正确姿势,不是给 Skill 定义 JSON Schema 入参(那是 Tool Use 的机制),而是通过 allowed-tools 把权限边界收窄,再在 SKILL.md 正文里写清楚输入约定和输出结构。用户再怎么胡言乱语,能干什么干不了什么都在这一行里被钉死:

allowed-tools: Read, Bash

纯文本处理的 Skill 只开 Read, Write 就够;需要跑确定性脚本时再开 Bash,并在项目 .claude/settings.json 里把允许执行的命令收窄到精确白名单。最小权限原则靠的是这一行,不是靠你在正文里写"请不要删库"这种口头约定。

③ 核心指令(SKILL.md 正文):固化的"肌肉记忆"

这是传统 Prompt 演变来的部分,但因为有了前面两层的铺垫,你在这里再也不需要写诸如"请以 JSON 格式输出"、"请不要说废话"这种防御性指令了。你只需要专注在业务逻辑上 —— 具体的架构规范、代码风格、步骤清单。

这一部分的关键工程习惯是:正文只写"步骤和决策规则",长知识挪到 references/。

很多人喜欢把风格指南、行业术语表、合规红线一股脑塞进 SKILL.md 正文,结果正文膨胀到几千行,模型每次命中都要啃完整份 —— token 成本和注意力成本同时爆炸。正确姿势是把长资料抽成 references/harmonyos-api-compat.md 这种分册,在正文里用一句"按 references/harmonyos-api-compat.md 的清单逐项核对"按需引用,Claude 只在执行到那一步时才会读那份文件。

④ 确定性脚本(scripts/):伸向物理世界的"手"

Skill 往往不是孤立的。在检查完代码后,它可能需要调用本地的 Linter 跑一下,或者按固定规则校验输出字数、Emoji 数、JSON 结构是否合法。

这些能交给代码的逻辑,就不要交给模型 —— 让模型"自己数 Emoji 个数"远不如让它跑一下 scripts/validate_output.py 靠谱。Skill 的 scripts/ 目录就是放这些确定性处理脚本的地方,通过 allowed-tools: Bash 授权后由模型在步骤里调用。

如果需要更复杂的外部能力(连数据库、调内网 API、访问第三方服务),则走 MCP —— 在项目里挂一个 MCP server,SKILL.md 里调用它暴露的 tool 即可。Skill 本身不直接管外部系统接入,这件事交给 MCP。

Skill 的生命周期:它是怎么被加载和激活的?

了解了构造,我们来看看一个 Skill 是如何在你的工作流里"活"过来的。它的生命周期主要分为三个阶段:

Skill 三阶段生命周期:注册与发现 → 意图匹配与指令加载 → 执行与工具调用

阶段一:注册与发现(扫描与挂载)

当你启动 Claude Code 时,系统会扫描两个目录:

  • 项目级:<repo>/.claude/skills/
  • 用户级:~/.claude/skills/

系统从每个 Skill 目录下读取 SKILL.md 的 frontmatter,把 name 和 description 放进"可发现 Skill 列表"。注意:此时正文还没被加载进 context —— 这是 Skill 相对于"塞进 system prompt 的超级 Prompt"最本质的优势,叫 progressive disclosure(渐进式披露)。否则你装 50 个 Skill,context 第一轮就爆炸了。

这时候,AI 就像一个拿着一串钥匙名牌的管家:它知道每把钥匙叫什么、能干什么,但还没真正取出钥匙。

阶段二:意图匹配与指令加载(路由)

当你在对话框输入:"帮我看一下 login_page.dart,马上要上鸿蒙了,查一下有没有坑。" Claude 底层会进行如下决策:

  1. 意图识别:用户在请求代码审查,涉及跨平台(HarmonyOS)。
  2. Skill 匹配:扫描可发现列表,发现 cross-platform-code-review 的 description 完美命中。
  3. 正文加载:把这个 Skill 的 SKILL.md 正文加载进当前 context,作为后续生成的指令基线。

这一步和 Tool Use 有一个本质差异:Skill 不会"从用户自然语言里强制抽取参数成 JSON" —— 用户的原话整段保留,由模型在加载了 SKILL.md 指令之后去自行理解和抽取。"待审查文件是 login_page.dart"、"目标平台是 HarmonyOS"这些信息的识别,发生在模型按 SKILL.md 步骤执行时,而不是在一个独立的"参数抽取器"里。

阶段三:执行与工具调用

拿到指令后,模型按 SKILL.md 的步骤逐条执行:

  • 需要读文件 → 调用 Read 工具(前提是 allowed-tools 允许)
  • 需要跑脚本 → 调用 Bash 执行 scripts/run_linter.sh
  • 需要长参考 → 读取 references/harmonyos-api-compat.md
  • 需要外部服务 → 调 MCP server 暴露的 tool

最后把干净、格式化的结果吐给你。整个过程,你只觉得是跟 AI 说了一句话,但在底层,它经历了一次**"发现 → 加载 → 按 runbook 执行"**的完整作业流程。

💡 关键心智模型:Skill 不是函数调用(那是 Tool Use),而更像"模型发现并执行了一份可复用的作业指导书(runbook)"。没有函数签名,没有强类型返回值,有的是步骤、决策、工具授权和确定性校验。

什么时候应该果断写一个 Skill?

虽然 Skill 很好,但如果你把所有需求都封装成 Skill,那叫过度设计。作为一个高阶工程师,你需要有一套判断标准。

三种情况:高频重复、团队纪律、自动化流转,立刻把它写成 Skill

当你遇到以下三种情况,立刻把它写成 Skill:

  • 🚨 场景一:高频重复的"脏活累活" 如果你发现自己这周已经是第三次输入"请帮我把这段逻辑转成包含完整单元测试的代码"时,这就是明确的信号。高频调用的场景值得被固化 —— 一次写好,未来每次只需要一句话触发。

  • 🚨 场景二:需要强迫 AI 遵守"团队纪律"时 团队协作最怕千人千面。如果你带一个十几人的研发组,你肯定不希望新人让 AI 生成的代码风格和老员工天差地别。把团队的架构规范、命名规约封装成项目级 Skill(放在仓库的 .claude/skills/ 下跟随代码走),相当于让 AI 扮演一个无情的、标准统一的代码审查员 —— 且规范版本随 Git 历史可追溯。

  • 🚨 场景三:上下游自动化流转(Pipeline)节点 如果这个 AI 任务的输出结果,不是给人看的,而是要喂给下一个脚本的(比如从网页提取数据后直接存入数据库,或者根据 PR 自动生成 Release Note 并在企微发通知)—— 面对这种对格式要求 100% 严苛的场景,正确做法是 SKILL.md 正文里明确写死输出结构 + scripts/ 里跑 schema 校验脚本 + allowed-tools 锁死权限边界,三板斧把不确定性压到最低。


总结

理解 Skill 的结构和生命周期,是我们掌控 AI 的前提。过去我们是把需求“抛”给大模型,祈祷它返回好结果;现在,我们是通过规范输入、定义边界,将大模型的能力“压榨”进我们设计好的管道里。

但光知道原理还不够,纸上得来终觉浅。在下一篇,我们将打开编辑器,从零开始完整构建一个工业级的 Skill,并聊聊如何像写单元测试一样,去测试和打磨它。