<!-- title: Claude Code Skill渐进披露与子Agent编排实战 -->

## 概述

本教程聚焦 Claude Code Skill 的进阶工程能力：**渐进式披露（Progressive Disclosure）、动态上下文注入、子 Agent 执行（`context: fork`）与触发词工程**。适合已能写出基础 `SKILL.md`、希望把零散提示词升级为"分层加载、权限收敛、可编排"工程化资产的开发者。我们将从启动期的上下文经济学讲起，最终交付一个完整可运行的 `release-notes`（发布说明生成器）Skill。

## 前置条件

- Claude Code v2.1.145 或更高（`/run`、`/verify` 等打包 Skill 需要该版本，自定义 Skill 在更早版本也可用）
- 已安装 Node.js（实战项目用到 `.mjs` 脚本）与 `git`
- 阅读过官方 Skills 概览，知道 `SKILL.md` 由 frontmatter + 正文两部分组成
- 一个有若干提交记录的 git 仓库用于演练

---

## 一、先理解上下文经济学：Skill 为什么必须分层

很多新手把 Skill 当成"放大的 prompt"，把几百行规范全塞进 `SKILL.md`。这是对加载机制的误解。

Claude Code 的 Skill 加载是**三段式**的：

1. **启动期（Preload）**：仅把所有 Skill 的 `name` + `description`（元数据）注入上下文。这是常驻成本，所以 description 必须精炼。
2. **激活期（Activate）**：当 Claude 判定某 Skill 与当前任务相关，才读取完整的 `SKILL.md` 正文。一旦加载，正文**跨轮次常驻**——每一行都是反复计费的 token。
3. **按需期（On-demand）**：`SKILL.md` 里引用的 `references/`、`scripts/`、`examples/` 等附属文件，只有在真正用到时才被读取。

```mermaid
flowchart LR
    A[会话启动] -->|仅注入元数据<br/>name+description| B{描述匹配<br/>当前任务?}
    B -->|否| C[保持休眠<br/>几乎零成本]
    B -->|是| D[加载 SKILL.md 正文<br/>跨轮常驻]
    D --> E{需要更多细节?}
    E -->|按需| F[读取 references/]
    E -->|按需| G[执行 scripts/]
    E -->|按需| H[套用 examples/]
    F --> I[完成任务]
    G --> I
    H --> I
```

官方文档把这个原则总结为一句话：**"上下文窗口是公共资源（The context window is a public good）"**。你的 Skill 和系统提示词、对话历史、其他 Skill 元数据、用户请求共享这同一块窗口。因此两个核心结论：

- **`SKILL.md` 正文要短**：一旦加载就常驻，每一行都是持续成本。只写"Claude 还不知道的"内容，默认假设 Claude 已经很聪明。
- **重内容下沉到附属文件**：长规范、大段示例、参考资料放进 `references/`，让 Claude 用到再读。这在 description 里几乎零成本。

> **常见问题**：我的 Skill 触发了但 Claude 总"忘记"细节。
> **解决**：把细节挪进 `references/xxx.md`，并在正文里写明"需要 X 规则时，读取 `references/xxx.md`"。常驻正文越短，注意力越集中。

---

## 二、SKILL.md 骨架与 frontmatter 全字段

一个 Skill 就是一个目录，`SKILL.md` 是入口：

```
my-skill/
├── SKILL.md            # 主指令（必需）
├── template.md         # 供 Claude 填充的模板
├── examples/
│   └── sample.md       # 期望输出的示例
├── references/
│   └── spec.md         # 按需加载的详细规范
└── scripts/
    └── validate.sh     # 可执行脚本
```

frontmatter 字段（全部可选，仅 `description` 强烈推荐）：

| 字段 | 作用 | 关键约束 |
|------|------|----------|
| `name` | 显示名，缺省取目录名 | 小写连字符，应与目录名一致 |
| `description` | 做什么 + 何时用，决定是否触发 | 与 `when_to_use` 合计在列表中被截断于 **1536 字符** |
| `when_to_use` | 触发短语/示例请求，拼接到 description 后 | 计入 1536 上限 |
| `allowed-tools` | Skill 可免确认使用的工具白名单 | 收敛权限，提升安全 |
| `disable-model-invocation` | `true` 时禁止自动触发，只能手动 `/name` | 手动流程用 |
| `user-invocable` | `false` 时从 `/` 菜单隐藏 | 纯背景知识用 |
| `context` | `fork` 表示在**隔离子 Agent**中运行 | 保护主上下文 |
| `argument-hint` | 自动补全提示，如 `[version]` | 改善手动调用体验 |
| `arguments` | 命名位置参数，供 `$name` 替换 | 空格分隔或 YAML 列表 |

下面是一个具备"高级感"的最小 frontmatter：

```yaml
---
name: release-notes
description: 从 git 历史生成发布说明。当用户要写 changelog、准备发版、询问"这版改了什么"时使用。
when_to_use: 关键词包括 release、changelog、发版、发布说明、version bump
allowed-tools: Bash Read Write
argument-hint: [version]
arguments: version
---
```

**操作说明**：在个人目录创建该 Skill，目录名即命令名：

```bash
mkdir -p ~/.claude/skills/release-notes
# 编辑 ~/.claude/skills/release-notes/SKILL.md
```

**预期结果**：保存后无需重启——Claude Code 会监视 Skill 目录，文件改动在本会话内即时生效（"Live change detection"）。此后输入 `/release-notes` 或说"帮我生成发版说明"都会命中。

> **常见问题**：description 里我写了 `<` 和 `>` 符号。
> **解决**：description 中禁止使用 `<` `>`（会破坏元数据解析），用括号或引号代替。

---

## 三、渐进式披露设计：把重内容下沉

好的 Skill 正文像一张"目录页"，把详细材料指向附属文件，需要时再读。这正是渐进式披露的工程化落地。

设计原则——**按"自由度"分层**。官方把指令的约束强度分为三档，正好对应三种存放方式：

- **高自由度（文本指令）**：多种做法都合理，写进正文当"流程指引"。如代码审查的检查清单。
- **中自由度（带参数的模板/脚本）**：有首选模式但允许变化。正文给范式，细节放 `references/`。
- **低自由度（固定脚本，几乎无参数）**：操作脆弱、必须严格一致。直接放 `scripts/`，正文只写"运行该脚本，勿加参数"。

以 `release-notes` 为例，把 Conventional Commits 和 Keep a Changelog 两套规范各拆成独立参考文件，正文里只在需要时点名：

```markdown
## 发布说明生成流程

1. 读取 `!git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"%h %s"`
2. 对提交进行分类（见下）
3. 若涉及破坏性变更，加载 `references/conventional-commits.md` 确认判定规则
4. 按 Keep a Changelog 格式起草，格式细节参考 `references/keep-a-changelog.md`
5. 运行 `scripts/validate-changelog.sh $version` 校验产物

### 分类速查（高频，常驻正文）
- `feat:` → ✨ 新功能（归入 Added）
- `fix:` → 🐛 修复（归入 Fixed）
- `BREAKING CHANGE` / `feat!` → ⚠️ 破坏性（归入 Changed，单列）
- `perf:` → ⚡ 性能（归入 Performance）
```

注意：分类速查是**高频且简短**的，留在常驻正文；两套长规范下沉到 `references/`，用到才加载。这就是"目录页"思维——常驻的永远是高频摘要，细节按需。

> **常见问题**：我每条规则都写了三段解释，Skill 正文涨到 2000 字。
> **解决**：对每一段问"Claude 真的需要这个解释吗？能假设它已经懂吗？"。把解释删掉或下沉。官方对比示例里，50 token 的精炼版完胜 150 token 的啰嗦版。

---

## 四、动态上下文注入：让 Skill 接地气

很多 Skill 的第一个痛点是"Claude 在猜"——猜你的代码、猜你的提交、猜你的配置。动态上下文注入（Dynamic Context Injection）用一行反引号命令解决：在 `!` 命令 `` 这种语法里，Claude Code 会**先执行命令、把输出替换进正文**，再让 Claude 看到内容。

这意味着指令到达时，当前的真实数据已经内联其中，Claude 不再靠猜：

```markdown
## 当前未发布提交
!`git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"%h|%s"`

## 当前版本号
!`node -p "require('./package.json').version"`
```

**操作说明**：把上面两行放进 `release-notes/SKILL.md` 顶部。

**预期结果**：每次激活 Skill，Claude 看到的正文里这两行已被替换成真实输出，例如：

```
## 当前未发布提交
a1b2c3d|feat: 支持断点续传
d4e5f6g|fix: 修复空指针崩溃
h7i8j9k|feat!: 重构上传 API（破坏性）

## 当前版本号
1.4.2
```

这是把"实时事实"喂给 Skill 的标准手法，比让 Claude 自己跑命令再总结更稳——数据天然嵌在指令语境里。

> **常见问题**：`!`命令`` 没有执行，原样出现在输出里。
> **解决**：检查命令在 `$SHELL` 下能否独立跑通；动态注入只支持单行命令，多步逻辑请封装进 `scripts/`。

---

## 五、子 Agent 执行：`context: fork` 隔离重活

起草一篇长 changelog 可能消耗上万 token。如果让主会话直接干，这笔上下文会**污染并常驻**主对话，挤压后续任务的窗口。解法是 `context: fork`：让该 Skill 在一个**隔离的子 Agent**里运行，子 Agent 用独立上下文完成工作，只把最终结果交回主会话。

```yaml
---
name: release-notes
description: ...
context: fork
allowed-tools: Bash Read Write
---
```

启用 `fork` 后的语义：

- 子 Agent 拥有独立上下文窗口，主会话不被草稿、中间推理、长 git log 淹没；
- 子 Agent 只能使用 `allowed-tools` 列出的工具——这同时实现了**权限收敛**与**上下文收敛**；
- 适合"输入复杂、输出收敛"的任务：检索 + 综合、批量转换、长文起草。

```mermaid
sequenceDiagram
    participant U as 用户主会话
    participant M as 主上下文(有限)
    participant S as fork 子Agent(独立窗口)
    U->>M: /release-notes 1.5.0
    M->>S: 激活 Skill(独立上下文)
    S->>S: 注入 git log / 版本号
    S->>S: 分类 + 起草 changelog
    S->>S: 跑 validate 脚本校验
    S-->>M: 仅返回最终 CHANGELOG 段落
    M-->>U: 展示结果(主上下文几乎无污染)
```

**何时用 fork**：任务会产生大量中间 token 但最终产物精简（如本例）；或任务需要严格工具沙箱。**何时不该用**：任务需要持续读取主对话历史、或需要与用户多轮交互确认——fork 是"一次性委派"，不适合交互式流程。

> **常见问题**：开了 fork 后 Skill 拿不到主会话里我粘贴的需求。
> **解决**：fork 子 Agent 不继承完整对话历史。把外部输入通过 `arguments` 传入（如 `/release-notes 1.5.0`），或在正文里用动态注入从文件读取。

---

## 六、触发词工程：让该触发时触发、不该触发时安静

触发是 Skill 最常翻车的环节：要么该触发不触发（描述太泛/太窄），要么不该触发乱触发（描述与高频词撞车）。官方把"description + when_to_use"在列表中截断于 1536 字符，所以每一个词都要精打细算。

四条工程化准则：

1. **首句即用例**：description 第一句写"做什么 + 何时用"，把最高频触发场景放最前，因为列表显示时靠前的内容权重最高。

2. **正向触发短语优先**：`when_to_use` 填具体的用户原话和关键词（"发版说明""这版改了什么""version bump"），而非抽象概念。Claude 靠语义相似度匹配，真实用户措辞命中率最高。

3. **避免与高频通用词撞车**：别把 description 写成"帮助用户处理各种文本任务"——这种描述会在几乎所有对话里被弱匹配，造成噪声。

4. **双向开关兜底**：纯手动流程加 `disable-model-invocation: true`（如 `deploy`）；纯背景知识加 `user-invocable: false`（如内部编码规范，不该被 `/` 直接调用，但 Claude 处理相关任务时自动引用）。

对比一个差的和一个好的 description：

```yaml
# ❌ 太泛，易误触发
description: 一个强大的工具，帮助处理发布相关的各种事项

# ✅ 具体，用例优先
description: 从 git 历史生成结构化发布说明。当用户要写 changelog、准备发版、
  或问"这版改了什么"时使用。输出遵循 Keep a Changelog 格式。
when_to_use: release、changelog、发版、发布说明、version bump、release notes
```

> **常见问题**：Skill 触发太频繁，写无关代码也跳出来。
> **解决**：收窄 description 用例边界（强调"发版/发布"语境），或直接加 `disable-model-invocation: true` 改为纯手动。

---

## 七、权限收敛：`allowed-tools` 最小化

Skill 默认可继承会话全部工具。但对于"只需读 + 跑脚本 + 写一个文件"的任务，授予全部工具既危险又不必要。`allowed-tools` 让 Skill 声明它真正需要的最小集合：

```yaml
allowed-tools: Bash Read Write
```

进阶用法：还能对 Bash 进一步限定命令前缀，把"能跑任意 shell"收敛为"只能跑这几条命令"：

```yaml
allowed-tools: Bash(git log:*), Bash(git describe:*), Read, Write
```

这样一来，`release-notes` 即便被恶意/异常输入诱导，也无法执行 `rm -rf` 之类的越权命令。结合 `context: fork`，子 Agent 的工具面被双重收窄——这是把 Skill 投入生产前的安全基线。

> **常见问题**：限制后 Skill 报"工具不可用"。
> **解决**：先把 `allowed-tools` 留空跑通流程，观察 Claude 实际调用了哪些工具，再据此收紧白名单。

---

## 八、实战案例：完整的 `release-notes` Skill

下面把前七节整合成一个开箱即用的发版说明生成器。目录结构：

```
~/.claude/skills/release-notes/
├── SKILL.md
├── references/
│   ├── conventional-commits.md
│   └── keep-a-changelog.md
├── scripts/
│   ├── classify-commits.mjs
│   └── validate-changelog.sh
└── examples/
    └── sample-CHANGELOG.md
```

**SKILL.md**（常驻正文刻意精简）：

```markdown
---
name: release-notes
description: 从 git 历史生成结构化发布说明。当用户要写 changelog、准备发版、或问"这版改了什么"时使用。输出遵循 Keep a Changelog 格式。
when_to_use: release、changelog、发版、发布说明、version bump、release notes
allowed-tools: Bash(git log:*), Bash(git describe:*), Bash(node:*), Bash(sh:*), Read, Write
argument-hint: [version]
arguments: version
context: fork
---

## 当前未发布提交
!`git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"%h|%s"`

## 当前版本号
!`node -p "require('./package.json').version"`

## 流程
1. 调用 `node scripts/classify-commits.mjs`（本 Skill 目录下）对上方提交分类
2. 破坏性变更判定规则，按需查阅 `references/conventional-commits.md`
3. 按 Keep a Changelog 起草，格式细节见 `references/keep-a-changelog.md`
4. 输出风格参考 `examples/sample-CHANGELOG.md`
5. 用 `sh scripts/validate-changelog.sh $version` 校验产物，失败则修正后重跑

参数 `$version` 由用户传入（如 `/release-notes 1.5.0`），未传则用"当前版本号"推断下一版本。
```

**scripts/classify-commits.mjs**（低自由度：固定逻辑，吃 stdin、吐 JSON）：

```javascript
import readline from "node:readline";
const rl = readline.createInterface({ input: process.stdin });
const buckets = { Added: [], Fixed: [], Changed: [], Performance: [], Other: [] };
rl.on("line", (line) => {
  const [hash, subject = ""] = line.split("|");
  const s = subject.trim();
  if (/BREAKING CHANGE|!:/i.test(s))      buckets.Changed.push(`⚠️ ${hash} ${s}`);
  else if (/^feat/i.test(s))              buckets.Added.push(`${hash} ${s.replace(/^feat(\(\w+\))?:/, "")}`);
  else if (/^fix/i.test(s))               buckets.Fixed.push(`${hash} ${s.replace(/^fix(\(\w+\))?:/, "")}`);
  else if (/^perf/i.test(s))              buckets.Performance.push(`${hash} ${s}`);
  else                                    buckets.Other.push(`${hash} ${s}`);
});
rl.on("close", () => console.log(JSON.stringify(buckets, null, 2)));
```

**scripts/validate-changelog.sh**（校验门禁）：

```bash
#!/usr/bin/env sh
set -e
ver="${1:?用法: validate-changelog.sh <version>}"
file="${2:-CHANGELOG.md}"
grep -q "## \[$ver\]" "$file"           || { echo "缺少 [$ver] 标题"; exit 1; }
grep -q "$(date +%Y-%m-%d)" "$file"     || { echo "缺少当天日期"; exit 1; }
echo "✅ 校验通过：$file 含 [$ver] 且日期合法"
```

**examples/sample-CHANGELOG.md**（输出范本，极简）：

```markdown
## [1.5.0] - 2026-06-13
### ⚠️ Changed
- 重构上传 API（破坏性，a1b2c3d）
### ✨ Added
- 支持断点续传（h7i8j9k）
### 🐛 Fixed
- 修复空指针崩溃（d4e5f6g）
```

**运行与验证**：

```bash
# 1. 让 Claude 自动触发
> 帮我准备 1.5.0 的发版说明
# 2. 或手动调用并传参
> /release-notes 1.5.0
```

**预期结果**：Claude 在隔离子 Agent 中读取真实提交、分类、起草、跑校验，最终把一段结构化 CHANGELOG 写回主会话/文件。主对话上下文几乎不被中间过程污染——这就是渐进披露 + 动态注入 + fork 子 Agent 三者协同的效果。

> **常见问题**：classify 脚本把 Skill 目录路径搞错。
> **解决**：Skill 的附属脚本以 Skill 目录为工作基点；若不确定，在正文用 `!`pwd`` 注入当前真实路径辅助排查。

---

## 九、完整工作流全景

把分散脚本/提示词升级为工程化 Skill 的决策路径如下：

```mermaid
flowchart TD
    A[重复粘贴的指令/CLAUDE.md里的流程] --> B{值得做成Skill?}
    B -- 否 --> Z[留在 CLAUDE.md]
    B -- 是 --> C[建目录 + 写 frontmatter]
    C --> D{内容多且重?}
    D -- 是 --> E[下沉到 references/<br/>正文留摘要]
    D -- 否 --> F[直接写在正文]
    E --> G{需要实时数据?}
    F --> G
    G -- 是 --> H[用 !`cmd` 动态注入]
    G -- 否 --> I{会产生大量中间token?}
    H --> I
    I -- 是 --> J[context: fork<br/>隔离子Agent]
    I -- 否 --> K[内联运行]
    J --> L[allowed-tools 最小化<br/>+ 触发词工程]
    K --> L
    L --> M[实战验证 + 收紧权限]
```

---

## 延伸阅读

- 官方 Skills 总览与命令参考：`code.claude.com/docs/en/skills`（含 frontmatter 全字段、动态注入、字符串替换）
- 官方 Skill 编写最佳实践：`platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices`（精炼度、自由度三档）
- Anthropic 工程博客《Equipping agents for the real world with Agent Skills》：`anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills`
- 官方公共 Skill 仓库：`github.com/anthropics/skills`（可直接克隆学习真实结构）
- Agent Skills 开放标准说明：Skills 遵循跨工具开放标准，同一 Skill 可在 Cursor、Roo Code、VS Code 等兼容环境复用

## 训练营适用性评估

- **适合人群**：已掌握 Claude Code 基础操作、能独立写出第一个 `SKILL.md` 的进阶开发者；也适合团队 Tech Lead 用于制定内部 Skill 规范。
- **训练营类型**：中高级"AI 工程化"训练营、"提示词与 Agent 架构"专题营；不建议作为零基础入门营的首课（需先建立 Skill 基本概念）。
- **预计教学时长**：理论 + 跟练约 **2.5–3 小时**（含亲手搭建 `release-notes` 并跑通校验）；若扩展到团队 Skill 库治理与版本分发，可设计为 **半天工作坊**。
- **实操比重**：约 60% 动手（建目录、写 frontmatter、调触发词、跑校验门禁）、40% 原理（上下文经济学、分层加载、权限模型）。
- **考核建议**：以"产出一个通过 `validate-changelog.sh` 门禁的 Skill，且主会话上下文增量低于阈值"作为通过标准——同时检验工程质量与上下文经济性。

## 参考来源

1. [Extend Claude with skills — Claude Code Docs](https://code.claude.com/docs/en/skills) — 官方 Skills 权威文档，含 frontmatter 全字段、动态上下文注入、`context: fork` 子 Agent 执行、Skill 存放位置与优先级
2. [Skill authoring best practices — Claude API Docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices) — 官方编写最佳实践，提出"上下文窗口是公共资源"原则与高/中/低自由度三档模型
3. [Equipping agents for the real world with Agent Skills — Anthropic Engineering](https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills) — Anthropic 工程博客，阐述 Skill 的设计哲学与渐进式披露机制
4. [anthropics/skills — GitHub](https://github.com/anthropics/skills) — 官方维护的公共 Agent Skills 仓库，可直接克隆学习真实目录结构
5. [Agent Skills in the SDK — Claude Code Docs](https://code.claude.com/docs/en/agent-sdk/skills) — SDK 视角的 Skill 自动发现与调用，补充 Skill 在编程化场景中的集成方式

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
