<!-- title: 造注释补全Skill：裸函数秒变自解释 -->

# 造注释补全Skill：裸函数秒变自解释

> 一份从零到发布的 Claude Code Skill 实战教程，带完整脚本、渐进式披露设计与可复现案例。

## 概述

本教程带你从零创建一个名为 **comment-doctor** 的自定义 Skill：它扫描项目源代码，精确定位缺失文档注释的函数、方法与类，再按目标语言规范（Python docstring、JSDoc、GoDoc、JavaDoc）生成准确的中文注释并写回文件。学完你将掌握 Skill 的目录结构、`SKILL.md` 元数据写法、渐进式披露（Progressive Disclosure）三层架构，以及如何用挂载脚本把"凭感觉分析"升级为"可量化、可复核"的工程化能力。适用人群：已跑通 Claude Code 并能创建项目的开发者，希望把重复性文档工作沉淀为团队可复用资产的人。

## 前置条件

- 已安装 Claude Code CLI（`claude --version` 可正常输出版本号）
- 本机装有 Python 3.9+（脚本用 `ast` 标准库做静态解析，无需第三方依赖）
- 一个用于测试的真实代码目录（任何含若干无注释函数的 Python/JS 项目均可）
- 了解 YAML 基本语法与 Markdown

---

## 第 1 步：理解 Skill 的本质——三层渐进式披露

在动手之前，必须先吃透 Skill 区别于"一段提示词"的核心设计：**渐进式披露（Progressive Disclosure）**。它的工程动机很朴素——上下文窗口是稀缺资源，不该把所有指令一股脑塞进去。

Skill 把信息分成三个加载层级：

```mermaid
flowchart TD
    A[用户提问/命令] --> B{Tier 1: 仅读 frontmatter description}
    B -->|不相关| C[不加载, 零成本]
    B -->|相关| D[Tier 2: 加载 SKILL.md 正文]
    D --> E[执行任务]
    E -->|需要细规范| F[Tier 3: 按需加载 references/ 脚本]
    F --> E
    style B fill:#fef3c7
    style D fill:#dbeafe
    style F fill:#dcfce7
```

| 层级 | 内容 | 何时加载 | 成本 |
|------|------|----------|------|
| Tier 1 | frontmatter 的 `description` | 每次对话都读 | 极低 |
| Tier 2 | `SKILL.md` 正文指令 | 仅当 Skill 被判定相关并触发 | 中 |
| Tier 3 | `references/`、`scripts/` 等附属文件 | 正文指令显式要求时才读 | 按需 |

这条铁律直接影响成败：**`description` 写不好，Skill 永远不会被触发；正文写太长，每次触发都浪费上下文**。后面每一步都围绕这条铁律展开。

## 第 2 步：创建 Skill 目录骨架

Claude Code 在两个位置查找 Skill：个人级 `~/.claude/skills/` 与项目级 `<repo>/.claude/skills/`。本教程选个人级，这样 comment-doctor 在任何项目里都能用。

Skill 的目录名必须与 `name` 字段一致，且用小写连字符（kebab-case）。一个自包含的 Skill 推荐结构如下：

```
~/.claude/skills/comment-doctor/
├── SKILL.md                      # 入口：元数据 + 正文指令
├── scripts/
│   └── find_undocumented.py      # Tier 3：静态扫描脚本
└── references/
    └── docstring-styles.md       # Tier 3：各语言注释风格规范
```

**操作命令**（在终端执行）：

```bash
mkdir -p ~/.claude/skills/comment-doctor/scripts
mkdir -p ~/.claude/skills/comment-doctor/references
```

**预期结果**：目录创建后，Claude Code 启动时会自动发现该 Skill 并把它的 `description` 注入可触发列表。你可以在会话里输入 `/` 或直接问"有没有补全注释的技能"来确认它已被识别。

**常见问题**：

- *目录建对了却没被识别？* 检查是否放在了 `~/.claude/skills/` 下而非误建到 `~/.claude/skill/`（少了个 s）；确认 `SKILL.md` 大小写正确，Windows 上尤其易错。
- *想只在某个项目里用？* 改放 `<repo>/.claude/skills/comment-doctor/`，并提交进 Git 供团队共享。

## 第 3 步：编写 SKILL.md——元数据是触发开关

`SKILL.md` 由两部分组成：顶部的 YAML frontmatter 与下方的正文指令。先看 frontmatter 的最小可用版本：

```yaml
---
name: comment-doctor
description: 扫描项目源代码，定位缺失文档注释的函数、方法与类，按目标语言规范（Python docstring、JSDoc、GoDoc、JavaDoc）生成准确的中文注释并写回文件。当用户要求"补全注释""给函数加文档""生成 docstring""让代码自解释"，或代码缺少文档时触发。
---
```

frontmatter 只有两个必填字段，但每一个都有硬约束：

| 字段 | 约束 | 写法要点 |
|------|------|----------|
| `name` | 最长 64 字符，须与目录名一致 | 全小写连字符，避免缩写歧义 |
| `description` | 最长 1024 字符 | **第三人称**，先说"做什么"，再列"何时触发"的关键短语 |

`description` 是整个 Skill 的命脉。Claude 仅凭它判断是否调用本 Skill，因此要"埋"进用户真实会说的高频短语（"补全注释""生成 docstring""让代码自解释"）。注意要用第三人称（"扫描…定位…"），不要写"我可以帮你"这类第一人称表述——那是反模式，会降低匹配准确率。

接着写正文指令。正文应聚焦"做什么 + 用什么工具做 + 边界在哪"，避免长篇大论：

```markdown
# Comment Doctor

## 何时使用
当用户希望为无注释的函数、方法、类补全文档注释时使用。语言涵盖 Python、JavaScript/TypeScript、Go、Java。

## 工作流程（务必按序）
1. **先扫描**：运行 `python3 ~/.claude/skills/comment-doctor/scripts/find_undocumented.py <目标路径>`，得到缺失注释的函数清单（JSON）。
2. **读上下文**：对清单中的每一项，读取该函数及其调用处的代码，理解真实行为，而非按函数名臆测。
3. **查规范**：按目标语言，参考 `references/docstring-styles.md` 中的格式样板生成注释。内容要准确反映实际逻辑（参数含义、返回值、副作用、抛出的异常）。
4. **写回文件**：用 Edit 工具把注释插入到函数定义正下方。每改完一个文件，向用户报告本次新增注释的函数数量。
5. **输出总结**：在会话末尾给出 Markdown 表格，列出已补全注释的文件与函数数。

## 边界（禁止行为）
- 不要修改函数体逻辑，只加注释。
- 不要生成显而易见的废话注释（如 `# 返回 a + b` 给 `def add(a, b): return a+b`）。如果函数确实简单，写一句总结即可，或主动跳过并说明。
- 不要为已经存在注释的函数重复添加。
```

正文刻意短小——把"各语言具体长什么样"这种细节挪到 Tier 3 的 `references/`，需要时才加载。

**常见问题**：

- *Skill 总是被错误触发（无关问题也调用）？* description 太宽泛。把"当…时触发"的短语收窄到具体场景。
- *Skill 该触发却没触发？* 描述里没有覆盖用户的真实措辞。补充同义短语，例如"加注释""写说明"。

## 第 4 步：编写挂载脚本——把"凭感觉"升级为"可量化"

Tier 2 正文只能让 Claude 读文件、靠理解来判断"哪些函数缺注释"，这在大型项目里既慢又不可靠。挂载脚本（Tier 3）的引入正是为了解决这个痛点：用确定性算法给出**精确清单**，Claude 据此逐个处理，可复核、可重跑。

创建 `~/.claude/skills/comment-doctor/scripts/find_undocumented.py`：

```python
#!/usr/bin/env python3
"""扫描源文件，输出缺失文档注释的函数/类清单（JSON）。
用法: python3 find_undocumented.py <path>
"""
import ast, json, sys, os

# 支持的扩展名 → 解析器（本脚本聚焦 Python；JS/TS 可用 tree-sitter 扩展）
SUPPORTED = {".py": "python"}
SKIP_DIRS = {"node_modules", ".git", "venv", ".venv", "__pycache__", "dist", "build"}

def find_py(path):
    """解析单个 Python 文件，返回缺 docstring 的函数/类。"""
    src = open(path, encoding="utf-8").read()
    tree = ast.parse(src)
    out = []
    for node in ast.walk(tree):
        if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
            if not ast.get_docstring(node):
                kind = "class" if isinstance(node, ast.ClassDef) else "function"
                out.append({"type": kind, "name": node.name,
                            "line": node.lineno, "file": path})
    return out

def walk(root):
    results = []
    for dp, dn, fn in os.walk(root):
        dn[:] = [d for d in dn if d not in SKIP_DIRS]   # 原地剪枝
        for f in fn:
            p = os.path.join(dp, f)
            if os.path.splitext(f)[1] in SUPPORTED:
                try:
                    results += find_py(p)
                except SyntaxError:
                    pass   # 跳过无法解析的文件
    return results

if __name__ == "__main__":
    root = sys.argv[1] if len(sys.argv) > 1 else "."
    print(json.dumps(walk(root), ensure_ascii=False, indent=2))
```

**运行预期结果**（对某个含无注释函数的目录执行）：

```json
[
  {"type": "function", "name": "calculate_tax", "line": 12, "file": "./billing/calc.py"},
  {"type": "class", "name": "OrderRepository", "line": 40, "file": "./billing/repo.py"}
]
```

这段脚本体现了三层设计的精髓：它独立于 Skill 体系，可单独测试、单独改进；Skill 正文只需说"运行它并处理清单"，把繁重的静态分析外包出去。

**常见问题**：

- *Python 脚本权限不够？* 脚本由 `python3 xxx.py` 调用，不依赖可执行位，无需 `chmod +x`。
- *想支持 JS/TS？* 把 `ast` 换成 `tree-sitter`，或调用项目已有的 `eslint`/`ts-doc` 插件输出未文档化清单，结构保持不变。

## 第 5 步：编写风格规范参考文件

创建 `~/.claude/skills/comment-doctor/references/docstring-styles.md`，这里集中存放每种语言的样板，正文只在需要时引导加载：

```markdown
# 文档注释风格规范

## Python（Google 风格 docstring）
"""计算含税金额。

Args:
    price: 不含税单价。
    rate: 税率，0~1 之间的小数。

Returns:
    含税后的总价。

Raises:
    ValueError: rate 超出 [0, 1] 时抛出。
"""

## JavaScript / TypeScript（JSDoc）
/**
 * 计算含税金额。
 * @param {number} price - 不含税单价。
 * @param {number} rate - 税率，0~1。
 * @returns {number} 含税总价。
 */

## Go（GoDoc，注释紧贴声明、以名字开头）
// CalculateTax 计算含税金额。price 为不含税单价，rate 为 0~1 的税率。
func CalculateTax(price float64, rate float64) float64 { ... }

## Java（JavaDoc）
/** 计算含税金额。
 * @param price 不含税单价
 * @param rate 税率，0~1
 * @return 含税总价
 */
```

把样板放进 Tier 3 而非正文，是因为它只在"生成注释"那一步才需要，提前加载纯属浪费上下文。

## 第 6 步：端到端测试

准备一个最小测试项目 `~/demo_shop/`，内含故意无注释的代码：

```python
# ~/demo_shop/billing.py
def apply_discount(price, pct):
    if pct < 0 or pct > 1:
        raise ValueError("pct 必须在 0~1")
    return price * (1 - pct)

class Cart:
    def add(self, sku, qty=1):
        self.items[sku] = self.items.get(sku, 0) + qty
```

在 Claude Code 会话里触发 Skill（自然语言即可）：

> 帮我把 ~/demo_shop/billing.py 里没注释的函数都补上文档。

**预期结果**：Claude 自动调用 comment-doctor，运行脚本得到清单，逐个生成注释并写回。最终 `billing.py` 变为：

```python
def apply_discount(price, pct):
    """对原价施加折扣。

    Args:
        price: 原价。
        pct: 折扣比例，0~1 之间（0.2 表示打 8 折）。

    Returns:
        折扣后的价格。

    Raises:
        ValueError: pct 不在 [0, 1] 区间时抛出。
    """
    if pct < 0 or pct > 1:
        raise ValueError("pct 必须在 0~1")
    return price * (1 - pct)

class Cart:
    """购物车，维护 SKU 到数量的映射。"""

    def add(self, sku, qty=1):
        """向购物车加入商品，已存在则累加数量。

        Args:
            sku: 商品唯一标识。
            qty: 本次添加数量，默认 1。
        """
        self.items[sku] = self.items.get(sku, 0) + qty
```

并给出类似总结表：

| 文件 | 新增注释函数/类 |
|------|----------------|
| `billing.py` | `apply_discount`、`Cart`、`Cart.add` |

**常见问题**：

- *Claude 没用脚本而是直接读文件？* 说明正文指令不够强硬。把第 1 步改为"**必须**先运行脚本"并强调"禁止凭函数名臆测"。
- *生成的注释是废话（`# 返回 apply_discount 结果`）？* 在边界条款里加一句"对简单包装函数允许跳过并说明"，并要求注释至少包含一个"非显而易见"的信息（如取值范围、副作用、异常）。

---

## 实战案例：给一个真实 Flask 项目批量补注释

把上述六步串成一个完整工作流，目标是一个 30+ 路由、文档缺失严重的 Flask 仓库。

1. **进入仓库**：`cd ~/my_flask_app`
2. **触发 Skill**：对 Claude 说"用 comment-doctor 扫描 app/ 目录，为所有缺失 docstring 的函数补注释，每改 5 个文件向我汇报一次"。
3. **Skill 自动执行**：
   - 跑 `find_undocumented.py app/`，假设命中 47 处；
   - 按文件分批，每批读上下文 → 查 `docstring-styles.md` → 用 Edit 写回 → 汇报；
   - 全程不碰业务逻辑，只增注释。
4. **校验**：`git diff --stat` 查看改动行数；`python -m compileall app/` 确认未引入语法错误；对抽样函数人工核对注释与逻辑是否一致。

整个案例的价值在于可复现：同样的脚本、同样的指令，换一个项目再跑一次，结果同样可信。这正是 Skill 相比"一次性提示词"的根本优势。

## 调优进阶：让 Skill 越用越准

```mermaid
flowchart LR
    U[真实使用] --> T[触发记录]
    T --> M{该触发时触发?}
    M -->|漏触发| D1[在 description 补同义短语]
    M -->|误触发| D2[收窄 description 场景]
    M -->|准| OK[保持]
    D1 --> U
    D2 --> U
    OK --> U
```

Skill 是"活"的资产，建议建立调优闭环：

- **收集失败案例**：把"该触发没触发"和"不该触发却触发"的真实对话记下来。
- **迭代 description**：针对漏触发，补充用户实际措辞；针对误触发，删掉过于宽泛的词。
- **回归脚本**：每次改完 Skill，用第 6 步的 demo 项目重跑，确保输出稳定。
- **版本化**：把 `~/.claude/skills/` 整体纳入一个 Git 仓库，团队成员克隆即用。

## 延伸阅读

- **官方 Agent Skills 总览**：`https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview`——理解 Skill 在整个 Agent 体系中的定位。
- **Skill 编写最佳实践**：`https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices`——frontmatter 字段约束与正文写作准则的权威来源。
- **anthropics/skills 仓库**：`https://github.com/anthropics/skills`——官方维护的 Skill 样例集，每个都是自包含文件夹，是抄结构范式的最佳参考。
- **skill-creator 技能**：Claude Code 内置的"造技能的技能"，输入 `/skill-creator` 可交互式生成脚手架，适合不想手写目录的人。

## 训练营适用性评估

| 维度 | 评估 |
|------|------|
| 适合的训练营类型 | AI 工程化实战营、研发效能提升营、Claude Code 专项训练营 |
| 学员基础要求 | 会用命令行、读过 YAML、写过任意一门后端语言 |
| 预计教学时长 | 讲解 + 跟练 90 分钟，独立完成实战案例另需 60 分钟 |
| 可交付成果 | 每位学员带走一个可运行、可复用的个人 Skill，并能套用到自己项目 |
| 进阶衔接 | 学完后可衔接"造量化基准测试体系""调优 Skill 描述"等专题，深化测试与触发优化 |

本教程把 Skill 的元数据、目录结构、渐进式披露三层与脚本挂载四个要点，全部压缩进一个能立刻用、能反复跑的真实技能里。掌握 comment-doctor 的搭建路径，你就掌握了造任何自定义 Skill 的通用方法。

## 参考来源

1. [Skill authoring best practices — Claude Platform Docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices) — 官方权威，规定 `name`/`description` 字段约束与正文写作准则。
2. [Agent Skills — Overview](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) — Skill 在 Agent 与工具体系中的定位与三原语概念。
3. [anthropics/skills — GitHub](https://github.com/anthropics/skills) — 官方 Skill 样例仓库，每个技能自包含于独立文件夹，是目录结构的最佳范式来源。
4. [Claude Code Skills 2026 — Progressive Disclosure](https://anhtu.dev/claude-code-skills-2026-progressive-disclosure-and-how-to-standardise-workflow-for-engineering-teams-1062) — 团队工程化视角下的三层渐进式披露深度解读。
5. [Anatomy of a Skill — Vercel Academy](https://vercel.com/academy/agent-friendly-apis/anatomy-of-a-skill) — SKILL.md 解剖与 YAML frontmatter 各字段含义。

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