הבנה של מחזור החיים של ההודעות, ביצוע כלים, חלון ההקשר, והארכיטקטורה שמפעילה את סוכני ה-SDK.
ה-Agent SDK מאפשר להטמיע את לולאת הסוכן האוטונומית של Claude Code ביישומים שלך. ה-SDK הוא חבילה עצמאית שנותנת שליטה תכנותית בכלים, בהרשאות, במגבלות עלות ובפלט.
גם ה-SDK של TypeScript וגם ה-SDK של Python אורזים קובץ בינארי מקומי של Claude Code, כך שרוב ההתקנות לא צריכות התקנה נפרדת של Claude Code. ראה את הערת ההתקנה ב-quickstart להתקנות שכן צריכות.
כשמפעילים סוכן, ה-SDK מריץ את אותה לולאת ביצוע שמפעילה את Claude Code: Claude מעריך את הפרומפט, קורא לכלים כדי לפעול, מקבל את התוצאות, וחוזר על כך עד שהמשימה הושלמה. הדף הזה מסביר מה קורה בתוך הלולאה כדי שתוכל לבנות, לנפות באגים ולייעל את הסוכנים ביעילות.
קבלת פרומפט. Claude מקבל את הפרומפט, יחד עם פרומפט המערכת, הגדרות הכלים והיסטוריית השיחה. ה-SDK מניב SystemMessage עם subtype "init" שמכיל מטא נתונים של הסשן.
הערכה ותגובה. Claude מעריך את המצב הנוכחי וקובע איך להמשיך. הוא עשוי להגיב בטקסט, לבקש קריאה אחת או יותר לכלים, או גם וגם. ה-SDK מניב אובייקט AssistantMessage אחד או יותר, אחד לכל בלוק תוכן, כמו בלוק טקסט או בקשת קריאה לכלי.
ביצוע כלים. ה-SDK מריץ כל כלי שהתבקש ואוסף את התוצאות. כל סט של תוצאות כלים חוזר ל-Claude להחלטה הבאה. אפשר להשתמש ב-hooks כדי ליירט, לשנות או לחסום קריאות לכלים לפני שהן רצות.
חזרה. שלבים 2 ו-3 חוזרים כמחזור. Claude ממשיך לקרוא לכלים ולעבד תוצאות עד שהוא מפיק תגובה בלי קריאות לכלים.
החזרת תוצאה. ה-SDK מניב AssistantMessage סופי עם תגובת הטקסט (בלי קריאות לכלים), ואחריו ResultMessage עם הטקסט הסופי, שימוש בטוקנים, עלות ומזהה סשן.
שאלה קצרה כמו "אילו קבצים יש כאן?" עשויה לקחת שניים או שלושה תורות: אחד או שניים שקוראים ל-Glob, ואז אחד שמגיב עם התוצאות. משימה מורכבת כמו "בצע refactor למודול ה-auth ועדכן את הבדיקות" יכולה לשרשר עשרות קריאות לכלים לאורך תורות רבים, בזמן ש-Claude מתאים את עצמו אחרי כל תוצאה.
תור הוא מעבר אחד דרך הלולאה: Claude מפיק פלט, ואם הוא כולל קריאות לכלים, ה-SDK מבצע אותן והתוצאות חוזרות ל-Claude אוטומטית. זה קורה בלי להחזיר שליטה לקוד שלך. התורות נמשכים עד ש-Claude מפיק פלט בלי קריאות לכלים, ואז הלולאה מסתיימת והתוצאה הסופית נמסרת.
שקול איך סשן מלא עשוי להיראות עבור הפרומפט "תקן את הבדיקות שנכשלות ב-auth.ts".
קודם ה-SDK שולח את הפרומפט ל-Claude ומניב SystemMessage עם מטא נתוני הסשן. אחר כך הלולאה מתחילה:
תור 1: Claude קורא ל-Bash כדי להריץ npm test. ה-SDK מניב AssistantMessage עם קריאת הכלי, מבצע את הפקודה, ואז מניב UserMessage עם הפלט (שלושה כשלונות).
תור 2: Claude קורא ל-Read על auth.ts ועל auth.test.ts. ה-SDK מניב AssistantMessage לכל קריאה ומחזיר את תוכן הקבצים.
תור 3: Claude קורא ל-Edit כדי לתקן את auth.ts, ואז קורא ל-Bash כדי להריץ שוב את npm test. כל שלוש הבדיקות עוברות. ה-SDK מניב AssistantMessage לכל קריאה.
תור סופי: Claude מפיק תגובת טקסט בלבד בלי קריאות לכלים: "תוקן באג ה-auth, כל שלוש הבדיקות עוברות עכשיו." ה-SDK מניב AssistantMessage סופי עם הטקסט הזה, ואז ResultMessage עם אותו טקסט בתוספת עלות ושימוש.
אלה היו ארבעה תורות: שלושה עם קריאות לכלים, ותגובת טקסט סופית אחת בלי כלים.
אפשר להגביל את הלולאה עם max_turns / maxTurns. סופרים כל תור עם קריאות לכלים, ועוד אחד לתגובת הטקסט הסופית בלי כלים. בלי התור הנוסף הזה, הריצה מסתיימת עם ResultMessage ש-subtype שלו הוא error_max_turns ובלי תגובה סופית. לדוגמה, max_turns=2 בלולאה שלמעלה היה עוצר לפני שלב העריכה. אפשר גם להשתמש ב-max_budget_usd / maxBudgetUsd כדי להגביל תורות לפי סף הוצאה.
בלי מגבלות, הלולאה רצה עד ש-Claude מסיים בעצמו, וזה מתאים למשימות עם היקף מוגדר, אבל יכול לרוץ זמן רב על פרומפטים פתוחים ("שפר את בסיס הקוד הזה"). הגדרת תקציב היא ברירת מחדל טובה לסוכני ייצור. ראה תורות ותקציב בהמשך לעיון באפשרויות.
"worker_shutting_down": המארח יוצא, או ש-Remote Control התנתק
ב-TypeScript, כל subtype מלבד "init" הוא טיפוס משלו ב-איחוד SDKMessage, ולא subtype של SDKSystemMessage.
AssistantMessage: מופק עבור כל בלוק תוכן בתגובות של Claude, כולל תגובת הטקסט הסופית בלי כלים. כל אחד נושא בלוק תוכן יחיד, כמו טקסט או קריאה לכלי, וההודעות מתגובה אחת חולקות מזהה הודעה.
UserMessage: מופק אחרי כל ביצוע כלי, עם תוכן תוצאת הכלי שנשלח בחזרה ל-Claude. מופק גם עבור כל קלט משתמש שמוזרם באמצע הלולאה.
StreamEvent: מופק רק כשהודעות חלקיות מופעלות. מכיל אירועי streaming גולמיים של ה-API (דלתאות טקסט, מקטעי קלט של כלים). ראה תגובות stream.
ResultMessage: מסמן את סוף לולאת הסוכן. מכיל את תוצאת הטקסט הסופית, שימוש בטוקנים, עלות ומזהה סשן. בדוק את השדה subtype כדי לקבוע אם המשימה הצליחה או פגעה במגבלה. מספר קטן של אירועי מערכת עוקבים, כמו prompt_suggestion, יכולים להגיע אחריו, לכן יש לעבור על הזרם עד סופו במקום לעצור על התוצאה. ראה טיפול בתוצאה.
חמשת הטיפוסים האלה מכסים את מחזור החיים המלא של לולאת הסוכן. שני ה-SDK גם מניבים אירועי observability כמו סטטוס rate-limit והתראות משימות, שאינם נדרשים כדי להניע את הלולאה. ראה את הפניה לסוגי הודעות ב-Python ואת הפניה לסוגי הודעות ב-TypeScript לרשימות המלאות.
תוצאות סופיות בלבד: לטפל ב-ResultMessage כדי לקבל את הפלט, העלות, והאם המשימה הצליחה או פגעה במגבלה.
עדכוני התקדמות: לטפל ב-AssistantMessage כדי לראות מה Claude עושה בכל תור, כולל אילו כלים הוא קרא.
streaming חי: להפעיל הודעות חלקיות (include_partial_messages ב-Python, includePartialMessages ב-TypeScript) כדי לקבל הודעות StreamEvent בזמן אמת. ראה תגובות stream בזמן אמת.
איך בודקים סוגי הודעות תלוי ב-SDK:
Python: בדיקת סוגי הודעות עם isinstance() מול מחלקות שיובאו מ-claude_agent_sdk (לדוגמה, isinstance(message, ResultMessage)).
TypeScript: בדיקת שדה המחרוזת type (לדוגמה, message.type === "result"). AssistantMessage ו-UserMessage עוטפים את הודעת ה-API הגולמית בשדה .message, כך שבלוקי התוכן נמצאים ב-message.message.content, ולא ב-message.content.
דוגמה: בדיקת סוגי הודעות וטיפול בתוצאות
Python:
import asyncio
from claude_agent_sdk import query, AssistantMessage, ResultMessage, TextBlock, ToolUseBlock
async def main():
try:
async for message in query(prompt="Summarize this project"):
if isinstance(message, AssistantMessage):
# Each AssistantMessage carries one content block
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
elif isinstance(block, ToolUseBlock):
print(f"Tool call: {block.name}")
if isinstance(message, ResultMessage):
if message.subtype == "success":
print(message.result)
else:
print(f"Stopped: {message.subtype}")
except Exception as error:
# A single-shot query() raises after yielding an error result. If the
# failure was an error result, the error subtype branches above have
# already run; connection or process failures yield no result message.
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: "Summarize this project" })) {
if (message.type === "assistant") {
// Each assistant message carries one content block
for (const block of message.message.content) {
if (block.type === "text") {
console.log(`Claude: ${block.text}`);
} else if (block.type === "tool_use") {
console.log(`Tool call: ${block.name}`);
}
}
}
if (message.type === "result") {
if (message.subtype === "success") {
console.log(message.result);
} else {
console.log(`Stopped: ${message.subtype}`);
}
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result. If the
// failure was an error result, the error subtype branches above have
// already run; connection or process failures yield no result message.
console.log(`Session ended with an error: ${error}`);
}
כלים נותנים לסוכן את היכולת לפעול. בלי כלים, Claude יכול להגיב רק בטקסט. עם כלים, Claude יכול לקרוא קבצים, להריץ פקודות, לחפש בקוד ולתקשר עם שירותים חיצוניים.
Claude קובע לאילו כלים לקרוא לפי המשימה, אבל אתה שולט אם הקריאות האלה מורשות לרוץ. אפשר לאשר אוטומטית כלים מסוימים, לחסום אחרים לגמרי, או לדרוש אישור לכל דבר. שלוש אפשרויות עובדות יחד כדי לקבוע מה רץ:
allowed_tools / allowedTools מאשר אוטומטית את הכלים שברשימה. סוכן לקריאה בלבד עם ["Read", "Glob", "Grep"] ברשימת הכלים המאושרים שלו מריץ את הכלים האלה בלי בקשת אישור, מלבד קריאות מנתיבי רשת. כלים שלא ברשימה עדיין זמינים, וקריאות אליהם שדורשות אישור עוברות למצב ההרשאה ול-canUseTool.
disallowed_tools / disallowedTools חוסם את הכלים שברשימה, בלי קשר להגדרות אחרות. ראה הרשאות לסדר שבו הכללים נבדקים לפני שכלי רץ.
permission_mode / permissionMode שולט בכמה פיקוח אנושי רוצים. ה-SDK מעריך את המצב הפעיל יחד עם כללי allow ו-deny שלך בסדר קבוע, שמתואר ב-איך הרשאות מוערכות. ראה מצב הרשאה למצבים הזמינים.
אפשר גם להגביל כלים בודדים עם כללים כמו "Bash(npm *)" כדי לאפשר רק פקודות מסוימות. ראה הרשאות לתחביר הכללים המלא.
כשכלי נדחה, Claude מקבל הודעת דחייה כתוצאת הכלי, ובדרך כלל מנסה גישה אחרת או מדווח שלא יכול להמשיך.
כש-Claude מבקש כמה קריאות לכלים בתור אחד, שני ה-SDK יכולים להריץ אותן במקביל או ברצף, לפי הכלי. כלים לקריאה בלבד (כמו Read, Glob, Grep, וכלי MCP שמסומנים כקריאה בלבד) יכולים לרוץ במקביל. כלים שמשנים מצב (כמו Edit, Write ו-Bash) רצים ברצף כדי למנוע התנגשויות.
כלים מותאמים אישית רצים כברירת מחדל ברצף. כדי לאפשר ביצוע מקבילי לכלי מותאם אישית, יש להגדיר את readOnlyHint ב-annotations שלו. גם ה-SDK של TypeScript וגם ה-SDK של Python משתמשים בשם השדה הזה מ-MCP SDK.
אפשר להגביל כמה תורות הלולאה לוקחת, כמה היא עולה, עד כמה Claude מנמק לעומק, והאם כלים דורשים אישור לפני הרצה. כל אלה הם שדות ב-ClaudeAgentOptions (Python) / Options (TypeScript).
כשאחת מההגבלות מושגת, ה-SDK מחזיר ResultMessage עם תת סוג שגיאה מתאים (error_max_turns או error_max_budget_usd). ראה טיפול בתוצאה לבדיקת תת הסוגים האלה, ו-ClaudeAgentOptions / Options לתחביר.
תקרת התקציב מכסה סוכני משנה: ההוצאה שלהם נספרת בסך הכולל. ברגע שההוצאה מגיעה לתקרה, יצירת סוכן משנה נוסף נכשלת עם Budget limit reached, ו-Claude Code עוצר סוכני משנה ברקע שעדיין רצים. התנהגויות אכיפת התקרה דורשות Claude Code v2.1.217 או חדש יותר.
עם קלט בזרימה, הודעה שעדיין בתור כשתורה מסתיימת במגבלת מקסימום התורות נשארת בתור. Claude Code לא מוסיף אותה לקריאת המודל האחרונה של אותה תורה. הוא מתחיל תורה חדשה עבור ההודעה, וספירת מקסימום התורות מתחילה מחדש עבור אותה תורה. סך התקציב ממשיך להצטבר בין הודעות, וברגע שההוצאה מגיעה ל-maxBudgetUsd, הודעות מאוחרות יותר באותה שיחה מסתיימות בתוצאת error_max_budget_usd. /clear מתחיל את התקציב מחדש.
Claude Code משווה את ההוצאה לתקרת max_budget_usd / maxBudgetUsd אחרי שתשובות המודל מגיעות, כי העלות של כל תשובה מגיעה משימוש הטוקנים שה-API מחזיר איתה. התשובה שמגיעה לתקרה עדיין מושלמת ונחשבת אל total_cost_usd. לכן ההוצאה יכולה לעבור את התקרה בעד עלות התשובה האחת הזו, בתוספת כל מה שסוכני משנה שעדיין רצים באותו רגע מוציאים לפני שהם נעצרים. השאר מרווח לזה כשמגדירים את התקרה.
האפשרות effort שולטת בכמה הנמקה Claude מפעיל. רמות מאמץ נמוכות יותר משתמשות בפחות טוקנים לתורה ומפחיתות עלות. לא כל המודלים תומכים בפרמטר המאמץ. ראה Effort לגבי אילו מודלים תומכים בו.
אם לא מגדירים effort, Claude Code קובע את רמת המאמץ בעצמו, בסדר שהתאמת רמת מאמץ מתאר.
[!NOTE]
effort מחליף השהיה ועלות טוקנים בעומק הנמקה בתוך כל תשובה. חשיבה מורחבת היא תכונה נפרדת שמייצרת בלוקי thinking בפלט, והשדה display ב-ThinkingConfig עבור Python או TypeScript שולט אם מקבלים את הטקסט שלהם. הם בלתי תלויים: אפשר להגדיר effort: "low" עם חשיבה מורחבת מופעלת, או effort: "max" בלי זה.
השתמש במאמץ נמוך יותר לסוכנים שמבצעים משימות פשוטות ומוגדרות היטב, כמו הצגת קבצים או הרצת grep יחיד, כדי להפחית עלות והשהיה. הגדר effort באפשרויות query() ברמה העליונה עבור הסשן, או לכל סוכן משנה עם השדה effort ב-AgentDefinition כדי לדרוס את רמת הסשן.
אפשרות מצב ההרשאות (permission_mode ב-Python, permissionMode ב-TypeScript) שולטת אם הסוכן מבקש אישור לפני שימוש בכלים:
מצב
התנהגות
מקרה שימוש
"default"
קריאות כלים שדורשות אישור ואינן מכוסות בכללי allow מפעילות את ה-callback canUseTool; בלי callback המשמעות היא דחייה
יישומים אינטראקטיביים עם callback אישור מותאם
"acceptEdits"
מאשר אוטומטית עריכות קבצים ופקודות מערכת קבצים נפוצות (mkdir, touch, mv, cp וכו') בתוך ספריות העבודה; פקודות Bash אחרות פועלות לפי כללי ברירת המחדל
אתה סומך על העריכות של Claude ורוצה איטרציה מהירה יותר, למשל במהלך אב טיפוס או כשעובדים בספרייה מבודדת
"plan"
Claude חוקר ומתכנן. עריכות שנעשות עם כלי הקבצים של Claude עוברות ל-callback canUseTool גם כשכלל allow מתאים להן
אתה רוצה ש-Claude ייצר תוכנית קודם, למשל במהלך סקירת קוד או לפני שינוי גדול
"dontAsk"
אף פעם לא מבקש. כלים שאושרו מראש על ידי כללי הרשאות רצים, וכך גם קריאות שלא צריכות אישור במצב default, כמו קריאות קבצים בתוך ספריות העבודה. כל קריאה שהייתה מבקשת אחרת נדחית, אם כי מוד שהתקנת עדיין יכול לאשר חלק מהקריאות האלה. כמה קריאות, כמו קריאות מנתיבי רשת, נדחות גם אם אישרת אותן. לרשימה, ראה מצב Don't ask
סוכנים ללא ממשק, בלי מי שיאשר קריאות
"auto"
משתמש במסווג מודל כדי לסקור פעולות כמו פקודות מעטפת ובקשות רשת, ומאשר או חוסם כל אחת שהוא סוקר. ראה מצב Auto לזמינות ולסדר ההחלטה
סוכנים אוטונומיים שעדיין רוצים מעקות בטיחות על שימוש בכלים
"bypassPermissions"
מריץ קריאות כלים בלי לבקש אישור, כולל קריאות לכלים שלא רשמת ב-allowedTools. כמה קריאות עדיין עוברות ל-callback canUseTool, והן מפורטות תחת מצב Bypass permissions. ב-SDK של TypeScript נדרש גם allowDangerouslySkipPermissions: true ב-options. אי אפשר להשתמש בזה כשרצים כ-root ב-Unix. השתמש רק בסביבות מבודדות שבהן פעולות הסוכן לא יכולות להשפיע על מערכות שאכפת לך מהן
CI, קונטיינרים, או סביבות מבודדות אחרות
ליישומים אינטראקטיביים, השתמש ב-"default" עם callback אישור כלים כדי להציג בקשות אישור. לסוכנים שעורכים קבצים במכונת פיתוח, השתמש ב-"acceptEdits". שמור את "bypassPermissions" ל-CI, קונטיינרים, או סביבות מבודדות אחרות. ראה הרשאות לפרטים המלאים.
חלון ההקשר הוא סך המידע הזמין ל-Claude במהלך סשן. הוא לא מתאפס בין תורות בתוך סשן. הכול מצטבר: הנחיית המערכת, הגדרות הכלים, היסטוריית השיחה, קלטי כלים ופלטי כלים. תוכן שנשאר זהה בין תורות (הנחיית מערכת, הגדרות כלים, CLAUDE.md) נשמר אוטומטית ב-מטמון הנחיות, מה שמפחית עלות והשהיה לקידומות שחוזרות. לאופן שבו הנחיית מערכת מותאמת או טקסט append משפיעים על שימוש חוזר במטמון בין סשנים, ראה שינוי הנחיות מערכת.
גדלה עם כל תורה: הנחיות, תשובות, קלטי כלים, פלטי כלים
תיאורי מיומנויות
תחילת הסשן, דרך מקורות הגדרות
סיכומים קצרים; התוכן המלא נטען רק כשמפעילים
פלטי כלים גדולים צורכים הקשר משמעותי. קריאת קובץ גדול או הרצת פקודה עם פלט מפורט יכולות להשתמש באלפי טוקנים בתורה אחת. ההקשר מצטבר בין תורות, כך שסשנים ארוכים עם הרבה קריאות כלים בונים משמעותית יותר הקשר מסשנים קצרים.
כשחלון ההקשר מתקרב למגבלה שלו, ה-SDK דוחס אוטומטית את השיחה: הוא מסכם היסטוריה ישנה יותר כדי לפנות מקום, ושומר על החילופים האחרונים ועל החלטות מפתח. ה-SDK פולט הודעה עם type: "system" ו-subtype: "compact_boundary" בזרם כשזה קורה (ב-Python זה SystemMessage; ב-TypeScript זה טיפוס נפרד SDKCompactBoundaryMessage).
הדחיסה מחליפה הודעות ישנות יותר בסיכום, כך שהוראות ספציפיות מתחילת השיחה אולי לא יישמרו. כללים מתמשכים שייכים ל-CLAUDE.md (שנטען דרך settingSources) ולא להנחיה הראשונית, כי תוכן CLAUDE.md מוזרק מחדש בכל בקשה.
אפשר להתאים את התנהגות הדחיסה בכמה דרכים:
הוראות סיכום ב-CLAUDE.md: הדוחס קורא את CLAUDE.md כמו כל הקשר אחר, כך שאפשר לכלול מקטע שאומר לו מה לשמר בסיכום. הדוחס מתאים לפי כוונה, כך שכותרת המקטע חופשית.
הוק PreCompact: הרץ לוגיקה מותאמת לפני שהדחיסה מתרחשת, למשל כדי לארכב את התמליל המלא. ההוק מקבל שדה trigger (manual או auto). ראה הוקים.
דחיסה ידנית: שלח /compact כמחרוזת הנחיה כדי להפעיל דחיסה לפי דרישה. פקודות שנשלחות כך הן קלטי SDK רגילים. ראה שליחת פקודות לפי שם.
[accordion] דוגמה: הוראות סיכום ב-CLAUDE.md
הוסף מקטע ל-CLAUDE.md של הפרויקט שאומר לדוחס מה לשמר. שם הכותרת אינו מיוחד; השתמש בכל תווית ברורה.
# Summary instructions
When summarizing this conversation, always preserve:
- The current task objective and acceptance criteria
- File paths that have been read or modified
- Test results and error messages
- Decisions made and the reasoning behind them
השתמש בסוכני משנה לתת משימות. סוכן משנה מחזיר רק את התשובה הסופית שלו, כך שההקשר של הסוכן הראשי גדל בסיכום, לא בתמליל של תת המשימה.
היה בררני עם כלים. כל הגדרת כלי תופסת מקום בהקשר. השתמש בשדה tools ב-AgentDefinition כדי להגביל סוכני משנה לסט המינימלי שהם צריכים.
עקוב אחרי עלויות שרתי MCP.חיפוש כלי MCP דוחה סכמות של כלי MCP כברירת מחדל וטוען אותן לפי דרישה. כשחיפוש כלים כבוי או נסוג לטעינה מראש, כל שרת MCP מוסיף את כל סכמות הכלים שלו לכל בקשה, כך שכמה שרתים עם הרבה כלים יכולים לצרוך הקשר משמעותי לפני שהסוכן עושה עבודה כלשהי. ראה הגדרת חיפוש כלים לתצורות שבהן הנסיגה חלה.
השתמש במאמץ נמוך יותר למשימות שגרתיות. הגדר מאמץ ל-"low" לסוכנים שצריכים רק לקרוא קבצים או להציג ספריות. זה מפחית שימוש בטוקנים ועלות.
כל אינטראקציה עם ה-SDK יוצרת או ממשיכה סשן. לכוד את מזהה הסשן מ-ResultMessage.session_id (זמין בשני ה-SDK) כדי לחדש מאוחר יותר. ה-SDK של TypeScript חושף אותו גם כשדה ישיר ב-SystemMessage של האתחול; ב-Python הוא מקונן ב-SystemMessage.data.
כשמחדשים, ההקשר המלא מתורות קודמות משוחזר: קבצים שנקראו, ניתוח שבוצע, ופעולות שננקטו. אפשר גם לפצל סשן כדי להסתעף לגישה אחרת בלי לשנות את המקור.
ראה ניהול סשנים למדריך המלא על דפוסי resume, continue ו-fork. כדי לחדש סשנים בין קונטיינרים חסרי מצב או מארחים serverless, העבר מתאם session_store / sessionStore כדי שה-SDK ישקף תמלילים לבקאנד שלך ומארח אחר יוכל לחדש אותם. תהליך המשנה של Claude Code עדיין כותב קודם לדיסק המקומי. ראה ארכיטקטורת כתיבה כפולה לגבי איזה עותק שורד סשן חדש לעומת הרצה שחודשה מהמאגר, ואיך לשמור את העותק המקומי זמני.
[!NOTE]
ב-Python, ClaudeSDKClient מטפל במזהי סשן אוטומטית בין כמה קריאות. ראה את הפניה ל-SDK של Python לפרטים.
כשהלולאה מסתיימת, ResultMessage אומר מה קרה ונותן את הפלט. השדה subtype (זמין בשני ה-SDK) הוא הדרך העיקרית לבדוק את מצב הסיום.
תת-סוג התוצאה
מה קרה
השדה result זמין?
success
Claude סיים את המשימה כרגיל
כן
error_max_turns
הגיע למגבלת maxTurns לפני הסיום
לא
error_max_budget_usd
הגיע למגבלת maxBudgetUsd לפני הסיום
לא
error_during_execution
שגיאה קטעה את הלולאה (לדוגמה, בקשה שבוטלה)
לא
error_max_structured_output_retries
לא הופק פלט מובנה תקין בתוך מגבלת הניסיונות החוזרים שהוגדרה: כל ניסיון נכשל באימות, או ש-fallback של מודל משך בחזרה את הפלט שהושלם בלי ניסיון חוזר מוצלח
לא
השדה result מחזיק את פלט הטקסט הסופי וקיים רק בוריאנט success, לכן תמיד בדוק את תת-הסוג לפני שקוראים אותו.
כל תת-סוגי התוצאה נושאים את total_cost_usd, usage, num_turns ו-session_id, כדי שאפשר לעקוב אחרי עלות ולחדש גם אחרי שגיאות. הוסף הגנה למקרים האלה:
אחרי קריסת סשן, התוצאה הסופית היא error_during_execution ששדות העלות שלו עשויים להיות מאופסים ושהשדה stop_reason שלו הוא null, והתהליך יוצא אחרי שהוא פולט אותה. ראה שחזור סכומים אחרי קריסת סשן.
ב-Python, total_cost_usd, usage ו-model_usage מוגדרים כאופציונליים, לכן בדוק שהם אינם None לפני שקוראים אותם.
השדה usage מכסה רק את לולאת הסוכן הראשית. השתמש ב-modelUsage, או ב-model_usage ב-Python, לחשבונאות טוקנים ועלות של כל העץ. ראה מעקב אחרי עלויות ושימוש לפרטים על פירוש שדות usage.
[!NOTE]
כששאילתה מסתיימת בתוצאת שגיאה:
קריאה חד-פעמית ל-query() מניבה את הודעת התוצאה הסופית, ואז מעלה שגיאה שכוללת את טקסט הכשל, כמו Reached maximum number of turns. ההעלאה מכוונת. עטוף את הלולאה בבלוק try אם הקוד צריך להמשיך מעבר לזה. תהליך Claude Code שמתחת גם יוצא עם קוד שאינו אפס.
סשן קלט בזרימה נשאר חי, ואפשר להמשיך לשלוח הודעות, למעט אחרי קריסת סשן, שפולטת תוצאת error_during_execution סופית ויוצאת מהתהליך.
התוצאה כוללת גם שדה stop_reason (string | null ב-TypeScript, str | None ב-Python) שמציין למה המודל הפסיק לייצר בתור הסופי שלו. ערכים נפוצים הם end_turn (המודל סיים כרגיל), max_tokens (הגיע למגבלת טוקני הפלט), ו-refusal (המודל סירב לבקשה). בתוצאות שגיאה שהלולאה יצרה, stop_reason נושא את הערך מתשובת העוזר האחרונה לפני שהלולאה הסתיימה. התוצאה ש-Claude Code מרכיב אחרי קריסת סשן נושאת null.
כדי לזהות סירובים, בדוק stop_reason === "refusal" (TypeScript) או stop_reason == "refusal" (Python). ראה SDKResultMessage (TypeScript) או ResultMessage (Python) לטיפוס המלא.
Hooks הם callbacks שנורים בנקודות מסוימות בלולאה: לפני שכלי רץ, אחרי שהוא חוזר, כשהסוכן מסיים, וכן הלאה. כמה הוקים נפוצים הם:
הוק
מתי הוא נורה
שימושים נפוצים
PreToolUse
לפני שכלי רץ
אימות קלטים, חסימת פקודות מסוכנות
PostToolUse
אחרי שכלי חוזר
ביקורת פלטים, הפעלת תופעות לוואי
UserPromptSubmit
כשנשלח פרומפט
הזרקת הקשר נוסף לפרומפטים
Stop
כשהסוכן מסיים
אימות התוצאה, שמירת מצב הסשן
SubagentStart / SubagentStop
כשתת-סוכן נוצר או משלים
מעקב וצבירה של תוצאות משימות מקבילות
PreCompact
לפני דחיסת הקשר
ארכוב התמליל המלא לפני סיכום
הוקים רצים בתהליך היישום, לא בתוך חלון ההקשר של הסוכן, ולכן הם לא צורכים הקשר. הוקים יכולים גם לקצר את הלולאה: הוק PreToolUse שדוחה קריאת כלי מונע את הביצוע שלה, ו-Claude מקבל את הודעת הדחייה במקום.
שני ה-SDK תומכים בכל האירועים שלמעלה. ה-SDK של TypeScript כולל אירועים נוספים ש-Python עדיין לא תומך בהם. ראה שליטה בביצוע עם הוקים לרשימת האירועים המלאה, לזמינות לפי SDK, ול-API המלא של ה-callback.
הדוגמה הזו משלבת את המושגים המרכזיים מהדף הזה לסוכן יחיד שמתקן בדיקות שנכשלות. היא מגדירה את הסוכן עם כלים מותרים (מאושרים אוטומטית כדי שהסוכן ירוץ באופן אוטונומי), הגדרות פרויקט, ומגבלות בטיחות על תורות ומאמץ חשיבה. בזמן שהלולאה רצה, היא לוכדת את מזהה הסשן לחידוש אפשרי, מטפלת בתוצאה הסופית, ומדפיסה את העלות הכוללת.
מכיוון שקריאה חד-פעמית ל-query() מעלה שגיאה אחרי שהיא מניבה תוצאת שגיאה, הלולאה עטופה בבלוק try כדי שהסקריפט ייצא בצורה נקייה כשמגיעים למגבלה.
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def run_agent():
session_id = None
try:
async for message in query(
prompt="Find and fix the bug causing test failures in the auth module",
options=ClaudeAgentOptions(
allowed_tools=[
"Read",
"Edit",
"Bash",
"Glob",
"Grep",
], # Listing tools here auto-approves them (no prompting)
setting_sources=[
"project"
], # Load CLAUDE.md, skills, hooks from current directory
max_turns=30, # Prevent runaway sessions
effort="high", # Thorough reasoning for complex debugging
),
):
# Handle the final result
if isinstance(message, ResultMessage):
session_id = message.session_id # Save for potential resumption
if message.subtype == "success":
print(f"Done: {message.result}")
elif message.subtype == "error_max_turns":
# Agent ran out of turns. Resume with a higher limit.
print(f"Hit turn limit. Resume session {session_id} to continue.")
elif message.subtype == "error_max_budget_usd":
print("Hit budget limit.")
else:
print(f"Stopped: {message.subtype}")
if message.total_cost_usd is not None:
print(f"Cost: ${message.total_cost_usd:.4f}")
except Exception as error:
# A single-shot query() raises after yielding an error result. If the
# failure was an error result, the error subtype branches above have
# already run; connection or process failures yield no result message.
print(f"Session ended with an error: {error}")
asyncio.run(run_agent())
import { query } from "@anthropic-ai/claude-agent-sdk";
let sessionId: string | undefined;
try {
for await (const message of query({
prompt: "Find and fix the bug causing test failures in the auth module",
options: {
allowedTools: ["Read", "Edit", "Bash", "Glob", "Grep"], // Listing tools here auto-approves them (no prompting)
settingSources: ["project"], // Load CLAUDE.md, skills, hooks from current directory
maxTurns: 30, // Prevent runaway sessions
effort: "high" // Thorough reasoning for complex debugging
}
})) {
// Save the session ID to resume later if needed
if (message.type === "system" && message.subtype === "init") {
sessionId = message.session_id;
}
// Handle the final result
if (message.type === "result") {
if (message.subtype === "success") {
console.log(`Done: ${message.result}`);
} else if (message.subtype === "error_max_turns") {
// Agent ran out of turns. Resume with a higher limit.
console.log(`Hit turn limit. Resume session ${sessionId} to continue.`);
} else if (message.subtype === "error_max_budget_usd") {
console.log("Hit budget limit.");
} else {
console.log(`Stopped: ${message.subtype}`);
}
console.log(`Cost: $${message.total_cost_usd.toFixed(4)}`);
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result. If the
// failure was an error result, the error subtype branches above have
// already run; connection or process failures yield no result message.
console.log(`Session ended with an error: ${error}`);
}
כשהסוכן מסיים בהצלחה, הדוגמה מדפיסה שורת Done: עם סיכום התיקון של הסוכן, ואז שורה כמו Cost: $0.0312.
בונה ממשק אינטראקטיבי? הפעל הזרמה כדי להציג טקסט חי וקריאות כלים בזמן שהלולאה רצה.
צריך שליטה הדוקה יותר במה שהסוכן יכול לעשות? נעל את הגישה לכלים עם הרשאות, והשתמש בהוקים כדי לבקר, לחסום, או לשנות קריאות כלים לפני שהן רצות.
מריץ משימות ארוכות או יקרות? העבר עבודה מבודדת לתת-סוכנים כדי לשמור על ההקשר הראשי רזה.
פורס כשירות? ראה אירוח Agent SDK להנחיה על קונטיינרים ו-serverless, ואחסון סשנים כדי לשמור סשנים בבקאנד שלך.
לתמונה המושגית הרחבה יותר של הלולאה הסוכנית (לא ספציפית ל-SDK), ראה איך Claude Code עובד. למדריך מעשי לעיצוב לולאות ב-Claude Code, מלולאות מבוססות תור ועד לולאות מבוססות יעד ולולאות יזומות, ראה הנדסת לולאות: התחלה עם לולאות בבלוג.