Skills 技能系统
本教程共 34 篇 · 第 21 篇 · 更新于 2026-07-26 · 约 11 分钟阅读
21. Skills 技能系统
本节目标:搞懂技能(Skill)是什么、和
CLAUDE.md有啥不一样。学会写SKILL.md、填 frontmatter、用渐进式披露省上下文,了解动态上下文注入、子代理运行和 skill-creator。学完你能把团队规范、固定流程打包成可复用的技能包,Claude 该用时自动用,不用时不占地方。
技能到底解决什么问题
用 Claude Code 时间长了,你会发现有些事反复做:每次提交代码都要按团队规范写 commit message,每次改 React 组件都要提醒它用你们的设计系统,每次部署都要走一遍固定流程。
这些说明你以前可能是这么处理的:把规范写进 CLAUDE.md,让 Claude 每次都读。问题来了——CLAUDE.md 是常驻上下文,里面的内容每轮对话都占 token。你写进去一份 2000 字的部署流程,哪怕这次只是改个错别字,那 2000 字也一直在那烧钱。
技能(Skill)就是解决这个的。它是一个独立的 Markdown 文件,平时只把名字和一句话描述放在上下文里(几乎不花成本),等你真正需要时才把完整内容加载进来。
打个比方:CLAUDE.md 像你桌上常摊开的笔记本,随时翻得到,但占桌面。技能像书架上的一本手册,你记得它讲什么(描述),要用时才取下来翻开(加载正文)。
技能遵循 Agent Skills 开放标准,同一份技能在 Claude.ai、Claude Code、VS Code Copilot、Cursor 等工具里都能用。Claude Code 在这基础上加了几个增强功能:控制谁来调用、子代理执行、动态上下文注入。
技能的最小结构
一个技能就是一个文件夹,里面必须有一个 SKILL.md:
my-skill/
└── SKILL.md # 唯一必需的文件
SKILL.md 分两部分:开头的 YAML frontmatter(夹在两个 --- 之间)告诉 Claude 这个技能是干嘛的、什么时候用;后面的 Markdown 正文是 Claude 调用时要遵循的具体说明。
最小的一个 SKILL.md 长这样:
---
name: python-naming
description: 团队 Python 命名规范。用户要求重构、审查或编写 Python 代码时使用。
---
## 指令
1. 所有内部辅助函数必须以 `_internal_` 前缀命名。
2. 发现不符合此规则的代码,主动提出修改建议。
## 示例
- 正确:`def _internal_calculate_risk():`
- 错误:`def _calculate_risk():`
目录名变成你输入的命令名。这个技能放在 .claude/skills/python-naming/ 下,你就能用 /python-naming 直接调用它。Claude 也会在你说「帮我写个 Python 函数」时自动加载它。
Note
.claude/commands/下的旧命令文件依然有效,行为和技能一样。但技能支持更多功能(支持文件、调用控制、自动加载),新项目建议直接用.claude/skills/。
技能放在哪里
存放位置决定谁能用到它:
| 位置 | 路径 | 谁能用 |
|---|---|---|
| 企业 | 托管设置分发 | 组织内所有用户 |
| 个人 | ~/.claude/skills/<技能名>/SKILL.md | 你的所有项目 |
| 项目 | .claude/skills/<技能名>/SKILL.md | 仅此项目 |
| 插件 | <插件>/skills/<技能名>/SKILL.md | 启用该插件的地方 |
同名技能的优先级:企业 > 个人 > 项目。任何一级的技能也会覆盖同名的捆绑技能。比如你在项目的 .claude/skills/ 里放一个 code-review,就会替掉内置的 /code-review。
插件技能用 插件名:技能名 命名,不会和其他级别冲突。
Tip项目技能适合提交到 Git,团队共享。个人技能放
~/.claude/skills/,跨项目复用,不进版本控制。
嵌套目录的技能
Monorepo 里每个包可以有自己的技能。Claude Code 会从当前目录往上找到仓库根,沿途的 .claude/skills/ 都加载。当你编辑 packages/frontend/ 里的文件时,packages/frontend/.claude/skills/ 里的技能也会按需出现。
如果嵌套技能和根目录的同名,两个都保留:根目录的用 /deploy,嵌套的用 /apps/web:deploy 这种限定名。Claude 会根据正在处理的文件自动选合适的那个。
实时变更检测
Claude Code 监视技能目录的文件变化。在 ~/.claude/skills/、项目 .claude/skills/ 里增删改技能,当前会话立即生效,不用重启。只有会话启动时不存在的顶级 skills 目录才需要重启才能识别。
frontmatter 字段参考
除了正文,SKILL.md 顶部的 YAML frontmatter 可以配置技能行为。所有字段都可选,但强烈建议写 description:
---
name: my-skill
description: 这个技能做什么、什么时候用
disable-model-invocation: true
allowed-tools: Read Grep
---
常用字段:
| 字段 | 作用 |
|---|---|
name | 显示名称,默认用目录名。仅小写字母、数字、短横线,最长 64 字符 |
description | 技能功能和使用时机,Claude 靠它判断是否自动加载。把关键用例放前面,组合文本上限 1536 字符 |
when_to_use | 额外的触发上下文,比如触发短语或示例请求,追加到 description 后 |
argument-hint | 自动补全时显示的参数提示,如 [issue-number] |
arguments | 命名位置参数,用于 $name 替换 |
disable-model-invocation | 设 true 禁止 Claude 自动调用,只能你手动 /name 触发 |
user-invocable | 设 false 从 / 菜单隐藏,只让 Claude 用 |
allowed-tools | 技能激活时 Claude 可免授权使用的工具 |
disallowed-tools | 技能激活时从工具池移除的工具 |
model | 技能激活时使用的模型,覆盖当前轮,下个提示恢复 |
effort | 工作量级别:low/medium/high/xhigh/max |
context | 设 fork 在子代理上下文中运行 |
agent | 配合 context: fork 使用的子代理类型 |
hooks | 限定于此技能生命周期的钩子 |
paths | glob 模式,限制只处理匹配文件时才激活 |
shell | 内联 shell 命令用的 shell,bash(默认)或 powershell |
Warning
name字段只影响显示标签,不改变你/后输入的命令名。命令名来自目录名(普通技能)或文件名(旧命令)。唯一例外是插件根SKILL.md,它没有目录名可用,这时name才决定命令名。
控制谁来调用技能
默认情况下,你和 Claude 都能调用任何技能。你可以 /技能名 直接调,Claude 也会在对话相关时自动加载。两个 frontmatter 字段帮你收紧控制:
disable-model-invocation: true:只有你能调。用于有副作用的工作流,比如 /deploy、/commit、/send-slack。你不想让 Claude 因为代码看起来准备好了就自己决定部署。
user-invocable: false:只有 Claude 能调。用于不能当命令操作的背景知识。比如一个 legacy-system-context 技能解释旧系统怎么运作,Claude 相关时该知道,但 /legacy-system-context 对你来说没意义。
| frontmatter | 你能调 | Claude 能调 | 何时加载 |
|---|---|---|---|
| 默认 | 是 | 是 | 描述常在上下文,调用时加载完整内容 |
disable-model-invocation: true | 是 | 否 | 描述不在上下文,你调用时才加载 |
user-invocable: false | 否 | 是 | 描述常在,调用时加载完整内容 |
渐进式披露:省上下文的关键
技能最聪明的地方是渐进式披露(Progressive Disclosure),分三层加载:
- 第一层:元数据。启动时只把每个技能的
name和description放进系统提示,让 Claude 知道有啥可用。这部分始终在上下文里,但很短。 - 第二层:核心指令。Claude 判断任务相关后,才读取
SKILL.md正文,加载完整说明。 - 第三层:资源文件。只在真正需要时才读取技能目录里的参考文档、示例,或执行脚本。
对比一下 CLAUDE.md:它所有内容都在第一层常驻。技能把大部分内容推到第二、三层,按需加载,所以长参考资料在你需要它之前几乎零成本。
多文件技能
复杂技能可以拆成多个文件,让 SKILL.md 聚焦要点:
my-skill/
├── SKILL.md # 主说明(必需)+ 导航
├── reference.md # 详细 API 文档,按需加载
├── examples.md # 使用示例,按需加载
└── scripts/
└── helper.py # 工具脚本,执行不加载
在 SKILL.md 里引用它们,让 Claude 知道每个文件装了什么、什么时候读:
## 额外资源
- 完整 API 细节见 [reference.md](reference.md)
- 使用示例见 [examples.md](examples.md)
Tip
SKILL.md控制在 500 行以内。详细参考资料挪到单独文件,按需加载。
给技能传参数
调用技能时可以传参数,用 $ARGUMENTS 占位符接收:
---
name: fix-issue
description: 修复 GitHub issue
disable-model-invocation: true
---
修复 GitHub issue $ARGUMENTS,遵循我们的编码规范。
1. 读取 issue 描述
2. 理解需求
3. 实现修复
4. 写测试
5. 创建 commit
运行 /fix-issue 123,Claude 收到的就是「修复 GitHub issue 123,遵循我们的编码规范…」。
按位置访问单个参数用 $ARGUMENTS[0] 或简写 $0:
---
name: migrate-component
description: 把组件从一个框架迁移到另一个
---
把 $0 组件从 $1 迁移到 $2。
保留所有现有行为和测试。
运行 /migrate-component SearchBar React Vue,$0 变成 SearchBar,$1 变成 React,$2 变成 Vue。
有用的内置变量
| 变量 | 含义 |
|---|---|
$ARGUMENTS | 所有参数 |
$ARGUMENTS[N] / $N | 第 N 个参数(0 基索引) |
$name | 在 arguments 里声明的命名参数 |
${CLAUDE_SESSION_ID} | 当前会话 ID,适合日志、临时文件 |
${CLAUDE_EFFORT} | 当前工作量级别 |
${CLAUDE_SKILL_DIR} | 技能所在目录,引用捆绑脚本 |
${CLAUDE_PROJECT_DIR} | 项目根目录 |
${CLAUDE_SKILL_DIR} 特别有用,无论技能装在个人、项目还是插件级别,它都正确解析到技能自己的目录,方便引用捆绑的脚本。
动态上下文注入
有时候你想让技能基于实时数据工作,比如总结当前 git diff。!`命令` 语法在技能内容发给 Claude 之前先执行 shell 命令,把输出插进去:
---
description: 总结未提交的更改并标记风险。
---
## 当前更改
!`git diff HEAD`
## 指令
用两三个要点总结上面的更改,然后列出你注意到的风险,比如缺少错误处理、硬编码值、需要更新的测试。如果 diff 为空,说明没有未提交的更改。
Claude 看到的不是 !git diff HEAD“ 这个命令,而是它的实际输出。这是预处理,不是 Claude 执行的。
多行命令用 ! 围栏代码块:
## 环境
```bash
node --version
npm --version
git status --short
```
Warning内联形式只在
!出现在行首或紧跟空白后才识别。KEY=!cmd“ 这种写法会被当成字面文本,命令不会跑。
在子代理里运行技能
加 context: fork,技能就在隔离的子代理上下文里跑,看不到你的对话历史:
---
name: deep-research
description: 彻底研究某个主题
context: fork
agent: Explore
---
彻底研究 $ARGUMENTS:
1. 用 Glob 和 Grep 找相关文件
2. 读取并分析代码
3. 带具体文件引用总结发现
运行时:创建新的隔离上下文 → 子代理收到技能内容作为提示 → agent 字段决定执行环境(Explore、Plan、general-purpose 或自定义子代理)→ 结果摘要返回主对话。
Warning
context: fork只适合有明确任务的技能。如果你的技能只是「使用这些 API 约定」之类的指南,子代理收到指南但没有可执行任务,会空手而归。
内置捆绑技能
Claude Code 自带一组捆绑技能,每个会话都可用(除非禁用),包括:
/doctor:诊断配置问题/code-review:代码审查/batch:批量处理/debug:调试/loop:循环任务/claude-api:Claude API 相关
还有三个协同工作来运行和验证你的应用:
| 技能 | 作用 |
|---|---|
/run | 启动并驱动应用,看改动是否生效 |
/verify | 构建并运行应用,确认代码改动按预期工作 |
/run-skill-generator | 教 /run 和 /verify 怎么构建启动你的项目 |
捆绑技能是基于提示的:它们给 Claude 详细说明,让 Claude 用自己的工具去编排工作,而不是直接执行固定逻辑。需要 v2.1.145 或更高版本。
技能内容生命周期
调用技能时,SKILL.md 渲染后的内容作为一条消息进入对话,并在会话剩余部分保持在那里。Claude Code 不会后续轮次重新读技能文件,所以要把应该贯穿整个任务的指导写成常设说明。
当 Claude 重新调用一个技能且内容没变,Claude Code 只加一句「该技能已加载」的说明,不会塞第二份副本。如果内容变了(参数变了或动态上下文产生了新输出),才会再附加完整内容。
自动压缩时,Claude Code 在总结后重新附加每个技能的最近一次调用,保留前 5000 token,所有重新附加的技能共享 25000 token 预算。从最近调用的开始填,所以一次会话调了太多技能,旧的可能会被压缩掉。
Tip如果某个技能在第一个响应后好像不再影响行为,内容其实还在,只是模型选了别的路子。强化
description和说明,或用钩子(Hook)强制行为。压缩后想恢复,重新调用一次就行。
用 skill-creator 造技能
写技能和写代码一样,需要迭代。Anthropic 官方提供了 skill-creator 插件,在 Claude Code 里自动化整个创建-测试-优化循环。
从官方市场安装:
/plugin install skill-creator@claude-plugins-official
装完运行 /reload-plugins 让当前会话能用,然后让 Claude 评估或创建技能,比如 evaluate my summarize-changes skill with skill-creator。
skill-creator 帮你做这些:
- 需求梳理:通过对话问清楚技能做什么、何时触发、输出格式
- 起草 SKILL.md:根据你的回答生成初稿和参考文件
- 测试用例:在技能目录的
evals/evals.json存提示、输入文件、预期行为 - 隔离运行:每个测试用例起一个子代理,从干净上下文跑,记录 token 和耗时
- 评分:检查每个断言,把通过/失败写进
grading.json - 基准对比:聚合通过率、时间、token,有技能 vs 无技能对比,放进
benchmark.json - 版本比较:两个版本的技能盲测 A/B,确认改动是真改进才提交
- 描述调整:生成应触发和不应触发的提示,测命中率,描述不准时提议修改
整个流程是个循环:想清楚需求 → 起草 SKILL.md → 设计测试 → 跑测试 → 看报告 → 改 SKILL.md → 重复。
Note如果 Claude Code 报告找不到该插件,运行
/plugin marketplace update claude-plugins-official刷新,或/plugin marketplace add anthropics/claude-plugins-official添加后重试。
技能 vs CLAUDE.md vs 子代理
这三个容易混,这里我踩过坑,帮你们理清楚:
| 维度 | CLAUDE.md | 技能(Skill) | 子代理(Subagent) |
|---|---|---|---|
| 加载时机 | 会话开始就全量加载 | 描述常在,正文按需加载 | 委托时才创建独立上下文 |
| 上下文成本 | 每轮都占 | 几乎零,调用时才占 | 主对话只收摘要 |
| 适合放什么 | 项目事实、约定、常驻规则 | 可复用流程、专项知识、有副作用的操作 | 探索、审查、调试等脏活 |
| 触发方式 | 自动 | 自动或手动 /name | Claude 自动委托 |
| 隔离性 | 无 | 无(内联)或有(context: fork) | 有,独立上下文 |
简单记:CLAUDE.md 写「这个项目是啥、有啥约定」,技能写「怎么做某件具体事」,子代理是「让另一个 AI 去干这件事,只把结论给我」。
技能不触发怎么办
如果 Claude 该用技能却没用:
- 检查
description是否包含用户会自然说的关键词 - 问 Claude「What skills are available?」确认技能被识别
- 把请求改得更贴近描述
- 如果技能是用户可调用的,直接
/技能名手动触发
frontmatter YAML 格式不对的话,Claude Code 会加载技能正文但元数据为空,/技能名 还能用,但 Claude 没有 description 去匹配自动触发。用 --debug 运行能看到解析错误。
技能触发太频繁
反过来,如果 Claude 老在不该用的时候用:
- 把 description 写得更具体,加上限定条件
- 只想手动触发就加
disable-model-invocation: true
描述被截断
技能列表有字符预算(按模型上下文窗口的 1% 扩展)。技能太多时,Claude Code 会从你最不常调用的开始砍描述。运行 /doctor 看列表的上下文成本和最大贡献者。
要释放预算:在 skillOverrides 设置里把低优先级技能设成 "name-only"(只列名字不显示描述)。或者在源处精简 description 和 when_to_use,把关键用例放前面。
共享技能
技能按受众分几种分发方式:
- 项目技能:把
.claude/skills/提交到版本控制,团队拉代码就有 - 插件:在插件里建
skills/目录,通过插件市场分发 - 托管:通过托管设置在企业内部署
技能遵循开放标准,你写的技能不只能给自己用。社区也有现成的技能集合,比如 anthropics/skills 仓库里有 PDF、PPT、Excel 等文档处理技能。
把那个仓库注册成插件市场:
/plugin marketplace add anthropics/skills
然后装文档技能集:
/plugin install document-skills@anthropic-agent-skills
装完重启 Claude Code,跟 Claude 说「用 PDF 技能提取这个文件的表单字段」就能调用 /document-skills:pdf 了。