<!-- title: 造Mock数据Skill：一键填充测试数据 -->

# Claude Code Skills 开发实战：从零造一个 Mock 数据生成 Skill

## 概述

本教程面向已装通 Claude Code、想掌握 Skills 开发全流程的开发者。你将从零创建一个**Mock 数据生成 Skill**——输入一个数据结构描述，Claude 自动产出符合约束的假数据（姓名、身份证、手机号、订单、嵌套对象、数组），并学会 SKILL.md frontmatter 的触发词设计、渐进披露（progressive disclosure）、脚本捆绑、权限收敛、触发准确性测试与团队分享。学完你能把任意重复性工作封装成"一句话触发"的能力，而不是每次都重写提示词。

## 前置条件

- 已安装 Claude Code（`claude` 命令可用，版本 ≥ 1.0.x，2026 年版）
- 一个可运行的项目目录（Node.js 或 Python 任一即可，本文用 Python，零额外依赖）
- 理解 Markdown 与 YAML 基本语法
- 终端能执行 `claude` 进入交互模式

---

## 一、先理解：Skill 到底是什么

很多人把 Skill、MCP、子代理（Subagent）混为一谈。一张表区分清楚：

| 能力载体 | 本质 | 何时加载 | 适合做什么 |
|---------|------|---------|-----------|
| **Skill** | 一个目录 + `SKILL.md` 指令包（可带脚本） | 触发时才读正文（渐进披露） | 教 Claude "怎么做某类事"的流程与约定 |
| **MCP 服务器** | 独立进程，暴露 tools/resources | 始终连接 | 给 Claude 新的"手"（外部 API、数据库） |
| **Subagent** | 独立上下文的代理实例 | 委派时启动 | 隔离上下文、并行处理大任务 |

Skill 最轻、最适合"把团队规范 / 重复套路固化下来"。它的杀手锏是**渐进披露**：

```mermaid
flowchart LR
    A["启动会话"] --> B["仅加载所有 Skill 的<br/>name + description"]
    B --> C{"用户输入<br/>是否匹配某 Skill？"}
    C -->|匹配| D["读取该 Skill 的 SKILL.md 正文"]
    C -->|不匹配| E["不加载，省 token"]
    D --> F{"正文是否引用<br/>脚本/参考文档？"}
    F -->|引用| G["按需读取 scripts/ references/"]
    F -->|不引用| H["直接执行"]
    G --> H
```

这意味着你的 Skill 可以塞进几千字的详细规则和几十个脚本，而**日常会话零开销**——因为正文只在被触发时才进上下文。理解这一点，你就不会再把所有规则堆进 CLAUDE.md 把全局上下文撑爆了。

Skill 存放位置有两种作用域：

- **个人级**：`~/.claude/skills/<skill-name>/SKILL.md` —— 跨所有项目可用
- **项目级**：`<project>/.claude/skills/<skill-name>/SKILL.md` —— 跟随仓库，团队共享（建议提交到 git）

---

## 二、步骤 1：用 skill-creator 生成脚手架

Claude Code 内置了 `skill-creator` 能力。最稳的起手式是直接让它帮你生成目录骨架，而不是手敲。

操作：在 Claude Code 交互模式里输入

```
/skill-creator 帮我创建一个名为 mock-data 的 Skill，作用是根据用户描述的数据结构生成贴近真实的 Mock 测试数据
```

预期结果：Claude 会在 `.claude/skills/mock-data/` 下生成：

```
.claude/skills/mock-data/
├── SKILL.md          # 主指令文件（含 frontmatter）
├── references/        # 可选：详细参考文档
└── scripts/           # 可选：可执行脚本
    └── gen_mock.py
```

> **常见问题**：生成的 `description` 太笼统（如 "生成 mock 数据"），导致触发不准。这正是下一步要重写的重点。

---

## 三、步骤 2：写好 frontmatter —— 整个 Skill 最关键的 5 行

frontmatter 不是装饰，它是 Claude 判断"要不要触发这个 Skill"的**唯一依据**（正文此时还没加载）。把 description 写废了，Skill 就永远沉睡。

打开 `SKILL.md`，把 frontmatter 改成：

```yaml
---
name: mock-data
description: Generate realistic mock/test data (Chinese names, IDs, phone numbers, addresses, nested JSON, arrays) from a data structure description. Use when the user needs fake sample data, test fixtures, seed data, dummy JSON for API development, or asks to "造点测试数据/生成假数据/mock 一下". Outputs deterministic, constraint-respecting data.
---
```

设计 description 的四条铁律：

1. **前两句话写"做什么 + 什么时候用"**：Claude 的触发匹配高度依赖开头。把动词和场景词放前面。
2. **塞进真实的触发词**：用户不会说"请生成符合约束的测试夹具"，他们会说"造点假数据"、"mock 一下"、"来几条测试用户"。把这些口语词写进去。
3. **声明输出特征**："deterministic, constraint-respecting" 告诉 Claude 期望的产出质量。
4. **同时覆盖中英文**：你的用户既可能英文也可能中文提问。

> **常见问题**："description 写得越详细越好吗？"——错。description 是给触发路由器看的，控制在 3-5 句。详细规则写进正文，正文不会参与初始匹配。

---

## 四、步骤 3：写 SKILL.md 正文 —— 用祈使句，像写给新同事的 SOP

正文是触发后才加载的"操作手册"。风格要像给一个聪明但不知情的新同事写的 SOP：直接、可执行、带例子。

```markdown
# Mock Data Generation

You generate realistic mock data that respects the user's stated constraints.
Do NOT hallucinate fields the user didn't ask for. When a field type is
ambiguous, ask one clarifying question, then proceed.

## Workflow

1. Parse the user's data structure description into a field list.
2. For each field, pick the most realistic generator (see references/field-types.md).
3. Respect constraints: count, uniqueness, value ranges, locale, format.
4. Output as the requested format (JSON / CSV / SQL INSERT / Python dict).
5. If count > 50, stream the output to a file instead of printing inline.

## Realism rules

- Chinese names: real-style surnames + given names, not "张三"/"李四" repeats.
- Phone numbers: start with valid Chinese prefixes (13x/15x/17x/18x/19x).
- ID numbers: valid checksum (use scripts/gen_mock.py --id to compute).
- Dates: spread across a plausible range, not all "2026-01-01".
- Money: realistic magnitude per domain (salary 5k–50k, not 999999).

## When to stop and ask

- If the user requests a field you cannot map to any generator.
- If two constraints conflict (e.g., "age between 0-3 AND employed").
- If output would exceed 200 rows — confirm the file path first.
```

注意几点：
- **祈使句开头**："Parse…", "Respect…", "Output…"，不要写 "你应该尽量…"
- **给边界**："count > 50 就写文件"、"冲突就停下来问"，把判断权显式化
- **反例约束**："不要重复张三李四"、"不要把日期都设成同一天"——告诉它**不要做什么**，比告诉它做什么更省事

---

## 五、步骤 4：捆绑脚本 —— 让 Skill 有真正的"手"

光靠 Claude 生成 ID 号的校验位很容易算错。把确定性的活交给脚本，Claude 只负责编排。在 `scripts/gen_mock.py` 写一个零依赖生成器：

```python
#!/usr/bin/env python3
"""Mock data generator. Zero external deps.
Usage: gen_mock.py --field id --count 5
       gen_mock.py --field phone --count 3
"""
import argparse, json, random, sys

SURNAME = list("王李张刘陈杨黄赵吴周徐孙马朱胡郭何高林罗")
GIVEN = ["伟","芳","娜","秀英","敏","静","丽","强","磊","洋",
         "艳","勇","军","杰","涛","明","超","秀兰","霞","平"]
PHONE_PREFIX = ["133","135","137","150","159","170","180","188","199"]

def gen_id():
    # Simplified 18-digit ID with valid-ish region + checksum
    region = random.choice(["110101","310115","440305","510107"])
    birth = f"{random.randint(1960,2008)}{random.randint(1,12):02d}{random.randint(1,28):02d}"
    seq = f"{random.randint(0,999):03d}"
    base = region + birth + seq
    # Weighted checksum (GB 11643-1999)
    w = [7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2]
    code = "10X98765432"
    s = sum(int(d)*wi for d, wi in zip(base, w))
    return base + code[s % 11]

def gen_name():
    return random.choice(SURNAME) + "".join(random.sample(GIVEN, random.randint(1,2)))

def gen_phone():
    return random.choice(PHONE_PREFIX) + "".join(str(random.randint(0,9)) for _ in range(8))

GENERATORS = {"id": gen_id, "name": gen_name, "phone": gen_phone}

if __name__ == "__main__":
    p = argparse.ArgumentParser()
    p.add_argument("--field", required=True)
    p.add_argument("--count", type=int, default=1)
    args = p.parse_args()
    fn = GENERATORS.get(args.field)
    if not fn:
        sys.exit(f"unknown field: {args.field}")
    print(json.dumps([fn() for _ in range(args.count)], ensure_ascii=False))
```

然后在 SKILL.md 正文里告诉 Claude 怎么用：

```markdown
## Using the bundled script

For ID numbers, phone numbers, and names, prefer calling the bundled script
to guarantee format validity:

    python3 scripts/gen_mock.py --field id --count 10
    python3 scripts/gen_mock.py --field phone --count 5

Compose the script's output into the larger structure the user asked for.
Do NOT hand-compute ID checksums — always delegate to the script.
```

这是 Skill 区别于普通提示词的核心价值：**把确定性的、容易出错的计算固化成代码，把语义理解交给模型**。

> **常见问题**：脚本路径用相对还是绝对？SKILL.md 里写相对路径（`scripts/gen_mock.py`），Claude 运行时会解析到 Skill 目录下，团队 clone 仓库后无需改路径。

---

## 六、步骤 5：渐进披露 —— references/ 装详细规则

正文保持精炼，把"各字段怎么生成"的查表式细节挪进 `references/field-types.md`，只在需要时加载：

```markdown
# references/field-types.md

| 字段语义 | 生成策略 | 示例 |
|---------|---------|------|
| email | 拼音名+域名，域名随机自 gmail/qq/163 | `wangwei88@qq.com` |
| address | 省+市+区+随机街道门牌 | `广东省深圳市南山区科技园路1号` |
| company | 行业词+公司类型 | `星河科技有限公司` |
| price | 按商品类目量级 | 电子产品 99–9999，生鲜 1–200 |
| timestamp | 最近 N 天内随机 ISO8601 | `2026-06-14T03:21:00Z` |
| boolean | 0.3–0.7 比例 True | `true` |
| enum | 从用户给的候选集随机 | `["active","pending","closed"]` |
```

正文里引用：

```markdown
For the full field-type mapping table, consult references/field-types.md
when you encounter a field type not covered in the realism rules above.
```

这就是渐进披露的二层结构：frontmatter（总在）→ SKILL.md 正文（触发时在）→ references（按需在）。上下文成本随深度递减，能力却随深度递增。

---

## 七、步骤 6：测试触发准确性 —— 正反例对照

Skill 写完不算完，必须验证它在**该触发时触发、不该触发时安静**。开新会话，跑正反例：

**应当触发的输入（期望命中）：**
- "帮我 mock 10 条用户数据，要有姓名手机号身份证"
- "造点测试数据，订单表，50 行"
- "generate 5 fake user records with nested address"
- "接口联调缺数据，给我点假的 JSON"

**不应触发的输入（期望不命中）：**
- "解释一下这段代码"（代码理解，无关）
- "帮我写个单元测试"（已有专门的单测 Skill）
- "mock 一下这个类"（"mock" 在这里是测试替身，不是数据——若误触发，回到 description 加否定词："Do NOT trigger for test doubles / mocking classes / mock objects in unit tests; this skill only generates fake DATA."）

> **常见问题**：调试触发最有效的办法——直接问 Claude："刚才那条输入，你为什么没/为什么用了 mock-data Skill？" 它会复述自己匹配到的关键词，据此微调 description。

---

## 八、步骤 7：用 allowed-tools 收敛权限

如果这个 Skill 只需要读描述、跑脚本、写文件，就别让它碰别的。在 frontmatter 加：

```yaml
---
name: mock-data
description: ...
allowed-tools: Read, Write, Bash(python3 scripts/gen_mock.py:*)
---
```

`Bash(python3 scripts/gen_mock.py:*)` 是关键——只允许执行这一个脚本及其任意参数，杜绝 Skill 顺手跑别的命令。这把"教 Claude 怎么做"和"限定它能做什么"结合，遵循最小权限原则。

---

## 九、实战案例：一句话产出 1000 行订单测试数据

最终目录结构：

```
.claude/skills/mock-data/
├── SKILL.md
├── references/
│   └── field-types.md
└── scripts/
    └── gen_mock.py
```

在新会话里输入一句话：

> 给我 1000 条订单测试数据，字段：订单号、买家姓名、手机、收货地址、商品名、单价、数量、下单时间（近 30 天）、状态(paid/shipped/done)。输出 JSON 数组存到 orders.json。

Claude 的执行路径：

```mermaid
sequenceDiagram
    participant U as 用户
    participant C as Claude Code
    participant S as mock-data Skill
    participant P as gen_mock.py
    U->>C: 一句话需求
    C->>S: 命中 mock-data 触发词<br/>加载 SKILL.md
    S->>C: 返回 workflow + 调用规则
    C->>P: Bash: gen_mock.py --field phone --count 1000
    P-->>C: 返回合规手机号数组
    C->>P: Bash: gen_mock.py --field id --count 1000
    P-->>C: 返回合规身份证数组
    C->>C: 组装商品/地址/时间/状态<br/>(查 references/field-types.md)
    C->>U: 写入 orders.json (1000 行)
    C->>U: 汇总：字段、约束、行数
```

预期产出（截取）：

```json
[
  {"order_id":"ORD-20260710-0001","buyer":"陈艳霞","phone":"137xxxx2841",
   "address":"广东省深圳市南山区科苑南路8号","item":"无线蓝牙耳机",
   "unit_price":199,"qty":2,"ts":"2026-06-22T11:03:00Z","status":"paid"},
  {"order_id":"ORD-20260710-0002","buyer":"林涛","phone":"188xxxx7710",
   "address":"北京市海淀区中关村大街1号","item":"机械键盘",
   "unit_price":459,"qty":1,"ts":"2026-07-01T08:45:00Z","status":"shipped"}
]
```

对比"不写 Skill、每次手动提示"：以前你要反复说明字段格式、手机号规则、价格量级，现在一句话搞定，且身份证/手机号格式由脚本保证永远合规。这就是 Skill 的复利——**写一次，用无数次，每次质量稳定**。

---

## 十、进阶：分享、版本与团队落地

- **分享**：把 `.claude/skills/mock-data/` 提交到仓库，队友 clone 即生效；或打包成 plugin 放进 `.claude/plugins/` 供跨项目安装。
- **版本**：frontmatter 可加 `version: 1.0.0`，变更时升版本号并在 references/ 留 changelog。
- **组合**：mock-data 可与已有的"单测 Skill"联动——先生成 Mock 数据，再喂给单测 Skill 造用例，形成测试数据→测试用例的流水线。
- **反模式**：别把十几个不相关的生成逻辑塞进一个 Skill。一个 Skill 一个职责，宁可多建几个小的，也不要造一个臃肿的"万能生成器"——那样 description 写不清楚，触发永远不准。

---

## 延伸阅读

- Claude Code 官方 Skills 文档：`https://code.claude.com/docs/en/skills` —— frontmatter 字段、发现规则、调用机制的权威定义
- Skills vs MCP vs Subagents 对比：`https://duet.so/guides/claude-code-skills-complete-guide` —— 何时该用哪种扩展方式
- SKILL.md frontmatter 全字段参考：`https://allahabadi.dev/blogs/ai/claude-code-skills-frontmatter-complete-guide/` —— 十五个支持字段的逐项说明
- 用 skill-creator 脚手架实战：`https://techsy.io/en/blog/claude-skills-tutorial` —— 从零构建首个 Skill 的完整流程

---

## 训练营适用性评估

- **适合类型**：中高级开发者训练营、企业内部 Claude Code 推广营、测试/QE 工程师提效营
- **前置门槛**：需先完成 Round 1 入门篇（装通 Claude Code、理解会话循环）
- **预计教学时长**：2.5–3 小时（讲解 45 min + 跟做 90 min + 触发调试 30 min）
- **作业建议**：每位学员针对自己业务再造一个 Skill（如造 SQL 种子数据 Skill、造 API 文档 Skill），并提交正反例触发测试结果
- **进阶衔接**：本教程为 Round 3（MCP 服务器开发）打底——Skill 管"流程"，MCP 管"外部能力"，下一轮把两者组合起来

---

## 参考来源

1. [Extend Claude with skills — Claude Code Docs](https://code.claude.com/docs/en/skills) — 官方权威：Skill 文件格式、frontmatter 字段、发现与调用规则
2. [Claude Code Skills Complete Guide: SKILL.md, MCP, Subagents & Teams (2026)](https://duet.so/guides/claude-code-skills-complete-guide) — Skills 与 MCP/Subagents 的全景对比与渐进披露机制解析
3. [Claude Code Skill Frontmatter: Every YAML Option Explained](https://allahabadi.dev/blogs/ai/claude-code-skills-frontmatter-complete-guide) — 十五个 frontmatter 字段的逐项语义与最佳实践
4. [Claude Skills Tutorial: Build Your First Skill — TECHSY](https://techsy.io/en/blog/claude-skills-tutorial) — 从零构建首个 Skill 的实操教程与 skill-creator 用法
5. [Claude Code Skills Setup Guide (2026)](https://padawanabhi.de/blog/claude-code-skills-setup-guide-en) — SKILL.md、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)
