<!-- title: 调优Skill描述：让技能精准触发 -->

# Claude Code Skill 描述字段调优实战：让技能精准触发

## 概述

很多开发者第一次创建 Skill，写完 `SKILL.md` 却发现：明明场景吻合，Claude 就是不调用它。本教程聚焦 Claude Code Skill 里**最关键、也最容易被忽视**的一个字段——`description`。你将从零创建一个 `api-error-triage` 技能，亲手经历「不触发 → 误触发 → 精准触发」的完整调优过程，掌握「what + when + 第三人称」的描述写法、三类探针验证法，以及一份可复用的故障排查清单。适合已跑通 Claude Code、想做出可靠自定义技能的中级用户。

## 前置条件

- 已安装并能正常启动 Claude Code（CLI 或 IDE 扩展均可）
- 一个可写入的测试目录（本教程用 `~/triage-lab`）
- 了解 Markdown 基本语法，能看懂 YAML frontmatter
- 不需要任何编程基础——Skill 的本质是「一个文件夹 + 一个 `SKILL.md`」

---

## 第 0 步：先搞懂一件事——Skill 的路由是「推理」不是「匹配」

在动手前，必须建立一个正确的心智模型，否则后面的所有调优都是盲目的。

绝大多数人以为 Skill 是靠「关键词命中」触发的，于是拼命往描述里堆关键词。但官方文档与社区实测都指向同一个事实：**Claude Code 的技能路由是纯 LLM 语义推理，而不是算法匹配（不是正则、不是关键词索引、不是 GBNF 规则）。**

这意味着：

| 常见误解 | 实际机制 |
|---|---|
| 描述里写了 `error` 就会在出现 error 时触发 | Claude 读懂**整句话的语义与意图**才决定是否调用 |
| 关键词越多、列表越长，触发率越高 | 堆砌关键词反而稀释语义、降低命中 |
| 技能名 `debug-tool` 决定何时触发 | 名字只影响可读性与 `/` 调用，**描述**才是路由信号 |

**结论**：你的 `description` 是写给一个「会推理的读者」看的。它需要在极短的篇幅里讲清楚两件事——**这个技能做什么（what）**，以及**什么情况下该用它（when）**。整篇文章都在围绕这两点展开。

---

## 第 1 步：搭出最小骨架

一个 Skill 的物理形态极其简单：一个文件夹，里面一个 `SKILL.md`。先把它搭出来。

**操作命令：**

```bash
# 准备实验室目录
mkdir -p ~/triage-lab/.claude/skills/api-error-triage/references
cd ~/triage-lab

# 写出第一个 SKILL.md（先故意写一个「会失败」的版本）
cat > .claude/skills/api-error-triage/SKILL.md <<'EOF'
---
name: api-error-triage
description: Helps with errors.
---

# API Error Triage

分析 API 错误，输出诊断报告。
EOF
```

**目录结构预期：**

```
~/triage-lab/
└── .claude/
    └── skills/
        └── api-error-triage/
            ├── SKILL.md
            └── references/
```

**验证已加载：** 在 `~/triage-lab` 下启动 Claude Code，输入：

```
/skills
```

应能看到 `api-error-triage` 出现在技能列表里。如果你看到的描述是空的，或技能根本没出现——**几乎可以断定是你的 frontmatter YAML 写坏了**（缩进错、冒号后没空格、引号没闭合）。官方文档明确指出：frontmatter 解析失败时，技能体会被以「空元数据」加载，于是 `/skills` 里它要么不显示、要么描述为空。

> **常见问题**：`name` 必须是 kebab-case（小写、连字符分隔，如 `api-error-triage`），且要和文件夹名一致。写成 `Api_Error_Triage` 会导致加载异常。

---

## 第 2 步：写一个「不触发」的描述（反面教材）

现在我们有了一个能加载、但永远不会被调用的技能。先实测它的失败表现。

**操作：** 在 Claude Code 里直接粘贴一段真实的 API 错误，不要点名任何技能：

```
我的请求返回了这个：
{"error":{"code":"permission_denied","message":"Missing access to resource res_abc123"}}

帮我看看怎么回事？
```

**预期（失败）结果：** Claude 会用自己的通用知识回答，**完全不会**调用 `api-error-triage`。因为描述 `Helps with errors.` 对一个推理引擎来说信息量约等于零——它既没说处理哪类错误，也没说何时该用。

**为什么不触发：** `Helps with errors.` 违反了三条铁律——

1. **没有 when**：没说处理哪种错误、什么场景下用。
2. **没有 what**：没说输出什么（报告？修复脚本？翻译？）。
3. **主语模糊**：「Helps」是第一人称视角的口语，不是对技能的客观描述。

---

## 第 3 步：用「what + when + 第三人称」重写描述

这是全文的核心。Anthropic 在《Lessons from building Claude Code: How we use skills》里反复强调：描述要用**第三人称**写，说清楚**做什么**和**何时用**。下面是同一技能的三版迭代，请逐字对照。

### 迭代 A：加 when，但主语还是错的

```yaml
description: Use this when the user pastes an API error.
```

进步：有了 when。但 `Use this` 是祈使句、隐含第二人称，语义仍偏弱，且没说做什么。

### 迭代 B：补上 what，但动词太泛

```yaml
description: Analyzes API errors when the user pastes a failing request or error response, and helps debug them.
```

进步：第三人称（`Analyzes`），有 when 也有 what。问题在 `helps debug them`——「debug」是个筐，什么都往里装，和 Claude 自带的调试能力区分度不够，**容易被忽略**。

### 迭代 C（最终版）：语义饱和、边界清晰

```yaml
description: Triages HTTP and API errors—4xx/5xx responses, stack traces, error JSON, connection or timeout failures—into a structured root-cause report with a category, the likely cause, and the single next troubleshooting step. Use whenever the user pastes an error, shares a failing request/response, or asks "why is this error happening" or "what does this error mean".
```

**为什么这版能稳定触发**，逐句拆解：

| 元素 | 写法 | 作用 |
|---|---|---|
| 动词 | `Triages`（第三人称单数） | 明确动作类型=分类诊断，区别于「修复」「翻译」 |
| 输入边界 | `4xx/5xx responses, stack traces, error JSON, connection or timeout failures` | 给推理引擎**具体的可识别形态**，不是抽象词 |
| 输出物 | `structured root-cause report with a category, the likely cause, and the single next troubleshooting step` | 告诉它产出什么，且独一无二 |
| 触发时机 | `Use whenever the user pastes an error, shares a failing request/response, or asks "why..."` | 直接列举用户会说的原话与动作 |

把这一版覆盖回 `SKILL.md` 的 frontmatter，保存。

> **口诀**：动词用第三人称单数；输入给具体形态；输出给独一无二的结构；when 直接引用用户原话。四件齐全，触发率立竿见影。

---

## 第 4 步：用三类探针验证触发可靠性

改完描述不能靠「感觉对了」收工。用一个最小测试套件——三类探针——量化验证。在同一个会话里依次抛出：

**探针 1：正例（应该触发）**

```
curl 返回 {"error":{"code":"permission_denied",...}}，怎么办？
```

✅ 期望：Claude 调用 `api-error-triage`，输出结构化报告。

**探针 2：边界正例（口语化触发）**

```
这个 502 是什么意思啊，帮我看看
```

✅ 期望：仍触发。检验描述里的「asks why...」语义是否覆盖口语。

**探针 3：反例（不该触发）**

```
帮我写一个返回 4xx 的 mock 接口
```

❌ 期望：**不触发**。这是「生成错误」而非「诊断错误」。如果这里也触发了，说明描述边界太宽（你写了 `errors` 却没限定「已发生的错误」），需要收紧。

**如何确认技能真的被调用**：调用时 Claude Code 会在界面显示技能加载提示（如「Loaded skill: api-error-triage」），你也能从输出风格（是否严格遵循报告格式）判断。建议每个探针跑 2–3 次——因为路由是推理、带一定随机性，单次不可靠，**多次稳定才是真稳定**。

> **常见问题**：正例偶尔触发、偶尔不触发。多半是描述里缺少「输入形态」清单（迭代 C 第一行那串具体例子），补上即可显著提升一致性。

---

## 第 5 步：渐进披露——SKILL.md 保持精简，细节拆到引用文件

触发解决后，下一个坑是**上下文预算**。技能一旦被调用，`SKILL.md` 正文会被**整篇**载入上下文。正文越长，每次调用越烧 token。正确做法是「渐进披露」：SKILL.md 只放骨架与指针，细节放进按语义命名的文件，让 Claude **按需**读取。

**操作：** 把错误码知识库拆出去。

`references/error-codes.md`：

```markdown
# 常见 API 错误码速查

## permission_denied
- 类别：鉴权/授权
- 常见原因：API Key 缺少该资源的 scope，或资源归属其他账号
- 下一步：检查 Key 权限范围，或在控制台重新授权该资源

## rate_limit_exceeded
- 类别：限流
- 常见原因：短时间请求过多
- 下一步：读取响应头 Retry-After，按指数退避重试

## 5xx / 502 / 503
- 类别：上游故障
- 常见原因：服务端过载或网关异常
- 下一步：等待 30s 重试；持续失败则查状态页
```

精简后的 `SKILL.md` 正文（frontmatter 保持迭代 C）：

```markdown
# API Error Triage

收到 API 错误时，输出一份结构化根因报告。

## 流程
1. 从错误中识别 code / status / message。查 `references/error-codes.md` 拿到对应条目。
2. 按下方格式输出，每项不超过一句话。

## 输出格式
- **类别**：<鉴权 / 限流 / 上游故障 / 参数错误 / 其它>
- **最可能原因**：<一句话>
- **下一步**：<单个、可立即执行的动作>
```

**为什么这样写有效：**

- 正文只剩骨架与格式约定，调用成本低。
- `references/error-codes.md` 这个**文件名本身就是触发线索**——Claude 在第 1 步读到「查 error-codes」时，语义上就知道该去读它，不必把整张表常驻上下文。
- 这就是「按需加载」：不读不烧，读了才加载。

> **常见问题**：把所有内容塞进 SKILL.md。后果是每次调用都把几百行知识库灌进上下文，既慢又贵。原则——SKILL.md 像目录页，引用文件像章节正文。

---

## 第 6 步：故障排查清单

把踩过的坑沉淀成一张速查表，遇到不触发直接对照：

| 症状 | 可能原因 | 修复 |
|---|---|---|
| `/skills` 里看不到技能 | YAML 解析失败 / 文件夹名与 `name` 不一致 | 检查缩进、冒号后空格；name 用 kebab-case 且等于文件夹名 |
| 看得到但从不触发 | 描述无 when、无 what、主语非第三人称 | 回到第 3 步四要素重写 |
| 偶尔触发、不稳 | 描述缺「输入形态」清单 | 补具体形态（如 4xx/5xx、stack trace） |
| 误触发（反例也中招） | 边界过宽，动词太泛（debug/help） | 收紧 when，用独一无二的结构输出 |
| 与其他技能打架 | 两个技能描述语义重叠 | 给每个补独有边界，必要时用 `disable-model-invocation` 让其一改为 `/` 手动调用 |

**关于 `disable-model-invocation`**：这是一个可选的布尔 frontmatter 字段。设为 `true` 时，该技能**不再被模型自动调用**，只能通过 `/技能名` 显式触发。适合那些「容易和别的技能抢戏、但你希望完全手动控制」的场景——比如一个重型的安全审查技能，宁可手动唤起也不要它擅自介入。

---

## 实战案例：完整的 `api-error-triage` 技能

把前面所有步骤合起来，这是一个可直接复制运行的完整项目。

**目录结构：**

```
~/triage-lab/.claude/skills/api-error-triage/
├── SKILL.md
└── references/
    └── error-codes.md
```

**`SKILL.md`（完整）：**

```markdown
---
name: api-error-triage
description: Triages HTTP and API errors—4xx/5xx responses, stack traces, error JSON, connection or timeout failures—into a structured root-cause report with a category, the likely cause, and the single next troubleshooting step. Use whenever the user pastes an error, shares a failing request/response, or asks "why is this error happening" or "what does this error mean".
---

# API Error Triage

收到 API 错误时，输出一份结构化根因报告。

## 流程
1. 从错误中识别 code / status / message。查 `references/error-codes.md` 拿到对应条目。
2. 按下方格式输出，每项不超过一句话。

## 输出格式
- **类别**：<鉴权 / 限流 / 上游故障 / 参数错误 / 其它>
- **最可能原因**：<一句话>
- **下一步**：<单个、可立即执行的动作>
```

`references/error-codes.md` 内容见第 5 步。

**端到端测试：** 启动 Claude Code，粘贴：

```
POST /v1/charges 返回：
HTTP 429
{"error":{"code":"rate_limit_exceeded","message":"Too many requests"}}
怎么办？
```

**期望输出：**

```
- 类别：限流
- 最可能原因：短时间请求过多，触发服务端限流。
- 下一步：读取响应头 Retry-After，按指数退避（如 1s → 2s → 4s）重试。
```

至此，你拥有了一个**会精准触发、上下文精简、输出稳定**的生产级技能。把它从项目目录 `.claude/skills/` 复制到 `~/.claude/skills/`，即可升级为个人全局技能，在所有项目里通用。

---

## 工作流程图

**图一：技能发现与调用流程**（路由靠语义推理）

```mermaid
flowchart TD
    A[用户输入消息] --> B{Skill 路由判断}
    B -->|纯 LLM 语义推理<br/>非关键词匹配| C{description 是否<br/>语义吻合?}
    C -->|否| D[使用通用能力回答<br/>技能未触发]
    C -->|是| E[加载该技能 SKILL.md 正文]
    E --> F{正文是否引用<br/>其它文件?}
    F -->|是| G[按需读取 references/* ]
    F -->|否| H[直接执行]
    G --> H
    H --> I[产出结构化输出]
```

**图二：描述字段调优闭环**

```mermaid
flowchart LR
    W[写 description<br/>what+when+第三人称] --> T[跑三类探针<br/>正例/边界/反例]
    T --> M{多次稳定触发?}
    M -->|否| R[诊断: 无when?/边界宽?/主语错?] --> W
    M -->|是| D[确认可靠, 投入使用]
```

---

## 延伸阅读

- **官方技能文档**：`code.claude.com/docs/en/skills` —— 创建、管理、分享技能的权威说明，含 frontmatter 解析失败的处置。
- **Skill 编写最佳实践**：`platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices` —— 第三人称描述、渐进披露的官方口径。
- **《Lessons from building Claude Code: How we use skills》**：`claude.com/blog/lessons-from-building-claude-code-how-we-use-skills` —— Anthropic 内部数百个技能的实战经验。
- **社区参考**：mellanon 的「Skills Structure and Usage Guide」gist，明确指出「路由是 LLM 推理而非算法匹配」。

---

## 训练营适用性评估

- **适用类型**：Claude Code / AI Agent 进阶训练营、企业内部「让团队共享技能」工作坊、个人效率提升班。不适合纯零基础班（需先跑通 Claude Code）。
- **预计教学时长**：1.5–2 小时。其中讲解心智模型 20 分钟、动手三版迭代 50 分钟、探针验证与排障 30 分钟。
- **学员产出**：每人交付一个**自己业务场景**下触发可靠的技能（如 `log-anomaly-triage`、`sql-explain-helper`），并附三类探针测试记录。
- **评估标准**：正例三次全触发、反例三次全不触发、SKILL.md 正文不超过 30 行。

---

## 参考来源

1. [Extend Claude with skills — Claude Code Docs](https://code.claude.com/docs/en/skills) — 官方技能创建/管理权威文档，含 frontmatter 解析失败处置
2. [Lessons from building Claude Code: How we use skills](https://claude.com/blog/lessons-from-building-claude-code-how-we-use-skills) — Anthropic 内部大规模使用技能的经验，强调描述第三人称写法
3. [Skill authoring best practices — Claude Platform Docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices) — 官方最佳实践：描述的 what+when 与渐进披露
4. [Claude Agent Skills Not Triggering? The Problem is in Your Description](https://smartscope.blog/en/blog/agent-skills-description-guide/) — 系统化的描述设计模式与触发率提升模板
5. [Claude Code Skills Structure and Usage Guide (gist)](https://gist.github.com/mellanon/50816550ecb5f3b239aa77eef7b8ed8d) — 明确「技能路由为 LLM 推理而非算法匹配」的关键结论

---

> 本文由「51学通信」原创整理，站长爱卫生（微信：gprshome201101）持续输出通信与 AI 工程实战内容。

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