<!-- title: 造CSV数据画像Skill：脚本Skill秒出体检报告 -->

## 概述

本教程带你从零造一个**带脚本的"计算型"Skill**——CSV 数据画像工具。学完你能掌握 Skill 的两种核心形态差异、frontmatter 全字段、`scripts/` 目录与 `${CLAUDE_SKILL_DIR}` 变量、渐进式披露、`allowed-tools` 预授权、热加载与 skill-creator 评测闭环。适合已跑通过首个 Claude Code 项目、想进阶把重复数据处理流程封装成可复用能力的开发者。

## 前置条件

- Claude Code v2.1.196 或更高（用到 `${CLAUDE_PROJECT_DIR}`、`disableSkillShellExecution` 等较新特性）
- 本机已装 Python 3（脚本仅用标准库，无需 pip）
- 一个含 CSV 文件的目录用于测试，或随手造一个样本
- 了解 Markdown 与 YAML 基本语法

---

## 一、先想清楚：你要的是哪种 Skill

很多人第一次写 Skill，只会写一个 `SKILL.md` 里全是"分析代码、列风险"的提示词——这叫**纯指令型 Skill**。它依赖模型当场推理，遇到要算的活儿（统计分布、聚合、排序）既慢又容易算错。

真正强大的 Skill 是**计算型 Skill（bundled-script skill）**：`SKILL.md` 只当"导航员"，告诉模型何时该跑、跑哪个脚本、怎么读结果；重活儿全交给 `scripts/` 下的可执行脚本。模型负责编排和解读，脚本负责精确计算。

```
┌─────────────────────────────────────────────┐
│  Skill 两种形态对比                          │
├──────────────────┬──────────────────────────┤
│ 纯指令型         │ 计算型（本教程）          │
├──────────────────┼──────────────────────────┤
│ 只有 SKILL.md    │ SKILL.md + scripts/*.py   │
│ 模型全程推理      │ 脚本精确计算，模型解读    │
│ 适合规则/规范     │ 适合统计/转换/生成        │
│ 计算易出错        │ 结果可复现                │
└──────────────────┴──────────────────────────┘
```

数据画像这种活儿——算每列空值率、基数、最大最小、高频值——天然属于计算型。交给模型逐格数会又慢又错，写个脚本秒出报告才是正解。

## 二、规划目录结构

Skill 是一个目录，`SKILL.md` 是入口，其余按需挂载。先想清楚再动手：

```text
csv-profiler/
├── SKILL.md              # 入口：导航 + 触发说明（必填）
├── scripts/
│   └── profile.py        # 核心计算脚本（执行的，不是读进上下文的）
├── reference/
│   └── metrics.md        # 各指标详细定义（按需加载）
└── examples/
    └── sample-report.md  # 期望输出的样例
```

关键原则：**`SKILL.md` 保持精简（官方建议 500 行以内），重材料拆到独立文件，并在导航里写清"什么时候去读哪个文件"**。这就是渐进式披露（progressive disclosure）——默认只把 `description` 塞进上下文，正文和附件只在被触发时才加载，闲时几乎零成本。

## 三、写 frontmatter：决定"何时触发、谁能调用、给什么权限"

frontmatter 是 YAML，夹在两个 `---` 之间。字段几乎都可选，但 `description` 强烈建议写好——它是模型决定是否加载本 Skill 的唯一依据。新建 `~/.claude/skills/csv-profiler/SKILL.md`：

```yaml
---
name: csv-profiler
description: Profile a CSV file and produce a per-column data quality report.
  Use when the user asks to inspect, profile, audit, or understand a CSV
  dataset, or wants column stats, null rates, cardinality, or distributions.
  Triggers on phrases like "看看这个表", "数据画像", "字段体检", "missing rate".
argument-hint: [path-to-csv]
arguments: [file]
allowed-tools: Bash(python3 *)
disable-model-invocation: false
user-invocable: true
---
```

逐字段拆解（这是后续所有 Skill 都通用的"配置盘"）：

| 字段 | 作用 | 本例取值与理由 |
| :--- | :--- | :--- |
| `name` | 展示名，默认取目录名，不改变 `/` 后输入 | `csv-profiler` |
| `description` | 模型匹配触发的主依据；**关键用例放开头**，因为列表里会被截断到 1536 字符 | 写明"画像/体检/null 率"等触发词 |
| `argument-hint` | 自动补全时显示的参数提示 | `[path-to-csv]` |
| `arguments` | 命名位置参数，映射到 `$name` | `file`，于是正文可用 `$file` |
| `allowed-tools` | 技能激活期间免审批放行的工具 | `Bash(python3 *)`——免得每次跑脚本都弹确认 |
| `disable-model-invocation` | `true` 则只允许人手动 `/csv-profiler` 触发 | `false`，希望模型在聊到 CSV 时自动启用 |
| `user-invocable` | `false` 则从 `/` 菜单隐藏 | `true`，允许人手动触发 |

> 预期结果：保存后，在任何项目里聊到"帮我看看这个 CSV"时，模型应自动加载本 Skill；也可直接 `/csv-profiler data.csv` 调用。

**常见问题**：写了 Skill 却不触发？多半是 frontmatter YAML 写坏（缩进错、`:` 后没空格）。Claude Code 会静默用空元数据加载，`/csv-profiler` 仍能用，但模型没了 `description` 就匹配不上。用 `claude --debug` 启动可看到解析报错。

## 四、写核心脚本 `scripts/profile.py`

脚本只做一件事：吃一个 CSV 路径，吐结构化的 Markdown 体检报告。全程用标准库，零依赖：

```python
#!/usr/bin/env python3
"""CSV 列级数据画像：类型推断、空值率、基数、数值统计、高频值。"""
import csv
import sys
from collections import Counter
from pathlib import Path

def infer_type(values):
    nums, non_empty = 0, 0
    for v in values:
        if v == "" or v is None:
            continue
        non_empty += 1
        try:
            float(v); nums += 1
        except ValueError:
            pass
    if non_empty == 0:
        return "empty"
    return "numeric" if nums / non_empty > 0.8 else "text"

def profile(path):
    rows = list(csv.DictReader(open(path, encoding="utf-8-sig")))
    if not rows:
        return "## 报告\n\n（文件为空或无数据行）"
    cols = rows[0].keys()
    lines = [f"## 数据画像：`{Path(path).name}`\n",
             f"- 总行数：**{len(rows)}**，列数：**{len(list(cols))}**\n",
             "| 列 | 类型 | 空值率 | 基数 | 高频值 / 范围 |",
             "|---|---|---|---|---|"]
    for c in rows[0].keys():
        vals = [r[c] for r in rows]
        n = len(vals)
        missing = sum(1 for v in vals if v == "" or v is None)
        non_empty = [v for v in vals if v != "" and v is not None]
        ctype = infer_type(vals)
        card = len(set(non_empty))
        top = Counter(non_empty).most_common(3)
        if ctype == "numeric":
            nums = sorted(float(v) for v in non_empty)
            scope = f"min {nums[0]:g} / max {nums[-1]:g}"
        else:
            scope = "; ".join(f"{k}({ct})" for k, ct in top)
        lines.append(f"| `{c}` | {ctype} | {missing/n:.1%} | {card} | {scope} |")
    return "\n".join(lines)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("用法: profile.py <csv路径>"); sys.exit(1)
    print(profile(sys.argv[1]))
```

**预期结果**：终端 `python3 profile.py sample.csv` 直接打印一张 Markdown 表，空值率、基数、数值范围一目了然。

**常见问题**：中文 CSV 用 Excel 另存的常带 BOM，故 `open(..., encoding="utf-8-sig")`；GBK 编码可在脚本里加个 `try/except` 兜底回退 `gb18030`。

## 五、写导航层正文：把脚本"挂"上去

frontmatter 下方写正文。核心是用 `${CLAUDE_SKILL_DIR}` 引用脚本——这个变量在运行时会被替换为 `SKILL.md` 所在目录，**无论 Skill 装在个人级、项目级还是插件级都能正确解析**，所以脚本路径绝不写死：

```markdown
## 任务

对用户给出的 CSV（路径在 $file，若未提供则先问用户要路径）生成列级数据画像。

## 步骤

1. 跑画像脚本，拿到结构化报告：
   ```bash
   python3 ${CLAUDE_SKILL_DIR}/scripts/profile.py "$file"
   ```
2. 把脚本输出的表格原样呈现给用户。
3. 针对**异常列**追加自然语言点评：空值率 >50% 的列提示"考虑删除或补全"；
   基数=1 的常量列提示"无信息量"；文本列基数接近行数提示"可能是 ID"。

## 何时不该用

- 文件不是 CSV（xlsx/json）→ 先转 CSV 或换工具
- 列数 >500 → 提醒用户可能需采样

## 附加资源
- 各指标精确定义见 [reference/metrics.md](reference/metrics.md)
- 期望输出样例见 [examples/sample-report.md](examples/sample-report.md)
```

注意 `reference/` 和 `examples/` 默认不进上下文，只在模型判断需要时才被读取——这正是渐进式披露省 token 的地方。

## 六、安装、热加载与触发测试

1. 把 `csv-profiler` 目录放到 `~/.claude/skills/`（个人级，所有项目可用）或项目 `.claude/skills/`（仅本项目）。
2. **无需重启**：Claude Code 实时监听 Skill 目录变化，改 `SKILL.md` 立即生效。
3. 两种测试方式：
   - 自动触发：在新会话里说"帮我体检一下 `orders.csv`"；
   - 手动触发：`/csv-profiler orders.csv`。

**预期结果**：模型先跑脚本拿到表，再补一段异常点评，全程 `python3` 不弹权限确认（因 `allowed-tools` 已预授权）。

> 常见问题：脚本路径报"找不到文件"？检查正文里是不是漏了 `${CLAUDE_SKILL_DIR}`、写成了相对路径 `scripts/profile.py`——相对路径会以当前工作目录解析，跨目录就崩。

## 七、用 skill-creator 跑评测，量化"触发准不准"

Skill 能触发 ≠ 它做对了事。官方推荐用 `skill-creator` 插件做对照基线测试：

```text
/plugin install skill-creator@claude-plugins-official
/reload-plugins
evaluate my csv-profiler skill with skill-creator
```

它会引导你写一批"应该触发/不该触发"的提示词（如"这表有多少空"应触发、"帮我画个柱状图"不应触发），每个用例开独立子代理分别跑"有 Skill"和"无 Skill"两遍，对比通过率、耗时、token，输出 `benchmark.json`。还能对两个版本做盲测 A/B，确认改动是真改进再提交。

## 实战案例：体检一份脏数据订单表

准备 `orders.csv`：

```csv
order_id,customer,amount,status,note
1,张三,99.5,paid,
2,李四,,pending,
3,张三,250.0,paid,VIP
4,,12.0,paid,
5,王五,12.0,paid,
```

在会话里 `/csv-profiler orders.csv`，输出报告：

| 列 | 类型 | 空值率 | 基数 | 高频值 / 范围 |
|---|---|---|---|---|
| `order_id` | numeric | 0.0% | 5 | min 1 / max 5 |
| `customer` | text | 20.0% | 3 | 张三(2); 李四(1); 王五(1) |
| `amount` | numeric | 20.0% | 4 | min 12 / max 250 |
| `status` | text | 0.0% | 2 | paid(4); pending(1) |
| `note` | text | 80.0% | 2 | VIP(1) |

模型据此点评：`customer`、`amount` 各缺 1 行（20%）需补全或确认；`note` 空值率 80% 几乎无信息量，建议删除；`status` 基数 2 适合做分组维度。一份本要人工翻半小时的脏表，秒级出结论。

## 整体工作流程

```mermaid
flowchart TD
    A[用户: 帮我体检这个CSV] --> B{description 匹配?}
    B -- 是 --> C[加载 SKILL.md 正文进上下文]
    B -- 否 --> Z[不触发本Skill]
    C --> D[模型读导航层<br/>决定跑哪个脚本]
    D --> E["执行 python3<br/>${CLAUDE_SKILL_DIR}/scripts/profile.py<br/>(allowed-tools 免审批)"]
    E --> F[脚本输出结构化表格]
    F --> G[模型: 表格原样呈现<br/>+ 异常列自然语言点评]
    G --> H[用户拿到数据画像报告]
    I[skill-creator 评测] -.基准对比.-> B
    I -.A/B盲测.-> D
```

## 延伸阅读

- 官方 Skills 文档（frontmatter 全字段、`${CLAUDE_SKILL_DIR}`、动态注入）：code.claude.com/docs/en/skills
- 进阶架构（渐进式披露、脚本、子代理编排）：claude-with-skills.vercel.app/03-advanced
- Skill 输出质量评测与迭代工作流：agentskills.io/skill-creation/evaluating-skills
- Agent Skills 跨工具开放标准：agentskills.io
- 官方 skill-creator 插件与公告：github.com/anthropics/claude-plugins-official

## 训练营适用性评估

- **适合人群**：已过 Claude Code 入门、想从"用别人 Skill"升级到"造自己 Skill"的中级开发者；数据/运维/测试岗尤佳。
- **训练营类型**：2～3 天的"Claude Code 进阶工作坊"，作为"自定义能力封装"模块的核心实验；也可作为"数据治理训练营"的自动化环节。
- **预计教学时长**：讲授 45 分钟 + 动手实操 90 分钟（含造脚本、跑触发、写评测用例）。前置若有 Python 基础可压缩到 2 小时内完成。
- **可扩展作业**：让学生把脚本换成"JSON Schema 推断""日志聚合"等其它计算任务，复用同一 Skill 骨架，巩固"计算型 Skill"范式。

## 参考来源

1. [Extend Claude with skills — Claude Code 官方文档](https://code.claude.com/docs/en/skills) — frontmatter 全字段、`${CLAUDE_SKILL_DIR}`、动态上下文注入、bundled-script 模式（codebase-visualizer 示例）与 skill-creator 评测的权威来源
2. [Advanced: Progressive Disclosure, Bundled Scripts, and Subagent Orchestration](https://claude-with-skills.vercel.app/03-advanced/) — 把 SKILL.md 当"导航员"、`scripts/` 挂载、渐进式披露保持上下文低成本的进阶架构讲解
3. [Evaluating skill output quality — agentskills.io](https://agentskills.io/skill-creation/evaluating-skills) — Agent Skills 开放标准的评测文件格式与"有/无 Skill 基线对比"迭代工作流
4. [Claude Agent Skills: A Complete 2025 Developer Guide](https://devtoolhub.com/agent-skills-guide-claude/) — 对 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)
