☰
Claude Code Skills 深度解析:SKILL.md 参数传递与上下文预注入实战
2026/9/27 20:17:28 网站建设 项目流程

1. 为什么你的 Claude Code Skills 总是"触发不了"或"参数丢了"

如果你已经在 Claude Code 里写过几个 Skill,大概率遇到过这两种情况:一是明明装好了技能,模型却像没看见一样,死活不自动调用;二是敲了/my-skill 参数,结果模型回复里压根没用到你传进去的值。这两个问题看起来是"玄学",其实都指向同一套机制——SKILL.md 的参数传递与上下文预注入。

Claude Code Skills 是 Anthropic 在 Claude Code 里引入的技能复用机制,本质是把一段可复用的提示词、脚本、参考资料打包成一个目录,让模型在合适的时候自动加载。它适合谁?适合那些每天重复写同样提示词的开发者,比如"按团队规范 review PR""生成符合约定的 commit message""检查某个文件的安全问题"。把这些固化成 Skill,你就不用每次重新交代背景。

但 Skill 真正难的地方不在"写提示词",而在于理解它的运行时行为:哪些内容在模型看到之前就已经被填好了,哪些是调用时才传进去的。这篇就围绕 SKILL.md 的配置骨架,把参数传递($ARGUMENTS、$1)和上下文预注入(!命令、@文件、${CLAUDE_PLUGIN_ROOT})拆开讲,每个片段都能直接复制去用。同时我会说明怎么通过统一的 Key/API 通道 TaoToken 完成接入和调用验证,避免你在多个 Key 之间来回切换。

2. 前置准备:用 TaoToken 统一 Key 与 API 通道

在动手写 SKILL.md 之前,先把调用通道理顺。Claude Code 需要能访问模型 API,如果你手上有多个来源的 Key,管理起来很麻烦。TaoToken 提供统一的 Key/API 通道,官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api (这个地址不加 UTM 参数)。

你需要做的准备只有三步:

第一步,在控制台创建一个 API Key。打开 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,登录后进入 API Keys 页面,新建一个 Key 并复制保存。这个 Key 就是后面 Claude Code 调用时要用的凭证。

第二步,确认你要用的模型。可以在模型对话页面 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 先试跑一句,确认通道正常、模型可用,再去配置 Claude Code。

第三步,把 Key 和 API 基址写进 Claude Code 的环境变量或配置里。Claude Code 读取的是ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY这类变量,把基址指向 TaoToken 的 API 地址,Key 填你刚创建的那个即可。

注意:API 基址用https://taotoken.net/api,不要带任何查询参数;官网链接才带 UTM。两者别混。

如果你打算长期在 Claude Code 里跑编码任务、Agent 流程,建议直接看 Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,它针对编码场景做了额度规划,比按次调用更省心。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,遇到字段不清楚可以对照。

3. SKILL.md 配置骨架:三级加载与 frontmatter 字段

先把心智模型立住:Skill 就是一张"会自动填好的任务纸条"。纸条上的字大部分是固定的,但可以留两类空——一类等你调用时临时告诉它(参数传递),一类让它自己去查了填上(上下文预注入)。无论哪种空,填空动作都发生在模型读到之前,模型拿到的是成品,它甚至不知道原文里有过占位符。

这个"填空"分三级渐进式加载:

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

L1 是真正的"预注入":你装的每个 Skill,它的 name 和 description 在对话还没开始时就写进了系统提示,这是模型判断"该不该自动调用"的唯一线索。所以 description 必须写成第三人称加具体触发短语:

# 好:模型能准确判断何时触发 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.

frontmatter 里控制参数与注入行为的字段如下:

--- name: pr-check description: Review PR against project checklist when user asks to "check PR" or "review pull request" argument-hint: [pr-number] [priority] [assignee] allowed-tools: Read, Bash(git:*), Bash(gh:*) model: sonnet disable-model-invocation: true context: fork agent: Explore ---

逐个说明:name/description是 L1 预注入的全部内容;argument-hint只是自动补全和/help里的说明书,不参与实际替换;allowed-tools限定可用工具,用!注入命令时必须放行对应命令,比如Bash(git:*);model可覆盖执行模型;disable-model-invocation: true表示仅用户可调、模型不能自动触发,适合部署、发送这类有副作用的操作;user-invocable: false表示仅模型可调、用户看不到,适合纯背景知识;context: fork让技能在隔离子代理中运行,不污染主会话。

调用权限一览:

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

4. 上下文预注入:!命令、@文件与插件路径

上下文预注入的核心是"让纸条自带背景信息"。当技能被触发、L2 正文加载时,正文里可以嵌入三种会被实时替换的写法。

第一种是!命令,注入命令的实时输出:

## 当前状态 - 分支: !`git branch --show-current` - 改动: !`git status --short`

运行时会先执行这些命令,把标准输出内联进正文。模型看到的不是那句git branch,而是已经变成- 分支: main的成品。这就是"预注入"最直白的体现:命令在模型接手前就跑完了。用!时,frontmatter 里要用allowed-tools: Bash(git:*)之类放行对应命令。

第二种是@文件,注入文件内容:

Review @src/api/users.ts for potential bugs.

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

第三种是${CLAUDE_PLUGIN_ROOT},插件内的可移植路径:

Run: !`node ${CLAUDE_PLUGIN_ROOT}/scripts/analyze.js`

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

把三者串起来看一次完整时序。以官方 pr-check 技能为例:

--- 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时,运行时的处理流水线是:先做参数展开(替换$ARGUMENTS/$1,没有则末尾追加),再执行命令注入(跑gh pr diff、gh pr view并内联输出),然后解析@文件与${CLAUDE_PLUGIN_ROOT},最后把一张"已物化"的纯文本注入上下文。因为context: fork,它进入独立子代理,模型开始工作时只看到成品,看不到任何占位符。

5. 运行时参数传递:$ARGUMENTS、$1与兜底规则

Skill 有两个调用入口,但共享同一套参数机制:用户显式调用(敲/skill-name 参数)和模型自动调用(根据 L1 描述判断相关后自行调用并传入参数)。一个关键事实是,传统的.claude/commands/*.md和新的.claude/skills/<name>/SKILL.md运行时加载方式完全一样,只是文件布局不同,所以下面的参数写法对两者通用。

三种占位符写法:

# $ARGUMENTS:全部参数当作一整个字符串 Fix issue #$ARGUMENTS following our coding standards. # /fix-issue 123 → Fix issue #123 following our coding standards. # $1 $2 $3:位置参数,分别对应第 1、2、3 个 Review PR #$1 with priority $2, then assign to $3. # /review-pr 123 high alice → Review PR #123 with priority high, then assign to alice. # 混合:前几个用位置,剩下的打包 Deploy $1 to $2 with options: $3 # /deploy api staging --force --skip-tests → Deploy api to staging with options: --force --skip-tests

有一条几乎没人注意的兜底规则:如果 SKILL.md 里根本没写$ARGUMENTS,运行时会把参数以ARGUMENTS: <值>的形式追加到内容末尾。也就是说参数永远不会丢,区别只在于——写了占位符,参数被精确插到指定位置;没写占位符,参数被兜底追加到结尾,交由模型自行理解。

再强调一次:argument-hint只是说明书,不参与传参。真正的传参靠$ARGUMENTS/$N。

还有一种风格值得对照:很多实用 Skill 几乎不用占位符,而是把一连串动作写成自然语言指令,让模型运行时自己去调工具收集上下文。比如一个提交流程 Skill,它不预先传"要提交哪些文件",而是在正文里指挥模型"先跑git status/git diff分析改动,再分组生成 commit message"——参数是模型在运行中动态产出的,不是调用时传入的。这说明参数传递不是必需品,"正文指令 + 模型自主收集"往往比硬塞参数更灵活。

6. 验证请求:确认参数与预注入真的生效

配置写完,必须验证。最直接的方式是造一个最小 Skill,把参数和注入都放进去,然后调用看输出。

在.claude/skills/echo-test/SKILL.md写入:

--- name: echo-test description: Use when user asks to "test skill params" or "verify skill injection" argument-hint: [name] [env] allowed-tools: Bash(git:*) --- ## 参数验证 - 第一个参数: $1 - 第二个参数: $2 - 全部参数: $ARGUMENTS ## 上下文预注入验证 - 当前分支: !`git branch --show-current`

然后在 Claude Code 里调用:

/echo-test alice staging

预期结果:模型回复里第一个参数显示alice,第二个参数显示staging,全部参数显示alice staging,当前分支显示你仓库的真实分支名。如果分支那行还是原样的!git branch --show-current``,说明allowed-tools没放行Bash(git:*),或者命令执行失败。

再验证兜底规则:把上面 SKILL.md 里的$1/$2/$ARGUMENTS全删掉,只留正文,再调用/echo-test alice staging。你应该在模型看到的正文末尾发现ARGUMENTS: alice staging被追加进来。这一步能帮你确认"参数不会丢"这条规则确实生效。

验证模型通道是否正常,可以先用模型对话页面 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 跑一句简单请求,确认返回正常,再回到 Claude Code 里测 Skill。如果 Skill 调用报鉴权错误,去 API Keys 页面 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 检查 Key 是否有效、是否复制完整。

7. 本篇常见错误排查

技能不自动触发。九成是 description 写得太笼统。模型对未触发的技能只看得见 L1 描述,所以要写成第三人称加具体触发短语,比如"当用户说'检查 PR'或'review pull request'时使用",而不是"处理提交相关事务"。

参数没被替换。检查占位符拼写:是$ARGUMENTS不是$ARGUMENT,是$1不是$01。另外确认你调用时确实带了参数,/my-skill后面空着,$1自然为空。

!命令没执行或报权限错误。frontmatter 里必须用allowed-tools放行对应命令,比如Bash(git:*)、Bash(gh:*)。只写Bash有时不够精确,建议带上命令前缀。

@文件读不到。路径要相对仓库根目录,或者用@$1让用户传绝对/相对路径。文件不存在时运行时不会报错,只是注入为空,模型会以为文件是空的。

${CLAUDE_PLUGIN_ROOT}解析成字面量。这个变量只在插件型 Skill 里有效,普通.claude/skills/目录下的 Skill 用不了,会原样输出。普通 Skill 直接用相对路径。

占位符替换不可逆。!cmd一旦跑完被内联,模型无法"重跑";要拿最新状态,只能靠下一次调用重新注入。`$ARGUMENTS` 是纯文本插值,不做校验,需要校验就在正文里显式写,比如用 `!`echo "$1" | grep -E ...验证环境名。

把所有东西堆进 SKILL.md。那会破坏 L2 的精简性,每次触发都白灌一堆上下文。细节挪到references/,靠指针按需加载(L3)。

还在用.claude/commands/。它是 legacy,两者加载行为一致,但目录格式能捆绑references/scripts/assets,才能发挥完整的渐进式披露能力。新技能优先用 SKILL.md 目录格式。

8. 把动态填充做成模型无感的预处理层

Claude Code 的 Skill 之所以强大,不在于"写了一段提示词",而在于它把动态填充做成了模型无感的预处理层。上下文预注入让技能自带实时背景——三级加载控制"何时进上下文",!/@/${CLAUDE_PLUGIN_ROOT}控制"注入什么内容";运行时参数传递让技能接受临时输入——$ARGUMENTS/$N精确插值,外加"末尾追加"的兜底。两者殊途同归:在模型读到之前,把一张模板纸条填成成品。

想清楚"哪些空由用户填、哪些空由纸条自己查",你就能设计出真正好用的 Skill。如果你还在为多 Key 管理头疼,直接用 TaoToken 的统一通道接入,把精力留给 Skill 设计本身。长期跑编码和 Agent 任务的话,Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 的额度规划会比零散调用更稳。接入细节对照文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 即可,遇到鉴权问题先查 API Keys 页面。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询