<!-- title: Skill失效诊断与全链路调试实战 -->

## 概述

本教程聚焦 Claude Code Skill 开发中最令人头疼的环节——**Skill 写完却"不工作"**：要么不触发、要么乱触发、要么触发了却执行出错。我们将建立一套从"发现层 → 触发层 → 执行层 → 验证层"的四层故障定位方法论，掌握 `--debug`、`--verbose`、`/skills`、`~/.claude` 日志、权限回放等真实调试工具链。适合已能写出第一个 SKILL.md、却卡在"它为什么不按我想的来"的开发者。

## 前置条件

- 已安装 Claude Code（CLI 版本 2.0+，2026 年的 Opus 4.8 默认环境即可）
- 手动创建过至少一个自定义 Skill（知道 `~/.claude/skills/<name>/SKILL.md` 的基本结构）
- 了解 YAML frontmatter（`name`、`description` 两个字段）
- 终端基础：会用 `ls`、`cat`、`tail`、`grep` 定位文件
- 一个能复现问题的真实 Skill（没有也无妨，本文实战案例会从零造一个"坏 Skill"）

---

## 正文：四层故障定位法

调试 Skill 和调试普通程序最大的区别在于：**Skill 的行为由两层逻辑决定**——一层是大模型对 `description` 的语义理解（触发层），另一层是你写在 SKILL.md 正文与脚本里的确定性逻辑（执行层）。当一个 Skill 失效，你必须先判断故障在哪一层，否则就是在黑暗中乱改。下面这套四层法，把"猜测"变成"测量"。

### 步骤 1：归类失效——先回答"坏在哪一层"

动手之前，先给问题贴标签。Skill 失效只有四种形态，每种对应不同的诊断路径：

| 失效形态 | 典型现象 | 故障层 | 首选工具 |
|---------|---------|--------|---------|
| **A. 完全不触发** | 明明该用它，Claude 却自己硬干 | 发现/触发层 | `/skills`、`--debug` |
| **B. 错误触发** | 不该用时它跳出来，干扰正常对话 | 触发层（描述过宽） | description 审查、盲测 |
| **C. 触发了但执行错** | Skill 被加载，但产出不符合 SKILL.md 指令 | 执行层（模型未遵循） | `--verbose`、日志回放 |
| **D. 执行中报错/卡住** | 脚本崩溃、权限被拒、路径找不到 | 执行层（确定性代码） | `~/.claude` 日志、`--debug` |

**操作说明**：在终端启动一个干净的会话，故意输入一个"本应触发你的 Skill"的提示词，观察 Claude 的反应。

**预期结果**：
- 如果 Claude 毫无反应地自己回答 → 形态 A
- 如果它调用了别的 Skill 或在不相干任务里激活 → 形态 B
- 如果它说"我来用 xxx skill"但做法完全偏离你的正文 → 形态 C
- 如果它报错、停下、或反复重试 → 形态 D

**常见问题**：很多人把形态 C（模型没读正文）误当成形态 A（不触发），于是一直改 `description`，越改越糟。判别关键：看 Claude 的回复里有没有出现你 SKILL.md 正文中的特定步骤或术语——有，说明被加载了，是执行层问题；没有，才是触发层问题。

### 步骤 2：发现层诊断——Claude 到底"看没看见"你的 Skill

Skill 的触发依赖**渐进披露**机制：Claude 启动时只会把所有 Skill 的 `name` + `description` 加载进上下文（轻量索引），只有当某个 Skill 被判定为相关，才会读取完整 SKILL.md 正文。所以第一步永远是确认你的 Skill **进了索引**。

**操作 1：用 `/skills` 命令查看已注册列表**

在交互式会话中直接输入：

```
/skills
```

它会列出当前会话可用的全部 Skill（含内置与你自定义的）。**如果你的 Skill 不在这个列表里，说明它压根没被发现**——问题出在文件系统，不在模型。

**操作 2：核对目录结构**

自定义 Skill 必须放在以下三个作用域之一，且文件名严格为 `SKILL.md`（大写、不是 `skill.md` 或 `SKILL.MD`）：

```
~/.claude/skills/<skill-name>/SKILL.md          # 用户级（全局）
<project>/.claude/skills/<skill-name>/SKILL.md   # 项目级
<plugin>/skills/<skill-name>/SKILL.md            # 插件级
```

用一条命令快速排查：

```bash
ls -la ~/.claude/skills/*/SKILL.md 2>/dev/null
ls -la .claude/skills/*/SKILL.md 2>/dev/null
```

**操作 3：验证 frontmatter 合法性**

`/skills` 列表是 Skill 被"发现"的硬门槛。最常见的"不进列表"原因是 frontmatter 格式错误。官方规范要求：

- `name`：最多 64 字符，必须与目录名一致，仅限 `kebab-case`（小写字母、数字、连字符）
- `description`：必填，自然语言说明"做什么 + 何时用"，建议 1-3 句

```yaml
---
name: pdf-form-filler
description: Fills PDF forms from structured data. Use when the user asks to populate, fill, or complete a PDF form with field values.
---
```

**常见问题与解决**：
- **目录名与 `name` 不一致** → 发现失败。改目录名或改 frontmatter，二者必须完全相同。
- **YAML 缩进/冒号后缺空格** → 整个 Skill 被静默忽略。用 `cat -A SKILL.md | head -5` 看是否有隐藏的 Tab 或异常字符。
- **`name` 含大写或下划线** → 如 `PDF_Filler`，直接被判非法。改成 `pdf-form-filler`。

### 步骤 3：触发层诊断——"看见了，为何不用我"

如果 Skill 在 `/skills` 里，却不被调用，问题在**语义匹配**：Claude 觉得你的 `description` 跟当前任务"不够相关"。这是 Skill 调试中最微妙的一层。

**操作 1：开 `--debug` 看模型在想什么**

最直接的诊断手段是带调试标志启动：

```bash
claude --debug
```

或针对单次提示：

```bash
claude -p "帮我把这个 CSV 转成 PDF 表单" --debug --verbose
```

`--debug` 会输出工具调用、Skill 加载、上下文裁剪等内部信息；`--verbose` 会显示更详细的推理过程。在输出里搜索你的 Skill 名，能看到它是否进入了"候选集"却最终落选。

**操作 2：审视 description 的三个失败模式**

触发层的病根 90% 在 `description`。对照下面三种失败模式自查：

1. **过窄（描述太具体，模型想不到用它）**  
   坏例子：`description: Fills IRS 1040 forms.`  
   用户说"帮我填税务表"时，模型可能不会联想到。  
   改进：`description: Fills PDF forms from structured data. Use when the user wants to populate, fill, or complete any PDF form with field values, including tax forms, applications, and contracts.`

2. **过宽（描述太泛，到处误触发）—— 即形态 B**  
   坏例子：`description: Helps with file operations.`  
   这会让它在每个涉及文件的任务里都跳出来。  
   改进：明确边界 + 反向约束，例如 `Use when ... Do NOT use for general file reading or editing; only for structured PDF form completion.`

3. **缺触发词（用户实际说法与描述词汇不重合）**  
   收集用户真实说法（"填表"、"生成表格"、"打印到 PDF"），把这些动词/名词织进 description。

**操作 3：盲测验证**

改完 description 后，用一批**你不告诉 Claude 用哪个 Skill** 的提示词测试。这正是 Evals 盲测的思路——构造 10-20 条真实用户问法，统计触发命中率与误触发率，迭代到稳定。本教程实战环节会给出一套最小可用的盲测脚本。

**常见问题**：`description` 越长越好？**否**。过长的描述会挤占索引上下文，反而稀释关键词。官方建议保持 1-3 句、关键词前置。

### 步骤 4：执行层诊断——"触发对了，却做错了"

这一层分两类：**模型没遵循正文**（形态 C）和**脚本/工具确定性报错**（形态 D）。诊断手段完全不同。

**操作 1：形态 C——用 `--verbose` 看模型读了什么**

形态 C 的典型表现是 Claude 说了"我来用 pdf-form-filler"，但实际步骤完全不对。原因往往是：SKILL.md 正文太长/太散，关键步骤被淹没；或正文里有歧义指令。

```bash
claude -p "..." --verbose
```

排查清单：
- 正文是否超过模型"愿意读完"的长度？关键步骤前置，把背景知识下沉到 `references/` 子文件（渐进披露）。
- 是否存在矛盾指令？例如正文先说"直接调用脚本"，又说"先询问用户"，模型无所适从。
- 是否缺少**预期输出格式**？明确写出"完成后输出 JSON 且包含 `status` 字段"，模型遵循率显著提升。

**操作 2：形态 D——读 `~/.claude` 日志**

形态 D 是确定性错误，必须看实际执行日志。Claude Code 把会话记录写入 `~/.claude/` 下。关键定位命令：

```bash
# 查看最近的会话日志文件
ls -lt ~/.claude/ | head

# 在日志中搜索你的 Skill 名与脚本调用
grep -n "pdf-form-filler" ~/.claude/*.jsonl
grep -n "fill_form.py" ~/.claude/*.jsonl

# 看最近的工具调用与报错
grep -n "error\|Error\|denied\|exit" ~/.claude/*.jsonl | tail -30
```

**操作 3：独立复现脚本**

Skill 正文里调用的脚本，**脱离 Claude 单独跑一遍**，是最快的定位手段：

```bash
# 假设 Skill 调用了 scripts/fill_form.py
cd ~/.claude/skills/pdf-form-filler
python3 scripts/fill_form.py --input sample.json --output out.pdf
echo "exit code: $?"
```

如果脚本单独跑就崩，那跟模型无关，先修脚本。常见确定性错误：

- **路径错误**：正文里写绝对路径 `/home/me/...`，换机器就失效。改用相对 Skill 目录的路径，或在正文里要求 Claude 先 `cd` 到 Skill 目录。
- **权限被拒**：脚本要写 `~/.aws/` 或执行 `rm`，命中权限策略被拦截。日志里会看到 `denied`。需在 `settings.json` 的 `permissions.allow` 里显式放行，或改用沙箱。
- **依赖缺失**：`import` 报 `ModuleNotFoundError`。在 SKILL.md 里加 `## Prerequisites` 说明 `pip install` 步骤，或用 inline 安装。

**操作 4：用 `--debug` 回放权限决策**

当 Skill 被权限系统拦截时，`--debug` 会打印每次工具调用前的权限判定链路，能看清是哪条规则（`allow`/`deny`/`ask`）命中了你：

```bash
claude -p "填表" --debug 2>&1 | grep -A3 "permission\|allow\|deny"
```

### 步骤 5：修复与回归——让 bug 不再回来

诊断完成后，最后一个习惯决定 Skill 质量：**把这次的失效案例固化成回归测试**。

1. 把触发该 bug 的提示词存进测试集。
2. 在 description 旁补一句 `# regression: <bug 简述>`，方便日后审计。
3. 对确定性脚本错误，给脚本本身加单测（`pytest`），在 SKILL.md 的 `## Verification` 里写明如何跑测试。
4. 重新跑步骤 3 的盲测集，确认旧 bug 修了、且没引入新回归。

> **调试心法**：四层法的精神是"二分定位"。先判断在不在索引（发现层），再判断匹不匹配（触发层），再判断模型读没读懂（执行层-语义），最后才是看脚本对不对（执行层-确定性）。**每一层只改一个变量**，改完重测，不要一次动 description 又动脚本——否则修好了也不知道是哪个起的作用。

---

## 实战案例：拯救一个"装死"的 Skill

我们从零造一个故意写坏的 Skill，然后用四层法把它救活。这个 Skill 叫 `csv-to-pdf-table`，目标是"把 CSV 转成 PDF 表格"。

### 第 0 步：造出"坏 Skill"

目录与 frontmatter 故意埋了三个雷：

```bash
mkdir -p ~/.claude/skills/CSV_to_PDF/scripts
```

写入 `~/.claude/skills/CSV_to_PDF/scripts/convert.py`：

```python
#!/usr/bin/env python3
import csv, sys
from fpdf import FPDF  # 故意不装依赖

def convert(csv_path, pdf_path):
    with open(csv_path) as f:
        rows = list(csv.reader(f))
    pdf = FPDF()
    pdf.add_page()
    for row in rows:
        pdf.cell(0, 8, " | ".join(row), ln=True)
    pdf.output(pdf_path)   # 故意用相对路径写死

if __name__ == "__main__":
    convert("data.csv", "out.pdf")  # 故意写死文件名，不接受参数
```

写入 `~/.claude/skills/CSV_to_PDF/SKILL.md`（注意目录名/大小写/name 全是坑）：

```markdown
---
name: CSV2PDF
description: helps with files
---

# CSV to PDF

Just run the script.
```

### 第 1 步：归类——它属于哪一层失效？

```
claude -p "把这个 sales.csv 转成 PDF 表格"
```

观察：Claude 直接尝试自己用 Python 写代码，**完全没碰这个 Skill**。→ 形态 A（完全不触发）。进入发现层诊断。

### 第 2 步：发现层——它进索引了吗？

```
/skills
```

列表里**没有** `CSV2PDF` 或 `csv-to-pdf-table`。说明根本没被发现。用排查命令定位：

```bash
ls -la ~/.claude/skills/*/SKILL.md
```

发现三个问题，逐一修：

| 问题 | 诊断 | 修复 |
|------|------|------|
| 目录名 `CSV_to_PDF` 含大写下划线 | 不符合 kebab-case 规范 | 改为 `csv-to-pdf-table` |
| frontmatter `name: CSV2PDF` 与目录名不符 | 发现失败 | 改为 `name: csv-to-pdf-table` |
| `description: helps with files` | 即便进索引也匹配不上 | 改写（见下） |

修复后的 frontmatter：

```yaml
---
name: csv-to-pdf-table
description: Converts a CSV file into a formatted PDF table. Use when the user asks to turn CSV data into a PDF, export a spreadsheet to PDF, or print CSV as a table document. Do NOT use for general file conversion or PDF reading.
---
```

重命名目录、改完 frontmatter 后，**新开会话**（旧会话的索引已缓存，必须重启）再 `/skills`——这次它出现了。

### 第 3 步：触发层——现在它会触发吗？

```
claude -p "把 sales.csv 转成 PDF 表格" --debug
```

在 debug 输出里搜索 `csv-to-pdf-table`，能看到它进入候选并最终被选中。✅ 触发层通过。

### 第 4 步：执行层——跑起来了吗？

被触发后，Claude 调用了 `convert.py`，但报错。读日志：

```bash
grep -n "csv-to-pdf-table\|convert.py\|error" ~/.claude/*.jsonl | tail -20
```

看到两类错误：

1. `ModuleNotFoundError: No module named 'fpdf'` —— 依赖缺失
2. `FileNotFoundError: 'data.csv'` —— 脚本写死文件名

独立复现确认：

```bash
cd ~/.claude/skills/csv-to-pdf-table
python3 scripts/convert.py; echo "exit: $?"
# ModuleNotFoundError
```

修复脚本——参数化 + 在 SKILL.md 声明依赖：

```python
#!/usr/bin/env python3
import csv, sys, os
from fpdf import FPDF

def convert(csv_path, pdf_path):
    if not os.path.exists(csv_path):
        sys.exit(f"input not found: {csv_path}")
    with open(csv_path) as f:
        rows = list(csv.reader(f))
    pdf = FPDF()
    pdf.add_page()
    pdf.set_font("Helvetica", size=8)
    for row in rows:
        pdf.cell(0, 6, " | ".join(row)[:120], ln=True)
    pdf.output(pdf_path)
    print(f"wrote {pdf_path}")

if __name__ == "__main__":
    convert(sys.argv[1], sys.argv[2])
```

在 SKILL.md 正文补依赖与调用约定：

```markdown
## Prerequisites
Run once: `pip install fpdf2`

## Steps
1. cd to this skill directory.
2. Run: `python3 scripts/convert.py <input.csv> <output.pdf>`
3. Report the output path to the user.
```

### 第 5 步：回归盲测

准备 12 条提示词（6 条应触发、6 条不应触发），统计：

| 指标 | 修复前 | 修复后 |
|------|--------|--------|
| 命中率（应触发） | 0/6 | 6/6 |
| 误触发率 | — | 0/6 |
| 执行成功率 | — | 6/6 |

全绿，Skill 救活。

---

## Mermaid 流程图：四层故障定位决策树

```mermaid
flowchart TD
    Start([Skill 失效]) --> Q1{在 /skills 列表里吗?}
    Q1 -->|否| L1[发现层: 排查目录名/文件名/frontmatter]
    L1 --> Fix1[改 kebab-case 目录 + name 一致 + description 合法]
    Fix1 --> Restart[重启会话重测]
    Restart --> Q1

    Q1 -->|是| Q2{被触发了吗?<br/>看 --debug}
    Q2 -->|否/乱触发| L2[触发层: 审查 description]
    L2 --> Q2a{问题描述过窄/过宽?}
    Q2a -->|过窄| Fix2a[扩写触发词与场景]
    Q2a -->|过宽| Fix2b[加反向约束 Do NOT use]
    Fix2a --> Blind[盲测集回归]
    Fix2b --> Blind

    Q2 -->|是| Q3{执行符合正文吗?}
    Q3 -->|否| L3[执行层-语义: 正文太长/有矛盾/缺输出格式]
    L3 --> Fix3[前置关键步骤, 下沉背景到 references/]
    Fix3 --> Blind

    Q3 -->|是但报错| L4[执行层-确定性: 读 ~/.claude 日志]
    L4 --> Solo[脱离 Claude 单独跑脚本复现]
    Solo --> Q4{错误类型?}
    Q4 -->|路径错误| Fix4a[相对路径化]
    Q4 -->|权限被拒| Fix4b[settings.json 放行]
    Q4 -->|依赖缺失| Fix4c[补 Prerequisites]
    Fix4a --> Verify
    Fix4b --> Verify
    Fix4c --> Verify
    Verify[独立运行 exit 0] --> Done([固化回归测试])
    Blind --> Done
    Fix3 --> Blind
```

---

## 延伸阅读

- **Claude Code 官方 Skills 文档**（`code.claude.com/docs/en/skills`）—— frontmatter 规范、渐进披露机制、作用域权威说明
- **Skill authoring best practices**（`platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices`）—— `name`/`description` 字段的官方约束与范例
- **Claude Code 2.1 Cheatsheet**—— `/skills`、`--debug`、`--verbose` 等 CLI 标志速查
- **Debugging and Diagnostics（claude-code-best-practice, DeepWiki）**—— `~/.claude` 日志结构与权限回放
- **Claude Code Skills: A Practical 2026 Guide（Nimbalyst）**—— 何时用 Skill vs MCP vs Subagent 的决策框架

---

## 训练营适用性评估

- **适合训练营类型**：中高级开发者训练营、AI 工程化实战营、企业内部 Claude Code 推广营。不适合纯零基础（需先有"能写出第一个 Skill"的前置课）。
- **建议前置课**：Round 1 入门篇 + "从零创建一个自定义 Skill"。
- **预计教学时长**：理论讲授 60 分钟 + 实战案例动手 90 分钟 + 学员自带 Skill 互诊 60 分钟，合计约 3.5 小时。
- **教学产出物**：每位学员带走一份"我的 Skill 调试检查清单"（即本文四层法表格）+ 一个修复后的可用 Skill。
- **延伸练习建议**：让学员两两交换各自的 Skill，互相当"用户"做盲测，统计命中率——这是体会触发层微妙性最有效的方式。

---

## 参考来源

1. [Extend Claude with skills — Claude Code Docs](https://code.claude.com/docs/en/skills) — 官方 Skill 体系文档，涵盖 frontmatter 规范、渐进披露、作用域与内置 Skill
2. [Skill authoring best practices — Claude API Docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices) — `name`/`description` 字段的官方约束与高质量范例
3. [Debugging Claude Code: Techniques for Skill Development — AI Skill Market](https://aiskill.market/blog/claude-code-debugging-techniques) — Skill 开发的系统化调试技术，含日志策略与常见错误模式
4. [Debugging and Diagnostics — claude-code-best-practice (DeepWiki)](https://deepwiki.com/shanraisihan/claude-code-best-practice/10.3-debugging-and-diagnostics) — `~/.claude` 日志结构、调试工具与诊断流程
5. [Claude Code Skills: A Practical 2026 Guide — Nimbalyst](https://nimbalyst.com/blog/claude-code-skills-guide/) — Skill vs MCP vs Subagent 决策框架与配置模式
6. [Claude Code 2.1 Cheatsheet (2026) — Awesome Claude](https://awesomeclaude.ai/code-cheatsheet) — `/skills`、`--debug`、`--verbose` 等 CLI 标志与命令速查

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