子代理是獨立的代理實例,您的主代理可以產生它們來處理專注的子任務。 使用子代理來隔離上下文以處理專注的子任務、平行執行多個分析,以及套用專門的指令而不會使主代理的提示詞膨脹。
本指南說明如何使用 agents 參數在 SDK 中定義和使用子代理。
您可以透過三種方式建立子代理:
query() 選項中使用 agents 參數(TypeScript、Python).claude/agents/ 目錄中將代理定義為 markdown 檔案(請參閱將子代理定義為檔案)general-purpose 子代理,無需您定義任何內容本指南著重於程式化方式,這是 SDK 應用程式的建議做法。
當您定義子代理時,Claude 會根據每個子代理的 description 欄位決定是否呼叫它們。撰寫清楚的描述來說明何時應該使用該子代理,Claude 將自動委派適當的任務。您也可以在提示詞中明確地按名稱請求子代理(例如,「使用 code-reviewer 代理來...」)。
子代理維護與主代理分離的上下文,防止資訊過載並保持互動的專注性。這種隔離確保專門的任務不會用無關的細節污染主對話上下文。
範例:一個 research-assistant 子代理可以探索數十個檔案和文件頁面,而不會用所有中間搜尋結果來混亂主對話,只回傳相關的發現。
多個子代理可以同時執行,大幅加速複雜的工作流程。
範例:在程式碼審查期間,您可以同時執行 style-checker、security-scanner 和 test-coverage 子代理,將審查時間從數分鐘縮短到數秒。
每個子代理可以擁有量身定制的系統提示詞,包含特定的專業知識、最佳實踐和約束條件。
範例:一個 database-migration 子代理可以擁有關於 SQL 最佳實踐、回滾策略和資料完整性檢查的詳細知識,這些在主代理的指令中會是不必要的雜訊。
子代理可以被限制使用特定工具,降低意外操作的風險。
範例:一個 doc-reviewer 子代理可能只能存取 Read 和 Grep 工具,確保它可以分析但永遠不會意外修改您的文件檔案。
直接在您的程式碼中使用 agents 參數定義子代理。此範例建立兩個子代理:一個具有唯讀存取權限的程式碼審查者和一個可以執行命令的測試執行者。Task 工具必須包含在 allowedTools 中,因為 Claude 透過 Task 工具呼叫子代理。
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(
# Task tool is required for subagent invocation
allowed_tools=["Read", "Grep", "Glob", "Task"],
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())| 欄位 | 類型 | 必填 | 描述 |
|---|---|---|---|
description | string | 是 | 描述何時使用此代理的自然語言描述 |
prompt | string | 是 | 定義代理角色和行為的系統提示詞 |
tools | string[] | 否 | 允許的工具名稱陣列。如果省略,則繼承所有工具 |
model | 'sonnet' | 'opus' | 'haiku' | 'inherit' | 否 | 此代理的模型覆寫。如果省略,則預設為主模型 |
子代理無法產生自己的子代理。不要在子代理的 tools 陣列中包含 Task。
您也可以在 .claude/agents/ 目錄中將子代理定義為 markdown 檔案。請參閱 Claude Code 子代理文件以了解此方法的詳細資訊。程式化定義的代理優先於同名的基於檔案系統的代理。
即使不定義自訂子代理,當 Task 在您的 allowedTools 中時,Claude 也可以產生內建的 general-purpose 子代理。這對於在不建立專門代理的情況下委派研究或探索任務很有用。
Claude 會根據任務和每個子代理的 description 自動決定何時呼叫子代理。例如,如果您定義了一個 performance-optimizer 子代理,其描述為「Performance optimization specialist for query tuning」,當您的提示詞提到最佳化查詢時,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", "Task"],
agents={
# Call the factory with your desired configuration
"security-reviewer": create_security_agent("strict")
}
)
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())子代理透過 Task 工具呼叫。要偵測子代理何時被呼叫,請檢查 name: "Task" 的 tool_use 區塊。來自子代理上下文內的訊息包含 parent_tool_use_id 欄位。
此範例遍歷串流訊息,記錄子代理何時被呼叫以及後續訊息何時來自該子代理的執行上下文。
SDK 之間的訊息結構不同。在 Python 中,內容區塊直接透過 message.content 存取。在 TypeScript 中,SDKAssistantMessage 包裝了 Claude API 訊息,因此內容透過 message.message.content 存取。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition
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", "Task"],
agents={
"code-reviewer": AgentDefinition(
description="Expert code reviewer.",
prompt="Analyze code quality and suggest improvements.",
tools=["Read", "Glob", "Grep"]
)
}
)
):
# Check for subagent invocation in message content
if hasattr(message, 'content') and message.content:
for block in message.content:
if getattr(block, 'type', None) == 'tool_use' and block.name == 'Task':
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 會在 Task 工具結果中收到其代理 ID。要以程式化方式恢復子代理:
session_idagentIdresume: 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' in message)) 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', 'Task'] }
})) {
// 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 Task 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', 'Task'], resume: sessionId }
})) {
if ('result' in message) console.log(message.result);
}
}子代理記錄獨立於主對話持久化:
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", "Task"],
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())| 使用案例 | 工具 | 描述 |
|---|---|---|
| 唯讀分析 | Read、Grep、Glob | 可以檢查程式碼但不能修改或執行 |
| 測試執行 | Bash、Read、Grep | 可以執行命令和分析輸出 |
| 程式碼修改 | Read、Edit、Write、Grep、Glob | 完整的讀寫存取權限,無命令執行 |
| 完整存取 | 所有工具 | 從父代理繼承所有工具(省略 tools 欄位) |
如果 Claude 直接完成任務而不是委派給您的子代理:
allowedTools 中在 .claude/agents/ 中定義的代理僅在啟動時載入。如果您在 Claude Code 執行時建立新的代理檔案,請重新啟動會話以載入它。
在 Windows 上,具有非常長提示詞的子代理可能因命令列長度限制(8191 字元)而失敗。保持提示詞簡潔或對複雜指令使用基於檔案系統的代理。
Was this page helpful?