<!-- title: Skill渐进披露：三层按需加载实战 -->

# Skill 渐进式披露：三层按需加载实战

> **学习目标**：掌握 Agent Skills 的"发现—激活—执行"三层架构，学会把一个臃肿的 Skill 重构为按需加载的分层结构，让 17 个 Skill 的发现总成本压到 ~1700 tokens，激活成本控制在 5000 tokens 以内。
> **适用人群**：已经写过第一个 Skill、想让 Skill 在大规模（10+ 技能）环境下稳定高效运行的开发者。

## 前置条件

- 已安装 Claude Code，能在 `~/.claude/skills/` 或项目 `.claude/skills/` 下跑通一个最简 Skill
- 理解 YAML frontmatter 与 Markdown 基本语法
- 安装 Node.js（用于 `skills-ref` 验证工具）

## 一、为什么不能把所有内容塞进一个 SKILL.md

很多开发者写第一个 Skill 时会犯同一个错误：把所有规则、所有示例、所有脚本说明，一股脑写进 `SKILL.md`，文件膨胀到 8000 tokens。表面上看"内容全在一处很方便"，实际却带来两个严重问题：

**问题 1：上下文不是免费的。** 大语言模型存在"lost in the middle"现象——上下文越长，模型对中间位置信息的提取准确率越低。研究表明，agent 同时挂载的工具一旦超过 10 个，准确率就开始下降；超过 20 个则明显劣化。指令和工具定义遵循同样的规律。当你挂了几个 MCP 服务器，工具的 JSON Schema 很容易就堆到 50000 tokens，模型还没开始推理，注意力已经被稀释。

**问题 2：激活成本暴涨。** Skill 一旦被判定为相关，整个 `SKILL.md` 会被加载进上下文。一个 8000 tokens 的 Skill 每次激活就吃掉这么多窗口；如果你有 20 个这样的 Skill，热点任务反复激活时，窗口被无效内容反复挤压。

Anthropic 官方仓库里 `skill-creator` 的 `SKILL.md` 确实达到约 8000 tokens，但那是少数——官方 17 个 Skill 的 `SKILL.md` body 中位数只有约 2000 tokens，最小的 `internal-comms` 仅 275 tokens。差距的全部秘密，就在于**渐进式披露（Progressive Disclosure）**。

## 二、三层架构：发现、激活、执行

渐进式披露是一个源自人机交互（Nielsen Norman Group）的经典设计原则：只展示当前任务需要的信息，把进阶选项藏到二级入口。Agent Skills 把这个原则应用到了上下文管理上，形成**三层加载模型**：

| 层级 | 触发时机 | 加载内容 | 典型成本 |
|------|---------|---------|---------|
| **Layer 1 发现** | 启动时，常驻 | 仅 `name` + `description` | ~80 tokens/skill |
| **Layer 2 激活** | 判定任务相关 | 完整 `SKILL.md` body | < 5000 tokens 推荐 |
| **Layer 3 执行** | 执行中按需 | `scripts/`、`references/`、`assets/` | 仅当前所需 |

对 Anthropic 官方 17 个 Skill 的实测显示：发现层成本从 55 tokens（`webapp-testing`）到 235 tokens（`xlsx`）不等，全部 17 个加起来约 1700 tokens——**让 agent "意识到"几十个技能存在，成本比激活单个技能还低**。这正是分层设计的威力。

```mermaid
flowchart TD
    A[Agent 启动] -->|扫描所有 Skill| B["Layer 1 发现<br/>仅 name+description<br/>~80 tokens/skill"]
    B --> C{description 与<br/>当前任务相关?}
    C -->|否| D[保持休眠<br/>零额外开销]
    C -->|是| E["Layer 2 激活<br/>加载完整 SKILL.md<br/>建议 < 5000 tokens"]
    E --> F[按指令执行]
    F --> G{遇到需要<br/>细节的步骤?}
    G -->|否| I[直接完成]
    G -->|是| H["Layer 3 执行<br/>按需读 references/scripts/assets"]
    H --> I
    I --> J[完成后缓存或卸载]
```

关键洞察：**路由准确性几乎完全取决于 description 的质量**。模型在 Layer 1 用纯推理判断"这个 Skill 该不该激活"，写好 description 就等于写好路由表。这也是为什么 `name` 和 `description` 是 frontmatter 里仅有的两个必填字段。

## 三、分步实战：从臃肿到分层

下面我们以一个"API 文档生成器"为案例，演示完整的三层重构过程。先看反例——一个把所有东西塞进 `SKILL.md` 的臃肿版本：

```markdown
---
name: api-doc-generator
description: Helps with API docs.
---

# API 文档生成器（臃肿版）

（此处省略 8000 tokens 的 OpenAPI 字段规范、
各框架解析规则、20 个示例、报错排查……全部堆在这一个文件里）
```

这个版本有三大病灶：description 模糊（"Helps with API docs" 缺少触发关键词）、body 臃肿（每次激活浪费数千 token）、没有执行层（细节和脚本混在一起）。我们逐层修复。

### 第一步：精修 frontmatter（优化 Layer 1 发现）

`description` 必须同时回答两个问题——**做什么**和**何时用**，并埋入用户真实会说的关键词。规范要求 1–1024 字符。

```yaml
---
name: api-doc-generator
description: 为 Express/FastAPI/Fastify/Spring Boot 项目自动生成 OpenAPI 3.x 接口文档。当用户说"生成API文档""导出OpenAPI/Swagger""列出所有端点""从路由代码提取接口"时使用；也可用于把现有路由转成可交互的 API 参考。
metadata:
  author: bootcamp-demo
  version: "1.0"
---
```

**frontmatter 字段速查**（基于 Agent Skills 开放规范）：

| 字段 | 必填 | 约束 |
|------|------|------|
| `name` | 是 | ≤64 字符；仅小写字母/数字/连字符；不得以连字符开头结尾、不得连续连字符；**必须与父目录名一致** |
| `description` | 是 | 1–1024 字符；同时说明做什么+何时用 |
| `license` | 否 | 许可证名或指向 LICENSE 文件 |
| `compatibility` | 否 | ≤500 字符；环境要求（系统包、网络等） |
| `metadata` | 否 | 任意 string→string 映射 |
| `allowed-tools` | 否 | 空格分隔的预批准工具（实验性） |

`name` 字段有几个易错点：`PDF-Processing`（大写不允许）、`-pdf`（连字符开头）、`pdf--processing`（连续连字符）都会验证失败。

**常见问题**：description 写了"帮助处理 API"，结果 Skill 死活不触发。
**解决**：用 `/help` 或 `skills-ref` 观察实际加载的 metadata，把用户真实措辞（"导出接口文档""Swagger"）作为关键词写进 description。

### 第二步：把 SKILL.md body 压到决策骨架（优化 Layer 2 激活）

激活层只放"决策骨架"——分支判断、高层流程、指针。目标是把 body 控制在 **500 行以内、5000 tokens 以内**：

```markdown
# API 文档生成器

## 决策流程
1. 识别项目框架（检查 package.json / requirements.txt / pom.xml）
2. 按下表选择解析脚本
3. 解析后套用输出模板，产出 OpenAPI 结构

## 框架 → 脚本映射
| 框架 | 解析脚本 |
|------|---------|
| Express / Koa | `scripts/parse_js_routes.py` |
| FastAPI | `scripts/parse_fastapi.py` |
| Spring Boot | `scripts/parse_spring.py` |

## 何时需要深入细节
- OpenAPI 字段写法不确定 → 读 `references/openapi-spec.md`
- 输出格式与模板 → 读 `references/output-templates.md`
- 完整示例 → 读 `references/example-output.md`

> 除非当前任务明确需要，**不要预读** references/ 下的文件。
```

这个 body 约 250 tokens，相比 8000 tokens 的臃肿版，激活成本骤降 96%。骨架里最关键的一句是最后那行**防预读指令**——明确告诉模型"没需要就别加载"，避免它好心把所有 reference 全读进来，前功尽弃。

### 第三步：把细节拆进 references/（构建 Layer 3 执行层）

执行层遵循一个铁律：**单个文件聚焦一个主题，越小越好**。因为模型按需加载，文件越小，单次加载越省。目录结构如下：

```
api-doc-generator/
├── SKILL.md                    # Layer 2 骨架（~250 tokens）
├── scripts/
│   ├── parse_js_routes.py      # Express/Koa 路由解析
│   ├── parse_fastapi.py        # FastAPI 装饰器解析
│   └── parse_spring.py         # Spring 注解解析
├── references/
│   ├── openapi-spec.md         # OpenAPI 3.x 字段规范
│   ├── output-templates.md     # 输出模板
│   └── example-output.md       # 完整示例
└── assets/
    └── example-openapi.json    # 静态示例文件
```

`references/openapi-spec.md`（节选）放的是字段级细节：

```markdown
### paths 对象
每个路径以 `/` 开头，键为路径模板，值为 Path Item Object。

### parameters
- `name`：必填，参数名
- `in`：query | header | path | cookie
- `required`：path 参数必须为 true
- `schema`：类型定义，引用 `$ref: '#/components/schemas/...'`

### responses
- HTTP 状态码作键（如 `200`、`404`）
- 每个值含 `description`（必填）和可选 `content`
```

当任务是"审查这个 FastAPI 项目的接口安全"时，模型**只会**加载 `scripts/parse_fastapi.py` 和 `references/openapi-spec.md`，而 Express 的解析脚本、Spring 的注解规则——全部留在磁盘上零开销。这就是分层加载的本质收益：**按任务裁剪上下文**。

### 第四步：正确引用文件，控制引用深度

规范明确要求：**文件引用用相对路径，且保持一层深度，避免深层嵌套引用链**。

正确写法（在 SKILL.md 中）：

```markdown
见 [OpenAPI 字段规范](references/openapi-spec.md) 了解详细字段。
运行解析：`python scripts/parse_fastapi.py`
```

错误写法：

```markdown
见 references/openapi-spec.md，它又指向 references/advanced/security.md，
后者再引用 references/advanced/oauth/flows.md ……
```

深层嵌套引用链会让模型陷入"读了 A 才知道要读 B，读了 B 才知道要读 C"的连环加载，既慢又费 token。每层 reference 应当自包含，直接被 SKILL.md 指向。

### 第五步：用 skills-ref 验证

写完后用官方参考库 `skills-ref` 校验 frontmatter 合法性与命名规范：

```bash
npx skills-ref validate ./api-doc-generator
```

它会检查 `name` 是否匹配目录名、是否含非法字符、`description` 是否非空等。验证通过再发布。

## 四、完整实战案例：API 文档生成器端到端

把上面片段拼成可运行的项目。先创建目录与最小文件：

```bash
mkdir -p ~/.claude/skills/api-doc-generator/{scripts,references,assets}
```

`scripts/parse_fastapi.py`（一个真实可跑的最小解析器）：

```python
"""从 FastAPI 项目提取路由定义，输出端点列表。
用法: python parse_fastapi.py <app_dir>
"""
import ast, sys, json
from pathlib import Path

VERBS = {"get", "post", "put", "delete", "patch"}

def extract(file_path: Path):
    tree = ast.parse(file_path.read_text(encoding="utf-8"))
    endpoints = []
    for node in ast.walk(tree):
        if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute):
            if node.func.attr in VERBS:
                path = ast.literal_eval(node.args[0]) if node.args else ""
                endpoints.append({"method": node.func.attr.upper(), "path": path,
                                  "file": str(file_path)})
    return endpoints

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("用法: python parse_fastapi.py <app_dir>", file=sys.stderr); sys.exit(1)
    root = Path(sys.argv[1])
    all_eps = []
    for py in root.rglob("*.py"):
        try: all_eps += extract(py)
        except SyntaxError: continue
    print(json.dumps({"openapi": "3.0.3", "paths_count": len(all_eps),
                      "endpoints": all_eps}, indent=2, ensure_ascii=False))
```

**预期结果**：对一个含 `@app.get("/users")` 的 FastAPI 文件运行，输出：

```json
{
  "openapi": "3.0.3",
  "paths_count": 1,
  "endpoints": [{"method": "GET", "path": "/users", "file": "app.py"}]
}
```

**触发演示**：在项目里对 Claude 说"帮我导出这个 FastAPI 服务的 OpenAPI 文档"，Claude 会：①Layer 1 匹配 description 命中 → ②Layer 2 加载 ~250 token 骨架，识别出是 FastAPI 分支 → ③Layer 3 仅加载 `parse_fastapi.py` + `openapi-spec.md` → ④产出文档。全程上下文干净，Express/Spring 那几个文件从不被加载。

## 五、三层结构 vs 单文件臃肿：一次量化对比

假设一个 agent 同时挂载 20 个 Skill，其中 5 个是本案例这样的"知识密集型"技能：

| 指标 | 单文件臃肿版 | 三层分层版 |
|------|------------|-----------|
| 单个 Skill 激活成本 | ~8000 tokens | ~250 tokens（骨架）|
| 20 个 Skill 发现总成本 | ~1600 tokens | ~1600 tokens（发现层不变）|
| 一次任务无关文件加载 | 0（全在一起）| 仅命中分支的文件 |
| "lost in the middle"风险 | 高 | 低 |

发现层成本两种结构相同（都只读 name+description），差异全在激活层和执行层。**分层结构的全部收益，体现在"只加载被命中的那一支"。**

```mermaid
flowchart LR
    subgraph 单文件臃肿版
        A1[激活即加载 8000 tokens<br/>所有规则/示例/脚本说明]
    end
    subgraph 三层分层版
        B1["骨架 250 tokens"] --> B2{命中分支?}
        B2 -->|FastAPI| B3["parse_fastapi.py<br/>+openapi-spec.md<br/>≈1200 tokens"]
        B2 -->|Express| B4["parse_js_routes.py<br/>≈900 tokens"]
        B2 -->|其余| B5[不加载]
    end
```

## 六、常见问题与解决方案

**Q1：我的 Skill 描述很详细，为什么还是不触发？**
A：description 里缺"用户真实措辞"。你写的是"处理文档"，但用户说的是"导出 Swagger"。把后者作为关键词写进去。路由纯靠 Layer 1 的推理，关键词就是路由表。

**Q2：模型激活后总是把 references 全读一遍，怎么办？**
A：在 SKILL.md 骨架末尾加一句显式指令："除非当前任务明确需要，不要预读 references/ 下的文件。" 这句指令的省 token 效果立竿见影。

**Q3：reference 文件该切多细？**
A：按"一次任务只会同时需要其中几个"来切分。OpenAPI 字段规范、输出模板、示例天然是独立主题，就拆成三个文件；如果两个文件几乎总是一起被读，就合并。

**Q4：跨平台（Claude Code / Codex / Gemini）格式一样吗？**
A：`SKILL.md` 格式是 2025-12-18 发布的开放标准，OpenAI、Google、GitHub、Cursor 均已采纳，格式一致；只是存放路径不同（Claude Code 用 `~/.claude/skills/`，Codex 用 `.agents/skills/`，Gemini 用 `.gemini/skills/`）。

**Q5：激活后卸载，下次又重载，会不会反复浪费？**
A：会。成熟的实现会缓存最近用过的 Skill、保持高频激活的 Skill"warm"，在上下文效率与重复加载成本间取平衡。设计上让骨架小，正是为了降低这个反复成本。

## 延伸阅读

- [Agent Skills Specification](https://agentskills.io/specification) — 官方完整格式规范（frontmatter、目录结构、渐进披露定义）
- [SwirlAI: Agent Skills — Progressive Disclosure as a System Design Pattern](https://www.newsletter.swirlai.com/p/agent-skills-progressive-disclosure) — 含 17 个官方 Skill 的 token 实测数据
- [Skills overview — Claude Docs](https://claude.com/docs/skills/overview) — Anthropic 官方 Skills 概览
- [Marcel Castro: Skills and the Art of Progressive Disclosure](https://marcelcastrobr.github.io/posts/2026-01-29-Skills-Context-Engineering.html) — 从上下文工程角度解读分层加载

## 训练营适用性评估

- **适合类型**：Claude Code 进阶训练营、企业 AI 工程实战营、上下文工程（Context Engineering）专题营。要求学员已能独立写出第一个 Skill。
- **教学时长**：约 4–6 学时。其中概念与三层架构 1 学时、frontmatter 精修与骨架拆分实操 2 学时、端到端案例重构 1.5 学时、量化对比与排障 1 学时。
- **交付物**：每人提交一个重构过的三层 Skill，附 `skills-ref validate` 通过截图与激活前后 token 对比报告。

## 参考来源

1. [Agent Skills Specification](https://agentskills.io/specification) — Agent Skills 开放标准的完整格式规范，含 frontmatter 字段约束、目录结构与渐进披露定义
2. [Agent Skills: Progressive Disclosure as a System Design Pattern — SwirlAI Newsletter](https://www.newsletter.swirlai.com/p/agent-skills-progressive-disclosure) — 对 Anthropic 17 个官方 Skill 的 token 实测（发现层 80 tokens 中位数、激活层 275–8000 tokens 区间）及三层架构系统设计分析
3. [Skills: the art of progressive disclosure in the era of context engineering — Marcel Castro](https://marcelcastrobr.github.io/posts/2026-01-29-Skills-Context-Engineering.html) — 从上下文工程视角解读 Skill 分层加载与 context curation
4. [Skills overview — Claude 官方文档](https://claude.com/docs/skills/overview) — Anthropic 官方 Skills 工作机制与元数据加载说明
5. [wshobson/agents: Agent Skills 文档](https://github.com/wshobson/agents/blob/main/docs/agent-skills.md) — 社区整理的 Agent Skills 实践文档与示例结构

> [!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)
