跳轉到主要內容
子代理是您的主代理可以生成的獨立代理實例,用於處理專注的子任務。 使用子代理來隔離專注子任務的上下文、並行運行多個分析,以及應用專門化指令,而不會使主代理的提示詞變得臃腫。 本指南說明如何使用 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 以自動批准子代理調用,無需權限提示。
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())

AgentDefinition 配置

欄位類型必需描述
descriptionstring何時使用此代理的自然語言描述
promptstring代理的系統提示詞,定義其角色和行為
toolsstring[]允許的工具名稱陣列。如果省略,繼承所有工具
disallowedToolsstring[]要從代理的工具集中移除的工具名稱陣列
modelstring此代理的模型覆蓋。接受別名,例如 'sonnet''opus''haiku''inherit',或完整模型 ID。如果省略,預設為主模型
skillsstring[]在啟動時預加載到代理上下文中的 skills 名稱列表。未列出的 skills 仍可通過 Skill 工具調用
memory'user' | 'project' | 'local'此代理的記憶體來源
mcpServers(string | object)[]此代理可用的 MCP 伺服器,按名稱或內聯配置
maxTurnsnumber代理停止前的最大代理轉數
backgroundboolean調用時將此代理作為非阻塞背景任務運行
effort'low' | 'medium' | 'high' | 'xhigh' | 'max' | number此代理的推理努力級別
permissionModePermissionMode此代理內工具執行的權限模式
在 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())

檢測子代理調用

子代理通過 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 存取。
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())

恢復子代理

子代理可以恢復以繼續中斷的地方。恢復的子代理保留其完整的對話歷史,包括所有先前的工具調用、結果和推理。子代理從停止的地方繼續,而不是從頭開始。 當子代理完成時,Claude 在 Agent 工具結果中接收其代理 ID。要以程式方式恢復子代理:
  1. 捕獲會話 ID:在第一個查詢期間從訊息中提取 session_id
  2. 提取代理 ID:從訊息內容中解析 agentId
  3. 恢復會話:在第二個查詢的選項中傳遞 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);
  }
}
子代理記錄獨立於主對話而持續存在:
  • 主對話壓縮:當主對話壓縮時,子代理記錄不受影響。它們存儲在單獨的檔案中。
  • 會話持久性:子代理記錄在其會話內持續存在。您可以通過恢復相同會話在重新啟動 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())

常見工具組合

使用案例工具描述
唯讀分析ReadGrepGlob可以檢查代碼但不能修改或執行
測試執行BashReadGrep可以運行命令並分析輸出
代碼修改ReadEditWriteGrepGlob完整的讀/寫訪問,無需命令執行
完全訪問所有工具從父代理繼承所有工具(省略 tools 欄位)

使用動態工作流程進行擴展

子代理適用於每轉委派幾個任務。對於協調數十到數百個代理的運行,請使用 Workflow 工具,它將編排移到運行時在對話上下文外執行的腳本中。請參閱動態工作流程以了解工作流程與逐轉子代理委派的區別。 Workflow 工具在 TypeScript Agent SDK v0.3.149 及更高版本中可用。在 allowedTools 中包含 Workflow 以自動批准工作流程運行。工具輸入和輸出架構列在 TypeScript 參考中。

故障排除

Claude 不委派給子代理

如果 Claude 直接完成任務而不是委派給您的子代理:
  1. 檢查 Agent 調用已獲批准:在 allowedTools 中包含 Agent 以自動批准子代理調用。沒有它,Agent 調用會轉到您的 canUseTool 回調,或在 dontAsk 模式下被拒絕
  2. 使用明確提示:在您的提示詞中按名稱提及子代理(例如,「使用代碼審查員代理來…」)
  3. 編寫清晰的描述:準確解釋何時應使用子代理,以便 Claude 可以適當地匹配任務

基於檔案系統的代理未加載

.claude/agents/ 中定義的代理僅在啟動時加載。如果在 Claude Code 運行時創建新的代理檔案,請重新啟動會話以加載它。

Windows:長提示詞失敗

在 Windows 上,具有非常長提示詞的子代理可能因命令行長度限制(8191 個字符)而失敗。保持提示詞簡潔或使用基於檔案系統的代理來處理複雜指令。

相關文檔