Claude Code Skills 深度解析:参数传递与上下文预注入

一、一个心智模型:Skill 是一张"会自动填好的任务纸条"

理解这两个机制,只需要抓住一句话:

Skill 的所有"动态能力",都发生在 Claude 读到它之前,由运行时(harness)完成填充。模型最终看到的,永远是一张已经填得满满当当的成品。

把 Skill 想象成一张写给 Claude 的任务纸条。平时纸条上的字是固定的;但它可以留两类"空":

  • 一类空,等你调用时临时告诉它 ------比如"修第几号 bug"。这就是参数传递
  • 一类空,让纸条自己去查了填上 ------比如"当前 git 分支是什么"。这就是上下文预注入

无论哪种空,填空动作都在交给模型之前完成。Claude 拿到手的是成品,它甚至不知道原文里曾有过占位符。记住这条主线,后面所有细节都能对号入座。


二、上下文预注入:让纸条"自带背景信息"

2.1 骨架:三级渐进式加载(Progressive Disclosure)

"预注入"首先是一套分层加载的设计,目的是在"让模型知道技能存在"和"不撑爆上下文"之间取得平衡:

层级 内容 何时进入上下文 体量
L1 元数据 name + description 会话一开始就注入,始终在场 ~100 词
L2 正文 SKILL.md 主体 技能被触发时才注入 建议 1.5k--2k 词
L3 资源 references/ scripts/ assets/ 模型按需读取/执行 近乎无限

这三层揭示了"预注入"最本质的一层含义:L1 是真正的"预" 。你安装的每一个 Skill,它的 name + description 在对话还没开始时,就已经被写进系统提示。这就是模型判断"该不该自动调用某个技能"的唯一线索

所以官方反复强调 description 要写成第三人称 + 具体触发短语:

yaml 复制代码
# ✅ 好:模型能准确判断何时触发
description: This skill should be used when the user asks to "create a hook",
  "add a PreToolUse hook", or mentions hook events.

# ❌ 差:太笼统,技能几乎不会被自动触发
description: Provides guidance for working with hooks.

描述写得含糊,技能就等于"存在但沉睡"------这是新手最常见的坑。

2.2 三种"动态源":把外部世界焊进纸条

当技能被触发、正文(L2)加载时,正文里可以嵌入三种会被实时替换的写法:

① ``!`命令``` ------ 注入命令的实时输出

markdown 复制代码
## 当前状态
- 分支: !`git branch --show-current`
- 改动: !`git status --short`

运行时会先执行 这些命令,把标准输出内联 进正文。模型看到的不是那句 git branch,而是已经变成 - 分支: main 的成品。这正是"预注入"四个字最直白的体现:命令在模型接手前就跑完了,结果被物化进 prompt。

! 时,通常要在 frontmatter 用 allowed-tools: Bash(git:*) 之类放行对应命令。

@文件 ------ 注入文件内容

markdown 复制代码
Review @src/api/users.ts for potential bugs.

@ 让运行时先把文件读进来 再交给模型。它还能和参数组合成 @$1,表示"读取用户传进来那条路径所指的文件"。

${CLAUDE_PLUGIN_ROOT} ------ 插件内的可移植路径

插件型 Skill 专用,自动解析为插件的绝对路径,用来引用插件自带的脚本或模板,避免硬编码:

markdown 复制代码
Run: !`node ${CLAUDE_PLUGIN_ROOT}/scripts/analyze.js`

三、运行时参数传递:让纸条"接受临时输入"

3.1 两条入口,一套语法

Skill 有两个调用入口,但共享同一套参数机制:

  • 用户显式调用 :在对话里敲 /skill-name 参数
  • 模型自动调用:模型根据 L1 描述判断相关,自行调用并传入参数

一个关键事实:传统的 .claude/commands/*.md 和新的 .claude/skills/<name>/SKILL.md,运行时是完全一样地加载的,只是文件布局不同。所以下面的参数写法对两者通用。

3.2 三种占位符

$ARGUMENTS ------ 全部参数当作一整个字符串

markdown 复制代码
Fix issue #$ARGUMENTS following our coding standards.

/fix-issue 123Fix issue #123 following our coding standards.

$1 $2 $3 ------ 位置参数,分别对应第 1、2、3 个

markdown 复制代码
Review PR #$1 with priority $2, then assign to $3.

/review-pr 123 high aliceReview PR #123 with priority high, then assign to alice.

混合 ------ 前几个用位置,剩下的打包

markdown 复制代码
Deploy $1 to $2 with options: $3

/deploy api staging --force --skip-testsDeploy api to staging with options: --force --skip-tests

3.3 一条几乎没人注意的兜底规则

如果 SKILL.md 里根本没写 $ARGUMENTS,运行时会把参数以 ARGUMENTS: <值> 的形式追加到内容末尾。

也就是说,参数永远不会丢。区别只在于:

  • 写了占位符 → 参数被精确插到指定位置;
  • 没写占位符 → 参数被兜底追加到结尾,交由模型自行理解。

3.4 argument-hint 只是"说明书",不参与传参

yaml 复制代码
argument-hint: [pr-number] [priority] [assignee]

它只影响自动补全提示和 /help 里的文档展示,不做任何实际替换 。真正的传参靠 $ARGUMENTS / $N


四、把两者串起来:一次调用的完整时序

参数替换、命令注入、文件读取------这些全部在模型之前 按序完成。以官方 pr-check 技能为例:

yaml 复制代码
---
name: pr-check
description: Review PR against project checklist
disable-model-invocation: true
context: fork
---
## PR Context
- Diff: !`gh pr diff`
- Description: !`gh pr view`

Review against [checklist.md](checklist.md).
For each item, mark ✅ or ❌ with explanation.

调用 /pr-check 时,运行时的处理流水线是:

bash 复制代码
用户输入 /pr-check
      │
① 参数展开   替换 $ARGUMENTS / $1...(没有则末尾追加 ARGUMENTS:)
      │
② 命令注入   执行 !`gh pr diff`、!`gh pr view`,把输出内联进正文
      │
③ 文件/路径  解析 @文件 与 ${CLAUDE_PLUGIN_ROOT}
      │
      ▼
 一张"已物化"的纯文本  ──►  注入到上下文(本例因 context: fork,进入独立子代理)
      │
      ▼
 模型开始工作(只看到成品,看不到任何占位符)

另一种风格 值得对照:很多实用 Skill 几乎不用占位符,而是把一连串动作写成自然语言指令 ,让模型运行时自己去调工具收集上下文。比如一个典型的提交流程 Skill:它不预先传"要提交哪些文件",而是在正文里指挥模型"先跑 git status/git diff 分析改动,再分组生成 commit message"------参数(改了哪些文件)是模型在运行中动态产出的,不是调用时传入的。

这说明:参数传递不是必需品。"正文指令 + 模型自主收集"往往比硬塞参数更灵活。


五、Frontmatter:控制这两件事的开关

字段 作用
name / description 技能身份与触发条件------L1 预注入的全部内容
argument-hint 参数用法提示(仅文档,不参与替换)
allowed-tools 限定可用工具,如 Read, Bash(git:*);用 ! 注入命令时需放行
model 覆盖执行模型(haiku/sonnet/opus)
disable-model-invocation: true 仅用户可调,模型不能自动触发------适合有副作用的操作(部署、发送)
user-invocable: false 仅模型可调,用户看不到------适合纯背景知识
context: fork 隔离子代理中运行,不污染主会话
agent: Explore fork 时用哪种代理类型

调用权限一览:

设置 用户 模型 用途
默认 通用技能
disable-model-invocation: true 有副作用的操作
user-invocable: false 后台知识

六、五条实战经验

  1. 描述质量 ≈ 自动触发概率。 模型对未触发的技能只看得见 L1 描述。用第三人称写清"用户说什么时该触发",而不是笼统一句"处理提交相关事务"。
  2. 占位符替换不可逆。 ``!`cmd``` 一旦跑完被内联,模型无法"重跑";要拿最新状态,只能靠下一次调用重新注入。
  3. $ARGUMENTS 是纯文本插值,不做校验。 需要校验就在正文里显式写(例如用 ``!`echo "$1" | grep -E ...``` 验证环境名)。
  4. 别把所有东西堆进 SKILL.md 那会破坏 L2 的精简性,每次触发都白灌一堆上下文。细节挪到 references/,靠指针按需加载(L3)。
  5. 新技能优先用 SKILL.md 目录格式。 .claude/commands/ 是 legacy;两者加载行为一致,但目录格式能捆绑 references/scripts/assets,才能发挥完整的渐进式披露能力。

结语

Claude Code 的 Skill 之所以强大,不在于"写了一段提示词",而在于它把动态填充做成了模型无感的预处理层:

  • 上下文预注入 让技能自带实时背景------三级加载控制"何时进上下文",! / @ / ${CLAUDE_PLUGIN_ROOT} 控制"注入什么内容";
  • 运行时参数传递 让技能接受临时输入------$ARGUMENTS / $N 精确插值,外加"末尾追加"的兜底。

两者殊途同归:在模型读到之前,把一张模板纸条填成成品。想清楚"哪些空由用户填、哪些空由纸条自己查",你就能设计出真正好用的 Skill。

相关推荐
薛定猫AI18 小时前
【技术干货】大模型能力评测实战:Python构建可复现的模型选型流水线
人工智能·后端
用户7138742290018 小时前
Claude Agent Skills 的四种设计模式;从渐进式披露到最小权限
后端
吃饱了得干活18 小时前
从0到1实现消息已读未读:从基础设计到高并发架构
java·后端·架构
梅头脑18 小时前
一条SQL从5秒到0.05秒:我拆开了B+Tree、MVCC和EXPLAIN,找到了慢查询优化的根
后端
云技纵横19 小时前
堆内存明明还有一半,接口为什么每隔几分钟卡死一次?
后端
是小李呀19 小时前
解决 “Your local changes will be overwritten by revert“ 报错
后端
fliter19 小时前
不用再反复 stash:用 Git Worktree 同时开发多个分支
后端·github
卷无止境19 小时前
KTransformers:让巨型模型跑在你家电脑上的黑科技
人工智能·后端
_waylau19 小时前
Spring Framework HTTP服务客户端详解
java·后端·网络协议·spring·http·spring cloud