把 Skills 接到 Claude Code 的 SDK 查询里之后,模型并不是靠向量检索或关键词匹配决定调用哪个 Skill——而是在启动时把所有 Skill 的 name 与 description 渲染进 Skill 工具的提示词,让模型在前向传播里凭语义判断挑一个。Anthropic 在官方文档中明确指出,description 字段是「决定 Skill 何时被加载」的最关键字段,描述质量直接决定 Skill 能否在合适的场景自动触发。
一、Skills 自动触发的两阶段决策
Skills 在 Claude Code 中存在两种触发形态:用户输入 /skill-name 直接调用,以及模型根据上下文自动加载。后者才真正考验 description 写得好不好。
| 阶段 | 触发形式 | 决策主体 | 主要依据 |
|---|---|---|---|
| 会话启动 | 自动(发现阶段) | Claude Code 扫描器 | 目录结构、YAML 字段合法性 |
| 对话中(直接调用) | 用户输入 /skill-name |
Claude Code 路由 | 斜杠命令命名 |
| 对话中(自动调用) | 模型按语义判断 | Claude 模型本身 | description 字段 |
整个调用链路是:启动时扫描 ~/.claude/skills/、项目内 .claude/skills/、插件中的 Skills,把每个 Skill 的 name 与 description 拼成 Skill 工具的描述;用户提问时,模型读到这份描述列表,用纯 LLM 推理判断哪个 Skill 与当前意图最匹配,再以 Skill({ command: "skill-name" }) 形式发起调用。匹配过程不依赖 embedding、分类器或正则,纯粹是模型在上下文中对所有候选描述做语义打分。
二、description 字段为什么是决策核心
description 之所以关键,原因是它在「Skills 列表」里是模型唯一能直接看到的字段。Claude Code 启动时只把每个 Skill 的 name 与 description 注入 Skill 工具的描述区,完整 SKILL.md 正文要在 Skill 被选中后才加载。模型要决定「调不调、调哪个」,只能依赖这两段简短文本。
一份可用的 description 通常包含三类信息。
| 信息要素 | 作用 | 示例片段 |
|---|---|---|
| 任务定义 | 告诉模型这个 Skill 是干什么的 | 「部署应用到生产或预发环境」 |
| 触发场景 | 列举用户会说的意图、关键词、邻近说法 | 「用户提到 push to prod、release、go live」 |
| 排除边界 | 明确不适用的情况,避免误触发 | 「不用于本地开发服务器启动」 |
经验上,描述长度控制在 80–200 字之间效果最稳。太短(”部署应用”)覆盖不了近义说法,模型在「push to prod」「release」等表达上不会触发;太长(多段长句)会冲淡触发关键词,且 description 与 when_to_use 在 Skills 列表里合计被截断到 1536 字符,关键触发词若埋在末尾可能被截掉。
三、加载的渐进式结构
Skills 用「三级渐进披露」控制上下文开销,这一设计与决策机制紧密相关:
- 启动时只注入
name+description,每个 Skill 约 30–50 tokens; - 模型选中后,整个
SKILL.md正文才作为用户消息注入到当前对话; - 正文里引用到的参考文档、脚本、模板再按需读取。
---
name: deploy
description: >
Deploy the application to production or staging. Use when the user wants
to push code live, release a new version, trigger a CI/CD pipeline, or
ship to any hosting platform. NOT for local development server starts.
allowed-tools:
- Bash
- Read
---
## Deploy procedure
1. Run pre-deploy checks
2. Commit and push to the deployment branch
3. Verify the deployment completed
4. Run post-deploy health checks
把 Skills 写成这样的结构后,100 个 Skill 安装进 Claude Code,启动时只占几千 tokens;只有模型判定当前任务匹配 deploy 描述时,整个正文才会被加载。
四、影响决策的前置元数据
除了 description,还有几个字段能左右自动调用行为,配合使用时效果更可控。
| 字段 | 作用 | 典型取值 |
|---|---|---|
when_to_use |
显式触发短语列表,会拼到 description 后面 |
「push to prod」「go live」 |
disable-model-invocation |
关闭自动调用,仅允许用户手动触发 | 部署、迁移等高风险任务设为 true |
user-invocable |
在 / 菜单里隐藏,但模型仍可加载 |
背景知识类资料 |
allowed-tools |
限制 Skill 内可调的工具集合 | Read, Write, Bash |
工程上建议:所有带副作用的 Skill(部署、发消息、删数据)都把 disable-model-invocation 设为 true,避免模型在含糊的提示下误触发;只读的参考知识则可以保留 user-invocable: false,让模型在背景里调用但不出现在 / 菜单中。
五、常见陷阱与排查路径
description 写得不到位是 Skill 「永远不自动触发」的头号原因。排查时按下面这条顺序走,能在不开新窗口的前提下覆盖九成问题:先确认 SKILL.md 顶部 YAML frontmatter 解析正常(缩进、英文冒号、引号配对),再检查 description 是否覆盖了用户实际会说的近义说法(同一件事可能有五六种表达),最后用一句显式触发句测试——把目标意图原样写进提示词,看模型是否加载了预期 Skill。
如果走完三步仍不触发,可以再确认两件事。一是发现路径:Skills 只在 ~/.claude/skills/、项目 .claude/skills/、插件目录三处加载,文件放在子目录深处不会被扫到;monorepo 场景下,v2.1.203 之后支持嵌套 .claude/skills/,子目录里的 Skill 会以 apps/web:deploy 形式被命名空间化。二是会话生命周期:Skills 在会话启动时一次性注入列表,会话内不会重新扫描;改完 SKILL.md 必须重启会话才会生效。
六、与 MCP 自动调用的对照
把 Skills 和 MCP 放在一起看,「自动调用」这件事在两者身上的实现路径截然不同,对调试非常关键:Skills 是「在提示词里挂一段描述让模型推理」,MCP 则是「启动时通过 JSON-RPC 拉工具清单让模型选用」。前者吃的是 prompt token 但不发起网络调用,后者吃的是工具 schema 的上下文但能落到真实外部系统;两者经常组合使用——Skill 内部指引模型去调某个 MCP 工具,组成一条从「教怎么做」到「真能动手」的完整链路。
到这里,Skills 在 SDK 查询里的决策路径就清楚了:启动时把元数据注入 Skill 工具描述,模型用语义推理从 description 中挑出最匹配的 Skill,全文加载后再把流程指令注入对话。description 是唯一一处人类可控、决定自动调用命中率的字段。
常见问题(FAQ)
Q1:Skills 是怎么被发现的?
Claude Code 启动时扫描 ~/.claude/skills/、项目 .claude/skills/、插件目录,解析每个 SKILL.md 的 YAML frontmatter。
Q2:Skills 调用是关键词匹配吗?
不是。模型用纯 LLM 语义推理在 description 列表里挑选,没有向量检索或正则匹配。
Q3:如何让 Skill 不被自动调用?
在 frontmatter 中设置 disable-model-invocation: true,该 Skill 仅在用户输入 /skill-name 时触发。