跳转到主要内容
子代理是您的主代理可以生成的独立代理实例,用于处理专注的子任务。 使用子代理来隔离上下文、并行运行多个分析,以及应用专门的指令,而不会增加主代理的提示词。 本指南说明如何使用 agents 参数在 SDK 中定义和使用子代理。

概述

您可以通过三种方式创建子代理:
  • 以编程方式:在您的 query() 选项中使用 agents 参数。请参阅 TypeScriptPython 参考文档
  • 基于文件系统:在 .claude/agents/ 目录中将代理定义为 markdown 文件。请参阅将子代理定义为文件
  • 内置通用代理:Claude 可以随时通过 Agent 工具调用内置的 general-purpose 子代理,无需您定义任何内容
本指南重点介绍编程方法,这是 SDK 应用程序的推荐方法。 定义子代理时,Claude 根据每个子代理的 description 字段确定是否调用它。编写清晰的描述,说明何时应使用子代理,Claude 将自动委派适当的任务。您也可以在提示词中按名称显式请求子代理,例如”使用代码审查员代理来…”。

使用子代理的好处

上下文隔离

每个子代理在其自己的新对话中运行。中间工具调用和结果保留在子代理内部;只有其最终消息返回到父代理。请参阅子代理继承的内容以了解子代理上下文中的确切内容。 示例: research-assistant 子代理可以探索数十个文件,而这些内容都不会在主对话中累积。父代理收到的是简洁的摘要,而不是子代理读取的每个文件。

并行化

多个子代理可以并发运行,因此独立的子任务完成时间为最慢的一个,而不是所有任务的总和。 示例: 在代码审查期间,您可以同时运行 style-checkersecurity-scannertest-coverage 子代理,而不是按顺序运行。

专门的指令和知识

每个子代理都可以有定制的系统提示词,具有特定的专业知识、最佳实践和约束。 示例: database-migration 子代理可以具有关于 SQL 最佳实践、回滚策略和数据完整性检查的详细知识,这些在主代理的指令中将是不必要的噪音。

工具限制

子代理可以限制为特定工具,降低意外操作的风险。 示例: doc-reviewer 子代理可能只能访问 Read 和 Grep 工具,确保它可以分析但永远不会意外修改您的文档文件。

创建子代理

使用 agents 参数直接在代码中定义子代理。Claude 通过 Agent 工具调用子代理,因此在 allowedTools 中包含 Agent 以自动批准子代理调用,无需权限提示。 本页面上的大多数示例仅打印最终结果。要确认 Claude 委派给了子代理而不是直接回答,请参阅检测子代理调用 此示例创建两个子代理:一个具有只读访问权限的代码审查员和一个可以执行命令的测试运行器。

AgentDefinition 配置

在 Python SDK 中,多字词字段名称(如 disallowedToolsmcpServers)保持其 camelCase 拼写以匹配线路格式,而不是遵循 Python 的 snake_case 约定。有关详细信息,请参阅 AgentDefinition 参考 Claude Code v2.1.198 中的两个子代理行为发生了变化:
  • 子代理默认在后台运行。省略 run_in_background 输入的 Agent 工具调用会启动后台子代理,当 Claude 需要结果后才继续时,它会设置 run_in_background: false。在 v2.1.198 之前,省略 run_in_background 会同步运行子代理。设置 background 字段为 true 以强制特定代理进行后台执行,无论 Claude 请求什么。
  • 子代理继承主会话的扩展思考配置。在早期版本中,无论主会话的设置如何,扩展思考在子代理内被禁用。
自 Claude Code v2.1.172 起,子代理可以生成自己的子代理。位于主代理下方五个级别的子代理无法生成进一步的子代理,无论其是在前台还是后台运行。要防止子代理生成其他子代理,请从其 tools 数组中省略 Agent 或将其添加到 disallowedTools。有关完整的深度规则,请参阅嵌套子代理

基于文件系统的定义(替代方案)

您也可以在 .claude/agents/ 目录中将子代理定义为 markdown 文件。有关此方法的详细信息,请参阅 Claude Code 子代理文档。以编程方式定义的代理优先于具有相同名称的基于文件系统的代理。
即使不定义自定义子代理,Claude 也可以生成内置的 general-purpose 子代理。这对于委派研究或探索任务而无需创建专门的代理很有用。在 allowedTools 中包含 Agent 以便这些调用自动批准,无需权限提示。

子代理继承的内容

子代理的上下文窗口从新开始,没有父对话,但不是空的。从父代理到子代理的唯一内容是 Agent 工具的提示词字符串,因此请直接在该提示词中包含子代理需要的任何文件路径、错误消息或决策。 具有 SendMessage 工具的子代理会从会话中运行的其他命名代理列表开始,因此它知道可以向哪些名称发送消息。Claude Code 会自动在子代理的第一轮中添加该列表。fork 不会获得该列表,因为它继承了父对话。该列表需要 Claude Code v2.1.206 或更高版本。
父代理逐字接收子代理的最终消息作为 Agent 工具结果,但可能在其自己的响应中总结它。要在面向用户的响应中逐字保留子代理输出,请在您传递给主 query() 调用的提示词或 systemPrompt 选项中包含一条指令。
结束子代理早期的 API 错误(例如速率限制)永远不会作为其结果传递。如果速率限制、过载或服务器错误中断了已经产生文本输出的前台子代理,Agent 工具会返回该部分输出并注明子代理未完成。未产生任何内容的子代理,或其唯一输出仅为工具调用且没有文本的子代理,会失败并显示错误消息 Agent terminated early due to an API error,后跟错误详情。有关前台和后台行为,请参阅 API errors in subagents 这种部分输出处理需要 Claude Code v2.1.199 或更高版本。在 v2.1.199 中,速率限制、过载或服务器错误会导致仅工具调用的形状出现空的部分结果,仅包含中断注记。

调用子代理

自动调用

Claude 根据任务和每个子代理的 description 自动决定何时调用子代理。例如,如果您定义了一个 performance-optimizer 子代理,其描述为”用于查询调优的性能优化专家”,当您的提示词提到优化查询时,Claude 将调用它。 编写清晰、具体的描述,以便 Claude 可以将任务匹配到正确的子代理。

显式调用

要保证 Claude 使用特定的子代理,请在您的提示词中按名称提及它:
这绕过自动匹配并直接调用命名的子代理。

动态代理配置

您可以根据运行时条件动态创建代理定义。此示例创建一个安全审查员,具有不同的严格级别,对严格审查使用更强大的模型。

检测子代理调用

Claude 通过 Agent 工具调用子代理。要检测何时调用子代理,请检查 tool_use 块,其中 name"Agent"。来自子代理上下文内的消息包含 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 访问。 此示例遍历流式消息,记录何时调用子代理以及后续消息何时源自该子代理的执行上下文。

恢复子代理

您可以恢复子代理以继续中断的地方,而不是重新开始。恢复的子代理保留其完整的对话历史,包括所有先前的工具调用、结果和推理。 当子代理完成时,Agent 工具结果包含一个包含 agentId: <id> 的文本块。内置的 ExplorePlan 代理 是一次性的,不返回 agentId,因此当您需要恢复时,请使用自定义代理或 general-purpose。要以编程方式恢复子代理:
  1. 捕获会话 ID:在第一个查询期间从消息中提取 session_id
  2. 提取代理 ID:从 Agent 工具结果文本中解析 agentId
  3. 恢复会话:在第二个查询的选项中传递 resume: sessionId,并在您的提示词中包含代理 ID
您必须恢复同一会话以访问子代理的记录。默认情况下,每个 query() 调用都会启动一个新会话,因此请传递 resume: sessionId 以在同一会话中继续。使用自定义代理时,在两个查询的 agents 参数中传递相同的代理定义。
下面的示例定义了一个自定义 endpoint-finder 代理。第一个查询运行它并从 Agent 工具结果中捕获会话 ID 和代理 ID,然后第二个查询恢复会话以提出需要来自第一个分析的上下文的后续问题。
子代理记录独立于主对话而持久存在:
  • 主对话压缩:当主对话压缩时,子代理记录不受影响。它们存储在单独的文件中。
  • 会话持久性:子代理记录在其会话内持久存在。您可以通过恢复同一会话在重启 Claude Code 后恢复子代理。
  • 自动清理:记录根据 cleanupPeriodDays 设置进行清理,默认为 30 天。

工具限制

子代理可以通过 tools 字段具有受限的工具访问:
  • 省略该字段:代理继承所有可用工具(默认)
  • 指定工具:代理只能使用列出的工具
此示例创建一个只读分析代理,可以检查代码但无法修改文件或运行命令。

常见工具组合

使用动态工作流进行扩展

子代理适用于每轮委派的几个任务。对于协调数十到数百个代理的运行,请使用 Workflow 工具,它将编排移到运行时在对话上下文外执行的脚本中。请参阅动态工作流以了解工作流与逐轮子代理委派的区别。 Workflow 工具在 TypeScript Agent SDK v0.3.149 及更高版本中可用。在 allowedTools 中包含 Workflow 以自动批准工作流运行。工具输入和输出架构列在 TypeScript 参考中。

故障排除

Claude 不委派给子代理

如果 Claude 直接完成任务而不是委派给您的子代理:
  • 检查 Agent 调用是否被批准:在 allowedTools 中包含 Agent 以自动批准子代理调用。如果没有它,Agent 调用将转到您的 canUseTool 回调,或在 dontAsk 模式下被拒绝
  • 使用显式提示:在您的提示词中按名称提及子代理,例如”使用代码审查员代理来…”
  • 编写清晰的描述:准确解释何时应使用子代理,以便 Claude 可以适当地匹配任务

基于文件系统的代理未加载

Claude Code 监视 ~/.claude/agents/.claude/agents/,并在几秒内拾取新的或编辑的代理文件,无需重启。如果定义从未出现,请排查这些原因:
  • 新的 agents 目录:监视程序仅覆盖会话启动时存在的目录,因此新目录中的第一个文件需要会话重启。这是最常见的原因。
  • 无效的 frontmatter 或重复的 name:检查文件的 YAML,以及现有代理是否已使用该 name
  • --disable-slash-commands:使用此标志启动的会话不监视这些目录,始终需要重启以加载新文件。
  • 具有相同名称的程序化代理:传递给 query()agents 会覆盖具有相同名称的文件系统代理。
有关文件格式,请参阅如何编写子代理文件

Windows 上的长提示词失败

在 Windows 上,具有非常长提示词的子代理可能因命令行长度限制(8191 个字符)而失败。保持提示词简洁或使用基于文件系统的代理来处理复杂指令。