本页目录22
- 技能以 `SKILL.md` 文件形式存在于磁盘,SDK 不提供编程方式注册技能,发现依赖 `settingSources`/`setting_sources` 是否包含 `user`/`project`
- `skills` 选项可传 `"all"`、具体技能名列表或 `[]`,用于控制 Claude 能调用哪些技能;设置该选项时 SDK 会自动把 `Skill` 加入 `allowedTools`
- 通过在 prompt 中发送 `/<name>` 可直接派发命令,该行为不受 `skills` 列表限制,即使技能未列入允许列表也能派发
- `skills` 列表中的名称必须是精确技能名,不允许空名、通配符(如裸 `*` 或 `:*` 后缀)、含括号/逗号/控制字符或有前后空白的名称,否则 `query()` 会在启动前抛错
- 对 project/personal 技能,`allowed-tools` frontmatter 字段仅在 Claude Code CLI 中生效;SDK 会话中应改用 `allowedTools`/`allowed_tools` 选项预授权工具
本文是对 Claude Agent SDK 官方文档「Extend agents with skills」页面的中文整理,完整与最新内容以原文为准:https://code.claude.com/docs/en/agent-sdk/skills
概述
Agent Skills 用于扩展 Claude 的专项能力,Claude 会在相关场景下自动调用。技能被打包为 SKILL.md 文件,其中包含说明、description 描述以及可选的配套资源。本文同时涵盖 Agent SDK 会话中的命令。
关于技能的完整概念性说明(优势、架构、编写指南),参见 Agent Skills overview。
技能在 Agent SDK 中的工作方式
使用 Claude Agent SDK 时,技能具有以下特性:
- 以文件系统制品形式定义:每个技能是自己目录下的一个
SKILL.md文件,例如.claude/skills/<name>/SKILL.md - 从文件系统加载:SDK 根据
settingSources(TypeScript)或setting_sources(Python)所控制的位置加载技能 - 自动发现:文件系统设置加载后,SDK 会在启动时从用户和项目目录发现技能元数据,并在 Claude 调用该技能时加载完整内容
- 由模型调用:Claude 会根据上下文自主决定何时使用
- 由用户调用:你可以在 prompt 中发送
/<name>直接派发某个技能,参见会话内命令的派发 - 通过
skills选项限定范围:被发现的技能默认启用;可传入技能名列表、"all"或[]来控制 Claude 能调用哪些技能
与可通过 agents 选项 编程定义的 subagent 不同,技能只能作为磁盘上的文件创建,SDK 不提供编程方式注册技能的 API。
Note 技能通过文件系统的 setting sources 被发现。使用默认的
query()选项时,SDK 会加载 user 和 project 来源,因此~/.claude/skills/、<cwd>/.claude/skills/以及<cwd>到仓库根目录之间任意父目录下的.claude/skills/中的技能都可用。如果显式设置了settingSources,需包含'user'或'project'才能保留技能发现;或使用plugins选项 从特定路径加载技能。
在 Agent SDK 中使用技能
在 query() 上设置 skills 选项,用于控制该会话中 Claude 能调用哪些技能。省略该选项时,被发现的技能默认启用,且 Skill 工具可用,行为与 CLI 一致。
skills 取值 | 说明 |
|---|---|
"all" | Claude 可以调用所有被发现的技能 |
技能名列表(如 ["pdf", "docx"]) | 只允许调用列表中的技能 |
[] | Claude 不能调用任何技能 |
例如,仅允许调用两个具名技能:
options = ClaudeAgentOptions(skills=["pdf", "docx"])
const options = { skills: ["pdf", "docx"] };
在会话中配置技能
设置 skills 后,SDK 会自动把 Skill 加入 allowedTools。如果你同时传入了显式的 tools 列表,需要在该列表中包含 "Skill",Claude 才能调用技能。
配置完成后,Claude 会自动从文件系统发现技能,并在与用户请求相关时调用。
下例在会话中启用所有被发现的技能,并预先批准技能常用的工具。示例将 cwd 设为进程当前工作目录,因此需要在包含 .claude/skills/ 目录(位于当前目录或到仓库根目录之间的任意父目录)的项目内运行:
import asyncio
import os
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
options = ClaudeAgentOptions(
cwd=os.getcwd(), # .claude/skills/ here or in a parent directory
setting_sources=["user", "project"], # Load skills from filesystem
skills="all", # Let Claude invoke every discovered skill
allowed_tools=["Read", "Write", "Bash"],
)
async for message in query(
prompt="Help me process this PDF document", options=options
):
print(message)
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Help me process this PDF document",
options: {
cwd: process.cwd(), // .claude/skills/ here or in a parent directory
settingSources: ["user", "project"], // Load skills from filesystem
skills: "all", // Let Claude invoke every discovered skill
allowedTools: ["Read", "Write", "Bash"]
}
})) {
console.log(message);
}
确认技能已加载
消息流开始不久,SDK 会发出一条 subtype 为 init 的 system 消息。检查其中的 skills 数组即可确认技能已在 Claude 开始工作前加载完成。该数组包含你定义的用户可调用技能,以及 Claude Code 自带的 bundled skills。
该数组只列出「用户可调用」的技能。frontmatter 中设置了 user-invocable: false 的技能会正常加载并可供 Claude 使用,但不会出现在该数组中。该数组反映的是本次会话发现的内容,无论技能是否在你的 skills 列表中,列出的都是相同技能集合。
仅允许特定技能
若只想允许 Claude 调用特定技能,在 skills 列表中传入其名称。名称需匹配 SKILL.md 中的 name 字段或技能所在目录名。插件提供的技能使用 plugin:skill 形式。
该列表只接受精确的技能名。如果某个条目无法作为精确名称使用,query() 会在会话启动前拒绝整个列表,详见无效技能名称报错。
模型看不到未列出的技能,Skill 工具也会拒绝调用它们,但对应文件仍在磁盘上,仍可通过 Read 和 Bash 访问。限制该列表不会限制按名称派发。
若要允许调用所有被发现的技能,应传 skills: "all",而非通配符写法。
Agent SDK 会话中的命令
本节是 SDK 的命令文档。命令(command)指的是在 prompt 中发送 /<name> 所运行的任何内容。命令面板上的条目背后支撑不同:
- 内置命令(Built-in commands):执行编码在 SDK 所运行的 Claude Code 进程中的逻辑,例如
/compact - 自带技能(Bundled skills):随 Claude Code 一起提供的 prompt 制品,例如
/code-review - 你自己的技能(Your skills):你编写的 prompt 制品,每个都是包含
SKILL.md文件的目录。用户可调用技能的名称会自动加入命令面板,因此派发你自己的/security-check与运行内置命令的方式相同 - 自定义命令文件(Custom command files):一种较早的制品形式,行为相同,是
.claude/commands/下的扁平 Markdown 文件,文件名即命令名。技能是它们推荐的继任形式
默认情况下,你和 Claude 都可以调用任意技能。你可以通过技能的 frontmatter 分别限制这两条路径。两个术语的定义参见词汇表中的 Command 与 Skill 条目。所有内置命令参见 Commands in Claude Code;两种制品形式的完整指南参见 Extend Claude with skills。
发现可用命令
通过 SDK 可以派发那些无需交互式终端即可运行的命令。system/init 消息的 slash_commands 字段会列出会话中可用的命令。需要交互式终端的命令(例如 /theme 和 /terminal-setup)不会出现在列表中。在会话开始时访问该字段:
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Hello Claude",
options: { maxTurns: 1 }
})) {
if (message.type === "system" && message.subtype === "init") {
console.log("Available commands:", message.slash_commands);
}
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, SystemMessage
async def main():
async for message in query(prompt="Hello Claude", options=ClaudeAgentOptions(max_turns=1)):
if isinstance(message, SystemMessage) and message.subtype == "init":
print("Available commands:", message.data["slash_commands"])
asyncio.run(main())
打印出来的列表会混合内置命令、自带技能、你的用户可调用技能以及 .claude/commands/ 文件:
Available commands: ["clear", "compact", "context", "usage", "code-review", "verify", "security-check", ...]
你的用户可调用技能会同时出现在这个列表和「确认技能已加载」一节中的 skills 数组里。slash_commands 列表则额外包含会话中其余可用命令。frontmatter 中设置了 user-invocable: false 的技能不会出现在这两个列表中任何一个里。配置了 MCP 服务器 的会话还可以将 MCP prompts 暴露为命令。
按名称派发命令
将命令包含在 prompt 字符串中即可发送,方式与发送普通文本相同。派发行为不依赖 skills 选项——即使你的 skills 列表中省略了某个技能,发送 /<name> 依然会运行该用户可调用技能。作用于会话历史的命令(如 /compact)需要已有的历史消息才能工作。
Note 命令与其他 prompt 一样可能触发
maxTurns/max_turns限制,此时查询会以 error 结果而非success结束。关于 error 结果的约定,参见 Handle the result。如果你的命令可能触发该限制,可参考 Single Message Input 的示例,在 TypeScript 中用try/catch、在 Python 中用try/except包裹调用,或者把maxTurns设置得足够大以完成工作。
用 /compact 压缩历史
/compact 命令会在保留重要上下文的同时,通过总结较早的消息来缩减对话历史的大小。压缩操作需要已有对话中有足够多的先前消息可供总结。下例先进行一次对话,然后执行压缩,并读取报告结果的 compact_boundary system 消息:
import { query } from "@anthropic-ai/claude-agent-sdk";
// Compaction needs existing history, so have a conversation first
try {
for await (const message of query({
prompt: "Explain what this project does",
options: { maxTurns: 2 }
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result,
// so the follow-up query below still runs.
console.error(`Session ended with an error: ${error}`);
}
// Compact the same conversation
for await (const message of query({
prompt: "/compact",
options: { continue: true, maxTurns: 1 }
})) {
if (message.type === "system" && message.subtype === "compact_boundary") {
console.log("Compaction completed");
console.log("Pre-compaction tokens:", message.compact_metadata.pre_tokens);
console.log("Trigger:", message.compact_metadata.trigger);
// Example output:
// Compaction completed
// Pre-compaction tokens: 1842
// Trigger: manual
}
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage, SystemMessage
async def main():
# Compaction needs existing history, so have a conversation first
try:
async for message in query(
prompt="Explain what this project does",
options=ClaudeAgentOptions(max_turns=2),
):
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
except Exception as error:
# A single-shot query() raises after yielding an error result,
# so the follow-up query below still runs.
print(f"Session ended with an error: {error}")
# Compact the same conversation
async for message in query(
prompt="/compact",
options=ClaudeAgentOptions(continue_conversation=True, max_turns=1),
):
if isinstance(message, SystemMessage) and message.subtype == "compact_boundary":
print("Compaction completed")
print("Pre-compaction tokens:", message.data["compact_metadata"]["pre_tokens"])
print("Trigger:", message.data["compact_metadata"]["trigger"])
# Example output:
# Compaction completed
# Pre-compaction tokens: 1842
# Trigger: manual
asyncio.run(main())
Note 只有在实际执行了压缩时才会出现
compact_boundary消息。如果没有可总结的内容,/compact会在结果文本中说明原因而不是抛出异常。这次运行仍会以success结果结束,但不会有compact_boundary消息,结果文本会携带原因,例如单次简短往来后返回Not enough messages to compact.。全新的一次性query()调用以空上下文开始,因此该模式应在带有先前对话轮次的会话中使用,例如在流式输入模式下,或在恢复会话时。
用 /clear 重置上下文
/clear 命令会把对话重置为空上下文,因此后续 prompt 不带有先前的对话历史。之前的对话仍保存在磁盘上,可以通过将其 session ID 传给 resume 选项 回到该对话。
/clear 在流式输入模式下很有用,因为该模式下你会在单个连接上发送多个 prompt。对于一次性的 query() 调用,每次调用本身就以空上下文开始,因此发送 /clear 没有实际效果——应直接发起一个新的 query()。
创建技能
将每个技能创建为一个目录,目录下放一个带 YAML frontmatter 与 Markdown 正文的 SKILL.md 文件。description 字段决定 Claude 何时调用该技能。
示例目录结构:
.claude/skills/security-check/
└── SKILL.md
选择发现级别
技能可保存在两个最常见的发现级别:
| 级别 | 路径 | 可用范围 |
|---|---|---|
| 项目技能(Project skills) | .claude/skills/ | 仅当前项目 |
| 个人技能(Personal skills) | ~/.claude/skills/ | 你所有的项目 |
如果你已有 .claude/commands/ 下的自定义命令文件,它们会继续正常工作。例如 .claude/commands/deploy.md 会创建 /deploy,行为与 .claude/skills/deploy/SKILL.md 形式的技能相同。若命令文件与技能同名,哪一个会运行参见 Where skills live。SDK 会从与技能相同的两个作用域加载 .claude/commands/ 和 ~/.claude/commands/ 文件。两种制品形式的完整指南参见 Extend Claude with skills。
创建并派发你的第一个技能
为演示完整流程,创建 .claude/skills/security-check/SKILL.md:
---
name: security-check
description: Run a security vulnerability scan
---
Analyze the codebase for security vulnerabilities including:
- SQL injection risks
- XSS vulnerabilities
- Exposed credentials
- Insecure configurations
文件一旦存在,该技能即可通过 SDK 使用。当请求与其描述匹配时 Claude 会调用它,你也可以直接派发:
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "/security-check",
options: { maxTurns: 10 }
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
async for message in query(
prompt="/security-check", options=ClaudeAgentOptions(max_turns=10)
):
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
asyncio.run(main())
一次成功运行会以 success 结果结束,结果文本携带扫描发现。针对一个种入了问题的小型 Express 应用,结果文本开头类似:
**Security scan of `app.js` — 4 findings (most severe first):**
1. **SQL Injection** (line 8) — `req.query.name` is concatenated directly into the SQL string. Trivially exploitable (`' OR '1'='1`, `'; DROP TABLE users;--`). **Fix:** use parameterized queries, e.g. `db.query("SELECT * FROM users WHERE name = ?", [req.query.name], cb)`.
...
该技能名称也会出现在 init 消息的 slash_commands 数组中。
Note Claude Code 自带
code-review和verify技能。如果你以其中之一命名.claude/commands/文件,例如.claude/commands/code-review.md,该文件对应的命令会覆盖(shadow)自带技能,slash_commands只会列出一次该名称。
为技能预授权工具
Note 对项目和个人技能而言,
allowed-toolsfrontmatter 字段仅在直接使用 Claude Code CLI 时生效。在 SDK 会话中,应通过 query 配置中的allowedTools选项(Python 中为allowed_tools)来管理这些技能的工具授权。从 claude.ai 同步而来的技能 遵循它们自己的 frontmatter 规则。
技能运行时使用的是当前会话的工具集。下例通过 allowedTools(Python 中为 allowed_tools)预先批准 Read、Grep、Glob,使 Claude 在运行 security-check 技能 时可以检查文件而不必停下来等待审批:
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
options = ClaudeAgentOptions(
setting_sources=["user", "project"], # Load skills from filesystem
skills="all",
allowed_tools=["Read", "Grep", "Glob"],
)
async def main():
async for message in query(prompt="Check this project for security issues", options=options):
print(message)
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Check this project for security issues",
options: {
settingSources: ["user", "project"], // Load skills from filesystem
skills: "all",
allowedTools: ["Read", "Grep", "Glob"]
}
})) {
console.log(message);
}
在消息流中,技能调用会表现为一次 Skill 工具调用,随后是针对项目文件的 Read 调用。运行结束时得到一个 success 结果,其文本携带发现内容。
该列表的作用是预先批准所列工具,而不是限制其他工具。完整的权限流程(包括权限模式与 canUseTool 回调),参见 Permissions。
故障排查
找不到技能
检查 settingSources 配置:SDK 通过 user 和 project 两个 setting source 发现技能。如果你显式设置了 settingSources/setting_sources 却省略了这两个来源,SDK 不会加载技能:
# Skills not loaded: setting_sources excludes user and project
options = ClaudeAgentOptions(setting_sources=[], skills="all")
# Skills loaded: user and project sources included
options = ClaudeAgentOptions(
setting_sources=["user", "project"],
skills="all",
)
// Skills not loaded: settingSources excludes user and project
const optionsWithoutSkills = {
settingSources: [],
skills: "all"
};
// Skills loaded: user and project sources included
const optionsWithSkills = {
settingSources: ["user", "project"],
skills: "all"
};
各来源加载哪些技能目录,参见文件系统来源表。关于 settingSources/setting_sources 的更多细节,参见 TypeScript SDK reference 或 Python SDK reference。
检查工作目录:SDK 会从 cwd 选项所指目录以及一直到仓库根目录的每一层父目录中的 .claude/skills/ 加载技能。确保 cwd 指向包含 .claude/skills/ 的目录、或该目录在同一仓库内的子目录:
# Ensure your cwd points to the directory containing .claude/skills/
options = ClaudeAgentOptions(
cwd="/path/to/project", # .claude/skills/ here or in a parent directory
setting_sources=["user", "project"], # Loads skills from these sources
skills="all",
)
// Ensure your cwd points to the directory containing .claude/skills/
const options = {
cwd: "/path/to/project", // .claude/skills/ here or in a parent directory
settingSources: ["user", "project"], // Loads skills from these sources
skills: "all"
};
完整用法参见在 Agent SDK 中使用技能。
核实文件系统位置:
# Check project skills
ls .claude/skills/*/SKILL.md
# Check personal skills
ls ~/.claude/skills/*/SKILL.md
技能未被使用
检查 skills 选项:如果你传入了 skills 列表,确认目标技能的名称包含在内。当 Claude 尝试调用一个未列入的技能时,Skill 工具会返回 Skill <name> is not in this session's skills allowlist。将该名称加入你的列表,或者直接在 prompt 中发送 /<name> 派发该技能——这种方式不要求技能在列表中。
检查 description:确保描述具体且包含相关关键词。编写有效描述的指南参见 Agent Skills best practices。
无效技能名称报错
当 skills 列表中的某个名称无法作为精确技能名使用时,query() 会在启动 Claude Code 进程之前就拒绝该列表。会触发拒绝的名称包括:
- 空名称
- 名称中包含括号、逗号或控制字符
- 名称前后带有空白
- 通配符形式,例如裸
*或:*后缀
各 SDK 对该拒绝的呈现方式不同:
TypeScript:TypeScript SDK 会抛出一个 Error,说明该条目违反了哪条规则。例如 skills: ["docs:*"] 会抛出:
Invalid skill name "docs:*": wildcard-suffix names are not allowed; list each skill by its exact name.
空名称会报 Skill names must be non-empty strings.
Python:Python SDK 会抛出 ValueError,说明该条目违反了哪条规则。例如 skills=["docs:*"] 会抛出:
ValueError: Invalid skill name 'docs:*': wildcard-suffix names are not allowed; list each skill by its exact name.
空名称会报 Skill names must be non-empty strings。
其他故障排查
关于更通用的技能故障排查(例如 YAML 语法错误与调试),参见 Claude Code skills troubleshooting section。
下一步
Claude Code skills 指南 深入讲解了技能编写方法,其指导内容同样适用于 SDK 会话,只有一处例外:对于项目和个人技能,为技能预授权工具 一节所述的 allowedTools 选项取代了 allowed-tools frontmatter 字段。可从以下小节开始:
- Frontmatter reference:所有支持的字段
- Pass arguments to skills:
$ARGUMENTS、$0、$1以及技能叠加(skill stacking)。完整的替换表参见 full substitution table,其中还包含具名参数与${CLAUDE_*}变量 - Inject dynamic context:在 Claude 看到技能内容之前运行的
!`command`行 - Where skills live:全部发现级别、插件命名空间,以及技能与命令文件同名时的处理方式
相关资源
- Commands in Claude Code:完整命令面板,含所有内置命令
- Agent Skills overview:概念性概览、优势与架构
- Agent Skills best practices:编写有效技能的指南
- Agent Skills cookbook:示例技能与模板
- Subagents in the SDK:类似的基于文件系统、带编程选项的 agent
- SDK overview:SDK 通用概念
- TypeScript SDK reference:完整 API 文档
- Python SDK reference:完整 API 文档