本教程聚焦 Claude Code Skill 的一项核心能力——动态上下文注入与参数化。你将学会把 git diff、gh pr 等命令的实时输出嵌入 Skill 指令,用 $ARGUMENTS 接收参数,用 ${CLAUDE_SKILL_DIR} 定位脚本,让一个 Skill 在不同仓库、不同任务上产出始终贴合当下代码状态的结论。适合已能写出基础 SKILL.md、希望让 Skill 从"静态说明书"升级为"数据驱动执行器"的开发者,预计 60–90 分钟可完成全部实战。
git 与 gh(GitHub CLI,已 gh auth login)的终端SKILL.md + YAML frontmatter)一个写死的 Skill,本质是一段固定文本。当它被触发时,整段内容作为一条消息进入上下文,并停留到会话结束。如果这段文本里写着"请分析当前改动",Claude 看到的只是字面字符串——它并不会自动知道"当前改动"是什么,而要靠自己再去调用工具、翻文件、猜上下文。
这带来三个典型问题:
description 里写满关键词确实能提高命中率,但命中之后若没有真实数据喂进去,输出仍可能是空泛套话。动态注入要解决的,正是"命中之后,把当下真实数据原封不动塞进指令"这件事。它是一套预处理机制:在 Claude 看到正文之前,Claude Code 先把占位符替换成命令的真实输出或参数的真实值,再整体送入模型。换句话说,模型收到的永远是渲染后的、贴合现场的文字,而不是一个待执行的命令模板。
Claude Code 提供四种互补的注入手段,按"数据来源"可分为两类:命令输出注入(来自本机命令)和变量替换(来自调用方与运行环境)。
| 原语 | 形态 | 数据来源 | 替换时机 |
|---|---|---|---|
| 内联命令注入 | !`git diff HEAD` |
shell 命令 stdout | 预处理,逐行替换 |
| 多行命令块 | ```! 围栏代码块 |
多条命令 stdout | 预处理,整块替换 |
| 位置/命名参数 | $ARGUMENTS、$0、$issue |
用户键入 /skill 后的参数 |
预处理,整段替换 |
| 内置环境变量 | ${CLAUDE_SKILL_DIR} 等 |
当前会话与 Skill 安装位置 | 预处理,整段替换 |
它们有一个共同且关键的特性:都是一次性预处理,命令输出作为纯文本插入后不会被二次扫描。这意味着一条命令不能输出另一个 !`...` 占位符来套娃扩展;也意味着变量替换对 Claude 而言与普通正文无异——它读到的是已经填好的值。
!在 SKILL.md 正文中,把任何需要在 Skill 加载前就拿到真实数据的命令,写成以感叹号开头的反引号包裹形式。官方示例——一个"未提交改动摘要"Skill——只用了这一招就把技能变得可靠:
---
description: Summarizes uncommitted changes and flags anything risky. Use when the user asks what changed, wants a commit message, or asks to review their diff.
---
## Current changes
!`git diff HEAD`
## Instructions
Summarize the changes above in two or three bullet points, then list any risks you notice such as missing error handling, hardcoded values, or tests that need updating. If the diff is empty, say there are no uncommitted changes.
把这段保存到 ~/.claude/skills/summarize-changes/SKILL.md,在一个有改动的仓库里启动 Claude Code,输入"我改了什么",Skill 会被自动触发。
Claude Code 在把正文发给模型之前,先执行 git diff HEAD,把它的完整输出粘贴到 ## Current changes 下方。模型收到的不是"请运行 git diff",而是已经渲染好的 diff 全文 + 指令。因此它能逐文件指出改了什么、哪些地方缺错误处理、哪些测试需要补。
! 必须出现在行首,或紧跟在空白字符之后。如果写成 KEY=!git status``(感叹号紧跟在等号后),它会被当作普通字面量,命令不会执行。```! 开头的围栏代码块,而不是把内联形式硬拼:text
## Environment!
node --version
npm --version
git status --short
**问:我加了 !git diff,但运行时正文里直接显示了命令原文。**
答:检查感叹号前面是不是非空白字符(如冒号紧贴)。把 `diff:!`git diff 改成 diff: !git diff``(冒号后加空格)即可。
问:命令执行失败导致 Skill 加载报错怎么办?
答:命令的标准错误也会被当作输出插入。对可能失败的命令(如 gh pr diff 在非 PR 仓库),在正文里加一句"若上述为空或报错,说明……"的容错说明,让模型自行判断。
$ARGUMENTS 与命名参数命令注入让 Skill 拿到"环境数据",参数化则让 Skill 拿到"调用方数据"——用户在 /skill-name 后面打的那串字。
最简形式是 $ARGUMENTS,它展开成 /skill-name 之后键入的全部原文:
---
name: fix-issue
description: Fix a GitHub issue
disable-model-invocation: true
---
Fix GitHub issue $ARGUMENTS following our coding standards.
1. Read the issue description
2. Understand the requirements
3. Implement the fix
4. Write tests
5. Create a commit
运行 /fix-issue 123 时,$ARGUMENTS 被替换为 123,模型收到"Fix GitHub issue 123…"。若正文里没有出现 $ARGUMENTS,Claude Code 会自动在正文末尾追加一行 ARGUMENTS: <你的输入>,保证参数不丢。
需要拆分多个参数时,用零基索引 $ARGUMENTS[N] 或简写 $N:
Migrate the $0 component from $1 to $2.
Preserve all existing behavior and tests.
/migrate-component SearchBar React Vue 会把 SearchBar、React、Vue 分别填入 $0/$1/$2。索引遵循 shell 风格引号规则:/my-skill "hello world" second 让 $0 = hello world、$1 = second。
为了让参数含义自解释,可在 frontmatter 用 arguments 声明名字,再在正文用 $名字 引用。名字按声明顺序映射到位置:
---
name: open-pr
description: Open a pull request from a source branch to a target branch
arguments: [source, target]
---
Open a PR from $source into $target.
- source branch: $source
- target branch: $target
/open-pr feature/login main 等价于 $source=feature/login、$target=main。这种方式在参数多于两个时显著优于 $0/$1/$2,可读性接近函数签名。
需要在正文里写真正的 $1.00(如金额),要用反斜杠转义:\$1.00。只有紧贴在 $ 与数字/ARGUMENTS/声明名之前的单个反斜杠才会被吃掉;\\$1 这种双反斜杠会原样保留两个反斜杠,且 $1 仍会被替换。
问:参数没传,$0 变成空,指令读起来很怪。
答:在正文里加防御性措辞,例如"若 $0 为空,请先用 AskUserQuestion 向用户询问组件名"。把"参数缺失"显式化,比静默生成错误结果更可控。
问:多词参数被拆开了。
答:调用时给多词值加引号,/open-pr "feature a" main 才能让 $source = feature a。
三个内置变量让 Skill 摆脱对绝对路径与会话状态的硬编码:
${CLAUDE_SKILL_DIR}:当前 SKILL.md 所在目录。这是写可移植脚本的命脉。无论 Skill 被装在个人目录、项目目录还是插件目录,脚本路径都用 ${CLAUDE_SKILL_DIR}/scripts/analyze.py,Claude Code 会解析到正确位置,而不必关心当前工作目录在哪。${CLAUDE_SESSION_ID}:当前会话 ID,适合写日志、做会话级文件隔离,如 logs/${CLAUDE_SESSION_ID}.log。${CLAUDE_EFFORT}:当前 effort 级别(low/medium/high/xhigh/max)。可用它让 Skill 在不同推理强度下调整指令粒度——低强度时给更直接的步骤,高强度时鼓励多方案对比。下面这个官方可视化 Skill 展示了 ${CLAUDE_SKILL_DIR} 的典型用法:正文只负责让 Claude"运行脚本并解释结果",真实工作由脚本完成:
---
name: codebase-visualizer
description: Generate an interactive collapsible tree visualization of your codebase. Use when exploring a new repo, understanding project structure, or identifying large files.
allowed-tools: Bash(python3 *)
---
# Codebase Visualizer
Generate an interactive HTML tree view that shows your project's file structure.
## Usage
Run the visualization script from your project root:
```bash
python3 ${CLAUDE_SKILL_DIR}/scripts/visualize.py .
This creates codebase-map.html in the current directory and opens it in your default browser.
注意 frontmatter 里的 `allowed-tools: Bash(python3 *)`——它让 Claude 在本 Skill 激活期间免确认运行 `python3`,省去每次弹窗确认。这是"动态注入 + 预授权工具 + 脚本编排"三件套的标准组合。
## 六、步骤四:实战——构建"PR 体检"Skill
把四种原语揉进一个真实可运行的项目。目标:输入 `/pr-checkup <PR号>`,Skill 自动拉取该 PR 的 diff、改动文件清单、评论,调用一个统计脚本算出每个文件的增删行数,最终输出"改动摘要 + 风险点 + commit message 草稿"三段式报告。
### 1. 建目录
```bash
mkdir -p ~/.claude/skills/pr-checkup/scripts
scripts/changed_files.py它从标准输入读 diff,按文件聚合增删行,输出 JSON 给 Claude 当结构化数据用。零依赖,仅用标准库:
#!/usr/bin/env python3
"""Parse a unified diff from stdin, emit per-file +/- stats as JSON."""
import sys, json, re
hunk_re = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@')
stats, cur, adds, dels = {}, None, 0, 0
for line in sys.stdin:
if line.startswith('+++ ') and line.strip() != '+++ /dev/null':
if cur: stats[cur] = {"added": adds, "deleted": dels}
cur = line[4:].strip().lstrip('b/'); adds = dels = 0
elif line.startswith('+') and not line.startswith('+++'): adds += 1
elif line.startswith('-') and not line.startswith('---'): dels += 1
if cur: stats[cur] = {"added": adds, "deleted": dels}
print(json.dumps(stats, ensure_ascii=False, indent=2))
chmod +x ~/.claude/skills/pr-checkup/scripts/changed_files.py
SKILL.md这是核心。它同时演示:命名参数 $pr、内联命令注入 !`gh ...`、管道把 diff 喂给脚本、allowed-tools 预授权。
---
name: pr-checkup
description: Inspect a GitHub pull request and produce a change summary, risk list, and draft commit message. Use when the user asks to review, summarize, or sanity-check a PR.
argument-hint: [pr-number]
arguments: [pr]
allowed-tools: Bash(gh *) Bash(python3 *)
---
# PR Checkup for #$pr
## 1. Live PR data (auto-injected)
- Title & metadata: !`gh pr view $pr --json title,author,state,additions,deletions,changedFiles`
- Changed files: !`gh pr diff $pr --name-only`
- Review comments: !`gh pr view $pr --comments`
## 2. Per-file change volume (auto-injected from script)
```!
gh pr diff $pr | python3 ${CLAUDE_SKILL_DIR}/scripts/changed_files.py
Using the data above ONLY, produce three sections:
Summary — 2-3 bullets naming what changed and why a reader should care. Cite file paths from section 2.
Risks — bullet list of concrete concerns: missing error handling, new public API without tests, hardcoded values, large files (>300 changed lines) that warrant a closer read. If a file in section 2 has added+deleted > 300, flag it explicitly.
Draft commit message — a Conventional Commits message (type(scope): subject + bullet body) summarizing the PR as if it were one commit.
If section 1 shows state: CLOSED or additions: 0, say so upfront and skip the rest.
### 4. 验收
在一个有 PR 的仓库里:
/pr-checkup 428
预期:Claude Code 先并行执行三条 `gh` 命令与一次管道脚本调用,把它们的输出分别填入三处占位符;模型随后基于渲染后的完整数据产出三段式报告。整个过程 Claude 不需要自己再去 `gh`——数据已经在它眼前。
### 为什么这个 Skill 比"裸问 Claude"强
- **数据真实性**:风险判断基于脚本算出的真实增删行数,而非模型对 diff 长度的猜测。
- **可移植**:`${CLAUDE_SKILL_DIR}` 让它在任何安装位置都能找到脚本,`$pr` 让它适配任意 PR。
- **零确认摩擦**:`allowed-tools` 免去了对 `gh`、`python3` 的逐次授权弹窗。
## 七、工作流程图
下面这张时序图展示一次 `/pr-checkup 428` 调用中,注入发生在"模型可见之前"的关键时序:
```mermaid
sequenceDiagram
participant U as 用户
participant CC as Claude Code
participant Shell as 本地 Shell
participant Script as changed_files.py
participant M as 模型
U->>CC: /pr-checkup 428
CC->>CC: 解析 $pr = 428,扫描正文占位符
par 并行预处理
CC->>Shell: gh pr view 428 ...
Shell-->>CC: PR 元数据
and
CC->>Shell: gh pr diff 428 --name-only
Shell-->>CC: 文件清单
and
CC->>Shell: gh pr view 428 --comments
Shell-->>CC: 评论
and
CC->>Shell: gh pr diff 428 | python3 ${CLAUDE_SKILL_DIR}/scripts/changed_files.py
Shell->>Script: diff 流
Script-->>Shell: 文件增删 JSON
Shell-->>CC: 统计结果
end
CC->>CC: 把四段输出替换进正文(纯文本,不二次扫描)
CC->>M: 渲染后的完整指令(含真实数据)
M-->>CC: 三段式报告
CC-->>U: 展示 Summary / Risks / Draft commit
注意图中的"纯文本,不二次扫描"——这是理解注入边界的核心:模型收到的是成品,不是配方。
动态注入把命令输出塞进正文,意味着这些文本会随 Skill 一起留在上下文里直到会话结束。官方对 Skill 生命周期有明确约束,做注入时必须心中有数:
description+when_to_use 合计占用模型上下文窗口的 1%。塞太多 Skill 或描述太长,命中率低的会被截断。可在 /doctor 查看哪些被裁剪,用 skillOverrides 把低优先级的设为 "name-only" 腾预算。实务建议:注入命令尽量"窄而准"——git diff HEAD 而非 git log -p、gh pr diff --name-only 而非整个 diff 仓库。大块参考材料(API 文档、长规范)不要用 ! 注入,而是放进 reference.md 这类支持文件,在正文里用相对链接引用,由 Claude 按需加载——这才是渐进式披露与动态注入的分工。
| 现象 | 根因 | 处置 |
|---|---|---|
!命令原文出现在输出里 |
! 未在行首/空白后 |
在 ! 前加空格或换行 |
${CLAUDE_SKILL_DIR} 没展开 |
变量名拼错或不在支持列表 | 仅这三个内置变量受支持,自定义环境变量不会替换 |
$0 取到空值 |
参数未传或被引号吞掉 | 正文加防御性提示;调用多词参数加引号 |
| 命令输出污染正文、上下文爆炸 | 注入了过大的数据源 | 收窄命令范围;大文本移入支持文件 |
| Skill 触发了但行为不符合预期 | 命中≠正确,指令强度不足 | 用 skill-creator 插件做 A/B 评测,强化 description 与指令 |
| 全公司禁用 shell 注入 | 安全策略 | 在 managed settings 设 disableSkillShellExecution: true |
命令注入本质是"Skill 作者预埋了会自动执行的 shell"。三条铁律:
!curl -H "Authorization: Bearer sk-xxx"` 这样的写法会把密钥写进 Skill 文件。外部凭证应通过 MCP 连接或环境变量提供。SKILL.md 与 scripts/,重点看 ! 命令和 allowed-tools——后者能让 Skill 在激活期免确认运行危险工具。.claude/skills/,其 allowed-tools 在接受工作区信任对话后才生效。审阅项目 Skill 应像审阅 .claude/settings.json 的权限规则一样严格。需要一刀切关闭外部 Skill 的命令执行时,在 settings 写 "disableSkillShellExecution": true。注意它只影响来自 user/project/plugin/additional-directory 的 Skill,不影响官方 bundled 与 managed Skill——后两者仍可执行,以保官方能力不被误伤。
code.claude.com/docs/en/skills——frontmatter 全字段表、子代理运行、支持文件的权威出处。agentskills.io——跨工具通用的 Skill 规范,Claude Code 在其上扩展了注入与调用控制。github.com/anthropics/skills/tree/main/skills——可直接当模板的现成 Skill。github.com/anthropics/claude-plugins-official——把"命中率"与"输出质量"两条评测自动化,闭环打磨 Skill。pr-checkup,现场比拼风险点的召回质量。pr-checkup 改造为 commit-checkup(无 PR 仓库可用),或新增 ${CLAUDE_EFFORT} 分支——高 effort 时输出多方案 commit message 供挑选。[!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 等场景全覆盖。
