首页 › tutorials › Skill参数化与动态注入实战

Claude Code Skill 参数化与动态上下文注入实战

概述

本教程聚焦 Claude Code Skill 中两个最实用却常被忽略的机制:参数化($ARGUMENTS/$N/命名参数/argument-hint)与动态上下文注入(!command`` 预处理)。学完你将能构建带变量、能"开箱即装现网数据"、可携带脚本与审批白名单的可复用工作流 Skill,适合已会用基础 Skill、希望把重复流程沉淀为命令行工具的中级开发者。

前置条件

本教程不重复"渐进披露三层结构""子 Agent 编排""触发词调优"等内容,而是从另一个切面切入:让一个 Skill 变成可以接收参数、可以预装实时数据、可以携带可执行脚本的"小型命令行程序"。


一、核心心智模型:Skill 是"带预处理器的命令"

很多人把 Skill 当成"一段提示词",这低估了它。Skill 的执行其实是两段式流水线:

flowchart LR
    A["/release-preflight v1.4.0"] --> B["1. 参数替换<br/>$ARGUMENTS / $N / 命名参数"]
    B --> C["2. 上下文注入<br/>!`command` 在 Claude 之前执行"]
    C --> D["3. 渲染后的 SKILL.md<br/>作为单条消息注入对话"]
    D --> E["Claude 按指令<br/>调用工具完成任务"]
    E --> F["结果返回主对话<br/>SKILL.md 内容常驻本会话"]

关键在于第 2 步:!command`` 不是让 Claude 去执行命令,而是在 Claude 看到任何东西之前,由 Claude Code 的运行时先把命令跑完、把输出文本替换到那个位置。所以 Claude 收到的永远是"现网的快照数据",而不是"一个待执行的命令"。这是消除幻觉、让 Skill 输出可复现的核心手段。

理解这一点后,后面所有字段都只是给这条流水线加"旋钮"。


二、第一步:创建带参数的 Skill 骨架

操作说明

在个人技能目录下创建一个发布前检查的 Skill,它接收一个版本号作为参数:

mkdir -p ~/.claude/skills/release-preflight/scripts

写入 ~/.claude/skills/release-preflight/SKILL.md:

---
name: release-preflight
description: 发布前自检。当用户要打 tag、发版、上线前做合规与质量检查时使用。
argument-hint: [version]
arguments: [version]
disable-model-invocation: true
---

## 发布目标
即将发布版本:**$version**

## 当前仓库快照
- 当前分支:!`git rev-parse --abbrev-ref HEAD`
- 最新提交:!`git log -1 --pretty=format:'%h %s'`
- 未提交文件:!`git status --porcelain | head -20`

## 自检清单
1. 若上述"未提交文件"非空,先提示用户提交或 stash,不要自动 commit。
2. 跑测试脚本:${CLAUDE_SKILL_DIR}/scripts/check.sh
3. 检查 CHANGELOG 是否包含 $version。
4. 给出"可以打 tag $version"或"阻塞项"结论。

预期结果

在仓库里执行 /release-preflight v1.4.0,Claude 收到的实际内容(伪表示)是:

## 发布目标
即将发布版本:**v1.4.0**

## 当前仓库快照
- 当前分支:main
- 最新提交:a1b2c3d feat: add export api
- 未提交文件: M src/api.py

## 自检清单
1. 若上述"未提交文件"非空,先提示...
2. 跑测试脚本:/home/you/.claude/skills/release-preflight/scripts/check.sh
...

注意三个细节:$version 被替换成了 v1.4.0;!git ...` 被替换成了**真实输出**;${CLAUDE_SKILL_DIR}` 被替换成了 Skill 目录的绝对路径——这意味着脚本路径不依赖你当前的工作目录,在任意子目录调用都正确。

常见问题与解决

现象 原因 解决
$ARGUMENTS 原样出现,没被替换 你用了未声明的占位符,或参数没传 用 arguments: [version] 声明后再用 $version;或显式写 $ARGUMENTS
!git status没执行,显示成字面量 | `!` 没出现在**行首或空格之后** | `KEY=!`cmd 这种紧跟字符的形式不会触发,需独占一行或前面是空白
脚本路径找不到 用了相对路径 ./scripts/check.sh 必须用 ${CLAUDE_SKILL_DIR}/scripts/check.sh
Claude 不肯跑脚本 缺少 allowed-tools 授权 见第三步

三、第二步:用 allowed-tools 预授权工具,免去逐次确认

操作说明

默认情况下,Claude 每次执行 bash 命令都会弹权限确认。在自动化 Skill 里这很烦人。把上一步的 frontmatter 扩展为:

---
name: release-preflight
description: 发布前自检。
argument-hint: [version]
arguments: [version]
disable-model-invocation: true
allowed-tools:
  - Bash(${CLAUDE_SKILL_DIR}/scripts/check.sh)
  - Bash(git status *)
  - Bash(git log *)
  - Bash(git diff *)
  - Bash(git tag *)
  - Read
  - Grep
---

关键认知(务必记牢)

allowed-tools 只授权、不限制。它的语义是"当这个 Skill 激活时,以下工具可免确认使用",而不是"只允许用这些工具"。Claude 仍然可以调用其它工具,只是会走正常的权限流程。

常见问题


四、第三步:用 !command`` 注入多维实时数据(进阶)

!command`` 的威力在于可以并列多条、可以做格式化、可以跨工具。下面是一个更完整的"PR 评审"风格 Skill,它一次性把 diff、CI 状态、变更文件清单都注入进来:

---
name: pr-xray
description: 对当前 PR 做穿透式评审。用户提到 review PR、看这个 PR、代码评审时使用。
context: fork
agent: Explore
allowed-tools: Bash(gh *) Bash(git *) Read Grep Glob
---

## PR 上下文(运行时注入)

### 变更概览
!`gh pr view --json title,author,additions,deletions,baseRefName,headRefName | jq -r '"标题:\(.title)\n作者:\(.author.login)\n+/-:\(.additions)/\(.deletions)\n分支:\(.baseRefName) ← \(.headRefName)"'`

### 变更文件
!`gh pr diff --name-only`

### CI 状态
!`gh pr checks 2>/dev/null | head -20 || echo "无 CI 检查"`

### 完整 diff(前 400 行)
```! 
gh pr diff | head -400

评审任务

基于上述真实数据,按以下顺序输出: 1. 风险分级:CRITICAL / HIGH / MEDIUM / LOW,各列具体文件:行。 2. 回归点:哪些改动可能破坏既有测试。 3. 遗漏项:有没有改了接口却没改调用方。 只引用上面真实出现过的文件名和行号,禁止臆测未出现的文件。

### 几个易踩的坑

1. **多行命令用代码块**。行内 `!`cmd`` 只适合单行;多行必须用 ` ```! ` 开头的围栏代码块,如上例最后一段。
2. **输出不会被二次扫描**。即一条命令的输出里如果**包含** `!`foo``,它不会被再次执行——这避免了递归注入攻击,但也意味着你不能"用命令生成命令"。
3. **`jq` 在管道里很好用**,但前提是机器装了 `jq`。生产环境建议在 Skill 里加一句 `!`command -v jq || echo "WARN: jq 未安装"`` 做软提示,而不是硬失败。
4. **`context: fork` + `agent: Explore` 的组合**:本 Skill 在一个**隔离的子 Agent** 里运行,它看不到你的对话历史,只有上面这份渲染后的内容作为唯一任务输入。`Explore`/`Plan` 这两个内置 Agent 还会**跳过 CLAUDE.md 和 git status**,所以上下文极小、成本极低,适合"只读分析"类任务。但要注意:fork 模式只适合**有明确任务**的 Skill;如果你的 Skill 只是"一些约定规范"没有任务,子 Agent 收到规范却无事可做,会直接空转返回。

---

## 五、第四步:理解 Skill 的"生命周期",别让它失效

这是最容易被忽略、却最容易导致"Skill 第一次好用、后面就不管用了"的根因。

### 加载与驻留机制

1. **启动时**:Claude Code 只把**所有 Skill 的 name + description** 装进系统提示(这就是为什么 `description` 的前几个词最关键)。完整 SKILL.md **不加载**——这是渐进披露的成本控制点。
2. **调用时**:你或 Claude 触发后,渲染后的 SKILL.md 作为**单条消息**进入对话,并**在剩余整个会话里常驻**。每一行都是**持续**的 token 成本,所以 SKILL.md 要像 `CLAUDE.md` 一样精炼。
3. **压缩时(auto-compaction)**:当上下文被摘要以腾空间时,Claude Code 会把"每个 Skill 最近一次调用"重新挂回,但**每个只保留前 5,000 token**,且所有重挂的 Skill **共享 25,000 token 总预算**,从最近调用的开始填。**结论:一个会话里调用了很多 Skill 之后,最早调用的可能被整体丢弃。**

### 实战建议

```mermaid
flowchart TD
    S1["启动:仅加载 name+description"] --> S2{"用户/Claude 调用?"}
    S2 -->|是| S3["渲染 SKILL.md 注入对话<br/>常驻整个会话"]
    S2 -->|否| S4["零成本待命"]
    S3 --> S5{"上下文触发压缩?"}
    S5 -->|是| S6["每个 Skill 留前 5000 token<br/>总计 25000 token 预算"]
    S6 --> S7["从最近向前填<br/>老的可能被丢弃"]
    S5 -->|否| S8["原样保留"]
    S7 --> S9{"行为似乎失效?"}
    S9 -->|是| S10["重新 /调用一次该 Skill<br/>恢复完整内容"]
    S9 -->|否| S11["继续工作"]

落地动作:


六、第五步:用 skillOverrides 统一治理团队 Skill

当你不想改某个 Skill 的源文件(比如它在共享仓库里、由 MCP 服务器提供),却想控制它的可见性时,用 /skills 菜单(选中后按空格切换状态)或直接写 settings.local.json:

{
  "skillOverrides": {
    "legacy-context": "name-only",
    "deploy": "off"
  }
}

四种状态语义:

状态 是否给 Claude 列出 是否出现在 / 菜单 适用场景
on(默认) 名称+描述 是 正常使用
name-only 仅名称 是 描述太吵、想降噪但保留手动调用
user-invocable-only 隐藏 是 只允许人调用、不让模型自动触发
off 隐藏 隐藏 完全停用

注意:skillOverrides 不影响插件 Skill(用 name-only 形式),插件 Skill 走 /plugin 管理。


七、实战案例:release-preflight 完整可运行项目

把前面碎片整合成一个端到端可跑的示例。目录结构:

~/.claude/skills/release-preflight/
├── SKILL.md              # 入口:参数 + 注入 + 授权
├── scripts/
│   └── check.sh          # 可执行脚本:测试+lint+CHANGELOG校验
└── reference.md          # 详细检查规则(按需加载,常驻预算外)

scripts/check.sh(记得 chmod +x)

#!/usr/bin/env bash
# 发布前自检脚本。退出码非0表示有阻塞项。
set -euo pipefail
VERSION="${1:?用法: check.sh <version>}"
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
cd "$ROOT"

fail=0
echo "== 测试 =="
if [ -f package.json ]; then npm test --silent || fail=1; fi
if [ -f Makefile ] && make -n test >/dev/null 2>&1; then make test || fail=1; fi
if [ -f pytest ] || [ -d tests ]; then python3 -m pytest -q 2>/dev/null || true; fi

echo "== Lint =="
if [ -f package.json ] && grep -q '"lint"' package.json; then npm run lint --silent || fail=1; fi

echo "== CHANGELOG 校验 =="
if ! grep -q "$VERSION" CHANGELOG.md 2>/dev/null; then
  echo "WARN: CHANGELOG.md 未发现 $VERSION"
fi

echo "== 工作区 =="
if [ -n "$(git status --porcelain)" ]; then
  echo "WARN: 存在未提交改动"
fi

exit $fail

reference.md(按需加载的细则)

# 发布检查细则

## 阻塞项(必须修复才能发版)
- 任一测试失败
- 存在 console.log / debugger / TODO(发布前)
- 接口签名变更但未更新调用方

## 建议项(可带 warning 发版)
- CHANGELOG 未更新
- 新增依赖未在 README 说明

在主 SKILL.md 里挂引用

在原 frontmatter 下追加一段:

## 细则参考
完整阻塞/建议项判定见 [reference.md](reference.md),只在需要判定边界情况时读取。

验证流程

# 1. 赋权
chmod +x ~/.claude/skills/release-preflight/scripts/check.sh

# 2. 进入任意 git 仓库
cd ~/my-project

# 3. 调用
# 在 Claude Code 里输入:
/release-preflight v1.4.0

Claude 会:① 把 v1.4.0 填入 $version;② 自动跑 git status/git log 注入快照;③ 调用 check.sh(已预授权,不弹窗);④ 输出"可发版/阻塞项列表"。整个过程零额外确认、数据全部来自现网、可复现。


八、把整套机制画成一张图

flowchart TB
    subgraph 编写期["编写期(开发者)"]
        D1["SKILL.md<br/>frontmatter + 正文"]
        D2["scripts/*.sh<br/>可执行脚本"]
        D3["reference.md<br/>按需加载细则"]
    end
    subgraph 运行期["运行期(Claude Code)"]
        R1["/release-preflight v1.4.0"] --> R2["参数替换<br/>\$version = v1.4.0"]
        R2 --> R3["上下文注入<br/>git/gh 命令预执行"]
        R3 --> R4["allowed-tools<br/>免确认授权生效"]
        R4 --> R5["渲染结果作为<br/>单条消息注入"]
    end
    subgraph 执行期["执行期(Claude)"]
        R5 --> E1["调用 check.sh<br/>\${CLAUDE_SKILL_DIR}"]
        E1 --> E2["按需 Read reference.md"]
        E2 --> E3["输出结论"]
    end
    subgraph 生命周期["会话生命周期"]
        E3 --> L1["SKILL.md 常驻"]
        L1 --> L2{"压缩触发?"}
        L2 -->|是| L3["留前5000 token<br/>总预算25000"]
        L2 -->|否| L4["原样保留"]
    end
    D1 -.-> R1
    D2 -.-> E1
    D3 -.-> E2

九、设计自检清单

把你的 Skill 拿来对照这 8 条,过线了就是一个"工程级"Skill:

  1. description 第一句话写清"做什么 + 什么时候用",前 100 字包含触发词。
  2. 有副作用的 Skill(deploy/commit/send-*)加 disable-model-invocation: true。
  3. 需要现网数据的,用 !command`` 预注入,而不是让 Claude 现场猜。
  4. 脚本一律通过 ${CLAUDE_SKILL_DIR} 引用,不用相对路径。
  5. allowed-tools 用精确 glob 授权,只授权不限制;要限制用 disallowed-tools。
  6. SKILL.md ≤ 500 行,大段细则拆到 reference.md 用链接引用。
  7. 指令写成"持续生效的立场句",不写成"一次性步骤"。
  8. 长会话里如果 Skill 行为漂移,先重新 /invoke 一次刷回完整内容。

延伸阅读


训练营适用性评估


参考来源

  1. Extend Claude with skills — Claude Code Docs — 官方权威文档,本文 frontmatter 字段表、!command` 注入语义、allowed-tools/disallowed-tools` 行为、Skill 内容生命周期(5000/25000 token 预算)均出自此处。
  2. Equipping agents for the real world with Agent Skills — Anthropic Engineering — 解释"启动时仅预载 name 与 description"的渐进披露设计动机与上下文成本权衡。
  3. Agent Skills overview — Claude Docs — Agent Skills 作为跨工具开放标准的元数据加载与渐进披露机制说明。
  4. skill-development SKILL.md — anthropics/claude-code (GitHub) — Anthropic 官方编写 Skill 的内部规范模板,本文"设计自检清单"参考其结构与字段约定。
  5. Claude Code Skills 2026 — Progressive Disclosure and How to Standardise Workflow for Engineering Teams — 2026 年第三方深度解析,补充了三层渐进披露与团队标准化落地视角。

[!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学通信知识星球海报-扫码加入