本教程带你从零造一个带脚本的"计算型"Skill——CSV 数据画像工具。学完你能掌握 Skill 的两种核心形态差异、frontmatter 全字段、scripts/ 目录与 ${CLAUDE_SKILL_DIR} 变量、渐进式披露、allowed-tools 预授权、热加载与 skill-creator 评测闭环。适合已跑通过首个 Claude Code 项目、想进阶把重复数据处理流程封装成可复用能力的开发者。
${CLAUDE_PROJECT_DIR}、disableSkillShellExecution 等较新特性)很多人第一次写 Skill,只会写一个 SKILL.md 里全是"分析代码、列风险"的提示词——这叫纯指令型 Skill。它依赖模型当场推理,遇到要算的活儿(统计分布、聚合、排序)既慢又容易算错。
真正强大的 Skill 是计算型 Skill(bundled-script skill):SKILL.md 只当"导航员",告诉模型何时该跑、跑哪个脚本、怎么读结果;重活儿全交给 scripts/ 下的可执行脚本。模型负责编排和解读,脚本负责精确计算。
┌─────────────────────────────────────────────┐
│ Skill 两种形态对比 │
├──────────────────┬──────────────────────────┤
│ 纯指令型 │ 计算型(本教程) │
├──────────────────┼──────────────────────────┤
│ 只有 SKILL.md │ SKILL.md + scripts/*.py │
│ 模型全程推理 │ 脚本精确计算,模型解读 │
│ 适合规则/规范 │ 适合统计/转换/生成 │
│ 计算易出错 │ 结果可复现 │
└──────────────────┴──────────────────────────┘
数据画像这种活儿——算每列空值率、基数、最大最小、高频值——天然属于计算型。交给模型逐格数会又慢又错,写个脚本秒出报告才是正解。
Skill 是一个目录,SKILL.md 是入口,其余按需挂载。先想清楚再动手:
csv-profiler/
├── SKILL.md # 入口:导航 + 触发说明(必填)
├── scripts/
│ └── profile.py # 核心计算脚本(执行的,不是读进上下文的)
├── reference/
│ └── metrics.md # 各指标详细定义(按需加载)
└── examples/
└── sample-report.md # 期望输出的样例
关键原则:SKILL.md 保持精简(官方建议 500 行以内),重材料拆到独立文件,并在导航里写清"什么时候去读哪个文件"。这就是渐进式披露(progressive disclosure)——默认只把 description 塞进上下文,正文和附件只在被触发时才加载,闲时几乎零成本。
frontmatter 是 YAML,夹在两个 --- 之间。字段几乎都可选,但 description 强烈建议写好——它是模型决定是否加载本 Skill 的唯一依据。新建 ~/.claude/skills/csv-profiler/SKILL.md:
---
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 体检报告。全程用标准库,零依赖:
#!/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 装在个人级、项目级还是插件级都能正确解析,所以脚本路径绝不写死:
## 任务
对用户给出的 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 的地方。
csv-profiler 目录放到 ~/.claude/skills/(个人级,所有项目可用)或项目 .claude/skills/(仅本项目)。SKILL.md 立即生效。orders.csv";
- 手动触发:/csv-profiler orders.csv。预期结果:模型先跑脚本拿到表,再补一段异常点评,全程 python3 不弹权限确认(因 allowed-tools 已预授权)。
常见问题:脚本路径报"找不到文件"?检查正文里是不是漏了
${CLAUDE_SKILL_DIR}、写成了相对路径scripts/profile.py——相对路径会以当前工作目录解析,跨目录就崩。
Skill 能触发 ≠ 它做对了事。官方推荐用 skill-creator 插件做对照基线测试:
/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:
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 适合做分组维度。一份本要人工翻半小时的脏表,秒级出结论。
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
${CLAUDE_SKILL_DIR}、动态注入):code.claude.com/docs/en/skills${CLAUDE_SKILL_DIR}、动态上下文注入、bundled-script 模式(codebase-visualizer 示例)与 skill-creator 评测的权威来源scripts/ 挂载、渐进式披露保持上下文低成本的进阶架构讲解[!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 等场景全覆盖。
