Agent Skills 使用指南
用一个 Markdown 文件,就能给 AI Agent 注入领域能力。本指南讲清 Skill 是怎么回事、怎么用,以及哪些坑必须避开。
Skill 是怎么回事
一句话:Skill(技能)= 一份带 YAML 元数据的 Markdown 文档(外加可选的 Shell 命令),用来把"某个领域怎么做事"的知识与流程,按需注入到 Agent 的上下文里。
它解决什么问题?
大模型很聪明,但它不知道你的项目约定、不知道你团队的发布流程、也不知道某个内部工具怎么用。Skill 就是把这些"私有知识 + 标准操作流程(SOP)"打包成文件,让 Agent 在合适的时机自动读取、按章办事。
和"直接写进 Prompt"有什么区别?
- 按需加载:不是把所有知识塞满上下文,而是模型判断需要时才调入对应 Skill,避免认知过载与 token 浪费。
- 可复用、可分享:一个 Skill 就是一个文件夹,可以提交进仓库、跨项目复用、团队共享。
- 零编程门槛:写 Markdown 就行,不需要写一行 TypeScript / Python。
- 能带实时状态:Skill 里可以内嵌 Shell 命令,调用时先在你机器上执行,把真实的
git status、目录列表等"现场信息"一起喂给模型。
一个 Skill 的构成
每个 Skill 的核心是一个名为 SKILL.md 的文件,由三部分组成:YAML 元数据头、Markdown 正文、可选的内嵌 Shell 命令。此外,文件夹里还能放独立的配套脚本(scripts/*.sh 等),由模型在执行时按需调用——这与内嵌 Shell 不同,详见后文对比。
三种来源
同样一个 Skill,可能来自三种渠道。来源不同,可信度与能力边界也不同 —— 这是后面"安全注意事项"的基础。
📂 File-based
放在本地 .claude/skills/ 目录下的 SKILL.md。由你或团队编写,可信度最高,允许执行内嵌 Shell。
📦 Bundled
随 Agent 程序一起打包分发的官方内建技能,开箱即用,无需安装。属于受信任来源。
🔌 MCP
来自外部 MCP Server 的能力,被映射成 Skill。来源不可控,出于安全不会执行内嵌 Shell。
目录结构
想新建一个技能,只需在约定目录下建一个文件夹,里面放一个 SKILL.md。Agent 启动时会自动扫描发现它。
三个可放置的位置(按优先级与作用域)
| 位置 | 作用域 | 典型用途 |
|---|---|---|
~/.claude/skills/ | 用户级(全局) | 个人通用技能,所有项目共享 |
<项目>/.claude/skills/ | 项目级 | 随仓库提交,团队共享的项目专属技能 |
| 策略管理目录 | 组织/策略级 | 企业统一下发、不可随意修改的技能 |
编写 SKILL.md
下面是一个完整可用的示例:一个帮你检查 Git 状态并给出建议的技能。注意它如何用内嵌 Shell 携带真实现场信息。
--- name: git-status-helper description: 查看当前 Git 状态并给出提交建议 when_to_use: 当用户询问代码改动、是否该提交、或想了解仓库状态时 allowed_tools: [Bash, Read] effort: low --- # Git 状态助手 当前分支与最近提交: !`git log --oneline -5` 未提交的变更: !`git status --short` 请根据以上真实信息,帮我判断: 1. 这些改动是否应该拆成多个 commit? 2. 给出建议的 commit message。
逐段解读
- YAML 头(
---之间):声明元数据。name是技能名,description让模型知道"这个技能干什么",when_to_use告诉模型"什么时候该用我"。 - Markdown 正文:就是你想喂给模型的指令。可以写步骤、规则、模板、示例。
- 内嵌 Shell
!`...`:调用技能时,这两条git命令会先在你机器上执行,命令本身被替换成真实输出。于是模型拿到的是"此刻仓库的真实状态",而不是空泛的占位符。
Frontmatter 字段速查
YAML 头里可用的全部字段。除 name 外大多可选,但 description / when_to_use 强烈建议写,它们决定模型能否在正确时机找到你的技能。
| 字段 | 类型 | 作用 |
|---|---|---|
name | string | 技能名,也是用户调用时的 /name |
description | string | string[] | 技能简介,帮助模型理解用途 |
when_to_use | string | 触发时机描述,模型据此自主选择是否调用 |
allowed_tools | string[] | 限定该技能可用的工具集合(白名单) |
model | string | 指定运行该技能使用的模型 |
effort | low | medium | high | 任务估时/算力档位 |
user_invocable | boolean | false = 仅供模型内部调用,不出现在 / 命令列表 |
paths | string[] | 条件触发的 glob:匹配文件变更时自动激活 |
version | string | 技能版本号 |
context | inline | fork | 注入当前上下文,还是派生子上下文执行 |
agent | string | 绑定到指定 agent 类型 |
shell | bash | powershell | 内嵌 Shell 使用的解释器 |
内嵌 Shell:让 Prompt 携带实时状态
这是 Skill 最强大的特性。Markdown 里嵌入的命令在技能被调用前先执行,输出回填正文,于是模型拿到的永远是"现场"而非"快照"。
两种语法
内联式
当前目录文件:!`ls -la`
代码块式
```! git diff --stat ```
配套脚本 ≠ 内嵌 Shell
技能文件夹里除了 SKILL.md,还能放独立的脚本文件(.sh / .py / .js …)。它们和正文里的内嵌 Shell 是两种完全不同的东西——最容易混淆,这里专门讲清。
一句话区分
- 内嵌 Shell
!`...`:写在 SKILL.md 正文里,技能加载/调用前由框架自动执行,输出回填进 Prompt。目的是给模型喂"现场状态"。它一定会跑,模型管不着。 - 配套脚本
scripts/xxx.sh:是文件夹里独立的可执行文件,模型在执行任务时按 SKILL.md 的指示、通过Bash工具主动调用。目的是封装可复用、确定性强的复杂逻辑。跑不跑、怎么传参,由模型决定。
逐维对比
| 维度 | 内嵌 Shell !`...` | 配套脚本 scripts/*.sh |
|---|---|---|
| 位置 | SKILL.md 正文内 | 独立文件,与 SKILL.md 同目录 |
| 执行时机 | 技能加载/调用前,自动执行 | 任务执行中,模型主动调用 |
| 谁决定运行 | 框架(一定会跑) | 模型(按正文指示判断) |
| 目的 | 把实时状态回填进 Prompt | 封装可复用、确定性的逻辑 |
| 如何引用 | 直接写命令 | 用 ${CLAUDE_SKILL_DIR}/scripts/xx.sh 定位 |
| 能否传参 | 固定命令,不便传参 | 可像普通脚本一样传参、循环、复用 |
| MCP 来源 | 不执行(防 RCE) | 仍可由模型调用(走 Bash 工具权限) |
正确写法:让模型去调用脚本
注意下面正文里的命令没有 ! 前缀——它不是内嵌 Shell,而是写给模型看的指令。模型读到后会用 Bash 工具去执行这个脚本。
--- name: release-helper description: 发布前自动化检查 allowed_tools: [Bash, Read] --- # 发布助手 发布前,请用 Bash 运行项目自带的预检脚本: bash ${CLAUDE_SKILL_DIR}/scripts/preflight.sh 根据脚本输出的检查结果,告诉我是否可以安全发布; 若有失败项,定位到对应文件并给出修复建议。
! 前缀(!`bash …`)会让它在加载期就被框架自动执行,脱离模型控制,也无法根据上下文传参——这通常不是你想要的。两种调用方式
写好的技能有两种被触发的途径:你手动调用,或模型自主判断后调用。
⌨️ 用户调用 /name
在对话框输入斜杠命令,例如 /git-status-helper,直接调起对应技能。可携带参数,正文里的占位符会被展开。
🤖 模型自主选择
模型读取所有技能的 description 与 when_to_use,在合适时机自动调用。这正是 when_to_use 要写清楚的原因。
调用时正文会被加工
无论哪种方式,技能被调用时,正文都会经过几步处理后才交给模型:
- 展开参数占位符:把你传入的 CLI 参数填进正文。
- 替换内置变量:
${CLAUDE_SKILL_DIR}(技能所在目录)、${CLAUDE_SESSION_ID}(当前会话 ID)会被替换成真实值,方便引用配套脚本。 - 执行内嵌 Shell:把
!`...`替换成真实输出(仅受信任来源)。
条件触发:paths 字段
声明了 paths 的技能叫"条件技能"。当用户操作或修改了匹配该 glob 的文件时,技能会自动激活并注入上下文 —— 一种精准的 Hook 订阅模式。
--- name: migration-reminder description: 改动数据库 schema 时提醒同步迁移脚本 paths: ["**/schema.prisma", "**/migrations/**"] --- 检测到你正在改动数据库 schema,请记得: 1. 运行迁移生成命令 2. 检查是否影响线上数据
注意事项
Skill 强大,也意味着它能在你机器上执行命令、能左右模型行为。下面分安全、性能、易踩的陷阱三类,逐条避坑。
安全谨防代码执行与来源信任
!`...` 都会在你机器上真实运行。不要直接安装来源不明的第三方 Skill,使用前务必通读其 SKILL.md,确认内嵌命令无害。!`...` 也不会执行,防止远程注入。不要试图绕过它。allowed_tools 给技能配最小工具白名单,遵循最小权限原则。性能别让技能拖慢或塞爆上下文
effort 与 context。重任务标 effort: high;需要隔离、不污染主上下文的,用 context: fork 派生子上下文执行。陷阱容易忽略的隐藏行为
| 陷阱 | 说明与对策 |
|---|---|
when_to_use 写得含糊 | 模型据此判断是否调用。写不清就会"该用的时候不用、不该用的时候乱用"。要具体描述触发场景。 |
user_invocable: false 的隐身技能 | 设为 false 后技能不出现在 / 列表,只能由模型内部调用。排查"命令找不到"时先看这个字段。 |
paths glob 过宽 | 范围太大会导致技能频繁自动激活、造成认知过载。glob 要尽量精确。 |
| 同名技能与缓存 | 发现结果会被缓存,且按真实路径去重。改了技能没生效时,检查是否命中缓存或被同名技能覆盖。 |
| 特殊字符替换污染 | 内嵌命令输出若含 $& 等替换符号,需注意被正确转义(实现已用函数式替换规避)。 |
原理补充:加载全流程
想深入了解底层机制?下面是从"发现技能文件"到"把最终 Prompt 交给模型"的完整流水线。日常使用无需关心,感兴趣可展开。
export const getSkillDirCommands = memoize(async (cwd) => { // 并行加载所有来源:策略级 / 用户级 / 项目级 / --add-dir / 旧版命令 const [managed, user, project, extra, legacy] = await Promise.all([...]) // inode 级去重,防软链重复 return deduplicateByRealpath([...managed, ...user, ...project, ...extra, ...legacy]) })
完整逐行剖析见配套文档 架构深度解析 · Skills 章节。