رفتن به محتوا

حلقه‌ی ایجنت چطور کار می‌کند

Understand the message lifecycle, tool execution, context window, and architecture that power your SDK agents.

Agent SDK به تو اجازه می‌دهد حلقه‌ی ایجنتِ خودمختارِ Claude Code را در اپلیکیشن‌های خودت جاسازی کنی. این SDK یک پکیجِ مستقل است که کنترلِ برنامه‌نویسی‌شده روی ابزارها، دسترسی‌ها، سقفِ هزینه و خروجی می‌دهد. برای استفاده از آن لازم نیست Claude Code CLI نصب باشد.

وقتی یک ایجنت را شروع می‌کنی، SDK همان حلقه‌ی اجرایی‌ای که Claude Code را پیش می‌برد را اجرا می‌کند: Claude پرامپتت را ارزیابی می‌کند، ابزارها را برای اقدام فراخوانی می‌کند، نتیجه‌ها را می‌گیرد و تا کاملِ شدنِ کار تکرار می‌کند. این صفحه توضیح می‌دهد داخلِ آن حلقه چه می‌گذرد تا بتوانی ایجنت‌هایت را به‌خوبی بسازی، عیب‌یابی و بهینه کنی.

هر نشستِ ایجنت همان چرخه را دنبال می‌کند:

Diagram of the agent loop: your prompt enters the agentic loop, where Claude evaluates and either requests tool calls, whose results feed back into another evaluation, or returns the final answer
  1. دریافتِ پرامپت. Claude پرامپتت را همراه با سیستم‌پرامپت، تعریفِ ابزارها و تاریخچه‌ی گفتگو دریافت می‌کند. SDK یک SystemMessage با زیرنوعِ "init" تولید می‌کند که فراداده‌ی نشست را در خود دارد.
  2. ارزیابی و پاسخ. Claude وضعیتِ فعلی را ارزیابی می‌کند و تعیین می‌کند چطور پیش برود. ممکن است با متن پاسخ بدهد، یک یا چند فراخوانیِ ابزار درخواست کند، یا هر دو. SDK یک AssistantMessage تولید می‌کند که متن و هر درخواستِ فراخوانیِ ابزار را در خود دارد.
  3. اجرای ابزارها. SDK هر ابزارِ درخواست‌شده را اجرا می‌کند و نتیجه‌ها را جمع می‌کند. هر مجموعه از نتایجِ ابزار برای تصمیمِ بعدی به Claude بازخورد داده می‌شود. می‌توانی با هوک‌ها فراخوانی‌های ابزار را پیش از اجرا رهگیری، تغییر یا مسدود کنی.
  4. تکرار. مرحله‌های ۲ و ۳ به‌صورتِ یک چرخه تکرار می‌شوند. هر چرخه‌ی کامل یک نوبت است. Claude تا وقتی پاسخی بدونِ هیچ فراخوانیِ ابزار تولید کند به فراخوانیِ ابزارها و پردازشِ نتایج ادامه می‌دهد.
  5. بازگرداندنِ نتیجه. SDK یک AssistantMessageِ نهایی با پاسخِ متنی (بدونِ فراخوانیِ ابزار) تولید می‌کند، و در پی‌اش یک ResultMessage با متنِ نهایی، مصرفِ توکن، هزینه و شناسه‌ی نشست.

یک پرسشِ سریع («چه فایل‌هایی اینجاست؟») شاید یک یا دو نوبت طول بکشد، با فراخوانیِ Glob و پاسخ با نتایج. یک کارِ پیچیده («ماژولِ احراز هویت را بازآرایی کن و تست‌ها را به‌روز کن») می‌تواند ده‌ها فراخوانیِ ابزار را در چند نوبت زنجیر کند، با خواندنِ فایل‌ها، ویرایشِ کد و اجرای تست‌ها، در حالی که Claude رویکردش را بر اساسِ هر نتیجه تنظیم می‌کند.

یک نوبت یک رفت‌وبرگشت داخلِ حلقه است: Claude خروجی‌ای تولید می‌کند که شاملِ فراخوانیِ ابزار است، SDK آن ابزارها را اجرا می‌کند، و نتیجه‌ها به‌صورتِ خودکار به Claude بازخورد می‌شوند. این بدونِ بازگرداندنِ کنترل به کدِ تو اتفاق می‌افتد. نوبت‌ها تا وقتی Claude خروجی‌ای بدونِ فراخوانیِ ابزار تولید کند ادامه می‌یابند، و در آن نقطه حلقه پایان می‌گیرد و نتیجه‌ی نهایی تحویل داده می‌شود.

ببین یک نشستِ کامل برای پرامپتِ «تست‌های شکست‌خورده در auth.ts را درست کن» چطور به نظر می‌رسد.

ابتدا SDK پرامپتت را به Claude می‌فرستد و یک SystemMessage با فراداده‌ی نشست تولید می‌کند. بعد حلقه شروع می‌شود:

  1. نوبت ۱: Claude برای اجرای npm test ابزارِ Bash را فراخوانی می‌کند. SDK یک AssistantMessage با فراخوانیِ ابزار تولید می‌کند، دستور را اجرا می‌کند، بعد یک UserMessage با خروجی (سه شکست) تولید می‌کند.
  2. نوبت ۲: Claude روی auth.ts و auth.test.ts ابزارِ Read را فراخوانی می‌کند. SDK محتوای فایل‌ها را برمی‌گرداند و یک AssistantMessage تولید می‌کند.
  3. نوبت ۳: Claude برای درست کردنِ auth.ts ابزارِ Edit را فراخوانی می‌کند، بعد برای اجرای دوباره‌ی npm test ابزارِ Bash را فراخوانی می‌کند. هر سه تست پاس می‌شوند. SDK یک AssistantMessage تولید می‌کند.
  4. نوبتِ نهایی: Claude یک پاسخِ فقط-متنی بدونِ فراخوانیِ ابزار تولید می‌کند: «باگِ auth درست شد، الان هر سه تست پاس می‌شوند.» SDK یک AssistantMessageِ نهایی با این متن تولید می‌کند، بعد یک ResultMessage با همان متن به‌علاوه‌ی هزینه و مصرف.

این چهار نوبت بود: سه‌تا با فراخوانیِ ابزار، یکی پاسخِ نهاییِ فقط-متنی.

می‌توانی حلقه را با max_turns / maxTurns سقف بگذاری، که فقط نوبت‌های استفاده از ابزار را می‌شمارد. مثلاً max_turns=2 در حلقه‌ی بالا پیش از مرحله‌ی ویرایش متوقف می‌شد. همچنین می‌توانی با max_budget_usd / maxBudgetUsd نوبت‌ها را بر اساسِ یک آستانه‌ی هزینه سقف بگذاری.

بدونِ محدودیت، حلقه تا وقتی Claude خودش تمام کند اجرا می‌شود، که برای کارهای خوش‌تعریف خوب است ولی روی پرامپت‌های بازانتها («این کدبیس را بهتر کن») می‌تواند طولانی شود. تعیینِ یک بودجه برای ایجنت‌های تولیدی یک پیش‌فرضِ خوب است. برای مرجعِ گزینه‌ها، نوبت‌ها و بودجه را در پایین ببین.

همان‌طور که حلقه اجرا می‌شود، SDK جریانی از پیام‌ها تولید می‌کند. هر پیام نوعی دارد که می‌گوید از کدام مرحله‌ی حلقه آمده است. پنج نوعِ هسته‌ای این‌هاست:

  • SystemMessage: رویدادهای چرخه‌ی عمرِ نشست. فیلدِ subtype آن‌ها را تفکیک می‌کند: "init" اولین پیام است (فراداده‌ی نشست)، و "compact_boundary" پس از فشرده‌سازی (compaction) فعال می‌شود. در TypeScript، مرزِ فشرده‌سازی به‌جای زیرنوعی از SDKSystemMessage، نوعِ مستقلِ خودش یعنی SDKCompactBoundaryMessage است.
  • AssistantMessage: پس از هر پاسخِ Claude، شاملِ پاسخِ نهاییِ فقط-متنی، منتشر می‌شود. بلوک‌های محتوای متنی و بلوک‌های فراخوانیِ ابزارِ آن نوبت را در خود دارد.
  • UserMessage: پس از هر اجرای ابزار، همراه با محتوای نتیجه‌ی ابزار که به Claude بازفرستاده می‌شود، منتشر می‌شود. همچنین برای هر ورودیِ کاربری که وسطِ حلقه استریم می‌کنی منتشر می‌شود.
  • StreamEvent: فقط وقتی پیام‌های جزئی فعال باشند منتشر می‌شود. رویدادهای خامِ استریمِ API (دلتای متن، تکه‌های ورودیِ ابزار) را در خود دارد. Stream responses را ببین.
  • ResultMessage: پایانِ حلقه‌ی ایجنت را نشانه می‌گذارد. نتیجه‌ی متنیِ نهایی، مصرفِ توکن، هزینه و شناسه‌ی نشست را در خود دارد. فیلدِ subtype را بررسی کن تا بفهمی کار موفق بوده یا به یک محدودیت خورده است. تعدادِ اندکی رویدادِ سیستمیِ دنباله‌ای، مثلِ prompt_suggestion، می‌توانند پس از آن برسند، پس به‌جای متوقف شدن روی نتیجه، جریان را تا انتها پیمایش کن. مدیریتِ نتیجه را ببین.

این پنج نوع کلِ چرخه‌ی عمرِ حلقه‌ی ایجنت را در هر دو SDK پوشش می‌دهند. TypeScript SDK رویدادهای رصدپذیریِ اضافی هم تولید می‌کند (رویدادهای هوک، پیشرفتِ ابزار، سقفِ نرخ، اعلان‌های وظیفه) که جزئیاتِ بیشتری می‌دهند ولی برای راندنِ حلقه لازم نیستند. برای فهرست‌های کامل، مرجعِ انواعِ پیامِ Python و مرجعِ انواعِ پیامِ TypeScript را ببین.

اینکه کدام پیام‌ها را مدیریت می‌کنی به این بستگی دارد که چه می‌سازی:

  • فقط نتیجه‌های نهایی: ResultMessage را مدیریت کن تا خروجی، هزینه و اینکه کار موفق بوده یا به محدودیت خورده را بگیری.
  • به‌روزرسانی‌های پیشرفت: AssistantMessage را مدیریت کن تا ببینی Claude در هر نوبت چه می‌کند، شاملِ اینکه کدام ابزارها را فراخوانده.
  • استریمِ زنده: پیام‌های جزئی را فعال کن (include_partial_messages در Python، includePartialMessages در TypeScript) تا پیام‌های StreamEvent را در زمانِ واقعی بگیری. Stream responses in real-time را ببین.

اینکه چطور انواعِ پیام را بررسی می‌کنی به SDK بستگی دارد:

  • Python: انواعِ پیام را با isinstance() در برابرِ کلاس‌های واردشده از claude_agent_sdk بررسی کن (مثلاً isinstance(message, ResultMessage)).
  • TypeScript: فیلدِ رشته‌ایِ type را بررسی کن (مثلاً message.type === "result"). AssistantMessage و UserMessage پیامِ خامِ API را در یک فیلدِ .message می‌پیچند، پس بلوک‌های محتوا در message.message.content هستند، نه message.content.
نمونه: بررسیِ انواعِ پیام و مدیریتِ نتیجه‌ها
from claude_agent_sdk import query, AssistantMessage, ResultMessage
async for message in query(prompt="Summarize this project"):
if isinstance(message, AssistantMessage):
print(f"Turn completed: {len(message.content)} content blocks")
if isinstance(message, ResultMessage):
if message.subtype == "success":
print(message.result)
else:
print(f"Stopped: {message.subtype}")
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({ prompt: "Summarize this project" })) {
if (message.type === "assistant") {
console.log(`Turn completed: ${message.message.content.length} content blocks`);
}
if (message.type === "result") {
if (message.subtype === "success") {
console.log(message.result);
} else {
console.log(`Stopped: ${message.subtype}`);
}
}
}

ابزارها به ایجنتت توانِ اقدام می‌دهند. بدونِ ابزار، Claude فقط می‌تواند با متن پاسخ بدهد. با ابزار، Claude می‌تواند فایل‌ها را بخواند، دستورها را اجرا کند، کد را جستجو کند و با سرویس‌های بیرونی تعامل کند.

این SDK همان ابزارهایی را دارد که Claude Code را پیش می‌برند:

دستهابزارهاچه می‌کنند
عملیاتِ فایلRead، Edit، Writeخواندن، تغییر و ساختِ فایل‌ها
جستجوGlob، Grepیافتنِ فایل بر اساسِ الگو، جستجوی محتوا با regex
اجراBashاجرای دستورهای شل، اسکریپت‌ها، عملیاتِ git
وبWebSearch، WebFetchجستجوی وب، واکشی و تجزیه‌ی صفحه‌ها
کشفToolSearchیافتن و بارگذاریِ پویای ابزارها به‌صورتِ on-demand به‌جای پیش‌بارگذاریِ همه‌ی آن‌ها
هماهنگ‌سازیAgent، Skill، AskUserQuestion، TaskCreate، TaskUpdateتولیدِ ساب‌ایجنت‌ها، فراخوانیِ Skillها، پرسش از کاربر، رهگیریِ وظیفه‌ها

فراتر از ابزارهای داخلی، می‌توانی:

  • سرویس‌های بیرونی را متصل کنی با سرورهای MCP (پایگاه‌های داده، مرورگرها، APIها)
  • ابزارهای سفارشی تعریف کنی با هندلرهای ابزارِ سفارشی
  • Skillهای پروژه را بار کنی از طریقِ setting sources برای ورک‌فلوهای قابلِ‌بازاستفاده

Claude بر اساسِ کار تعیین می‌کند کدام ابزارها را فراخوانی کند، ولی تو کنترل می‌کنی که آیا آن فراخوانی‌ها اجازه‌ی اجرا داشته باشند. می‌توانی ابزارهای مشخصی را خودکار تأیید کنی، بعضی را کلاً مسدود کنی، یا برای همه‌چیز درخواستِ تأیید بگذاری. سه گزینه با هم تعیین می‌کنند چه چیزی اجرا شود:

  • allowed_tools / allowedTools ابزارهای فهرست‌شده را خودکار تأیید می‌کند. یک ایجنتِ فقط-خواندنی با ["Read", "Glob", "Grep"] در فهرستِ ابزارهای مجازش، آن ابزارها را بدونِ پرسش اجرا می‌کند. ابزارهایی که فهرست نشده‌اند همچنان در دسترس‌اند ولی به مجوز نیاز دارند.
  • disallowed_tools / disallowedTools ابزارهای فهرست‌شده را مسدود می‌کند، صرف‌نظر از سایرِ تنظیمات. برای ترتیبی که قواعد پیش از اجرای ابزار بررسی می‌شوند، Permissions را ببین.
  • permission_mode / permissionMode کنترل می‌کند برای ابزارهایی که قواعدِ اجازه یا انکار پوششان نمی‌دهد چه اتفاقی بیفتد. برای حالت‌های در دسترس، حالتِ دسترسی را ببین.

همچنین می‌توانی ابزارهای منفرد را با قواعدی مثلِ "Bash(npm *)" محدود کنی تا فقط دستورهای مشخصی مجاز باشند. برای نحوِ کاملِ قواعد، Permissions را ببین.

وقتی ابزاری انکار می‌شود، Claude یک پیامِ ردّ به‌عنوانِ نتیجه‌ی ابزار دریافت می‌کند و معمولاً رویکردی متفاوت امتحان می‌کند یا گزارش می‌دهد که نتوانست پیش برود.

وقتی Claude در یک نوبت چند فراخوانیِ ابزار درخواست می‌کند، هر دو SDK می‌توانند بسته به ابزار آن‌ها را هم‌زمان یا متوالی اجرا کنند. ابزارهای فقط-خواندنی (مثلِ Read، Glob، Grep و ابزارهای MCP که فقط-خواندنی علامت خورده‌اند) می‌توانند هم‌زمان اجرا شوند. ابزارهایی که وضعیت را تغییر می‌دهند (مثلِ Edit، Write و Bash) برای پرهیز از تداخل متوالی اجرا می‌شوند.

ابزارهای سفارشی به‌صورتِ پیش‌فرض متوالی اجرا می‌شوند. برای فعال کردنِ اجرای موازیِ یک ابزارِ سفارشی، readOnlyHint را در حاشیه‌نویسی‌هایش تنظیم کن. هر دو SDKِ TypeScript و Python از این نامِ فیلد از MCP SDK استفاده می‌کنند.

کنترلِ نحوه‌ی اجرای حلقه

Section titled “کنترلِ نحوه‌ی اجرای حلقه”

می‌توانی محدود کنی که حلقه چند نوبت طول بکشد، چقدر هزینه کند، Claude چقدر عمیق استدلال کند، و اینکه آیا ابزارها پیش از اجرا به تأیید نیاز دارند. همه‌ی این‌ها فیلدهایی روی ClaudeAgentOptions (Python) / Options (TypeScript) هستند.

گزینهچه چیزی را کنترل می‌کندپیش‌فرض
حداکثر نوبت (max_turns / maxTurns)حداکثر رفت‌وبرگشت‌های استفاده از ابزاربدونِ محدودیت
حداکثر بودجه (max_budget_usd / maxBudgetUsd)حداکثر هزینه پیش از توقفبدونِ محدودیت

وقتی هر کدام از این محدودیت‌ها به سقف بخورد، SDK یک ResultMessage با زیرنوعِ خطای متناظر (error_max_turns یا error_max_budget_usd) برمی‌گرداند. برای نحوه‌ی بررسیِ این زیرنوع‌ها مدیریتِ نتیجه و برای نحو ClaudeAgentOptions / Options را ببین.

گزینه‌ی effort کنترل می‌کند Claude چقدر استدلال به کار بگیرد. سطوحِ effortِ پایین‌تر در هر نوبت توکنِ کمتری مصرف می‌کنند و هزینه را کاهش می‌دهند. همه‌ی مدل‌ها از پارامترِ effort پشتیبانی نمی‌کنند. برای اینکه کدام مدل‌ها از آن پشتیبانی می‌کنند، Effort را ببین.

سطحرفتارخوب برای
"low"استدلالِ حداقلی، پاسخ‌های سریعجستجوی فایل، فهرست کردنِ دایرکتوری‌ها
"medium"استدلالِ متوازنویرایش‌های روتین، کارهای استاندارد
"high"تحلیلِ دقیقبازآرایی‌ها، عیب‌یابی
"xhigh"عمقِ استدلالِ گسترده‌ترکدنویسی و کارهای ایجنتیک؛ روی Fable 5 و Opus 4.7+ توصیه می‌شود
"max"بیشینه‌ی عمقِ استدلالمسائلِ چندمرحله‌ای که به تحلیلِ عمیق نیاز دارند

اگر effort را تنظیم نکنی، هر دو SDK پارامتر را تنظیم‌نشده می‌گذارند و به رفتارِ پیش‌فرضِ مدل واگذار می‌کنند.

برای ایجنت‌هایی که کارهای ساده و خوش‌تعریف انجام می‌دهند (مثلِ فهرست کردنِ فایل‌ها یا اجرای یک grepِ منفرد) از effortِ پایین‌تر استفاده کن تا هزینه و تأخیر کاهش یابد. effort را در گزینه‌های سطحِ‌بالای query() برای کلِ نشست تنظیم کن، یا برای هر ساب‌ایجنت با فیلدِ effort روی AgentDefinition تا سطحِ نشست را بازنویسی کند.

گزینه‌ی حالتِ دسترسی (permission_mode در Python، permissionMode در TypeScript) کنترل می‌کند که آیا ایجنت پیش از استفاده از ابزارها درخواستِ تأیید می‌کند:

حالترفتار
"default"ابزارهایی که قواعدِ اجازه پوششان نمی‌دهد کال‌بکِ تأییدت را فعال می‌کنند؛ نبودِ کال‌بک یعنی انکار
"acceptEdits"ویرایش‌های فایل و دستورهای رایجِ فایل‌سیستم (mkdir، touch، mv، cp و غیره) را خودکار تأیید می‌کند؛ سایرِ دستورهای Bash از قواعدِ default پیروی می‌کنند
"plan"Claude کاوش و برنامه‌ریزی می‌کند بدونِ ویرایشِ فایل‌های منبعت؛ ویرایش‌های فایل هرگز خودکار تأیید نمی‌شوند و از کال‌بکِ canUseToolِ تو می‌پرسند
"dontAsk"هرگز نمی‌پرسد. ابزارهایی که با قواعدِ دسترسی پیش‌تأیید شده‌اند اجرا می‌شوند، بقیه انکار می‌شوند
"auto" (فقط TypeScript)از یک دسته‌بندِ مدل برای تأیید یا انکارِ هر فراخوانیِ ابزار استفاده می‌کند. برای در دسترس بودن و رفتار، Auto mode را ببین
"bypassPermissions"همه‌ی ابزارهای مجاز را بدونِ پرسش اجرا می‌کند، مگر یک قاعده‌ی askِ صریح مطابقت کند؛ برای اینکه قواعدِ ask کجای ترتیبِ اولویت می‌نشینند How permissions are evaluated را ببین. هنگامِ اجرا به‌عنوانِ root روی Unix نمی‌توان از آن استفاده کرد. فقط در محیط‌های جداشده‌ای به کار ببر که اقداماتِ ایجنت نمی‌تواند به سیستم‌هایی که برایت مهم‌اند آسیب بزند

برای اپلیکیشن‌های تعاملی، از "default" با یک کال‌بکِ تأییدِ ابزار استفاده کن تا درخواست‌های تأیید نمایان شوند. برای ایجنت‌های خودمختار روی یک ماشینِ توسعه، "acceptEdits" ویرایش‌های فایل و دستورهای رایجِ فایل‌سیستم (mkdir، touch، mv، cp و غیره) را خودکار تأیید می‌کند و در عینِ حال سایرِ دستورهای Bash را همچنان پشتِ قواعدِ اجازه نگه می‌دارد. "bypassPermissions" را برای CI، کانتینرها یا سایرِ محیط‌های جداشده نگه دار. برای جزئیاتِ کامل، Permissions را ببین.

اگر model را تنظیم نکنی، SDK از پیش‌فرضِ Claude Code استفاده می‌کند، که به روشِ احراز هویت و اشتراکت بستگی دارد. برای میخ کردنِ یک مدلِ مشخص یا استفاده از یک مدلِ کوچک‌تر برای ایجنت‌های سریع‌تر و ارزان‌تر، آن را صریحاً تنظیم کن (مثلاً model="claude-sonnet-4-6"). برای شناسه‌های در دسترس، models را ببین.

پنجره‌ی کانتکست کلِ مقدارِ اطلاعاتی است که در طولِ یک نشست برای Claude در دسترس است. بینِ نوبت‌های داخلِ یک نشست بازنشانی نمی‌شود. همه‌چیز انباشته می‌شود: سیستم‌پرامپت، تعریفِ ابزارها، تاریخچه‌ی گفتگو، ورودی‌های ابزار و خروجی‌های ابزار. محتوایی که بینِ نوبت‌ها یکسان می‌ماند (سیستم‌پرامپت، تعریفِ ابزارها، CLAUDE.md) به‌صورتِ خودکار کشِ پرامپت می‌شود، که هزینه و تأخیر را برای پیشوندهای تکراری کاهش می‌دهد.

چه چیزی کانتکست مصرف می‌کند

Section titled “چه چیزی کانتکست مصرف می‌کند”

این‌طور هر مؤلفه در SDK بر کانتکست اثر می‌گذارد:

منبعکِی بار می‌شوداثر
سیستم‌پرامپتهر درخواستهزینه‌ی ثابتِ کوچک، همیشه حاضر
فایل‌های CLAUDE.mdشروعِ نشست، از طریقِ settingSourcesمحتوای کامل در هر درخواست (ولی کشِ پرامپت می‌شود، پس فقط اولین درخواست هزینه‌ی کامل را می‌پردازد)
تعریفِ ابزارهاهر درخواست؛ شِماهای MCP به‌صورتِ پیش‌فرض موکول می‌شوندشِماهای ابزارِ داخلی در هر درخواست بار می‌شوند. Tool search شِماهای ابزارِ MCP را به‌صورتِ پیش‌فرض موکول می‌کند و روی Vertex AI یا یک ANTHROPIC_BASE_URLِ غیرشخصِ‌اول به بارگذاریِ پیشاپیش برمی‌گردد. برای ماتریسِ کامل Configure tool search را ببین
تاریخچه‌ی گفتگودر طولِ نوبت‌ها انباشته می‌شودبا هر نوبت رشد می‌کند: پرامپت‌ها، پاسخ‌ها، ورودی‌های ابزار، خروجی‌های ابزار
توصیفِ Skillهاشروعِ نشست، از طریقِ setting sourcesخلاصه‌های کوتاه؛ محتوای کامل فقط هنگامِ فراخوانی بار می‌شود

خروجی‌های بزرگِ ابزار کانتکستِ قابلِ‌توجهی مصرف می‌کنند. خواندنِ یک فایلِ بزرگ یا اجرای دستوری با خروجیِ پرحرف می‌تواند در یک نوبت هزاران توکن مصرف کند. کانتکست در طولِ نوبت‌ها انباشته می‌شود، پس نشست‌های طولانی‌ترِ با فراخوانی‌های ابزارِ زیاد کانتکستِ به‌مراتب بیشتری از نشست‌های کوتاه می‌سازند.

وقتی پنجره‌ی کانتکست به سقفش نزدیک می‌شود، 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 را به‌عنوانِ یک رشته‌ی پرامپت بفرست تا فشرده‌سازی به‌صورتِ on-demand فعال شود. دستورهایی که این‌طور فرستاده می‌شوند ورودی‌های SDK هستند، نه میان‌برهای فقط-CLI. دستورها در SDK را ببین.
نمونه: دستورالعمل‌های خلاصه‌سازی در 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

کانتکست را بهینه نگه دار

Section titled “کانتکست را بهینه نگه دار”

چند راهبرد برای ایجنت‌های طولانی‌اجرا:

  • برای زیرکارها از ساب‌ایجنت‌ها استفاده کن. هر ساب‌ایجنت با یک گفتگوی تازه شروع می‌شود (بدونِ تاریخچه‌ی پیامِ پیشین، هرچند سیستم‌پرامپتِ خودش و کانتکستِ سطحِ پروژه مثلِ CLAUDE.md را بار می‌کند). نوبت‌های والد را نمی‌بیند، و فقط پاسخِ نهایی‌اش به والد به‌عنوانِ نتیجه‌ی ابزار برمی‌گردد. کانتکستِ ایجنتِ اصلی به اندازه‌ی همان خلاصه رشد می‌کند، نه به اندازه‌ی کلِ رونوشتِ زیرکار. برای جزئیات، What subagents inherit را ببین.
  • در انتخابِ ابزارها گزینشی باش. هر تعریفِ ابزار فضای کانتکست می‌گیرد. از فیلدِ tools روی AgentDefinition استفاده کن تا ساب‌ایجنت‌ها را به حداقلِ مجموعه‌ی موردِ نیازشان محدود کنی.
  • مراقبِ هزینه‌های سرورِ MCP باش. MCP tool search شِماهای ابزارِ MCP را به‌صورتِ پیش‌فرض موکول می‌کند و آن‌ها را on-demand بار می‌کند. وقتی tool search خاموش است، روی Vertex AI، یا پشتِ یک ANTHROPIC_BASE_URLِ غیرشخصِ‌اول، هر سرورِ MCP همه‌ی شِماهای ابزارش را به هر درخواست اضافه می‌کند، پس چند سرور با ابزارهای زیاد می‌توانند پیش از اینکه ایجنت کاری کند کانتکستِ قابلِ‌توجهی مصرف کنند.
  • برای کارهای روتین از effortِ پایین‌تر استفاده کن. برای ایجنت‌هایی که فقط باید فایل بخوانند یا دایرکتوری فهرست کنند، effort را روی "low" بگذار. این مصرفِ توکن و هزینه را کاهش می‌دهد.

برای تفکیکِ دقیقِ هزینه‌های کانتکستِ هر قابلیت، Understand context costs را ببین.

هر تعامل با SDK یک نشست می‌سازد یا ادامه می‌دهد. شناسه‌ی نشست را از ResultMessage.session_id (در هر دو SDK در دسترس است) بگیر تا بعداً از سر بگیری. TypeScript SDK آن را به‌عنوانِ یک فیلدِ مستقیم روی SystemMessageِ initِ هم نمایش می‌دهد؛ در Python در SystemMessage.data تو در تو است.

وقتی از سر می‌گیری، کلِ کانتکست از نوبت‌های پیشین بازیابی می‌شود: فایل‌هایی که خوانده شده‌اند، تحلیلی که انجام شده، و اقداماتی که انجام گرفته. همچنین می‌توانی یک نشست را fork کنی تا بدونِ تغییرِ اصل، به رویکردی متفاوت شاخه بزنی.

برای راهنمای کاملِ الگوهای resume، continue و fork، Session management را ببین.

وقتی حلقه پایان می‌گیرد، ResultMessage به تو می‌گوید چه شد و خروجی را می‌دهد. فیلدِ subtype (در هر دو SDK در دسترس است) راهِ اصلیِ بررسیِ حالتِ خاتمه است.

زیرنوعِ نتیجهچه شدفیلدِ result در دسترس است؟
successClaude کار را عادی تمام کردبله
error_max_turnsپیش از اتمام به محدودیتِ maxTurns خوردنه
error_max_budget_usdپیش از اتمام به محدودیتِ maxBudgetUsd خوردنه
error_during_executionیک خطا حلقه را قطع کرد (مثلاً یک شکستِ API یا درخواستِ لغوشده)نه
error_max_structured_output_retriesهیچ خروجیِ ساخت‌یافته‌ی معتبری در حدِ تلاشِ مجدِ پیکربندی‌شده تولید نشد: هر تلاش از اعتبارسنجی رد شد، یا یک فال‌بکِ مدل خروجیِ تکمیل‌شده را بدونِ یک تلاشِ موفقِ مجدد پس گرفتنه

فیلدِ result (خروجیِ متنیِ نهایی) فقط روی واریانتِ success حاضر است، پس همیشه پیش از خواندنش subtype را بررسی کن. همه‌ی زیرنوع‌های نتیجه total_cost_usd، usage، num_turns و session_id را حمل می‌کنند تا بتوانی حتی پس از خطا هزینه را رهگیری و از سر بگیری. در Python، total_cost_usd و usage به‌صورتِ optional تایپ شده‌اند و ممکن است در بعضی مسیرهای خطا None باشند، پس پیش از قالب‌بندی‌شان محافظت بگذار. برای جزئیاتِ تفسیرِ فیلدهای usage، Tracking costs and usage را ببین.

نتیجه همچنین یک فیلدِ stop_reason دارد (string | null در TypeScript، str | None در Python) که نشان می‌دهد چرا مدل در نوبتِ نهایی‌اش از تولید بازایستاد. مقادیرِ رایج end_turn (مدل عادی تمام کرد)، max_tokens (به سقفِ توکنِ خروجی خورد) و refusal (مدل درخواست را رد کرد) هستند. روی زیرنوع‌های خطای نتیجه، stop_reason مقدارِ آخرین پاسخِ دستیار پیش از پایانِ حلقه را حمل می‌کند. برای تشخیصِ ردها، stop_reason === "refusal" (TypeScript) یا stop_reason == "refusal" (Python) را بررسی کن. برای نوعِ کامل، SDKResultMessage (TypeScript) یا ResultMessage (Python) را ببین.

هوک‌ها کال‌بک‌هایی هستند که در نقطه‌های مشخصی از حلقه فعال می‌شوند: پیش از اجرای یک ابزار، پس از بازگشتش، وقتی ایجنت تمام می‌کند و غیره. چند هوکِ پرکاربرد این‌هاست:

هوککِی فعال می‌شودکاربردهای رایج
PreToolUseپیش از اجرای یک ابزاراعتبارسنجیِ ورودی‌ها، مسدود کردنِ دستورهای خطرناک
PostToolUseپس از بازگشتِ یک ابزارممیزیِ خروجی‌ها، فعال کردنِ اثرهای جانبی
UserPromptSubmitوقتی یک پرامپت فرستاده می‌شودتزریقِ کانتکستِ اضافی به پرامپت‌ها
Stopوقتی ایجنت تمام می‌کنداعتبارسنجیِ نتیجه، ذخیره‌ی وضعیتِ نشست
SubagentStart / SubagentStopوقتی یک ساب‌ایجنت تولید یا تمام می‌شودرهگیری و تجمیعِ نتایجِ وظیفه‌های موازی
PreCompactپیش از فشرده‌سازیِ کانتکستبایگانیِ رونوشتِ کامل پیش از خلاصه‌سازی

هوک‌ها در فرایندِ اپلیکیشنِ تو اجرا می‌شوند، نه داخلِ پنجره‌ی کانتکستِ ایجنت، پس کانتکست مصرف نمی‌کنند. هوک‌ها همچنین می‌توانند حلقه را اتصالِ‌کوتاه کنند: یک هوکِ PreToolUse که یک فراخوانیِ ابزار را رد می‌کند جلوی اجرایش را می‌گیرد، و Claude به‌جایش پیامِ ردّ را دریافت می‌کند.

هر دو SDK از همه‌ی رویدادهای بالا پشتیبانی می‌کنند. TypeScript SDK رویدادهای اضافی‌ای دارد که Python هنوز پشتیبانی نمی‌کند. برای فهرستِ کاملِ رویدادها، در دسترس بودنِ هر-SDK و API کاملِ کال‌بک، Control execution with hooks را ببین.

این نمونه مفاهیمِ کلیدیِ این صفحه را در یک ایجنتِ واحد که تست‌های شکست‌خورده را درست می‌کند ترکیب می‌کند. ایجنت را با ابزارهای مجاز (خودکار تأییدشده تا ایجنت خودمختار اجرا شود)، تنظیماتِ پروژه و محدودیت‌های ایمنی روی نوبت‌ها و سطحِ effortِ استدلال پیکربندی می‌کند. همین‌طور که حلقه اجرا می‌شود، شناسه‌ی نشست را برای از سر گرفتنِ احتمالی می‌گیرد، نتیجه‌ی نهایی را مدیریت می‌کند و هزینه‌ی کل را چاپ می‌کند.

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def run_agent():
session_id = None
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}")
asyncio.run(run_agent())
import { query } from "@anthropic-ai/claude-agent-sdk";
let sessionId: string | undefined;
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)}`);
}
}

حالا که حلقه را می‌فهمی، بسته به اینکه چه می‌سازی این‌جا برو:

  • هنوز ایجنتی اجرا نکرده‌ای؟ با quickstart شروع کن تا SDK را نصب کنی و یک نمونه‌ی کامل را سرتاسر در حالِ اجرا ببینی.
  • آماده‌ای به پروژه‌ات وصل شوی؟ CLAUDE.md، Skillها و هوک‌های فایل‌سیستم را بار کن تا ایجنت به‌صورتِ خودکار قراردادهای پروژه‌ات را دنبال کند.
  • یک رابطِ تعاملی می‌سازی؟ استریمینگ را فعال کن تا متن و فراخوانی‌های ابزارِ زنده را همین‌طور که حلقه اجرا می‌شود نشان دهی.
  • به کنترلِ سفت‌تری روی آنچه ایجنت می‌تواند بکند نیاز داری؟ دسترسیِ ابزار را با permissions قفل کن، و از هوک‌ها برای ممیزی، مسدود کردن یا دگرگون کردنِ فراخوانی‌های ابزار پیش از اجرا استفاده کن.
  • کارهای طولانی یا گران اجرا می‌کنی؟ کارِ جداشده را به ساب‌ایجنت‌ها بسپار تا کانتکستِ اصلی‌ات لاغر بماند.

برای تصویرِ مفهومیِ گسترده‌ترِ حلقه‌ی ایجنتیک (نه مخصوصِ SDK)، How Claude Code works را ببین.