13 KiB
سناریوی قابلیتهای runtime ایجنت — subagent، ابزار موازی، context پایدار
تاریخ: ۱۴۰۵/۰۵/۲۸ (۱۸ اوت ۲۰۲۶)
وضعیت: فازهای PRM-04 ۰–۱، TOOL-06 A–B+D، AGT-06 ۰–۲ پیاده شد — UI موازی و دانش-بهابزار موکول
مرجع ممیزی: AI_AGENT_SYSTEM_AUDIT.md (AGT-06، TOOL-06، PRM-04)
رقیب مرجع: Cursor Task/subagent، Claude Code، ChatGPT agent teams، OpenAI Agents SDK
این سند پاسخ خطبهخط به سه سوال محصول است و برای هر شکاف فاز اجرا با معیار پذیرش میدهد. تا وقتی آیتم ممیزی انجامشده نشده، پیادهسازی شروع نشود مگر مالک صریح بخواهد.
۱. جمعبندی سریع
| قابلیت | در سیستم امروز | کجا | شکاف با سطح جهانی |
|---|---|---|---|
| ساخت و هدایت subagent | هست (فاز ۰–۲) | spawn_subagent / await_subagent / cancel_subagent روی حلقهٔ تو در تو analyzer |
UI تایملاین و persist SQL هنوز نیست |
| چند ابزار در یک نوبت، موازی | هست (read) | مدل میتواند چند tool_calls بدهد؛ بکاند read را تا ۴تایی موازی و write را سریال اجرا میکند |
UI موازیبودن را نشان نمیدهد؛ نوبت اول سوال complex با tool_choice روی یک ابزار plan قفل میشود |
| تکرار بینش/حافظه/دانش در هر سوال | لایهٔ semi_static cacheپذیر | static + semi_static (حافظه/بینش/کانکتور) + dynamic (datetime/دانش/…) |
دانش سوالوابسته هنوز در system است اگر RAG لازم باشد |
نتیجه برای فرض سوم: فرض «این اطلاعات داخل تاریخچهٔ گفتوگو تکرار میشود» دقیق نیست. پیامهای ذخیرهشدهٔ جلسه فقط user/assistant/tool هستند. آنچه تکرار میشود بلاک runtime سیستم است که بدون آن مدل در درخواست بعدی آن را به یاد ندارد. راهحل درست حذف از تاریخچه نیست (آنجا نیست)؛ راهحل لایهٔ cache نیمهپایدار و ارسال مجدد فقط وقتی محتوا عوض شده است.
۲. یافتهٔ ۱ — Subagent
۲.۱ آنچه در کد هست
- یک حلقهٔ ایجنت در
chat_completion_streamبا بودجه، todo، continuation، write guard. - Run persist در
ai_agent_runsو ادامه باPOST .../runs/{run_id}/continue(AGT-01). هنوز همان درخواست/همان حلقه است (AGT-02). - هیچ ابزار
spawn_subagent/delegate_taskدر registry نیست. GAP-07(چند شخصیت حسابدار/انباردار) با این قابلیت یکی نیست: آن نقش ثابت است؛ subagent اجرای موقت با هدف و allowlist است.
۲.۲ رفتار مطلوب (Cursor / Claude)
- والد تشخیص میدهد کار چنددامنهای است (مثلاً فروش + موجودی + بدهکاران).
- یک یا چند subagent با
goal،tool_allowlist،max_iterations،execution_mode=analyzerساخته میشود. - والد میتواند صبر کند، ادامه بدهد، یا subagent را قطع کند.
- خروجی subagent یک envelope است (یافتهها + citations + خطا)؛ والد آن را نقد میکند و پاسخ نهایی را میسازد.
- subagent حق write ندارد مگر والد صریحاً بسپارد (پیشفرض ممنوع).
۲.۳ فاز اجرا
| فاز | کار | معیار پذیرش | ریسک |
|---|---|---|---|
| ۰ — قرارداد ✓ | ابزار spawn_subagent + store درونپردازهای ai_subagent_runs |
schema در function_registry + intent + l10n |
بدون UI هنوز |
| ۱ — حلقهٔ تو در تو ✓ | AIService با operation=subagent، سقف نوبت ۴، allowlist، approve_writes=False |
تست واحد: دو read در فرزند؛ write در فرزند fail-closed | انفجار هزینه اگر سقف نباشد |
| ۲ — کنترل والد ✓ | tool result شامل subagent_id؛ ابزار await_subagent / cancel_subagent |
والد بعد از cancel دیگر token فرزند را مصرف نکند | race با SSE والد |
| ۳ — ادغام | envelope استاندارد + citation از فرزند به والد | پاسخ نهایی بدون عدد بدون منبع از فرزند | نشت PII بین دامنه |
| ۴ — UI | گام trace_step با kind=subagent در تایملاین |
کاربر ببیند کدام زیر-اجرا زنده/تمام/قطع است | شلوغی God Widget |
سقف پیشنهادی محصول: حداکثر ۲ subagent همزمان، حداکثر ۴ نوبت ابزار برای هر کدام، فقط کانال چت درونبرنامه (تلگرام/CRM/ورکفلو نه در فاز ۱).
سناریوی پذیرش دستی
- «گزارش فروش این ماه، موجودی کالاهای کم، و سه بدهکار برتر را یکجا بده.»
- انتظار: والد plan میسازد؛ حداقل یک spawn؛ نتایج در پاسخ نهایی با منبع.
- کاربر Stop روی والد: فرزند هم cancel شود.
- سوال ساده «موجودی کالای X؟» نباید spawn کند.
۳. یافتهٔ ۲ — اجرای موازی ابزار
۳.۱ آنچه در کد هست (انجامشده)
- اگر مدل در یک پیام assistant چند
tool_callsبدهد،handle_function_calls_asyncآنها را بهrun_tool_calls_partitionedمیدهد. - Read حداکثر
MAX_PARALLEL_READ_TOOLS = 4با semaphore؛ هر write سد سریال است؛ ترتیب مدل حفظ میشود. - Prompt مسیریابی صریحاً میگوید: «ابزارهای read-only مستقل را در یک نوبت parallel صدا بزن» (
ai_tool_routing_prompt.py). parallel_tool_calls=falseدر OpenAI وdisable_parallel_tool_useدر Anthropic ست نشده — یعنی ارائهدهنده موازی را اجازه میدهد.- تست:
tests/test_ai_tool_parallel.py.
۳.۲ آنچه نیست
- UI: تایملاین ابزارها را پشتسرهم نشان میدهد حتی اگر موازی اجرا شده باشند.
- نوبت صفر سوال
complex:tool_choiceرویcreate_session_planاست → در آن نوبت موازی عملاً قفل است (عمدی). - مدل گاهی هنوز سریالی کار میکند؛ این محدودیت مدل است نه بکاند.
۳.۳ فاز اجرا (تکمیل، نه ساخت از صفر)
| فاز | کار | معیار پذیرش |
|---|---|---|
| A — مشاهده ✓ | لاگ AI_METRIC با tool_calls_in_round و parallel_read_count |
رویداد tool_round_parallel |
| B — eval ✓ | کیس طلایی «فروش+موجودی+بدهکار» assertion که حداقل دو tool در یک round باشد | ai_eval_assertions + DEFAULT_EVAL_CASES |
| C — UI | در trace، ابزارهای همنوبت با یک bundleId نمایش موازی | کاربر زمان انتظار را کوتاهتر حس کند |
| D — سقف ✓ | اگر مدل >۴ read بدهد، همان semaphore فعلی کافی است؛ در prompt سقف را بنویس | stampede DB رخ ندهد |
سناریوی پذیرش دستی
- همان سوال چنددامنهای پس از ساختهشدن plan.
- در لاگ سرور یک round با ≥۲ function همزمان (زمان شروع همپوشان).
- Write (مثلاً ایجاد فاکتور) هرگز با write دیگر موازی نشود.
۴. یافتهٔ ۳ — بینش و context در هر سوال جدید
۴.۱ مسیر واقعی هر پیام کاربر
POST .../messages?stream=true
→ persist پیام user
→ build_system_prompt_stream
static_core = نقش + سیاست untrusted ← cacheپذیر
business_anchor = شناسه کسبوکار + تقویم ← cacheپذیر
semi_static = حافظه + بینش + کانکتور ← cacheپذیر جدا
execution/plan = حالت اجرا + todos
runtime = datetime، دانش، مهارت، پیوست، todo
→ تاریخچه جلسه (حداکثر ۴۰ پیام؛ در صورت تنگی بودجه خلاصه)
→ حلقهٔ مدل + ابزار
بینش (format_insights_for_prompt) حدود چند خط KPI است (فروش امروز/هفته، بدهکاران، کمموجود) و با TTL ۳۰۰ ثانیه در حافظهٔ فرایند کش میشود تا SQL تکرار نشود. متن همان KPI هر نوبت دوباره در system میآید.
دانش فقط اگر query_needs_knowledge(user_query) باشد لود میشود — یعنی وابسته به سوال است و نباید cache بلندمدت شود.
تاریخچهٔ DB شامل بینش نیست. پس «تکرار در تاریخچه» رخ نمیدهد؛ «تکرار در ورودی مدل» رخ میدهد و برای HTTP stateless طبیعی است.
Prompt cache (ai_prompt_cache.py) دو breakpoint دارد: static_core + business_anchor و لایهٔ semi_static (حافظه/بینش/کانکتور). datetime و دانش در dynamic_system میمانند.
۴.۲ راهحل پیشنهادی (ترتیب امن)
نباید بینش را بهکلی حذف کرد: مدل بدون آن در سوال «وضعیت امروز چطوره؟» مجبور به چند tool اضافه میشود. هدف کاهش توکن تکراری است نه حذف قابلیت.
| فاز | کار | معیار پذیرش |
|---|---|---|
| ۰ — اندازه ✓ | در context_usage فیلدهای runtime_tokens / insights_tokens / static_tokens / semi_static_tokens |
عدد واقعی در لاگ AI_METRIC context_usage |
| ۱ — لایهٔ نیمهپایدار ✓ | semi_static = بینش + حافظهٔ دستورات + کانکتور؛ hash محتوا در cache_key |
برای Anthropic، cache_read_tokens در نوبت ۲+ همان جلسه > ۰ وقتی KPI عوض نشده |
| ۲ — دانش فقط با ابزار | دانش را از system درآور؛ search_knowledge اجباری وقتی RAG لازم است |
سوال غیر دانشمحور runtime بدون بلوک دانش |
| ۳ — datetime جدا ✓ | ساعت همیشه dynamic بماند (نباید کل cache را بشکند) | breakpoint cache قبل از datetime |
| ۴ — اختیاری | اگر hash بینش عوض شد (فروش جدید)، یک خط «بینش بهروز شد» در runtime | مدل عدد کهنه ندهد |
آنچه نباید کرد
- چسباندن بینش به پیام assistant در تاریخچه (تاریخچه را آلوده میکند و با خلاصه قاطی میشود).
- حذف کامل بینش از نوبتهای بعدی بدون cache لایهٔ سیستم (مدل کور میشود).
- گذاشتن دانش بازیابیشدهٔ هر سوال داخل prefix ثابت (cache غلط و پاسخ کهنه).
سناریوی پذیرش دستی
- دو سوال پشتسرهم در یک جلسه: «سلام» سپس «فروش امروز چقدر بود؟»
- انتظار: نوبت دوم SQL بینش نزند اگر TTL نگذشته (کش ۳۰۰ثانیه).
- پس از فاز ۱: usage نوبت دوم
cache_readداشته باشد؛ متن بینش در پیامهای DB نباشد.
۵. ترتیب پیشنهادی اجرا
- PRM-04 فاز ۰–۱ ✓
- TOOL-06 تکمیل A–B ✓ (+ سقف prompt فاز D)
- AGT-06 فاز ۰–۲ ✓ — فاز ۳–۴ (ادغام citation در UI / تایملاین) بعدی است.
وابستگی: subagent موازیِ چند فرزند روی همان run_tool_calls_partitioned سوار میشود؛ سقف ۲ همزمان و ۴ نوبت اعمال شده.
۶. چکلیست PR وقتی یکی از فازها پیاده شد
- ابزار جدید: registry + permission + intent + l10n + write guard
- تست واحد مسیر اصلی + مسیر شکست (cancel subagent، write در فرزند، cache miss)
- کیس eval یا سناریوی دستی بالا
- بهروز کردن وضعیت آیتم در ممیزی و یک سطر تاریخچه
- متریک
AI_METRICبرای spawn / parallel_round / cache_hit