AI 编程教程中文版
从原理到实战

06 · 把重复的话写成文件

Skills 不是给 Claude 装新能力,而是把你反复说的流程写成文件。description 决定何时触发,正文决定怎么做。

翔宇有一段时间每天都跟 Claude Code 说同样的话:处理 PDF 先提取文本,再处理表格;扫描件走 OCR;表格结果转 CSV;最后给一份可复核摘要。说了十几遍以后突然意识到——这不是提示词技巧,这是一个应该写进文件的工作流。——翔宇

这一篇用 15 分钟换什么:前 5 篇分别讲了位置、上下文、记忆、提示词和思考深度。现在进入第一个"复用层":Skills(技能)。读完你会知道,什么该写进 CLAUDE.md,什么该写成 SKILL.md,什么时候让 Claude 自动触发,什么时候必须你手动输入 /skill-name

1. 你每天重复的不是"知识",是"流程"

先看一个具体场景。

你让 Claude 处理一个 PDF:

👤 你:帮我把这个 PDF 里的表格提出来。

Claude 能做吗?能。第 1 篇讲过,Claude Code 住在你电脑上。你电脑装了 pdfplumber、OCR 工具、Python 脚本,它就能读文件、跑命令、改脚本。

但第一次结果常常不稳。它可能先尝试普通文本提取,漏掉扫描页;也可能把表格当段落处理;还可能直接给你总结,没有留下 CSV。

你只好补一句:

处理 PDF 时先判断是不是扫描件。普通 PDF 用 pdfplumber 提取文本和表格。
扫描件先 OCR。表格转 CSV,保留页码,最后输出摘要和异常页列表。

第二天又来一个 PDF。你再说一遍。

第三天又说一遍。

这时要停下来判断:你重复的不是"PDF 是什么",也不是"pdfplumber 怎么安装"。Claude 大概率知道这些。你重复的是你的处理流程

第一性原理:Skill 解决的不是"Claude 不会什么",而是"Claude 不知道你遇到某类任务时希望它按什么流程做"。

这句话很关键。很多人写 Skill 写偏,就是因为把 Skill 当成百科词条,开始解释 PDF、CSV、OCR 的定义。真正该写的是:

  • 先判断什么
  • 用哪个工具
  • 遇到什么异常怎么分支
  • 输出什么格式
  • 做完怎么验收

这些才是你每天反复说的东西。

这一篇要回答的三个核心问题

写一个 Skill 的代码很容易,难的是理解它怎么被 Claude 看见 / 何时被加载 / 跟其它机制怎么分工。后面 12 节就是按这三个问题展开:

  1. description 写什么 Claude 才会真用它?——§3 看 description 怎么作为"触发索引"被模型在每轮决策前扫一遍;§5 看 frontmatter 控制面板的全部字段。
  2. 一篇 SKILL.md 几千字 Claude 不会被淹?——§6 看 supporting files 外置;§7 看渐进式加载怎么把"装很多"和"上下文不爆"同时做到。
  3. Skill 跟 CLAUDE.md / SubAgent / Plugin 边界在哪?——§9 看跟 CLAUDE.md / Hook / MCP 的 4 维对照;§11 看跟 SubAgent 的衔接;12 篇 Plugin 看怎么被打包分发。

读完每一节自检:这一节回答了哪个问题、用什么机制回答的、为什么不是另一种实现。

2. 写进 SKILL.md

最小 Skill 只有一个文件:SKILL.md

目录长这样:

SKILL.md

文件可以这样写:

---
description: 从 PDF 中抽取文本和表格。用户提到处理 PDF、抽表格、跑 OCR、把 PDF 数据转成 CSV 时使用。
---

## 工作流程

1. 先检查 PDF 本身,判断每页是文本型还是扫描图像。
2. 文本型页面用 pdfplumber 抽取文本和表格。
3. 扫描页面先跑 OCR 再抽取。
4. 提取出来的表格按页码存成 CSV。
5. 返回摘要:包含产出文件、跳过的页、置信度偏低的 OCR 段落。

注意它没有写"PDF 是 Portable Document Format"。也没有写"OCR 是光学字符识别"。这些不是你的流程,是百科。

它写的是:遇到 PDF 任务时,Claude 应该怎么做

一句话理解SKILL.md 是"遇到这类任务时,请按这个流程处理"的说明书。它不是代码,也不是插件,更不是知识库百科。

这就是 Skills 和第 4 篇提示词的关系:提示词是本轮临时说明,Skill 是反复出现的说明。当你发现一段提示词第三次出现,就该考虑把它写成 Skill。

新手最常见的写法误区:把 Skill 当百科词条写。开篇先解释"PDF 是什么"、"OCR 是什么",然后才进流程。Claude 已经知道这些定义,正文应该直接进流程。把"概念解释"塞进 SKILL.md 等于让 Claude 每次触发都把百科再"读"一遍——既占上下文又稀释流程主线。

3. description 才是触发器

只写流程还不够。Claude 怎么知道什么时候读这个文件?

关键在 frontmatter(文件开头 --- 之间的元数据)。

官方文档说,每个 Skill 需要 SKILL.md,frontmatter 告诉 Claude 什么时候用,正文告诉 Claude 用的时候怎么做。description 帮 Claude 决定是否自动加载这个 Skill。完整说明见 Extend Claude with skills

所以 description 不是简介文案,它是触发索引

坏写法:

---
description: 处理文件相关的任务。
---

这个描述太泛。PDF 是文件,图片是文件,代码也是文件。Claude 无法判断它什么时候该触发。

好写法:

---
description: 从 PDF 中抽取文本和表格。用户提到处理 PDF、抽表格、跑 OCR、把 PDF 数据转成 CSV 时使用。
---

这里有四类触发词:PDF、抽表格、OCR、CSV。用户说"把这个扫描 PDF 里的发票表格转成 CSV",Claude 就容易匹配上。

flowchart LR
    User["👤 用户请求<br/>把扫描 PDF 表格转 CSV"]
    Index["📇 Skill 索引<br/>description 常驻上下文"]
    Match{"匹配到<br/>PDF / OCR / CSV?"}
    Load["📖 加载 SKILL.md 正文"]
    Work["🛠️ 按流程执行"]

    User --> Index
    Index --> Match
    Match -->|是| Load
    Match -->|否| Work
    Load --> Work

    style Index fill:#dbeafe,stroke:#3b82f6
    style Match fill:#fef3c7,stroke:#f59e0b,stroke-width:2px
    style Load fill:#dcfce7,stroke:#22c55e

要写好 description,得先理解它什么时候被读、被谁读

注册时机:会话启动时,Claude Code 把所有可用 Skill 的 name + description + frontmatter(不含正文)拼进 system prompt(system prompt = 启动时 Claude 看到的指令背景)注册,相当于给 Claude 摆了一份"工具菜单"。

决策时机:你每发一句话,Claude 在生成回答前会扫一遍菜单,决定要不要打开某个 Skill 的正文。这跟 09 篇 MCP 里 tool 的发现机制是同一类——区别是 Skill 描述的是"工作流",MCP tool 描述的是"动作"。

Token 经济学:每个 Skill metadata 大约 50-150 token。装 50 个 Skill 启动时常驻约 5-8 K token——只占 1M 上下文窗口的不到 1%,但占启动 system prompt 的相当一块。这就是为什么 description 写法直接决定 Skill 是不是真有用:

写法后果
写得太宽("处理文件相关的任务")模型每轮都把它当候选,误触发率高 —— 用户说"打开 README" 也可能错触发,主对话被 SKILL.md 正文淹
写得太窄("处理 2026 Q4 发票 PDF")模型在用户说"提取这个 PDF"时识别不到,该用没用
写得精准 + 列触发词("从 PDF 抽取... 用户提到 PDF / OCR / CSV 时使用")模型只在真相关时拉正文,不污染主对话

为什么 Anthropic 选"模型决策"而不是"keyword 索引":keyword 匹配(grep)会被语义近义、跨语言、措辞变体打败——用户说"扫描发票转表格"包含"发票"、"扫描"、"表格",但没"PDF"也没"CSV",keyword 匹配就漏了。让模型自己读 description 决策能跟人类自然语言对齐,代价是占 system prompt token——这是 Anthropic 在"准确率 vs 上下文成本"之间选了准确率。

类比:description 像菜单上的菜名 + "什么时候点"。菜名太泛("美食")服务员(Claude)不知道你想吃什么;菜名太窄("周三限定×××套餐")你点了别的相似菜它也认不出。

这里有一个设计细节:Claude 会自动判断,但你也可以手动调用。

如果 Skill 叫 pdf-workflow,你可以直接输入:

/pdf-workflow 处理 invoice.pdf

官方文档也明确说,custom commands 已经合并进 Skills:.claude/commands/deploy.md.claude/skills/deploy/SKILL.md 都能创建 /deploy,现有 .claude/commands/ 还可用,但 Skills 支持 supporting files、frontmatter 控制自动触发等更多能力。

关键点:不要把 Skill 理解成"只能自动触发"。它同时有两种入口:Claude 觉得相关时自动加载;你也可以用 /skill-name 手动调用

4. 什么时候自动,什么时候手动

这一步很容易混。

不是所有 Skill 都应该让 Claude 自动触发。

PDF 提取这种流程,自动触发没问题。用户说 PDF、OCR、表格,Claude 自动用它,符合预期。

但 PDF 自动覆盖原文件 / 处理完直接发邮件给客户这种有副作用的流程,不能让 Claude 自己看起来"时机合适"就执行。

这时用 disable-model-invocation: true

---
name: pdf-archive-and-email
description: 处理 PDF 后用结果覆盖原文件并发邮件给收件人。
disable-model-invocation: true
---

意思是:Claude 不会自动调用,只有你输入 /pdf-archive-and-email 才会触发。

另一个方向也存在:有些 Skill 只是背景知识,不适合人手动调用。比如:

---
name: pdf-legacy-format-notes
description: 说明 2020 年以前归档 PDF 的特殊格式约定与解析陷阱。
user-invocable: false
---

它可以让 Claude 在相关任务中自动加载(用户处理老 PDF 时自动参考),但不出现在你日常要手动执行的命令入口里。

可以这样判断:

  • PDF 提取、读取分析、生成摘要:默认自动即可,Claude 能安全自动触发。
  • PDF 自动覆盖、自动发邮件、自动归档删源文件:disable-model-invocation: true,必须由你决定时机。
  • PDF 历史格式说明、领域词典、旧系统约定:user-invocable: false,给 Claude 读,不给人当命令用。

关键原则:只要一个 Skill 会产生真实外部副作用(覆盖文件 / 发消息 / 调用付费 API / 删数据),就不要让它自动触发。自动触发适合"指导 Claude 怎么思考和处理",不适合"替你决定何时发布、提交或通知别人"。

为什么 Anthropic 设计成"默认允许 + 高危 opt-out"而不是反过来

如果默认全部禁止自动触发,所有 Skill 都要 /skill-name 手动调——失去 Skill 最大价值"按需自动加载"。如果默认全部允许自动,副作用 Skill 危险。Anthropic 选了"默认允许 + 高危显式 opt-out"——把"什么算危险"的判断权交给 Skill 作者,因为:

  • 平台不知道每个 Skill 实际做什么(覆盖文件?只读分析?)
  • 静态扫描判断"是否有副作用" 太弱(脚本里调外部 API 难自动识别)
  • 让作者声明意图,比让平台猜更准确

代价:坏作者可以写"自动覆盖"还不加 opt-out。这就是 12 篇 Plugin 强调"插件是 high-trust 组件"的根因——Skill 系统的安全模型依赖作者诚信 + 安装者审查,不靠平台兜底。

新手最常踩的坑:把"PDF 自动归档" Skill 默认 auto,description 写得宽("处理 PDF 文件")。当用户说"这个 PDF 太长帮我看看" 时,Claude 误识别成归档场景,把原文件覆盖成提取摘要——真实数据没了。修复方式不是改提示词,是改 Skill 配置:副作用 Skill 必须 disable-model-invocation: true

5. frontmatter 是控制面板

到这里,Skill 已经不是一段纯文字了。frontmatter 让你控制它的工作方式。

常用字段一张表看清:每个字段的作用 + 什么时候用 + 不写会怎样

字段作用什么时候用不写会怎样 / 默认
name显示名 / 命令名想固定 /skill-name 调用时默认用目录名(如目录叫 pdf-workflow 就是 /pdf-workflow
description触发索引几乎每个 Skill 都该写不写 = Claude 完全不知道何时用,等于装了等于没装
when_to_use追加触发场景触发条件复杂、单条 description 写不完时不写 = 仅靠 description;写了 = 跟 description 叠加增强匹配
argument-hint/ 自动补全显示参数提示手动命令型 Skill不写 = 手动调用时用户不知道传什么参数(如 /pdf-workflow 不知道传不传路径)
allowed-tools预批准某些工具确认安全、想减少重复确认时不写 = 用户全局权限规则约束(11 篇 Permissions);列了 = 这些工具在 Skill 激活时无需逐次确认
modelSkill 激活时临时切模型某类任务固定需要 Opus / Haiku 时不写 = 沿用主会话模型
effortSkill 激活时覆盖思考深度审计类深想、格式类低 effort不写 = 沿用主会话 effort(详见 05 篇
contextfork 时在子代理上下文运行不想污染主对话时不写 = 在主对话执行;写 fork = 启动 SubAgent(07 篇
disable-model-invocation禁止自动触发副作用 Skill默认 false(允许自动)
user-invocable用户能否手动调用后台知识 Skill默认 true(用户可 /cmd

第 5 篇刚讲过 effort。这里它开始进入工程配置。

比如 PDF 审查 Skill 需要深度推理:

---
name: pdf-content-review
description: 审查 PDF 中的合同条款是否存在风险点。
effort: xhigh
allowed-tools: Read Grep Glob
---

这说明:这个 Skill 主要读文件、搜文本,不应该随便改文件;同时合同审查需要更深推理,所以 effort 提高。

再比如 PDF 格式润色 Skill 路径很直,不需要高 effort:

---
name: pdf-extracted-text-polish
description: 润色已抽取的 PDF 文本格式(断行 / 表头 / 标点),不改事实。
effort: low
---

边界要讲清allowed-tools 是预批准工具,不是唯一可用工具。官方文档说明,它让列出的工具在 Skill 激活时无需逐次确认;其它工具仍受你的 11 篇权限设置 约束。不要把它当成完整沙箱。

新手最常漏写的字段是 argument-hint:写了一个 /pdf-workflow Skill 但不写 hint,用户在终端打 /pdf-workflow 后不知道下一步该输什么——是空格加路径?还是带引号?还是直接回车?hint 一行就解决:argument-hint: "[PDF 路径]"

6. 支持文件:别把正文写成仓库

很多人第一次写 Skill,会把所有东西都塞进 SKILL.md

  • 20 个示例
  • 详细 API 文档
  • 项目模板
  • 完整检查清单
  • 大段背景说明

这样很快失控。3000 行 SKILL.md 触发后会一次性注入主对话——主任务上下文直接被挤压,Claude 还没干活就已经"满桌子",跟 02 篇上下文 讲的"桌子要干净"原则反着干。

官方建议 SKILL.md 控制在 500 行以内。这不是协议硬限,是经验阈值

  • 一行 markdown 平均 8-12 token,500 行 ≈ 5-7 K token
  • Skill 触发后正文一次性注入主对话,5-7 K token 是"显著占空间但不挤压主对话"的临界点
  • 超过 1 万 token 的 Skill 正文会让 Claude 在每轮都得重读这一大段——上下文经济崩了
  • 低于 200 行又意味着流程描述不够细,Claude 仍然要靠猜

所以"500 行" 的本质是:在 Claude 当前 1M 上下文 + 多 Skill 同时启用 + 每轮重读全文的约束下,给单个 Skill 留约 0.5-0.7% 的上下文配额。

大型参考资料应该放到同目录的 supporting files。比如:

extract_tables.py # 辅助脚本

SKILL.md 只写导航:


## 附加资源

- 表格抽取边界情况详见同目录 `reference.md`
- 最终报告格式见 `templates/extraction-report.md` 模板。
- 辅助脚本见 [scripts/extract_tables.py](scripts/extract_tables.py),需要时直接运行。

这样 Claude 先读流程。只有当它真的需要处理表格边界、生成报告或执行脚本时,才去看对应文件。

为什么这种"分层"特别划算:你写 100 个 PDF 处理示例放 examples/,单次任务可能只用到 1-2 个发票类。如果全塞 SKILL.md,触发后 100 个示例全进上下文;放 supporting files 只在 Claude 真要参考时 Read 进来——上下文成本差几十倍。

7. 渐进式加载:装很多,但只读当前需要的

Skills 能规模化,靠的是渐进式加载。

它不是启动时把所有 Skill 正文都塞进上下文。它更像三层索引:

flowchart TB
    Level1["第 1 层:Skill metadata<br/>name / description 常驻"]
    Level2["第 2 层:SKILL.md 正文<br/>触发后加载"]
    Level3["第 3 层:supporting files<br/>需要时再读"]
    Work["当前任务上下文"]

    Level1 -->|匹配用户请求| Level2
    Level2 -->|正文提示需要| Level3
    Level2 --> Work
    Level3 --> Work

    style Level1 fill:#dbeafe,stroke:#3b82f6
    style Level2 fill:#dcfce7,stroke:#22c55e
    style Level3 fill:#fef3c7,stroke:#f59e0b
    style Work fill:#f3e8ff,stroke:#a855f7

这解决了一个实际矛盾:

  • 你希望装很多 Skill,让 Claude 懂你的各种工作流
  • 你又不希望上下文被无关 Skill 塞满

渐进式加载让两件事同时成立。

加载层级加载什么为什么这样设计
启动时name / description 等元数据Claude 需要知道有哪些 Skill 可用
触发时SKILL.md 正文只把当前任务相关流程放进上下文
执行中reference.md / examples/ / scripts/详细资料按需读取,不常驻

把"渐进式加载"摊到一次真实会话的时间线上,更直观:

flowchart TB
    T0["🚀 <b>T0 启动会话</b><br/>注册全部 Skill metadata<br/>≈ 50-150 token / 个 · <b>常驻整场</b>"]
    T1["💬 <b>T1 用户输入</b><br/>把这个 PDF 表格转 CSV<br/>Claude 扫菜单 → 命中 pdf-workflow"]
    T2["📖 <b>T2 触发加载正文</b><br/>SKILL.md ≤ 500 行 / 5-7K token<br/>进主对话 · <b>常驻直到 /compact 或 /clear</b>"]
    T3["📂 <b>T3 执行中按需读</b><br/>Read reference.md / 跑脚本<br/><b>单次读完不常驻</b>,除非被引入对话"]
    T4["✅ <b>T4 完成回报</b><br/>摘要 + 输出文件列表给你"]

    T0 --> T1 --> T2 --> T3 --> T4

    style T0 fill:#fef3c7,stroke:#f59e0b,stroke-width:2px
    style T1 fill:#dbeafe,stroke:#3b82f6
    style T2 fill:#dcfce7,stroke:#22c55e,stroke-width:2px
    style T3 fill:#f3e8ff,stroke:#a855f7
    style T4 fill:#fee2e2,stroke:#ef4444

读一遍这条时间线,几个反直觉的点会变直观:

  • metadata 永远在 system prompt:装了 50 个 Skill,不管你今天用不用,启动时这 50 份 metadata 都在线——这是"自动触发"的代价。
  • 正文进了主对话就在主对话:触发后 Skill body 不会"用完释放"。如果同一会话连续触发 5 个 Skill,主对话上下文会累积 5 份正文。这是为什么"不要在一个会话里调一堆 Skill",跟 02 篇 的桌子原则一致。
  • supporting files 是真的"按需":只有 Claude 显式 Read 才进上下文,这就是为什么 500 行的硬数据外置最划算——你写 100 个示例放 examples/,Claude 大多数任务只读 1-2 个。

一句话理解description 像书架目录,SKILL.md 像当前打开的书,references/scripts/ 像书里的附录。你不会把整座图书馆都摊在桌上。

这也解释了为什么 description 要写得准。metadata 常驻,但正文不常驻。Claude 是否能打开正确那本书,首先取决于目录条目写得清不清楚。

8. 放在哪里:个人、项目、插件

Skill 的位置决定作用范围。

官方列了几类位置,日常最常用的是个人级和项目级:

位置路径适合放什么
个人级~/.claude/skills/<skill-name>/SKILL.md你自己跨项目都用的 PDF 通用流程
项目级.claude/skills/<skill-name>/SKILL.md这个项目独有的 PDF 处理约定(如发票格式 / 业务字段映射),可提交 git
插件级<plugin>/skills/<skill-name>/SKILL.md随插件分发的 PDF 工具集(详见 12 篇
企业级managed settings公司统一下发的合规 PDF 审查 Skill

如果同名 Skill 出现在多个层级,企业级 > 个人级 > 项目级。插件 Skill 会带插件命名空间(详见 12 篇),避免和普通 Skill 冲突。

还有一个细节:Claude Code 会监听 Skill 目录变化。你在现有 ~/.claude/skills/ 或项目 .claude/skills/ 里新增、编辑、删除 Skill,当前会话内会自动生效。只有顶层 skills 目录本身原来不存在、你刚创建时,可能需要重启 Claude Code 才能被监听。

把它和第 3 篇记忆系统对应起来:

  • 个人偏好型 PDF 流程:放 ~/.claude/skills/pdf-workflow/
  • 团队共享 PDF 流程:放项目 .claude/skills/pdf-invoice/
  • 单纯项目事实(用 pdfplumber 不用 PyMuPDF):放 CLAUDE.md
  • 复杂可复用 PDF 工作流:放 SKILL.md

9. Skills 和 CLAUDE.md / Hook / MCP 的边界

这一步最容易和 03 篇 / 10 篇 / 09 篇 混。

四者都是"配置 Claude 行为"的方式,但职责不同。一张 4 维对照表看清:

维度CLAUDE.md03 篇SKILL.md(本篇)Hook(10 篇MCP(09 篇
加载时机每次会话启动全量注入触发后才注入正文事件点自动运行工具被调用时连接
上下文成本全量常驻(建议 ≤200 行)metadata 约 50-150 token / Skill;触发后正文进上下文Hook 自身不占上下文,输出可能进工具 schema 常驻;输出可能进
触发条件不需要触发,启动即生效description 模型语义匹配事件类型 + matcher模型决定 / 用户 @ 引用
复用粒度项目 / 用户 / 系统 / 本地 4 层项目 / 用户 / 插件 / 企业 4 类settings scope(同 CLAUDE.md)local / project / user 3 类
典型用法项目规则 / 团队约定 / 个人偏好任务流程 / 领域工作流自动化检查 / 副作用拦截接外部系统 / 数据源
何时升级重复 ≥3 次的话 → 写 CLAUDE.md重复 ≥3 次的流程 → 写 Skill漏一次会出事的规则 → 写 Hook频繁复制粘贴的外部系统数据 → 装 MCP

读这张表的诀窍:机制选错的代价——CLAUDE.md 写流程会膨胀;Skill 写规则会"加载晚了不起作用";Hook 写偏好会"动不动就拦你";MCP 写本地操作是"用大炮打蚊子"。每个机制有它最贴的活,错配是大多数 Claude Code 配置失控的根因。

3 个判断练习——下面三句话,分别该写进哪里?读完答案再看你判断对了几个:

场景 A:团队约定 PDF 处理一律用 pdfplumber,不要 PyMuPDF。

场景 B:处理 PDF 的完整 7 步流程(判断扫描 → OCR → 抽表 → 转 CSV → 摘要)。

场景 C:每次写 PDF 处理代码后自动跑 pytest tests/pdf_test.py

📌 看答案
  • A → CLAUDE.md:是项目级"用什么库"约定,每次会话都要知道,不需要触发。
  • B → SKILL.md:是反复出现的工作流,只在 PDF 任务时才需要。
  • C → Hook(PostToolUse):是"动作完成后自动执行"的规则,不依赖 Claude 触发判断。

判断诀窍——问自己:

  1. 这条信息每次会话都要进上下文吗?是 → CLAUDE.md。
  2. 这条信息只在某类任务才需要?是 → SKILL.md。
  3. 这条规则漏一次就出事?是 → Hook。
  4. 这条信息来自外部系统(GitHub / 数据库 / SaaS)?是 → MCP。

10. 一个合格 Skill 长什么样

回到 PDF 例子。一个更完整的版本可以这样写:

---
name: pdf-workflow
description: 从 PDF 中抽取文本和表格。用户提到处理 PDF、抽表格、给扫描页跑 OCR、把 PDF 数据转成 CSV 时使用。
argument-hint: "[PDF 路径]"
allowed-tools: Read Bash(python *) Bash(mkdir *) Bash(ls *)
effort: medium
---

## 目标

从 PDF 中抽取可用的文本和表格,保留每段内容到对应页码的追踪关系。

## 工作流程

1. 从 $ARGUMENTS 拿到 PDF 路径。
2. 判断每一页是文本型还是扫描图像。
3. 文本型页面用 pdfplumber 抽取。
4. 扫描页面用 OCR 抽取。
5. 表格按页码导出成 CSV。
6. 写一份摘要:含产出文件、跳过的页、置信度偏低的段落。

## 输出

返回:

- 抽取出的文本文件路径
- 各 CSV 文件路径
- 跳过或需人工复核的页
- 一段话摘要

这个 Skill 有几个优点:

  • description 含清晰触发词(PDF / OCR / CSV / 抽表格)
  • argument-hint 让手动调用更顺
  • allowed-tools 只预批准必要命令
  • effort: medium 和任务复杂度匹配
  • 正文写流程,不写百科
  • 输出格式明确

再对照一个坏版本:

---
description: 帮忙处理文档。
---

PDF 是 Adobe 推出的文件格式。OCR 指光学字符识别。
请使用工具处理文件,并返回有用的结果。

坏在哪里?

  • description 太泛:容易误触发,或该触发时不触发。
  • 写百科知识:占上下文,不改变执行质量。
  • 没有流程:Claude 还是要猜先后顺序。
  • 没有输出契约:每次结果格式不稳定。
  • 没有边界:可能动不该动的文件或命令。

这就是 Skill 写作的核心:描述要窄,流程要清,输出要定,参考资料要外置

理解 Skill 的所有设计选择,可以压成一张决策矩阵——这一篇所有"为什么"汇总:

flowchart TB
    Core["💡 <b>Skills 的核心设计选择</b>"]

    subgraph 触发["🎯 触发方式"]
        T1["默认<b>自动</b><br/>+ 高危 opt-out<br/>责任在作者"]
    end

    subgraph 加载["📦 加载策略"]
        L1["<b>渐进式</b>三层<br/>metadata 常驻<br/>正文触发加载<br/>files 按需读"]
    end

    subgraph 表达["📝 表达层级"]
        E1["<b>prompt 层 markdown</b><br/>不是 typed function<br/>不是 flat command"]
    end

    subgraph 安全["🔒 安全模型"]
        S1["作者诚信 + 用户审查<br/>平台不兜底<br/>详见 12 篇 Plugin"]
    end

    Core --> 触发
    Core --> 加载
    Core --> 表达
    Core --> 安全

    style Core fill:#fef3c7,stroke:#f59e0b,stroke-width:3px
    style 触发 fill:#dbeafe,stroke:#3b82f6
    style 加载 fill:#dcfce7,stroke:#22c55e
    style 表达 fill:#f3e8ff,stroke:#a855f7
    style 安全 fill:#fee2e2,stroke:#ef4444

4 个选择各自的"为什么不是另一种"

  • 触发为什么不是默认全手动:失去自动加载价值,新手记不住命令名 = 装了等于没装。
  • 加载为什么不是全量注入:50 个 Skill 全量 ≈ 50 万 token,主对话直接爆。
  • 表达为什么不是 typed function:function 强参数校验,但工作流里"这页是不是扫描件"是自然语言判断,schema 表达不了"if-else 内嵌经验"。
  • 安全为什么不靠平台:平台不知道每个 Skill 实际做什么,作者声明意图比让平台静态扫描更准确。

底层取舍:Skill 是"用 system prompt token 换语义触发的灵活性"。装得多 = 启动 token 成本上升 + 误触发概率上升;装得少 = 自动复用价值丢失。所以这一篇所有"description 写窄一点"、"500 行外置"、"高危 opt-out" 的劝告,本质都是在帮你对齐这个取舍。

11. 和 SubAgents 的连接

下一篇会讲 SubAgents(子代理 = 派分身做子任务,详见 07 篇)。这里先提前接一条线:Skill 可以在主会话里运行,也可以在 forked subagent context(分叉子代理上下文)里运行。

为什么需要这个?

还是 PDF 例子。普通 PDF 提取,主会话直接做就行。

但如果你让 Claude 批量处理 200 个 PDF,中间会读大量文件、跑很多命令、产出许多日志。这些过程会污染主会话上下文。

这时可以让 Skill 在子代理里跑:

---
name: pdf-batch-workflow
description: 批量处理一整个目录的 PDF,返回抽取出的文本、CSV 文件和异常报告。
context: fork
agent: general-purpose
effort: medium
---

主会话只拿回结果摘要,具体处理过程留在子代理上下文里。

实际何时升级到 SubAgent,按这张决策树判断:

flowchart TD
    Start["拿到一个反复出现的 PDF 任务"]
    Q1{"流程能写清楚吗?<br/>步骤、判断、输出格式"}
    Q2{"主对话装得下吗?<br/>过程产出大量日志/文件"}
    Q3{"任务之间需要互相对齐吗?<br/>多角色多模块"}
    OneShot["单步 prompt 解决<br/>不要做 Skill"]
    Skill["写 Skill<br/>放在主对话执行"]
    Sub["Skill 用 context: fork<br/>跑在子代理里"]
    Teams["不用 Skill<br/>开 Agent Teams"]

    Start --> Q1
    Q1 -->|否,每次任务都不一样| OneShot
    Q1 -->|是,能模板化| Q2
    Q2 -->|装得下| Skill
    Q2 -->|装不下,过程会污染主对话| Q3
    Q3 -->|否,单点任务| Sub
    Q3 -->|是,多角色协作| Teams

    style Skill fill:#dcfce7,stroke:#22c55e,stroke-width:2px
    style Sub fill:#dbeafe,stroke:#3b82f6,stroke-width:2px
    style Teams fill:#f3e8ff,stroke:#a855f7,stroke-width:2px
    style OneShot fill:#fef3c7,stroke:#f59e0b

读这张图的诀窍:Skill 是默认选项,SubAgent 是"上下文太脏"时的升级,Agent Teams 是"需要协作"时的再升级。从下往上反着选——先问"能不能用 Skill 就解决",再考虑分身和团队。这跟 07 篇 讲的"SubAgent 不是任务拆分仪式" 是同一逻辑。

回到 PDF:

  • 单个 PDF 处理 → Skill(主对话)
  • 200 个 PDF 批量处理 → Skill + context: fork(SubAgent)
  • 200 个 PDF + 财务 / 法务 / 技术多角色审查 + 互相确认 → 不用 Skill,开 Agent Teams(08 篇

提前剧透:当一个 Skill 的执行过程很长、会读很多文件、会跑很多命令时,就开始接近 SubAgent 的使用场景。

12. 检验你真懂了吗

试着用自己的话回答:

  1. 有人说"Skill 就是给 Claude 装插件"。你能解释为什么这个说法不准确吗?对应 §1 + §2。
  2. 为什么 description 比正文第一段更像 Skill 的入口?一个太泛的 description 会造成什么问题?对应 §3。
  3. 动手题 ⭐:现在打开一个真实项目,写一个 Skill 的 description 字段(≤80 字),让 Claude 在用户说"扫描发票转表格"时触发,但在用户说"打开这个 PDF 让我看看" 时不触发。写完检查:触发词覆盖了"扫描"、"发票"、"表格" 三类输入吗?有没有把"PDF" 单字作为唯一锚点(这会让"看这个 PDF" 也命中)?

过关标准:能用一句话说清——Skill 是按需加载的工作流文件:description 负责触发,正文负责流程,supporting files 负责深层资料;长期事实进 CLAUDE.md,任务流程进 SKILL.md。 加上动手题真写过一遍 description,你才算真会。

13. 还没回答的问题

为了不把本篇撑爆,几个进阶问题被推到后面或官方文档:

  • 多个 Skill 命名冲突时怎么办? → §6 命名空间已点;完整规则在 12 篇 Plugin 的 namespace 章节
  • Skill 内部能不能 @import 引用其它 markdown? → 行为类似 03 篇 CLAUDE.md 的 import;具体限制看 Anthropic skills 文档 当前版本
  • Skill 能不能跨会话保留状态? → 不能直接保留;要持久化用 03 篇 Auto Memory 或自己写文件
  • Skill 跟 Permissions / Hooks 怎么联动? → Skill frontmatter allowed-tools 是 Permission 的预批准入口;Skill 触发后仍受 10 篇 Hooks 拦截
  • Skill 怎么版本化分发? → 单仓 Skill 跟 git 走;要打包给团队 / 社区,看 12 篇 Plugin 的 marketplace 章节
  • Skill description 实际匹配的算法是什么? → 当前实现是模型基于 system prompt 决策(详见 §3),具体调权细节官方未公开

把这些标记出来不是写不全,是想让你知道:Skill 是个完整子系统,但它依赖 CLAUDE.md / Permission / Hook / Plugin 这些相邻系统。理解 Skill 的最大杠杆,是搞清楚它跟谁联动、谁负责什么——本篇 §9 对照表和 §11 决策树就是这层联动的入口。

📖 本篇术语速查表
  • Skill:技能,按需加载的任务流程文件。
  • SKILL.md:Skill 入口文件,frontmatter + 正文流程。
  • frontmatter:文件头元数据,--- 包裹的配置字段。
  • description:触发描述,Claude 判断是否加载 Skill 的主要依据。
  • supporting files:支持文件,Skill 目录下按需读取的参考、模板、脚本。
  • slash command:斜杠命令,用 /skill-name 手动调用 Skill 的入口。
  • disable-model-invocation:禁止模型自动调用,让 Skill 只能由用户手动触发。
  • user-invocable:用户是否可调用,设为 false 时可作为后台知识 Skill。
  • system prompt:系统提示,启动时 Claude 看到的指令背景,Skill metadata 注册在这里。
  • forked subagent context:分叉子代理上下文,Skill context: fork 时启动的隔离上下文(详见 07 篇)。

官方资料

接下来去哪

如果你只记一个判断:凡是你第三次复制粘贴给 Claude 的流程,就该考虑写成 Skill。

本页目录