پرش به محتوای اصلی

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

بیشتر شکست‌های چند-ایجنی که به استدلال مدل نسبت داده می‌شوند، شکست‌های زمان‌بندی هستند. fan-out بی‌کران، نبود backpressure و نبود admission control یک ازدحام را به طوفان retry تبدیل می‌کند.

A thematic Star Wars droids display at Disney's Hollywood Studios in Bay Lake, Florida.

نشانه و تشخیص نادرست

یک حادثه ازدحام به‌ندرت با برچسب مسئله زمان‌بندی می‌رسد. به‌شکل یک مسئله استدلال می‌رسد. یک ایجنت حلقه می‌زند، دو ایجنت با هم تناقض پیدا می‌کنند، سه ایجنت همان artefact را از promptهای کمی متفاوت تولید می‌کنند، و postmortem به‌سمت مدل می‌رود: planner بیش از حد مبهم بود، sub-agent دستوراتش را بد فهمید، critic به‌قدر کافی انتقادی نبود.

بررسی trace معمولاً داستان دیگری می‌گوید. حلقه در پایین‌دست یک صف قرار دارد. یک tool call — یک جست‌وجوی کند، یک API با rate limit، یک دیتابیسی که تصمیم گرفته فلسفی باشد — بیشتر از timeout فراخوان طول می‌کشد. فراخوان retry می‌کند. چون retry یک task تازه است و نه re-claim همان واحد کار، دوباره fan-out می‌شود. ایجنت‌های خواهری که منتظر همان نتیجه بالادستی بودند حالا خودشان هم timeout می‌خورند و retry می‌کنند. هر retry همان context را حمل می‌کند، پس هزینه توکن حادثه به‌صورت فوق‌خطی رشد می‌کند در حالی که کار واقعی اصلاً رشد نمی‌کند.

کیفیت استدلال در این traceها غالباً کافی است. ایجنت‌ها خروجی میانی معقولی تولید می‌کنند؛ فقط آن را چند بار، به ترتیب اشتباه، و بر پایه فرض‌های کهنه تولید می‌کنند. آنچه غایب است یک planner بهتر نیست. مکانیزمی برای shed یا تعویق بار است.

این تمایز مهم است چون دو تشخیص، راه‌حل‌های متضاد را ایجاب می‌کنند. اگر مسئله استدلال باشد، راه‌حل کار روی prompt و انتخاب مدل است. اگر مسئله صف‌بندی باشد، راه‌حل معماری است: admission control، backpressure، idempotency، و یک scheduler که محدودیت‌های خودش را می‌شناسد.

admission control به‌عنوان نخستین تصمیم طراحی

هر یال fan-out در یک task graph به دو عدد اعلام‌شده نیاز دارد: یک عرض بیشینه و یک عمق بیشینه. عرض یعنی چند فرزند می‌توانند هم‌زمان در جریان باشند. عمق یعنی چند نسل تفویض مجاز است پیش از آنکه graph باید نتیجه برگرداند. هر دو ثابت‌های زمان طراحی هستند، در مشخصات graph اعلام می‌شوند، نه اینکه در production با تماشای صورت‌حساب کشف شوند.

یک قاعده admission مفید، عطفی است: یک task تنها زمانی پذیرفته می‌شود که هم یک worker slot و هم یک budget slice در دسترس باشد. worker slotها هم‌زمانی را محدود می‌کنند. budget sliceها هزینه و مواجهه با زمان دیواری را محدود می‌کنند. اگر هرکدام تمام شده باشد، task شروع نمی‌شود. با یک deadline در صف قرار می‌گیرد، یا با دلیل ثبت‌شده حذف می‌شود.

A close-up view of a DJ mixer, showcasing its knobs and controls.

حذف یک نتیجه مشروع است. دیسپچری که نمی‌تواند کار را رد کند، دیسپچر نیست؛ یک قیف است. گسترش بی‌کران و بی‌صدا حالت شکست است، و دقیقاً به این دلیل بی‌صداست که هیچ‌چیز در سیستم اجازه ندارد نه بگوید.

یک مکانیزم مشخص: وضعیت ارکستراتور را به‌جای یک گفت‌وگو، به‌صورت یک دفتر کل بازنمایی کنید. هر task پذیرفته‌شده یک lease نگه می‌دارد — (task_id, worker_slot, budget_slice, deadline). lease در زمان تکمیل، در شکست صریح، یا در انقضا آزاد می‌شود. کار scheduler در هر tick تطبیق taskهای در صف با leaseهای آزاد است. این کار بی‌زرق‌وبرق است و تمام بازی همین است.

backpressure میان ایجنت‌ها

sub-agentها باید بتوانند «الان نه» را علامت بدهند، به‌جای اینکه کار را جذب کنند و دیر شکست بخورند. شکست دیرهنگام گران است: کار پیش‌تر context، توکن و زمان مصرف کرده، و شکست در نقطه‌ای ظاهر می‌شود که والد اطلاعات لازم برای بازیابی ارزان را از دست داده است.

دو مکانیزم، رد کردن زودهنگام را ایمن می‌کنند.

نخست، یک صف مشترک با visibility timeout. یک task دقیقاً توسط یک worker برای یک بازه محدود claim می‌شود. اگر worker در آن بازه تکمیل نکند یا تمدید نکند، claim منقضی می‌شود و task دوباره قابل مشاهده می‌شود. این جلوگیری می‌کند از اینکه دو ایجنت همان واحد کار را claim کنند، که شایع‌ترین منبع خروجی تکراری در ازدحام‌هایی است که به‌نظر می‌رسد با هم تناقض دارند. آن‌ها اختلاف نظر ندارند؛ هر دو یک کار را انجام می‌دهند.

دوم، idempotency key روی هر عملیات دارای side effect. وقتی یک retry همان کلید تلاش اصلی را حمل می‌کند، سیستم پایین‌دستی می‌تواند deduplicate کند به‌جای اجرای دوباره. این همان چیزی است که اجازه می‌دهد backpressure تهاجمی باشد. بدون idempotency، رد کردن و retry تهاجمی خطرناک است، چون یک retry ممکن است دوباره بنویسد. با idempotency، رد کردن کار ارزان و ایمن است، و سیستم می‌تواند طوری تنظیم شود که بار را زود shed کند به‌جای جذب و فروپاشی.

این trade-off واقعی است: idempotency نیازمند همکاری از هر tool و هر سرویس خارجی در graph است، و بعضی از آن‌ها این را فراهم نمی‌کنند. جایی که فراهم نمی‌کنند، دیسپچر باید یا دسترسی به آن tool را سریال کند یا semantics حداکثر-یک‌بار را بپذیرد و شکاف‌ها را صریحاً مدیریت کند. تظاهر به اینکه مسئله وجود ندارد، روشی است که یک ازدحام دسته‌ای از باگ پیدا می‌کند که فقط زیر

چهار اندازه‌گیری به‌ازای هر نوع task بیشتر زمین تشخیصی را پوشش می‌دهد:

Close-up of an automated can filling machine in a beverage production line.

  • عمق صف — چه مقدار کار در انتظار است، نمونه‌برداری‌شده در طول زمان.
  • زمان انتظار — تأخیر admission، از enqueue تا اعطای lease.
  • زمان claim تا تکمیل — تأخیر اجرا، جدا از زمان انتظار تا بتوان این دو را به هم نسبت داد.
  • ضریب تقویت retry — کل تلاش‌ها تقسیم بر واحدهای متمایز کار.

ضریب تقویت، تک‌سیگنال مفیدتر است. وقتی نزدیک یک است، سیستم هر تکه کار را تقریباً یک بار انجام می‌دهد. وقتی بالا می‌رود، ازدحام ظرفیتش را صرف بازتولید نتایجی می‌کند که از قبل داشته، و هیچ مقدار پالایش prompt آن را پایین نمی‌آورد.

یک اجرا باید به‌صورت یک timeline از admissionها بازسازی‌پذیر باشد — task در صف قرار گرفت، lease اعطا شد، lease تمدید شد، lease منقضی شد، task تکمیل شد، task به dead-letter رفت — نه به‌صورت فهرستی از پیام‌ها. logهای پیام می‌گویند ایجنت‌ها چه گفتند. timelineهای admission می‌گویند سیستم چه کرد، و فقط دومی یک حادثه را توضیح می‌دهد.

روی ضریب تقویت alert بگذارید، نه روی تعداد ایجنت. تعداد ایجنت یک معیار نمایشی است که هم در یک انفجار سالم و هم در یک شکست آبشاری به‌نرمی بالا می‌رود. ضریب تقویت این دو را از هم متمایز می‌کند.

یک قاعده طراحی

با ارکستراتور مثل یک دیسپچر با سه جزء رفتار کنید: یک scheduler، یک دفتر کل بودجه، و یک مسیر dead-letter. scheduler مالک admission است. دفتر کل مالک حسابداری هزینه و هم‌زمانی است. مسیر dead-letter مالک هر چیزی است که retryهایش تمام شده، تا شکست‌ها قابل مشاهده و قابل بررسی باشند به‌جای اینکه بی‌صدا تا ابد دوباره در صف قرار بگیرند.

خروجی planner باید یک task graph با عرض‌ها و عمق‌های اعلام‌شده باشد، نه تفویض آزاد. plannerی که نثری مثل «بازار را بررسی کن و یافته‌ها را ترکیب کن» تولید می‌کند، یک آرزو تولید کرده، نه یک graph. plannerی که nodeهایی با fan-out کران‌دار، وابستگی‌های صریح، و سقف بودجه به‌ازای هر node تولید می‌کند، چیزی تولید کرده که یک دیسپچر می‌تواند اجرا کند و یک دفتر کل بودجه می‌تواند اعمال کند.

ازدحام را روی throughput و تکمیل زیر بار اندازه بگیرید، نه روی ظرافت گفت‌وگویش. کیفیت گفت‌وگو یک proxy است که در demoها با موفقیت همبستگی دارد و در production از آن جدا می‌شود. throughput زیر یک بودجه هم‌زمانی ثابت، نرخ تکمیل در یک deadline ثابت، و ضریب تقویت اعدادی هستند که پیش‌بینی می‌کنند سیستم با ترافیک واقعی دوام می‌آورد یا نه.

پیامد ناخوشایند این است که ازدحامی با استدلال متوسط و زمان‌بندی عالی، از ازدحامی با استدلال عالی و بدون admission control بهتر عمل می‌کند، چون دومی ظرفیتش را صرف دوباره انجام دادن کاری می‌کند که قبلاً انجام داده. زمان‌بندی بخش غیرجذاب سیستم نیست. بخشی است که تعیین می‌کند آیا بخش جذاب اصلاً فرصت اجرا پیدا می‌کند یا نه.

اشتراک‌گذاریXLinkedInپیوند یکتا5 دقیقه مطالعه

خواندن مرتبط

پرسش‌هایی که این پاسخ می‌دهد

Why are multi-agent failures usually misdiagnosed as reasoning errors?

Incident reports describe symptoms that look cognitive — looping, contradiction, duplicated work — so the first hypothesis is prompt or model quality. Trace inspection usually shows those symptoms are downstream of a queue: a slow tool call causes siblings to time out, retry, and re-enter the same work. The reasoning is often adequate; the system simply has no mechanism to shed or defer load.

What does admission control mean for an agent swarm?

Every fan-out edge declares a maximum width and a maximum depth at design time. A task is admitted only when a worker slot and a budget slice are both available; otherwise it is queued with a deadline or dropped with a recorded reason. Dropping is a legitimate outcome. Silent unbounded expansion is not.

How does backpressure work between agents?

Sub-agents signal 'not now' instead of absorbing work and failing late. A shared queue with visibility timeouts ensures only one worker claims a unit of work at a time, and idempotency keys make retries safe, which is what allows refusal to be aggressive rather than risky.

What should be instrumented in a multi-agent system?

Queue depth, wait time, claim-to-completion time, and retry amplification factor per task type. A run should be reconstructable as a timeline of admissions rather than a list of messages. Alert on amplification factor, not on agent count.

Should the orchestrator be a planner or a dispatcher?

A dispatcher with a scheduler, a budget ledger, and a dead-letter path. Planner output should be a task graph with declared widths and depths, not free-form delegation. The swarm should be measured on throughput and completion under load, not on the elegance of its dialogue.