动手开发 MCP 工具 里我们讲了怎么把工具做成远程服务,但很多时候你的需求没那么重,就是想把本地一些反复要做的操作想固化下来,每次一句话就能执行。这就是 Skill 要解决的问题。
Skills 最早由 Claude Code 推出,把重复的工作流写成一个 Markdown 文件(SKILL.md),AI 按需加载,一个 / 命令就能触发。因为确实好用,现在几乎所有主流 AI 编程工具都跟进了,包括 Codex、Cursor、GitHub Copilot 等,基本成了标配。
这篇文章以 Claude Code 为例讲解 Skill 的创建和使用。如果你用的是其他工具,核心概念完全一样,区别只是 Skill 文件的存放位置:
.claude/skills/
/.claude/skills/ Codex CLI
.agents/skills/
/.agents/skills/ Cursor
.cursor/skills/
/.cursor/skills/ GitHub Copilot
.github/skills/
/.copilot/skills/
各家的结构都差不多:一个文件夹下放一个 SKILL.md,用 YAML 头部声明元信息,Markdown 正文写具体指令。
虽然目录名不同,但 Cursor 和 GitHub Copilot 都内置了对 .claude/skills/ 的兼容,会自动扫描 Claude Code 的 Skill 目录。唯一需要手动处理的是 Codex CLI,加一个软链接就行:
# Codex CLI 不会自动读 .claude/skills,需要链接一下 ln -s ~/.claude/skills /.agents/skills
这样只维护 /.claude/skills/ 一个目录,所有工具都能用上。
下面直接上手做一个 Skill,就知道怎么用了,最后再讲一下 Skill 的渐进式加载机制,看看它是如何节省上下文的。
一个 Skill 就是 .claude/skills/ 下的一个文件夹,唯一必须的文件是 SKILL.md,其他文件(脚本、模板、参考资料)都是可选的。
我们来做一个图片优化 Skill,把图片压缩、缩放、转成 WebP。
Skill 放在 ~/.claude/skills/ 下是个人级的,所有项目可用;放在项目的 .claude/skills/ 下是项目级的,只在当前项目生效。
整个 Skill 的内容如下,你可以点开文件查看:
SKILL.md 分两部分:
YAML 头部(两行 --- 之间)声明元信息:Skill 叫什么名字、什么时候该被触发、需要哪些权限。
Markdown 正文(--- 下方)是给 Claude 看的具体指令,告诉它拿到这个 Skill 之后该怎么做。可以理解为一个操作手册。
YAML 头部各字段的含义后面会展开讲,这里先关注整体结构:头部定义「我是谁」,正文定义「怎么做」。
代码脚本主要用来封装固定的流程,比如这个例子里 SKILL.md 引用了 scripts/optimize.py 这个代码文件,用 Pillow 库做图片缩放、压缩和格式转换。
如果让 Claude 自由发挥,它肯定也能自己写个脚本完成任务,单每次结果可能不一样,而且消耗 token。把这些不变的流程沉淀成脚本直接让 Claude Code 调用,既能保证一致性,又能节省 token,只需在 SKILL.md 里告诉它脚本怎么用就行了。
但代码脚本并不是必须的,如果流程本身比较简单,纯文本描述就够了。
比如我们写一个 git 提交规范检查 Skill:
--- name: commit-check description: 检查 commit message 是否符合规范。提交代码、git commit 时使用。 disable-model-invocation: true allowed-tools: Bash(git *) --- 检查 git log 最近一条 commit message 是否符合格式:
(
):
type 必须是 feat/fix/refactor/docs/test/chore 之一。 如果格式不对,给出修改建议并用 git commit --amend 修正。
disable-model-invocation 和 allowed-tools 这几个参数的作用后面会讲,这里先看整体结构:没有脚本,没有额外文件,一个简单的文本文件,Claude Code 照样能准确执行。
文件保存好就行,不需要重启 Claude Code,它会自动检测到新的 Skill。
Skill.md 的 description 字段内容会加载到上下文,每次会话都会携带这些信息,所以直接跟 Claude Code 说「帮我把 screenshots 下的图片都压缩一下」,Claude Code 会自动加载合适 Skill 并按照文档的要求执行。
但是以我的实际经验来看,如果你的 description 写的太模糊宽泛、Skill 比较多、或者存在多个功能相近的 Skill 时,Claude Code 可能不会自动加载,甚至加载错误的 Skill。
所以我一般都是直接使用 /
明确指定 Skill 名称来触发,例如这样:
帮我按照 /xxx skill 的要求,执行 xxx 任务。
你可能会想:Skill 越写越多,启动时全加载进来,上下文窗口不会撑爆吗?
实际上不会。Skill 用的是三级渐进式加载,不是一股脑把所有内容塞进上下文,而是按需分层:只在需要的时候,才加载需要的那部分。
下面这张时序图展示了从启动到执行 Skill 的完整过程:
Claude Code 启动时,只读取每个 Skill 的 name 和 description,放进上下文。
每个 Skill 大约几十到一百 token(取决于 description 长度),十几二十个 Skill 在上下文窗口里基本可以忽略。
不过所有 Skill 的描述共享一个总预算(约为上下文窗口的 1%),如果你定义了特别多 Skill 或者每个 description 都写得很长,排在后面的可能被截断。
所以每个 Skill 的 description 要简明扼要,把最关键的信息放前面。
这些描述信息相当于一份目录。Claude 知道有哪些 Skill 可用、每个大概做什么,但 SKILL.md 的正文一个字都没加载。
你发了一条指令,Claude Code 能判断是否需要加载某个 Skill 来完成任务。
如果匹配上了(或者你直接输入 /skill-name 明确指定了某个 Skill),Claude 才从文件系统读取 SKILL.md 的内容追加到上下文。
读取 SKILL.md 后,Claude Code 会根据 SKILL.md 的正文内容判断是否需要加载附属资源(脚本、模板、参考文档)。
官方建议 SKILL.md 仅作为「操作手册」,内容控制在 500 行以内,具体的执行细节放在脚本、参考文档中作为附属资源。
如果你理解了前文 实现一个 chatbot 中 LLM 的调用过程,应该就很容易理解这里面的原理。
Claude Code 判断是否需要 Skill,并不是一个独立的关键词匹配算法,而是 LLM 自身的语言理解能力:
Claude Code 的 System Prompt 里面肯定写清楚了 Skill 是个什么东西,并写明了如何加载和使用 Skill。
所有 Skill 的 description 和用户的指令都追加到了上下文(messages 数组)中,所以 Claude Code 可以判断是否需要加载某个 Skill 来完成任务。
比如前面举例的 img-optimize 的 description 写「压缩、缩放图片并转换为 WebP 格式」,你随口说「帮我把截图弄小点」,Claude Code 也能理解并调用 img-optimize Skill 来完成任务。
Skill 目录里的脚本、模板、参考文档,只在执行过程中需要时才读取。
关键在于,Claude 并不需要「读懂」一个脚本才能用它。SKILL.md 的正文就是操作手册,里面写清楚了这个脚本干什么、接受哪些参数、怎么调用。Claude 照着手册执行就行,脚本源码本身不需要加载到上下文里。
比如前面 img-optimize 的 SKILL.md 里写了 uv run ${CLAUDE_SKILL_DIR}/scripts/optimize.py
<图片路径>图片路径>,Claude 只需要知道这行命令和参数含义,不需要读 optimize.py 的 Python 代码。执行后也只有脚本的输出结果进入上下文,源码始终不占位置。
针对 Skill 的这种加载机制,我总结了几条编写 Skill 脚本的**实践:
- 脚本内容不会进入上下文,所以
SKILL.md中记录的脚本用法一定要正确,脚本最好提供-h显示详尽的用法说明,供 Claude Code 使用时参考。 - 如果脚本出现异常,一定要说明异常的原因,以及排查方法。这是个非常有用的技巧,你不需要在
SKILL.md中穷举所有可能的异常情况,而是把脚本的报错输出作为SKILL.md的补充,这样就能辅助 Claude Code 更快更准确地解决问题。
前面已经展示了 Skill 的基本用法和加载原理,这里集中讲一下 YAML 头部几个重要的字段。
Claude Code 在执行 bash 命令等操作前,默认会暂停等你确认。allowed-tools 可以让指定的操作跳过确认,直接执行。格式是 工具名(匹配模式),其中 Bash 是 Claude Code 内置的命令行工具,括号里用 * 做通配符。比如 Bash(uv run *) 允许所有 uv run 开头的命令,Bash(git *) 允许所有 git 命令。
${CLAUDE_SKILL_DIR} 是 Claude Code 加载 Skill 时自动展开的内置变量,指向 SKILL.md 所在的目录。它不是系统环境变量,只在 SKILL.md 里有效。
disable-model-invocation: true 禁止 Claude Code 自动触发这个 Skill,只能手动用 /name 调用。从加载角度看,设了这个标记后 Level 1 直接跳过它,description 不进上下文,Claude 完全不知道这个 Skill 的存在。部署、发布这类有副作用的操作适合这么设。
$ARGUMENTS 是正文里的占位符,接收用户传入的参数。比如 /fix-issue 42 会把 $ARGUMENTS 展开为 42。
根据我的实践,这个 $ARGUMENTS 变量用的不多,因为编写 Skill 不需要像 shell 脚本那样精确,毕竟 LLM 的理解力是很强的。
直接用 /
的方式指定 Skill,然后用自然语言描述清楚想用 Skill 做什么,Claude Code 就能准确的理解并调用。
手写 SKILL.md 当然没问题,但有个更省事的办法。
Anthropic 官方维护了一个 skill-creator Skill,装上之后你只需要用自然语言描述想让 Claude Code 做什么,它会自动创建完整的 Skill 目录结构、写好 SKILL.md,需要脚本的地方也会帮你生成。
安装方式很简单,从 GitHub 仓库复制到个人 Skill 目录:
git clone https://github.com/anthropics/skills.git /tmp/anthropic-skills cp -r /tmp/anthropic-skills/skills/skill-creator ~/.claude/skills/
装好后,在 Claude Code 里输入 /skill-creator,然后描述你的需求就行:
使用 /skill-creator 帮我创建一个 Skill,能帮我 xxx
Claude Code 会分析你的需求,决定哪些部分适合用脚本固化、哪些用文本描述,然后自动生成完整的 Skill。你看一眼生成的内容,觉得合适就直接用。
skill-creator 效果不错,因为它的 SKILL.md 里沉淀了不少写 Skill 的**实践:description 怎么写匹配率更高,什么时候该用脚本,文件怎么组织。
你也可以直接读一下它的 SKILL.md,本身就是一份很好的 Skill 编写指南。
如果你现在已经想到了几个可以做成 Skill 的重复性流程,装上 skill-creator,描述清楚需求,让 Claude Code 自己搞定吧!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/267185.html