本教程带你从零构建一个名为 impact-analyze 的自定义 Claude Code Skill,专门做改动影响面分析(blast-radius analysis):给定一个函数、类或文件,它自动定位所有调用方、定义点、相关测试,产出带风险评级的影响报告、建议的回归测试范围,以及一张 Mermaid 调用关系图。在构建过程中,你会一次性掌握 2026 年 Skill 体系的全部核心能力——SKILL.md 结构、YAML frontmatter、可执行脚本封装、动态上下文注入(!command`)、渐进披露(progressive disclosure)、参数替换、allowed-tools权限预授与、paths` 路径触发,以及 description 的触发调优。
适用人群:已经能用 Claude Code 完成日常编码、想从「粘贴提示词」升级到「沉淀可复用工作流」的开发者;尤其适合重构频繁、担心改动波及面的大型代码库维护者。
paths、动态注入等特性在该版本已稳定)。git 与 rg(ripgrep)可用。若没有 ripgrep,可改用 grep -rn,但速度差异明显,建议装上。在动手前,先回答一个问题:什么样的工作流值得封装成 Skill? 官方文档给了一个清晰的标准——
Create a skill when you keep pasting the same instructions, checklist, or multi-step procedure into chat, or when a section of CLAUDE.md has grown into a procedure rather than a fact.
提炼成三条判据:
CLAUDE.md 的核心优势:CLAUDE.md 常驻上下文,Skill 只在触发时加载。「改动影响面分析」完美命中这三条:每次重构前你都得找调用方、判断风险、圈定测试范围;它天然是多步骤(查引用 → 分类 → 评级 → 出图);而它的判定规则(什么算高风险、如何打分)属于「长参考材料」,平时不需要,重构时才用。选它做教学样本,是因为它能自然地逼出 Skill 的所有特性:需要脚本(grep 引用)、需要动态注入(把实时引用结果喂给模型)、需要渐进披露(风险评判规则独立成文件)、需要参数化(传入符号名)。
为避免膨胀,明确边界——它不负责:跨语言类型推断(交给 LLM 判断即可)、自动改代码(只做分析,不写 patch)、CI 集成(那是 hooks 的活)。Skill 越聚焦,description 越精准,触发越可靠。
动手前,先对齐几个容易被旧教程带偏的事实。
| 级别 | 路径 | 作用范围 |
|---|---|---|
| 个人级 | ~/.claude/skills/<name>/SKILL.md |
你的所有项目 |
| 项目级 | .claude/skills/<name>/SKILL.md |
仅当前项目 |
| 插件级 | <plugin>/skills/<name>/SKILL.md |
启用该插件处 |
同名时,个人级覆盖项目级;插件级带 plugin-name: 命名空间,不会冲突。
SKILL.md 是唯一必需的入口,其余文件按需放入,形成渐进披露结构:
impact-analyze/
├── SKILL.md # 主指令(必需,建议 < 500 行)
├── risk-rubric.md # 风险评判标准(按需加载)
├── report-template.md # 输出模板(按需加载)
└── scripts/
└── find-refs.sh # 可执行脚本(被执行,而非读入上下文)
关键区别:reference.md 这类文件是被读入上下文的(Claude 需要时主动 Read),scripts/ 下的脚本是被执行的(输出结果喂给 Claude,源码不进上下文)。后者省 token,适合任何「机械、确定、量大」的工作。
SKILL.md,当前会话即时生效,无需重启。注意:仅 SKILL.md 文本走热加载;若该目录同时是插件,hooks/、.mcp.json 等改动需 /reload-plugins。SKILL.md 内容作为单条消息进入对话并停留整个会话。压缩(auto-compaction)时会保留每个 Skill 最近一次调用的前 5,000 token,多个被调用 Skill 共享 25,000 token 预算,从最近调用的开始填。这意味着:Skill 正文每多一行都是反复的 token 成本——保持精简。impact-analyze Skill个人级(跨项目复用):
mkdir -p ~/.claude/skills/impact-analyze/scripts
如果是项目专属,改用仓库根目录下的 .claude/skills/impact-analyze/scripts。
把机械的 grep 工作交给脚本,让 LLM 只做它擅长的「分类与判断」。新建 ~/.claude/skills/impact-analyze/scripts/find-refs.sh:
#!/usr/bin/env bash
# find-refs.sh — locate references to a symbol across the repo
# Usage: find-refs.sh <symbol-or-path>
set -euo pipefail
SYMBOL="${1:-}"
if [[ -z "$SYMBOL" ]]; then
echo "ERR: no symbol provided"; exit 1
fi
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
echo "# Target: $SYMBOL"
echo "# Repo root: $ROOT"
echo
# 1. 文件级命中清单(用于判断波及面广度)
echo "## Files referencing '$SYMBOL'"
rg -l --no-heading "$SYMBOL" "$ROOT" 2>/dev/null | head -50 || true
echo
# 2. 命中密度 Top20(密度高 = 可能是核心调用点)
echo "## Match density (top 20 by file)"
rg -c --no-heading "$SYMBOL" "$ROOT" 2>/dev/null \
| sort -t: -k2 -rn | head -20 || true
echo
# 3. 疑似定义点(多语言常见定义关键字)
echo "## Candidate definitions"
rg -n --no-heading \
"(def |function |func |class |const |export (default )?function |interface )" \
"$ROOT" 2>/dev/null \
| rg "\b${SYMBOL}\b" | head -20 || true
echo
# 4. 命中该符号的测试文件(回归测试范围线索)
echo "## Test files touching '$SYMBOL'"
rg -l --no-heading "$SYMBOL" "$ROOT" \
-g '*test*' -g '*spec*' -g '*.test.*' 2>/dev/null | head -20 || true
赋予执行权限:
chmod +x ~/.claude/skills/impact-analyze/scripts/find-refs.sh
预期结果:在任意 git 仓库里运行 ~/.claude/skills/impact-analyze/scripts/find-refs.sh checkoutSession,会打印四段结构化文本——文件清单、密度排序、定义点候选、测试文件清单。这四段正是后续 LLM 评级所需的全部原始素材。
常见问题:
- rg: command not found → brew install ripgrep 或 apt install ripgrep;实在没有把 rg 换成 grep -rn(性能下降)。
- 仓库太大、命中上万行 → 脚本已用 head 截断,但若密度图被截断可放宽到 50。
SKILL.md(frontmatter + 动态注入)新建 ~/.claude/skills/impact-analyze/SKILL.md:
---
description: Analyze the blast-radius of a code change. Use when the user asks "who calls X", "what will this affect", "is it safe to change/rename/delete X", or before any refactor / rename / delete of a function, class, method, or constant. Produces a risk-rated impact report plus a Mermaid call graph.
argument-hint: <symbol or file path>
allowed-tools: Read Grep Glob Bash
---
## References to "$1"
!`${CLAUDE_SKILL_DIR}/scripts/find-refs.sh "$1"`
## Instructions
You are performing a **change-impact (blast-radius) analysis** of the symbol
above. Work through these steps, then produce the report.
1. **Identify the definition.** From "Candidate definitions", pick the real
definition site(s). Read 1-2 of them to confirm signature & visibility.
2. **Classify references** into: direct callers, indirect/transitive callers,
re-exports, and tests. Use "Match density" to spot hotspots.
3. **Rate the risk** of *changing/renaming/deleting* this symbol using the
rubric in risk-rubric.md — load it: see [risk-rubric.md](risk-rubric.md).
4. **Recommend regression scope** — list the test files that must pass, and any
caller that has no test coverage (a gap that itself is a risk).
5. **Draw a Mermaid call graph** of the top callers → target → top callees.
## Output format
Follow [report-template.md](report-template.md) exactly:
definition location, risk level (low/medium/high) with one-line reason,
caller table, recommended tests, and a fenced ```mermaid graph.
Keep prose tight. Tables > paragraphs.
这里用到了四个 2026 关键特性:
argument-hint:在 / 自动补全里显示 <symbol or file path>,降低误用。!${CLAUDE_SKILL_DIR}/scripts/find-refs.sh "$1"`:Claude Code 会在把内容交给模型**之前**先执行这行命令,把输出原地替换进去。于是模型看到的不是「请去查引用」,而是「引用已经在这里了」。${CLAUDE_SKILL_DIR}解析为该 Skill 目录的绝对路径,保证脚本在任何 cwd 下都能找到。$1` 是位置参数替换,展开为用户传入的第一个参数。allowed-tools:预授这些工具权限,免去逐次确认弹窗。注意:它只授权、不限制——未列出的工具仍可调用,受全局权限规则约束。[risk-rubric.md](risk-rubric.md) 与 [report-template.md](report-template.md) 告诉模型「需要时去读」,常驻正文只保留主线,省 token。关于
$1在注入块内的展开:字符串替换($1、$ARGUMENTS、${CLAUDE_SKILL_DIR})作用于整段 Skill 内容,因此注入块里的$1会被先替换、再执行。如果你的版本对注入块内参数替换支持不一致,最稳妥的写法是/impact-analyze checkoutSession(符号作为第一个词),脚本从$1读取;或退化为在正文里用一行Bash工具调用find-refs.sh,效果一致。
新建 risk-rubric.md:
# Risk rubric for blast-radius
Rate the risk of changing/renaming/deleting the target symbol:
- **High** — exported public API / entry point / called by >5 files / part of
an interface or base class / has no direct test.
- **Medium** — internal helper used by 2-5 files, or public but well-tested.
- **Low** — single-file local, private, fully covered by tests.
Tie-breakers: any "no test coverage on a caller" bumps the level up one notch.
新建 report-template.md:
# Impact report: <symbol>
**Definition:** `path/to/file.py:42` (visibility)
**Risk: HIGH | MEDIUM | LOW** — <one-line reason>
## Callers (top)
| Caller | File | Has test? |
|:--|:--|:--|
## Regression scope
- Must pass: <test files>
- Coverage gaps (risk): <callers without tests>
## Call graph
```mermaid
graph LR
A[Caller] --> T[Target]
T --> C[Callee]
这两个文件故意不塞进 `SKILL.md` 正文——它们只在「评级」和「排版」两步才需要,常驻是浪费。
### 步骤 5:验证热加载
由于目录已存在,**无需重启**。在仓库里启动 `claude`,输入 `/` 应能看到 `impact-analyze`(带 argument-hint)。
---
## 四、三种调用方式与效果验证
1. **显式调用**:`/impact-analyze checkoutSession`
2. **自然语言触发**(靠 description 命中):直接问「我把 `checkoutSession` 的返回值从对象改成 Promise,会影响哪些地方?」
3. **带引号的多词参数**:`/impact-analyze "processOrder"` —— 若符号含特殊字符,用 shell 风格引号包起来。
预期:模型先呈现「References to ...」段(即脚本实时输出),再按 `report-template.md` 给出定义位置、风险评级、调用方表格、回归测试范围,最后一张 Mermaid 图。
---
## 五、进阶配置
### `paths`:只在改相关文件时触发
若你希望这个 Skill 只在用户编辑源码时自动激活(而非写文档时),加 frontmatter:
```yaml
paths: "**/*.{ts,js,py,go,java,rs,c,cpp}"
设置后,Claude 仅在操作匹配文件时才考虑自动加载它,降低误触发与无关 token。
disable-model-invocation vs user-invocable| frontmatter | 你能调用 | 模型能调用 | 上下文加载 |
|---|---|---|---|
| 默认 | 是 | 是 | description 常驻,调用时加载全文 |
disable-model-invocation: true |
是 | 否 | description 不进上下文,你 / 时才加载 |
user-invocable: false |
否 | 是 | description 常驻,模型按需加载 |
对 impact-analyze,默认即可——它无副作用(只读分析),适合让模型在「用户说要重构」时自动调用。若是 /deploy 这类有副作用的,务必 disable-model-invocation: true。
allowed-tools 让 Skill 自授工具权限。项目级 Skill 的 allowed-tools 在你接受工作区信任对话框后才生效——评审别人的仓库前,先扫一眼 .claude/skills/ 里有没有可疑的 allowed-tools 自授。
场景:一个 Node 服务,准备把 checkoutSession(sessionId: string) 的返回值从 Session 改为 Promise<Session>。
> /impact-analyze checkoutSession
模型产出(节选):
# Impact report: checkoutSession
**Definition:** src/auth/session.ts:88 (exported, public)
**Risk: HIGH** — exported public API, called by 7 files, 3 callers lack tests.
## Callers (top)
| Caller | File | Has test? |
|:--|:--|:--|
| handleCheckout | src/routes/checkout.ts:21 | yes |
| refreshIfNeeded | src/middleware/auth.ts:54 | yes |
| adminForceCheckout | src/admin/sessions.ts:33 | no |
| ... | ... | ... |
## Regression scope
- Must pass: tests/routes/checkout.test.ts, tests/middleware/auth.test.ts
- Coverage gaps (risk): src/admin/sessions.ts (no test — bump risk)
## Call graph
```mermaid
graph LR
R[checkout route] --> T[checkoutSession]
M[auth middleware] --> T
A[admin tool] --> T
T --> S[(Session store)]
随后模型给出建议:先给 adminForceCheckout 补测试,再改签名,最后在迁移期提供临时包装以保持同步调用方不立即报错。
这正是「把改动从凭感觉变成有数据支撑」的价值。
description 没把关键用例放最前。description 与 when_to_use 合计在 Skill 列表里截断到 1,536 字符,且「第一个用例」权重最高。把「who calls / what will this affect / safe to rename」放在句首。/impact-analyze 一次恢复全文。reference.md,正文只留「做什么 + 何时读哪个文件」。${CLAUDE_SKILL_DIR},别写死相对路径——否则换 cwd 就 404。SKILL.md 控制 < 500 行是官方建议的舒适区。Skill 加载与运行时数据流:
flowchart TD
U[用户: /impact-analyze checkoutSession] --> RND[渲染 SKILL.md]
RND --> SUB[字符串替换: $1, $ARGUMENTS, ${CLAUDE_SKILL_DIR}]
SUB --> INJ[动态注入: 执行 find-refs.sh]
INJ --> CTX[实时引用结果 进入正文]
CTX --> M[Claude 接到 含数据的指令]
M --> S1[确认定义点 Read]
M --> S2[分类调用方 Grep]
S2 --> S3[读 risk-rubric.md 评级]
S3 --> S4[套 report-template.md]
S4 --> OUT[影响报告 + Mermaid 调用图]
style INJ fill:#fde68a,stroke:#b45309
style CTX fill:#bbf7d0,stroke:#15803d
paths 与 disable-model-invocation 对照表,保留「脚本 + 动态注入 + 渐进披露」主线即可。impact-analyze 适配到自己的语言栈(如 Go 的 func、Java 的 public),并提交一次真实重构前的影响分析报告。/impact-test Skill(生成回归测试骨架),形成 Skill 编排雏形。name + description + markdown 的跨平台兼容性。[!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 等场景全覆盖。
