文档索引
在此处获取完整文档索引:https://code.claude.com/docs/llms.txt 使用此文件发现所有可用页面,然后再进一步探索。
SDK 中的子智能体
在 Claude Agent SDK 应用中定义和调用子智能体以隔离上下文、并行运行任务和应用专门指令。
子智能体是独立的智能体实例,你的主智能体可以生成它们来处理聚焦的子任务。 使用子智能体来隔离聚焦子任务的上下文、并行运行多个分析,以及在不膨胀主智能体提示的情况下应用专门指令。
本指南解释了如何使用 agents 参数在 SDK 中定义和使用子智能体。
概述
你可以通过三种方式创建子智能体:
- 编程方式:在
query()选项中使用agents参数(TypeScript,Python) - 基于文件系统:在
.claude/agents/目录中将智能体定义为 markdown 文件(参见将子智能体定义为文件) - 内置通用型:Claude 可以随时通过 Agent 工具调用内置的
general-purpose子智能体,无需你定义任何内容
本指南重点介绍编程方式,推荐用于 SDK 应用。
当你定义子智能体时,Claude 根据每个子智能体的 description 字段决定是否调用它们。编写清晰的描述来解释何时应该使用子智能体,Claude 会自动委托适当的任务。你也可以在提示中按名称显式请求子智能体(例如"使用 code-reviewer 智能体来...")。
使用子智能体的优势
上下文隔离
每个子智能体在自己的全新对话中运行。中间的工具调用和结果保留在子智能体内;只有其最终消息返回给父级。有关子智能体上下文中包含的确切内容,请参阅子智能体继承什么。
示例: 一个 research-assistant 子智能体可以探索数十个文件,而不会有任何这些内容累积在主对话中。父级收到简洁的摘要,而不是子智能体读取的每个文件。
并行化
多个子智能体可以并发运行,显著加速复杂工作流。
示例: 在代码审查期间,你可以同时运行 style-checker、security-scanner 和 test-coverage 子智能体,将审查时间从分钟减少到秒。
专门指令和知识
每个子智能体可以拥有定制的系统提示,包含特定的专业知识、最佳实践和约束。
示例: 一个 database-migration 子智能体可以拥有有关 SQL 最佳实践、回滚策略和数据完整性检查的详细知识,这些在主智能体的指令中将是不必要的噪音。
工具限制
子智能体可以被限制为特定工具,减少非预期操作的风险。
示例: 一个 doc-reviewer 子智能体可能只有 Read 和 Grep 工具的访问权限,确保它可以分析但永远不会意外修改你的文档文件。
创建子智能体
编程定义(推荐)
使用 agents 参数在代码中直接定义子智能体。此示例创建两个子智能体:一个具有只读访问权限的代码审查器和一个可以执行命令的测试运行器。Claude 通过 Agent 工具调用子智能体,因此在 allowedTools 中包含 Agent 以自动批准子智能体调用,无需权限提示。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition
async def main():
async for message in query(
prompt="Review the authentication module for security issues",
options=ClaudeAgentOptions(
# Auto-approve these tools, including Agent for subagent invocation
allowed_tools=["Read", "Grep", "Glob", "Agent"],
agents={
"code-reviewer": AgentDefinition(
# description tells Claude when to use this subagent
description="Expert code review specialist. Use for quality, security, and maintainability reviews.",
# prompt defines the subagent's behavior and expertise
prompt="""You are a code review specialist with expertise in security, performance, and best practices.
When reviewing code:
- Identify security vulnerabilities
- Check for performance issues
- Verify adherence to coding standards
- Suggest specific improvements
Be thorough but concise in your feedback.""",
# tools restricts what the subagent can do (read-only here)
tools=["Read", "Grep", "Glob"],
# model overrides the default model for this subagent
model="sonnet",
),
"test-runner": AgentDefinition(
description="Runs and analyzes test suites. Use for test execution and coverage analysis.",
prompt="""You are a test execution specialist. Run tests and provide clear analysis of results.
Focus on:
- Running test commands
- Analyzing test output
- Identifying failing tests
- Suggesting fixes for failures""",
# Bash access lets this subagent run test commands
tools=["Bash", "Read", "Grep"],
),
},
),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Review the authentication module for security issues",
options: {
// Auto-approve these tools, including Agent for subagent invocation
allowedTools: ["Read", "Grep", "Glob", "Agent"],
agents: {
"code-reviewer": {
// description tells Claude when to use this subagent
description:
"Expert code review specialist. Use for quality, security, and maintainability reviews.",
// prompt defines the subagent's behavior and expertise
prompt: `You are a code review specialist with expertise in security, performance, and best practices.
When reviewing code:
- Identify security vulnerabilities
- Check for performance issues
- Verify adherence to coding standards
- Suggest specific improvements
Be thorough but concise in your feedback.`,
// tools restricts what the subagent can do (read-only here)
tools: ["Read", "Grep", "Glob"],
// model overrides the default model for this subagent
model: "sonnet"
},
"test-runner": {
description:
"Runs and analyzes test suites. Use for test execution and coverage analysis.",
prompt: `You are a test execution specialist. Run tests and provide clear analysis of results.
Focus on:
- Running test commands
- Analyzing test output
- Identifying failing tests
- Suggesting fixes for failures`,
// Bash access lets this subagent run test commands
tools: ["Bash", "Read", "Grep"]
}
}
}
})) {
if ("result" in message) console.log(message.result);
}
AgentDefinition 配置
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
description | string | 是 | 何时使用此智能体的自然语言描述 |
prompt | string | 是 | 定义智能体角色和行为的系统提示 |
tools | string[] | 否 | 允许的工具名称数组。如果省略,继承所有工具 |
disallowedTools | string[] | 否 | 要从智能体工具集中移除的工具名称数组 |
model | string | 否 | 此智能体的模型覆盖。接受别名如 'sonnet'、'opus'、'haiku'、'inherit',或完整的模型 ID。如果省略则默认为主模型 |
skills | string[] | 否 | 要在启动时预加载到智能体上下文中的技能名称列表。未列出的技能仍可通过 Skill 工具调用 |
memory | 'user' | 'project' | 'local' | 否 | 此智能体的内存来源 |
mcpServers | (string | object)[] | 否 | 此智能体可用的 MCP 服务器,按名称或内联配置 |
maxTurns | number | 否 | 智能体停止前的最大轮次 |
background | boolean | 否 | 调用时将此智能体作为非阻塞后台任务运行 |
effort | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | number | 否 | 此智能体的推理努力级别 |
permissionMode | PermissionMode | 否 | 此智能体内工具执行的权限模式 |
在 Python SDK 中,这些字段名称使用 camelCase 以匹配线格式。有关详情,请参阅 AgentDefinition 参考。
子智能体不能生成自己的子智能体。不要在子智能体的 tools 数组中包含 Agent。
基于文件系统的定义(替代方式)
你也可以在 .claude/agents/ 目录中将子智能体定义为 markdown 文件。有关此方法的详情,请参阅 Claude Code 子智能体文档。编程定义的智能体优先于同名的基于文件系统的智能体。
即使不定义自定义子智能体,Claude 也可以生成内置的 general-purpose 子智能体。这对于委托研究或探索任务而无需创建专门智能体很有用。在 allowedTools 中包含 Agent,以便这些调用自动批准,无需权限提示。
子智能体继承什么
子智能体的上下文窗口是全新的(没有父对话),但并非为空。从父级到子智能体的唯一通道是 Agent 工具的提示字符串,因此请将子智能体所需的任何文件路径、错误消息或决策直接包含在该提示中。
| 子智能体接收的内容 | 子智能体不接收的内容 |
|---|---|
它自己的系统提示(AgentDefinition.prompt)和 Agent 工具的提示 | 父级的对话历史或工具结果 |
项目 CLAUDE.md(通过 settingSources 加载) | 预加载的技能内容,除非在 AgentDefinition.skills 中列出 |
工具定义(从父级继承,或 tools 中的子集) | 父级的系统提示 |
父级逐字接收子智能体的最终消息作为 Agent 工具结果,但可能会在自己的响应中对其进行摘要。要在用户可见的响应中保留子智能体输出的原始内容,请在传递给主 query() 调用的提示或 systemPrompt 选项中包含相应指令。
调用子智能体
自动调用
Claude 根据任务和每个子智能体的 description 自动决定何时调用子智能体。例如,如果你定义了一个描述为"用于查询调优的性能优化专家"的 performance-optimizer 子智能体,当你的提示提到优化查询时,Claude 会调用它。
编写清晰、具体的描述,以便 Claude 可以将任务匹配到正确的子智能体。
显式调用
要保证 Claude 使用特定子智能体,请在提示中按名称提及它:
"Use the code-reviewer agent to check the authentication module"
这会绕过自动匹配,直接调用命名的子智能体。
动态智能体配置
你可以根据运行时条件动态创建智能体定义。此示例创建一个具有不同严格级别的安全审查器,对严格审查使用更强大的模型。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition
# Factory function that returns an AgentDefinition
# This pattern lets you customize agents based on runtime conditions
def create_security_agent(security_level: str) -> AgentDefinition:
is_strict = security_level == "strict"
return AgentDefinition(
description="Security code reviewer",
# Customize the prompt based on strictness level
prompt=f"You are a {'strict' if is_strict else 'balanced'} security reviewer...",
tools=["Read", "Grep", "Glob"],
# Key insight: use a more capable model for high-stakes reviews
model="opus" if is_strict else "sonnet",
)
async def main():
# The agent is created at query time, so each request can use different settings
async for message in query(
prompt="Review this PR for security issues",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob", "Agent"],
agents={
# Call the factory with your desired configuration
"security-reviewer": create_security_agent("strict")
},
),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
import { query, type AgentDefinition } from "@anthropic-ai/claude-agent-sdk";
// Factory function that returns an AgentDefinition
// This pattern lets you customize agents based on runtime conditions
function createSecurityAgent(securityLevel: "basic" | "strict"): AgentDefinition {
const isStrict = securityLevel === "strict";
return {
description: "Security code reviewer",
// Customize the prompt based on strictness level
prompt: `You are a ${isStrict ? "strict" : "balanced"} security reviewer...`,
tools: ["Read", "Grep", "Glob"],
// Key insight: use a more capable model for high-stakes reviews
model: isStrict ? "opus" : "sonnet"
};
}
// The agent is created at query time, so each request can use different settings
for await (const message of query({
prompt: "Review this PR for security issues",
options: {
allowedTools: ["Read", "Grep", "Glob", "Agent"],
agents: {
// Call the factory with your desired configuration
"security-reviewer": createSecurityAgent("strict")
}
}
})) {
if ("result" in message) console.log(message.result);
}
检测子智能体调用
子智能体通过 Agent 工具调用。要检测子智能体何时被调用,请检查 name 为 "Agent" 的 tool_use 块。来自子智能体上下文的消息包含 parent_tool_use_id 字段。
该工具名称在 Claude Code v2.1.63 中从 "Task" 重命名为 "Agent"。当前 SDK 版本在 tool_use 块中发出 "Agent",但在 system:init 工具列表和 result.permission_denials[].tool_name 中仍使用 "Task"。在 block.name 中检查两个值可确保跨 SDK 版本的兼容性。
此示例遍历流式消息,记录子智能体被调用的时间以及后续消息来自该子智能体执行上下文的时间。
消息结构在两个 SDK 之间有所不同。在 Python 中,内容块通过 message.content 直接访问。在 TypeScript 中,SDKAssistantMessage 包装了 Claude API 消息,因此内容通过 message.message.content 访问。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition, ToolUseBlock
async def main():
async for message in query(
prompt="Use the code-reviewer agent to review this codebase",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Grep", "Agent"],
agents={
"code-reviewer": AgentDefinition(
description="Expert code reviewer.",
prompt="Analyze code quality and suggest improvements.",
tools=["Read", "Glob", "Grep"],
)
},
),
):
# Check for subagent invocation. Match both names: older SDK
# versions emitted "Task", current versions emit "Agent".
if hasattr(message, "content") and message.content:
for block in message.content:
if isinstance(block, ToolUseBlock) and block.name in (
"Task",
"Agent",
):
print(f"Subagent invoked: {block.input.get('subagent_type')}")
# Check if this message is from within a subagent's context
if hasattr(message, "parent_tool_use_id") and message.parent_tool_use_id:
print(" (running inside subagent)")
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Use the code-reviewer agent to review this codebase",
options: {
allowedTools: ["Read", "Glob", "Grep", "Agent"],
agents: {
"code-reviewer": {
description: "Expert code reviewer.",
prompt: "Analyze code quality and suggest improvements.",
tools: ["Read", "Glob", "Grep"]
}
}
}
})) {
const msg = message as any;
// Check for subagent invocation. Match both names: older SDK versions
// emitted "Task", current versions emit "Agent".
for (const block of msg.message?.content ?? []) {
if (block.type === "tool_use" && (block.name === "Task" || block.name === "Agent")) {
console.log(`Subagent invoked: ${block.input.subagent_type}`);
}
}
// Check if this message is from within a subagent's context
if (msg.parent_tool_use_id) {
console.log(" (running inside subagent)");
}
if ("result" in message) {
console.log(message.result);
}
}
恢复子智能体
子智能体可以被恢复以从中断处继续。恢复的子智能体保留其完整的对话历史,包括所有之前的工具调用、结果和推理。子智能体从停止的地方恢复,而不是重新开始。
当子智能体完成时,Claude 在 Agent 工具结果中接收其智能体 ID。要以编程方式恢复子智能体:
- 捕获会话 ID:在第一次查询期间从消息中提取
session_id - 提取智能体 ID:从消息内容中解析
agentId - 恢复会话:在第二次查询的选项中传递
resume: sessionId,并在提示中包含智能体 ID
你必须恢复同一会话才能访问子智能体的记录。每个 query() 调用默认启动新会话,因此传递 resume: sessionId 以在同一会话中继续。
如果你使用的是自定义智能体(非内置),你还需要在两次查询的 agents 参数中传递相同的智能体定义。
以下示例演示了此流程:第一个查询运行子智能体并捕获会话 ID 和智能体 ID,然后第二个查询恢复会话以提出需要第一次分析上下文的后续问题。
import { query, type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
// Helper to extract agentId from message content
// Stringify to avoid traversing different block types (TextBlock, ToolResultBlock, etc.)
function extractAgentId(message: SDKMessage): string | undefined {
if (message.type !== "assistant" && message.type !== "user") return undefined;
// Stringify the content so we can search it without traversing nested blocks
const content = JSON.stringify(message.message.content);
const match = content.match(/agentId:\s*([a-f0-9-]+)/);
return match?.[1];
}
let agentId: string | undefined;
let sessionId: string | undefined;
// First invocation - use the Explore agent to find API endpoints
for await (const message of query({
prompt: "Use the Explore agent to find all API endpoints in this codebase",
options: { allowedTools: ["Read", "Grep", "Glob", "Agent"] }
})) {
// Capture session_id from ResultMessage (needed to resume this session)
if ("session_id" in message) sessionId = message.session_id;
// Search message content for the agentId (appears in Agent tool results)
const extractedId = extractAgentId(message);
if (extractedId) agentId = extractedId;
// Print the final result
if ("result" in message) console.log(message.result);
}
// Second invocation - resume and ask follow-up
if (agentId && sessionId) {
for await (const message of query({
prompt: `Resume agent ${agentId} and list the top 3 most complex endpoints`,
options: { allowedTools: ["Read", "Grep", "Glob", "Agent"], resume: sessionId }
})) {
if ("result" in message) console.log(message.result);
}
}
import asyncio
import json
import re
from claude_agent_sdk import query, ClaudeAgentOptions
def extract_agent_id(text: str) -> str | None:
"""Extract agentId from Agent tool result text."""
match = re.search(r"agentId:\s*([a-f0-9-]+)", text)
return match.group(1) if match else None
async def main():
agent_id = None
session_id = None
# First invocation - use the Explore agent to find API endpoints
async for message in query(
prompt="Use the Explore agent to find all API endpoints in this codebase",
options=ClaudeAgentOptions(allowed_tools=["Read", "Grep", "Glob", "Agent"]),
):
# Capture session_id from ResultMessage (needed to resume this session)
if hasattr(message, "session_id"):
session_id = message.session_id
# Search message content for the agentId (appears in Agent tool results)
if hasattr(message, "content"):
# Stringify the content so we can search it without traversing nested blocks
content_str = json.dumps(message.content, default=str)
extracted = extract_agent_id(content_str)
if extracted:
agent_id = extracted
# Print the final result
if hasattr(message, "result"):
print(message.result)
# Second invocation - resume and ask follow-up
if agent_id and session_id:
async for message in query(
prompt=f"Resume agent {agent_id} and list the top 3 most complex endpoints",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob", "Agent"], resume=session_id
),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
子智能体记录独立于主对话持久化:
- 主对话压缩:当主对话压缩时,子智能体记录不受影响。它们存储在单独的文件中。
- 会话持久化:子智能体记录在其会话内持久化。你可以通过恢复同一会话在重启 Claude Code 后恢复子智能体。
- 自动清理:记录根据
cleanupPeriodDays设置(默认:30 天)进行清理。
工具限制
子智能体可以通过 tools 字段限制工具访问:
- 省略字段:智能体继承所有可用工具(默认)
- 指定工具:智能体只能使用列出的工具
此示例创建一个只读分析智能体,可以检查代码但不能修改文件或运行命令。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition
async def main():
async for message in query(
prompt="Analyze the architecture of this codebase",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob", "Agent"],
agents={
"code-analyzer": AgentDefinition(
description="Static code analysis and architecture review",
prompt="""You are a code architecture analyst. Analyze code structure,
identify patterns, and suggest improvements without making changes.""",
# Read-only tools: no Edit, Write, or Bash access
tools=["Read", "Grep", "Glob"],
)
},
),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Analyze the architecture of this codebase",
options: {
allowedTools: ["Read", "Grep", "Glob", "Agent"],
agents: {
"code-analyzer": {
description: "Static code analysis and architecture review",
prompt: `You are a code architecture analyst. Analyze code structure,
identify patterns, and suggest improvements without making changes.`,
// Read-only tools: no Edit, Write, or Bash access
tools: ["Read", "Grep", "Glob"]
}
}
}
})) {
if ("result" in message) console.log(message.result);
}
常见工具组合
| 用例 | 工具 | 描述 |
|---|---|---|
| 只读分析 | Read, Grep, Glob | 可以检查代码但不能修改或执行 |
| 测试执行 | Bash, Read, Grep | 可以运行命令并分析输出 |
| 代码修改 | Read, Edit, Write, Grep, Glob | 完整读/写访问但不执行命令 |
| 完全访问 | 所有工具 | 从父级继承所有工具(省略 tools 字段) |
故障排除
Claude 未委托给子智能体
如果 Claude 直接完成任务而不是委托给你的子智能体:
- 检查 Agent 调用是否已批准:在
allowedTools中包含Agent以自动批准子智能体调用。没有它,Agent 调用会回退到你的canUseTool回调,或者在dontAsk模式下被拒绝 - 使用显式提示:在提示中按名称提及子智能体(例如"使用 code-reviewer 智能体来...")
- 编写清晰的描述:准确解释何时应该使用子智能体,以便 Claude 可以适当地匹配任务
基于文件系统的智能体未加载
在 .claude/agents/ 中定义的智能体仅在启动时加载。如果你在 Claude Code 运行时创建新的智能体文件,请重启会话以加载它。
Windows:长提示失败
在 Windows 上,具有很长提示的子智能体可能会因命令行长度限制(8191 个字符)而失败。保持提示简洁,或对复杂指令使用基于文件系统的智能体。
相关文档
- Claude Code 子智能体:全面的子智能体文档,包括基于文件系统的定义
- SDK 概述:Claude Agent SDK 入门