Claude Code 学习站

Agent SDK 技能(Skills)与会话内命令指南

整理 Claude Agent SDK 中 Skills 的加载、`skills` 选项配置、自定义技能创建、工具预授权及会话内命令(如 /compact、/clear)的官方参考。

本页目录22
AI 摘要 · 已核查整理于 2026-08-06原文:Extend agents with skills(Anthropic)Agent SDKSkillsClaude Code斜杠命令
要点速览
  • 技能以 `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 分别限制这两条路径。两个术语的定义参见词汇表中的 CommandSkill 条目。所有内置命令参见 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-reviewverify 技能。如果你以其中之一命名 .claude/commands/ 文件,例如 .claude/commands/code-review.md,该文件对应的命令会覆盖(shadow)自带技能,slash_commands 只会列出一次该名称。

为技能预授权工具

Note 对项目和个人技能而言,allowed-tools frontmatter 字段仅在直接使用 Claude Code CLI 时生效。在 SDK 会话中,应通过 query 配置中的 allowedTools 选项(Python 中为 allowed_tools)来管理这些技能的工具授权。从 claude.ai 同步而来的技能 遵循它们自己的 frontmatter 规则。

技能运行时使用的是当前会话的工具集。下例通过 allowedTools(Python 中为 allowed_tools)预先批准 ReadGrepGlob,使 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 通过 userproject 两个 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 referencePython 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 字段。可从以下小节开始:

相关资源