תיעוד 140
תת-סוכנים ב-SDK
הגדר והפעל תת-סוכנים כדי לבודד הקשר, להריץ משימות במקביל, ולהחיל הוראות ייעודיות ביישומי Claude Agent SDK שלך.
תת-סוכנים הם מופעי סוכן נפרדים שהסוכן הראשי שלך יכול להפעיל כדי לטפל במשימות משנה ממוקדות. השתמש בהם כדי לבודד הקשר, להריץ מספר ניתוחים במקביל, ולהחיל הוראות ייעודיות מבלי להעמיס על ההנחיה של הסוכן הראשי.
#סקירה כללית
באפשרותך ליצור תת-סוכנים בשלוש דרכים:
- באופן תכנותי: השתמש בפרמטר
agentsבאפשרויות שלquery(). ראה את הפניות התיעוד של TypeScript ושל Python - מבוסס מערכת קבצים: הגדר סוכנים כקובצי markdown בספריות
.claude/agents/. ראה הגדרת תת-סוכנים כקבצים - כללי מובנה (Built-in general-purpose): Claude יכול להפעיל את תת-הסוכן המובנה
general-purposeבכל עת באמצעות הכליAgentמבלי שתגדיר דבר
מדריך זה מתמקד בגישה התכנותית, שהיא המומלצת עבור יישומי SDK.
#יתרונות השימוש בתת-סוכנים
מכיוון שתת-סוכנים הם מופעי סוכן נפרדים, האצלת עבודה אליהם מעניקה לך ארבעה יתרונות:
- בידוד הקשר (Context isolation): כל תת-סוכן רץ בשיחה משלו, שמתחילה מחדש אלא אם תת-הסוכן הוא פיצול (fork). בכל מקרה, קריאות ביניים לכלים ותוצאותיהן נשארות בתוך תת-הסוכן, ורק ההודעה הסופית שלו חוזרת אל ההורה. תת-סוכן
research-assistantיכול לחקור עשרות קבצים מבלי שאף חלק מתוכן זה יצטבר בשיחה הראשית. ההורה מקבל סיכום תמציתי, ולא כל קובץ שתת-הסוכן קרא. ראה מה תת-סוכנים יורשים כדי לראות בדיוק מה נמצא בהקשר של תת-הסוכן. - מקביליות (Parallelization): מספר תת-סוכנים יכולים לרוץ בו-זמנית, כך שמשימות משנה בלתי תלויות מסתיימות בזמן של האיטית שבהן ולא בסכום הזמנים של כולן. במהלך סקירת קוד, תוכל להריץ את תת-הסוכנים
style-checker,security-scannerו-test-coverageבו-זמנית במקום בזה אחר זה. - הוראות וידע ייעודיים: לכל תת-סוכן יכולה להיות הנחיית מערכת מותאמת אישית עם מומחיות ספציפית, שיטות עבודה מומלצות ואילוצים. לתת-סוכן
database-migrationיכול להיות ידע מפורט על שיטות עבודה מומלצות ב-SQL, אסטרטגיות שחזור לאחור (rollback) ובדיקות תקינות נתונים, שיהוו רעש מיותר בהוראות של הסוכן הראשי. - הגבלות כלים (Tool restrictions): ניתן להגביל תת-סוכנים לכלים ספציפיים, מה שמפחית את הסיכון לפעולות לא רצויות. לתת-סוכן
doc-reviewerעשויה להיות גישה רק לכליםReadו-Grep, מה שמבטיח שהוא יוכל לנתח אך לעולם לא לשנות בטעות את קובצי התיעוד שלך.
#יצירת תת-סוכנים
#הגדרה תכנותית (מומלץ)
הגדר תת-סוכנים ישירות בקוד שלך באמצעות הפרמטר agents. Claude מפעיל תת-סוכנים באמצעות הכלי Agent.
רוב הדוגמאות בדף זה מדפיסות רק את התוצאה הסופית. כדי לאשר ש-Claude האציל משימה לתת-סוכן במקום לענות ישירות, ראה זיהוי הפעלת תת-סוכן.
דוגמה זו יוצרת שני תת-סוכנים: סוקר קוד עם גישת קריאה בלבד, ומריץ בדיקות שיכול לבצע פקודות.
#Python
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
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())#TypeScript
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
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[] | לא | מערך של שמות כלים להסרה מסט הכלים של הסוכן. מתקבלות גם תבניות ברמת שרת MCP: התבנית mcp__server או mcp__server__* מסירה כל כלי מאותו שרת, והתבנית mcp__* מסירה כל כלי MCP מכל שרת |
model | string | לא | דריסת מודל עבור סוכן זה. מקבל כינוי כגון 'fable', 'opus', 'sonnet', 'haiku', 'inherit', או מזהה מודל מלא. הערך 'inherit' משתמש במודל הראשי. כאשר משמיטים אותו, Claude Code בוחר את המודל לפי סדר עדיפות מודל תת-הסוכן |
skills | string[] | לא | רשימה של שמות מיומנויות לטעינה מראש אל תוך ההקשר של הסוכן בעת ההפעלה. מיומנויות שלא נכללו ברשימה נשארות ניתנות להפעלה באמצעות הכלי Skill |
memory | 'user' | 'project' | 'local' | לא | מקור הזיכרון עבור סוכן זה |
mcpServers | (string | object)[] | לא | שרתי MCP הזמינים לסוכן זה, לפי שם או תצורה מוטבעת |
initialPrompt | string | לא | נשלח אוטומטית כתור המשתמש הראשון כאשר סוכן זה רץ כסוכן השרשור הראשי. מנוטרל כאשר הסוכן מופעל כתת-סוכן |
maxTurns | number | לא | מספר מרבי של תורות סוכן לפני שהסוכן עוצר. כאשר הסוכן מגיע למגבלה, Claude Code מחזיר את הפלט שלו כשהוא מסומן כחלקי, ובאפשרותך לחדש את פעולת הסוכן כדי להמשיך. הסימון כחלקי דורש את Claude Code בגרסה v2.1.246 ומעלה |
background | boolean | לא | הרץ סוכן זה כמשימת רקע שאינה חוסמת בעת הפעלתו |
effort | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | number | לא | רמת מאמץ החשיבה עבור סוכן זה |
permissionMode | PermissionMode | לא | מצב הרשאות להרצת כלים בתוך סוכן זה |
ב-Python SDK, שמות שדות המורכבים ממספר מילים, כגון disallowedTools ו-mcpServers, שומרים על איות ב-camelCase כדי להתאים למבנה המועבר ברשת, במקום לעקוב אחר מוסכמת snake_case של Python. ראה את הפניית התיעוד של AgentDefinition לפרטים נוספים.
תת-סוכנים רצים ברקע כברירת מחדל. קריאה לכלי Agent המשמיטה את הקלט run_in_background מפעילה תת-סוכן ברקע, ו-Claude מגדיר run_in_background: false כאשר הוא זקוק לתוצאה לפני שימשיך. הגדר את השדה background כ-true כדי לאלץ הרצה ברקע עבור סוכן ספציפי ללא תלות במה ש-Claude מבקש. לפני Claude Code בגרסה v2.1.198, ברירת המחדל להרצה ברקע נפרסה בהדרגה, וקריאה לכלי Agent שהשמיטה את run_in_background יכלה להריץ את תת-הסוכן באופן סינכרוני.
תת-סוכנים יכולים גם להפעיל תת-סוכנים משלהם. כדי להגביל את עומק הקינון, את מספר תת-הסוכנים שרצים בו-זמנית, ואת הסכום שהשאילתה מוציאה, ראה הגבלת עומק תת-סוכנים, ריצה מקבילית ועלויות.
#הגדרה מבוססת מערכת קבצים (חלופה)
באפשרותך גם להגדיר תת-סוכנים כקובצי markdown בספריות .claude/agents/. ראה את תיעוד תת-הסוכנים של Claude Code לפרטים על גישה זו. סוכנים המוגדרים באופן תכנותי מקבלים עדיפות על פני סוכנים מבוססי מערכת קבצים בעלי אותו שם.
הערה: כאשר Claude קורא לכלי
Agentללאsubagent_type, הוא מקבל את תת-הסוכן המובנהgeneral-purpose, ש-Claude יכול להפעיל גם כאשר אינך מגדיר אף סוכן משלך. הגדרתCLAUDE_AGENT_SDK_DISABLE_BUILTIN_AGENTS=1מסירה את ברירת המחדל הזו, וקריאה כזו תיכשל עם השגיאהsubagent_type is required.
#מה תת-סוכנים יורשים
אלא אם תת-הסוכן הוא פיצול (fork), חלון ההקשר שלו מתחיל מחדש, ללא שיחת ההורה, אך אינו ריק. התוכן היחיד שאתה מעביר מההורה לתת-הסוכן הוא מחרוזת ההנחיה של הכלי Agent, לכן כלול כל נתיב קובץ, הודעת שגיאה או החלטה שתת-הסוכן זקוק להם ישירות בתוך הנחיה זו.
תת-סוכן שיש לו את הכלי SendMessage מתחיל עם רשימה של שאר הסוכנים בעלי השם שרצים בסשן, כך שהוא יודע לאילו שמות הוא יכול לשלוח הודעות. Claude Code מוסיף את הרשימה לתור הראשון של תת-הסוכן באופן אוטומטי. פיצול (fork) אינו מקבל את הרשימה מכיוון שהוא יורש את שיחת ההורה במקום זאת.
תת-סוכן יורש גם את תצורת החשיבה המורחבת (extended thinking) של הסשן הראשי.
הטבלה שלהלן מפרטת מה מכיל ההקשר של תת-סוכן שאינו פיצול וממה הוא נמנע.
| תת-הסוכן מקבל | תת-הסוכן אינו מקבל |
|---|---|
הנחיית מערכת משלו (AgentDefinition.prompt) ואת ההנחיה של הכלי Agent | היסטוריית השיחה או תוצאות הכלים של ההורה |
קובץ CLAUDE.md של הפרויקט (נטען באמצעות settingSources) | תוכן מיומנויות (skills) שנטען מראש, אלא אם צוין ב-AgentDefinition.skills |
הגדרות כלים (מורשות מההורה או תת-הקבוצה המוגדרת ב-tools, מסוננות להרצות רקע) | הנחיית המערכת של ההורה |
הערה: ההורה מקבל את ההודעה הסופית של תת-הסוכן כתוצאה של הכלי
Agent, אך עשוי לסכם אותה בתגובה שלו. כדי לשמור על פלט תת-הסוכן מילה במילה בתגובה המוצגת למשתמש, כלול הוראה לעשות זאת בהנחיה או באפשרותsystemPromptשאתה מעביר לקריאה הראשית שלquery().בגרסה v2.1.210 ואילך, Claude Code סורק את ההודעה הסופית לאיתור תבניות בעלות מבנה של הוראות לפני שההורה קורא אותה. הסריקה מתייחסת לשלושה סוגי תבניות באופן שונה:
- חיקוי תגי בקרה (Control-tag imitation): Claude Code מנטרל במקום תג שרק סביבת ההרצה פולטת, כגון בלוק
<system-reminder>. הוא מכניס לוכסן שמאלי (backslash) אחרי סוגר הזווית הפותח ואינו מוחק דבר.- אזכורים של תצורת הרשאות: Claude Code משאיר התייחסויות לתצורת הרשאות, כגון
.claude/settings.json,bypassPermissions, או--dangerously-skip-permissions, כפי שנכתבו.- סמני תור (Turn markers): שורה שמתחילה ב-
Human:או ב-Assistant:מקבלת לוכסן שמאלי לפני הנקודתיים, כדי שההודעה לא תוכל לחקות גבול של תור בשיחה.עבור התאמה של תג בקרה או תצורת הרשאות, Claude Code מוסיף בתחילה שורת סימון
[harness: ...]המציינת את התבניות שהותאמו. התאמה של סמן תור אינה מוסיפה את שורת הסימון. אלו השינויים היחידים שהסריקה מבצעת: היא לעולם אינה מסירה או מנסחת מחדש את הטקסט של תת-הסוכן.
שגיאת API שמסיימת את תת-הסוכן מוקדם מהצפוי, כגון מגבלת קצב (rate limit), לעולם אינה נמסרת כתוצאה שלו. ראה שגיאות API בתת-סוכנים להתנהגות בחזית וברקע.
#הפעלת תת-סוכנים
#הפעלה אוטומטית
Claude מחליט אוטומטית מתי להפעיל תת-סוכנים על סמך המשימה וה-description של כל תת-סוכן. לדוגמה, אם תגדיר תת-סוכן performance-optimizer עם התיאור "Performance optimization specialist for query tuning", Claude יפעיל אותו כאשר ההנחיה שלך תזכיר ייעול שאילתות.
כתוב תיאורים ברורים וספציפיים כדי ש-Claude יוכל להתאים משימות לתת-הסוכן הנכון.
#הפעלה מפורשת
כדי להבטיח ש-Claude ישתמש בתת-סוכן ספציפי, ציין אותו בשמו בהנחיה שלך:
"Use the code-reviewer agent to check the authentication module"פעולה זו עוקפת את ההתאמה האוטומטית ומפעילה ישירות את תת-הסוכן בעל השם.
#תצורת סוכן דינמית
באפשרותך ליצור הגדרות סוכן באופן דינמי על סמך תנאים בזמן ריצה. דוגמה זו יוצרת סוקר אבטחה עם רמות קפדנות שונות, תוך שימוש במודל בעל יכולות גבוהות יותר עבור סקירות קפדניות.
#Python
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())#TypeScript
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);
}#זיהוי הפעלת תת-סוכן
Claude מפעיל תת-סוכנים באמצעות הכלי Agent. כדי לזהות מתי תת-סוכן מופעל, בדוק אם יש בלוקי tool_use שבהם name הוא "Agent". הודעות מתוך ההקשר של תת-סוכן כוללות שדה parent_tool_use_id.
הערה: הכלי מופיע כ-
"Agent"בבלוקיtool_use, אך כ-"Task"ברשימת הכלים שלsystem:init. לפני Claude Code בגרסה v2.1.63, בלוקיtool_useכינו אותו גם"Task". כדי להבטיח שהזיהוי ימשיך לפעול בכל גרסאות ה-SDK, התאם את שני הערכים ב-block.name.
מבנה ההודעה שונה בין ספריות ה-SDK. ב-Python, הגישה לבלוקי התוכן נעשית ישירות דרך message.content. ב-TypeScript, האובייקט SDKAssistantMessage עוטף את הודעת ה-API של Claude, ולכן הגישה לתוכן היא דרך message.message.content.
דוגמה זו עוברת על הודעות המוזרמות, מתעדת ביומן מתי תת-סוכן מופעל ומתי הודעות עוקבות מגיעות מתוך הקשר ההרצה של אותו תת-סוכן.
#Python
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())#TypeScript
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);
}
}#חידוש תת-סוכנים
באפשרותך לחדש את פעולתו של תת-סוכן כדי להמשיך מהנקודה שבה עצר במקום להתחיל מחדש. תת-סוכן שחודש שומר על היסטוריית השיחה המלאה שלו, כולל כל הקריאות הקודמות לכלים, התוצאות ותהליכי החשיבה.
כאשר תת-סוכן עוצר בהגעה למגבלת maxTurns שלו, Claude Code מסמן את הפלט בתוצאת הכלי Agent כחלקי, כך ש-Claude יודע שההרצה לא הושלמה.
כאשר תת-סוכן מסיים, תוצאת הכלי Agent כוללת בלוק טקסט המכיל את המחרוזת agentId: <id>. סוכני Explore ו-Plan המובנים מיועדים להרצה חד-פעמית ואינם מחזירים agentId, לכן השתמש בסוכן מותאם אישית או ב-general-purpose כאשר יש צורך בחידוש הפעולה. כדי לחדש פעולת תת-סוכן באופן תכנותי:
- לכידת מזהה הסשן: חלץ את
session_idמהודעות במהלך השאילתה הראשונה - חילוץ מזהה הסוכן: נתח את
agentIdמתוך טקסט התוצאה של הכליAgent - חידוש פעולת הסשן: העבר
resume: sessionIdבאפשרויות השאילתה השנייה, וכלול את מזהה הסוכן בהנחיה שלך. כל קריאה ל-query()מתחילה סשן חדש כברירת מחדל, וחובה לחדש את אותו סשן כדי לגשת לתמליל של תת-הסוכן.
הערה: בעת שימוש בסוכן מותאם אישית, העבר את אותה הגדרת סוכן בפרמטר
agentsעבור שתי השאילתות.
הדוגמה שלהלן מגדירה סוכן מותאם אישית בשם endpoint-finder. השאילתה הראשונה מריצה אותו ולוכדת את מזהה הסשן ואת מזהה הסוכן מתוצאת הכלי Agent, ולאחר מכן השאילתה השנייה מחדשת את הסשן כדי לשאול שאלת המשך הדורשת הקשר מניתוח המידע הראשוני.
#Python
import asyncio
import re
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition, ToolResultBlock
AGENTS = {
"endpoint-finder": AgentDefinition(
description="Locates and catalogs API endpoints in a codebase.",
prompt="You find and document API endpoints. Report each endpoint's path, method, and handler.",
tools=["Read", "Grep", "Glob"],
)
}
def extract_agent_id(block: ToolResultBlock) -> str | None:
"""Extract agentId from an Agent tool result's text content."""
parts = block.content if isinstance(block.content, list) else [{"text": block.content}]
for part in parts:
if match := re.search(r"agentId:\s*([\w-]+)", part.get("text") or ""):
return match.group(1)
return None
async def main():
agent_id = None
session_id = None
# First invocation - run the endpoint-finder subagent
try:
async for message in query(
prompt="Use the endpoint-finder agent to find all API endpoints in this codebase",
options=ClaudeAgentOptions(allowed_tools=["Read", "Grep", "Glob", "Agent"], agents=AGENTS),
):
# Capture session_id from ResultMessage (needed to resume this session)
if hasattr(message, "session_id"):
session_id = message.session_id
# Search tool results for the agentId trailer
for block in getattr(message, "content", None) or []:
if isinstance(block, ToolResultBlock):
agent_id = extract_agent_id(block) or agent_id
# Print the final result
if hasattr(message, "result"):
print(message.result)
except Exception as error:
# A single-shot query() raises after yielding an error result,
# so session_id and agent_id have already been captured by the loop above.
print(f"Session ended with an error: {error}")
# 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"], agents=AGENTS, resume=session_id
),
):
if hasattr(message, "result"):
print(message.result)
else:
print("No agentId found in the first query, so there is no subagent to resume.")
asyncio.run(main())#TypeScript
import { query, type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
const agents = {
"endpoint-finder": {
description: "Locates and catalogs API endpoints in a codebase.",
prompt: "You find and document API endpoints. Report each endpoint's path, method, and handler.",
tools: ["Read", "Grep", "Glob"]
}
};
// Stringify content to search for agentId without traversing nested block types
function extractAgentId(message: SDKMessage): string | undefined {
if (message.type !== "assistant" && message.type !== "user") return undefined;
const content = JSON.stringify(message.message.content);
const match = content.match(/agentId:\s*([\w-]+)/);
return match?.[1];
}
let agentId: string | undefined;
let sessionId: string | undefined;
// First invocation - run the endpoint-finder subagent
try {
for await (const message of query({
prompt: "Use the endpoint-finder agent to find all API endpoints in this codebase",
options: { allowedTools: ["Read", "Grep", "Glob", "Agent"], agents }
})) {
// 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);
}
} catch (error) {
// A single-shot query() throws after yielding an error result,
// so sessionId and agentId have already been captured by the loop above.
console.error(`Session ended with an error: ${error}`);
}
// 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"], agents, resume: sessionId }
})) {
if ("result" in message) console.log(message.result);
}
} else {
console.log("No agentId found in the first query, so there is no subagent to resume.");
}תמלילי תת-סוכנים נשמרים בקבצים נפרדים ונשארים ללא תלות בשיחה הראשית. ראה חידוש תת-סוכנים ב-Claude Code עבור התנהגות דחיסה (compaction) ותקופת הניקוי cleanupPeriodDays.
#הגבלות כלים
השתמש בשדה tools כדי להגביל את מה שתת-סוכן יכול לעשות:
- השמטת
tools: תת-הסוכן מקבל כל כלי שזמין לתת-סוכנים - ציון רשימת כלים: תת-הסוכן מקבל רק אותם. לדוגמה, סוקר קוד שלעולם אינו אמור לערוך קבצים מקבל
["Read", "Grep", "Glob"]
כלי שאינך כולל אינו נמצא בסשן של תת-הסוכן כלל: Claude עובד בלעדיו, ללא בקשת הרשאה וללא שגיאה.
דוגמה זו יוצרת סוכן ניתוח לקריאה בלבד שיכול לבחון קוד אך אינו יכול לשנות קבצים או להריץ פקודות.
#Python
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())#TypeScript
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) |
#הגבלת עומק תת-סוכנים, ריצה מקבילית ועלויות
הערה: סעיף זה מתאר את TypeScript SDK בגרסה v0.3.219 ואת Python SDK בגרסה v0.2.127 ואילך, המהדורות הכוללות את Claude Code בגרסה v2.1.219 ואילך. במהדורות קודמות, חלק ממגבלות אלו חסרות או מוגדרות עם ברירות מחדל שונות, לכן שדרג לפני שאתה מסתמך עליהן להגבלת הרצה. תיעוד משתני הסביבה ו-תורות ותקציב מתעדים את גרסת Claude Code שהוסיפה כל משתנה ואת אכיפת תקרת ההוצאות על תת-סוכנים.
Claude מחליט בעצמו מתי להפעיל תת-סוכן וכמה להפעיל. כל תת-סוכן מבצע בקשות API משלו, הנחשבות לחלק מ-total_cost_usd של השאילתה, ותת-סוכן יכול להפעיל תת-סוכנים משלו, כך שהנחיה אחת עלולה לצמוח לעץ של סוכנים.
באפשרותך להגביל צמיחה זו בשלוש דרכים: עומק הקינון של תת-הסוכנים, כמה מהם רצים בו-זמנית, וכמה כל השאילתה מוציאה. הגדר את מגבלות העומק והמקביליות כמשתני סביבה באמצעות האפשרות env, ואת מגבלת ההוצאה כאפשרות שאילתה:
| מגבלה | הגדרה באמצעות | ברירת מחדל | מה Claude Code עושה בהגעה למגבלה |
|---|---|---|---|
| עומק | CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH | 3 שכבות של תת-סוכנים מתחת לסוכן הראשי שלך. הערך 1 מונע מתת-הסוכנים שלך להפעיל תת-סוכנים משלהם | משאיר תת-סוכן בשכבה התחתונה ללא יכולת להפעיל סוכנים נוספים, כך שהוא מבצע את העבודה שהואצלה לו בעצמו. ראה תת-סוכנים מקוננים |
| מקביליות | CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS | 20 תת-סוכנים הרצים בו-זמנית, בספירת כל תת-סוכן ש-Claude מפעיל באמצעות הכלי Agent | מסרב להפעיל תת-סוכן נוסף ומחזיר Concurrent subagent limit reached, עד שמספר הסוכנים הרצים יורד מתחת למגבלה. סשנים שבהם ultracode פעיל אינם מסורבים לעולם. ראה מגבלת תת-סוכנים מקביליים |
| עלות | maxBudgetUsd ב-TypeScript, או max_budget_usd ב-Python | ללא מגבלה. מושווה מול total_cost_usd, כך שבקשות של תת-סוכנים נספרות | אוכף את התקרה בשלוש דרכים: מסרב להפעיל תת-סוכנים נוספים ומחזיר Budget limit reached, עוצר תת-סוכנים ברקע שעדיין רצים, ומסיים את השאילתה עם תת-סוג תוצאה error_max_budget_usd. ראה תורות ותקציב |
שתי ספריות ה-SDK מתייחסות לאפשרות env באופן שונה: ה-TypeScript SDK מחליף באמצעותה את סביבת תהליך המשנה (subprocess environment), לכן פרוס לתוכה את process.env כדי לשמור על משתנים כמו PATH, בעוד ש-Python SDK ממזג אותה אל תוך הסביבה שירש. דוגמה זו מבטלת קינון, מאפשרת לכל היותר חמישה תת-סוכנים בו-זמנית, ועוצרת את השאילתה ברגע שההוצאה המשוערת מגיעה ל-5 דולר:
#Python
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
try:
async for message in query(
prompt="Audit every service in this repo for unhandled promise rejections",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob", "Agent"],
# env is merged on top of the inherited environment
env={
"CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH": "1",
"CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS": "5",
},
max_budget_usd=5.0,
),
):
if isinstance(message, ResultMessage):
print(f"{message.subtype}: ${message.total_cost_usd}")
except Exception as error:
# A single-shot query() raises after yielding an error result,
# so the budget-capped result has already been printed above.
print(f"Session ended with an error: {error}")
asyncio.run(main())#TypeScript
import { query } from "@anthropic-ai/claude-agent-sdk";
try {
for await (const message of query({
prompt: "Audit every service in this repo for unhandled promise rejections",
options: {
allowedTools: ["Read", "Grep", "Glob", "Agent"],
// env replaces the subprocess environment, so spread process.env to keep PATH
env: {
...process.env,
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH: "1",
CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS: "5",
},
maxBudgetUsd: 5,
},
})) {
if (message.type === "result") {
console.log(`${message.subtype}: $${message.total_cost_usd}`);
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result,
// so the budget-capped result has already been logged above.
console.error(`Session ended with an error: ${error}`);
}מה שתראה תלוי באיזו מגבלה, אם בכלל, השאילתה מגיעה אליה:
- מתחת לתקרת ההוצאה: אתה רואה
successואת העלות המשוערת. - בתקרת ההוצאה: אתה רואה
error_max_budget_usdעם עלות של 5 או יותר, ולאחר מכן מופעל מטפל השגיאות שלך. - במגבלת המקביליות: אתה רואה בלוק
tool_resultבזרם ההודעות הנושא אתConcurrent subagent limit reached. Claude מקבל את אותו בלוק כתוצאה של הכליAgent.
#הרצת Opus 5 עם תת-סוכנים
Claude Opus 5 מאציל משימות לתת-סוכנים בקלות רבה יותר מדגמים קודמים, לכן מגבלות העומק, המקביליות וההוצאה חשובות במיוחד בשאילתות המריצות את Opus 5. מדריך ההנחיות של Opus 5 כולל הוראת האצלה שבאפשרותך להוסיף לכל הנחיה. השאלה אם Claude Code מוסיף הוראה משלו תלויה באיזו הנחיית מערכת אתה משתמש:
- הגדרה מראש (preset) של
claude_code: כאשר המודל הוא Opus 5, Claude Code מוסיף שורה להנחיית המערכת שלו המורה ל-Claude לא לקרוא לכליAgentאלא אם התבקש לעשות זאת. הכליAgentנשאר זמין. - הנחיה מותאמת אישית, או ללא
systemPrompt: Claude Code אינו בונה את הנחיית המערכת שלו, ולכן שורה זו נעדרת. הוסף את הוראת ההאצלה ממדריך ההנחיות להנחיה שלך.
כל אחת מההוראות רק מכוונת את Claude, לכן הגדר גם את המגבלות. Claude Code אוכף אותן ללא קשר לאופן שבו Claude מחליט להאציל משימות.
#הגדלת היקף העבודה באמצעות תהליכי עבודה דינמיים
תת-סוכנים מתאימים היטב למספר קטן של משימות מואצלות בכל תור. עבור הרצות שמתאמות בין עשרות עד מאות סוכנים, השתמש בכלי Workflow, אשר מעביר את התיאום לסקריפט שסביבת ההרצה מפעילה מחוץ להקשר השיחה. ראה תהליכי עבודה דינמיים כדי לראות כיצד תהליכי עבודה נבדלים מהאצלה לתת-סוכנים מתור לתור.
הכלי Workflow זמין ב-TypeScript Agent SDK בגרסה v0.3.149 ואילך. כלול את Workflow ב-allowedTools כדי לאשר אוטומטית הרצות של תהליכי עבודה. סכמות הקלט והפלט של הכלי מפורטות ב-הפניית התיעוד של TypeScript.
#פתרון בעיות
#Claude אינו מאציל משימות לתת-סוכנים
אם Claude משלים משימות ישירות במקום להאציל אותן לתת-הסוכן שלך:
- השתמש בהנחיה מפורשת: ציין את תת-הסוכן בשמו בהנחיה שלך, לדוגמה "Use the code-reviewer agent to..."
- כתוב תיאור ברור: הסבר בדיוק מתי להשתמש בתת-הסוכן כדי ש-Claude יוכל להתאים משימות בצורה נכונה
#סוכנים מבוססי מערכת קבצים אינם נטענים
Claude Code עוקב אחר ~/.claude/agents/ ו-.claude/agents/ ומזהה קובץ סוכן חדש או ערוך תוך שניות בודדות, ללא צורך בהפעלה מחדש. אם הגדרה אינה מופיעה לעולם, בדוק את הסיבות הבאות:
- ספריית
agentsחדשה: רכיב המעקב מכסה רק ספריות שהיו קיימות כאשר הסשן התחיל, ולכן הקובץ הראשון בספרייה חדשה דורש הפעלה מחדש של הסשן. זוהי הסיבה הנפוצה ביותר. - frontmatter לא תקין או
nameכפול: בדוק את ה-YAML של הקובץ, והאם סוכן קיים כבר משתמש ב-nameזה. --disable-slash-commands: סשנים שהופעלו עם דגל זה אינם עוקבים אחר ספריות אלו ותמיד דורשים הפעלה מחדש כדי לטעון קבצים חדשים.- קובץ תחת ספרייה שנוספה: Claude Code טוען את
.claude/agents/מספריות שנוספו עם האפשרותadd_dirs(ב-Python) אוadditionalDirectories(ב-TypeScript), או דרך--add-dirאו/add-dirב-CLI, אך אינו עוקב אחריהן, ולכן קובץ חדש או ערוך שם דורש הפעלה מחדש של הסשן. - סוכן תכנותי בעל אותו שם: פרמטר
agentsהמועבר ל-query()דורס סוכן ממערכת הקבצים בעל אותו שם.
עבור מבנה הקובץ, ראה כיצד לכתוב קובצי תת-סוכנים.
#תיעוד קשור
- תת-סוכנים ב-Claude Code: תיעוד מקיף על תת-סוכנים כולל הגדרות מבוססות מערכת קבצים
- תהליכי עבודה דינמיים: תיאום תת-סוכנים רבים מתוך סקריפט עבור משימות גדולות מכדי לנהלן בשיחה אחת
- סקירת SDK: תחילת העבודה עם Claude Agent SDK