چیت‌شیت

محیط‌های اجرای عملیاتی و صف‌های ایجنت

Production Agent Runtimes and Queues

انتخاب ساختار محیط اجرا، چک‌پوینت و بازپخش، اجاره و مسدودسازی وظایف، تلاش مجدد خوانش‌های محدود به دامنه. Python و Go.

  • ۱۲ بخش
  • ۳ درس مرتبط
  • کد و دستورها عیناً از دوره‌ی اصلی
فهرست مطالب
  1. انتخاب ساختار محیط اجرا
  2. مخزن پایدار وظایف
  3. چرخه‌ی حیات وظیفه در مراحل
  4. CLI وظایف پایدار
  5. اجرای دموها
  6. بازپخش اکتیویتی از لاگ رویدادها
  7. چک‌پوینت به ازای هر ابرگام
  8. قرارداد خواننده‌ی ابری محدود به دامنه
  9. پیش‌فرض‌ها
  10. عیب‌یابی
  11. پرسش‌ها
  12. نکات کاربردی

انتخاب ساختار محیط اجرا

مفهوم‌ها
درخواست-پاسخ
HTTP همگام. کاربر منتظر می‌ماند. فقط وظایف کوتاه (کمتر از 30 ثانیه).
استریمینگ
SSE یا WebSocket. پایش تاخیر اولین توکن و تاخیر دنباله.
اجرای پایدار
ثبت چک‌پوینت وضعیت پس از هر گام. ادامه‌ی خودکار پس از خرابی.
مبتنی بر صف
تولیدکننده، استخر ورکرها، DLQ. پایش عمق صف و اندازه‌ی DLQ.
رویدادمحور
ایجنت محرک‌ها را سابسکرایب می‌کند. پایش تاخیر رویداد-تا-شروع.
زمان‌بندی‌شده
در قالب cron. ترکیب با اجرای پایدار.
جریان کاری و اکتیویتی
کد ارکستراسیون قطعی. هر فراخوانی LLM یا ابزار یک اکتیویتی لاگ‌شده است.
در عمل دقیقاً یک‌بار
تحویل حداقل یک‌بار به همراه مصرف‌کننده‌ی بی‌اثر در تکرار.

مخزن پایدار وظایف

معماری
خواندن-ویرایش-نوشتناسنپ‌شاتمتنClaimNextرسیدافزودن به صف--store, --inputledger.lockقفل مشورتیjobs.jsonID, State, Versionورکرclaim, effect, completeinputs/<id>.jsonورودی تغییرناپذیرeffects/<id>.jsonرسید تغییرناپذیر

چرخه‌ی حیات وظیفه در مراحل

گام‌به‌گام
  1. NewJobشناسه باید با ^[a-z][a-z0-9-]{0,63}$ مطابقت داشته باشد. وضعیت queued، نسخه‌ی 0.
  2. ClaimJobنیازمند نسخه‌ی موردانتظار و وضعیت queued است. در غیر این صورت ErrConflict.
  3. ClaimJobشرط Attempts >= maxAttempts خروجی ErrLimit می‌دهد.
  4. ClaimJobاعمال Version++، Attempts++، LeaseUntil = now + ttl، وضعیت running.
  5. Finishنسخه‌ی جاری، وضعیت running و now < LeaseUntil. وضعیت completed.
  6. Reclaimوضعیت running و now >= LeaseUntil. وضعیت queued، با Version++ ورکر قبلی مسدود می‌شود.
  7. Saveمتد ValidateJobs، نوشتن موقت، f.Sync()، os.Rename. سقف 4 MiB.

CLI وظایف پایدار

دستورها
دستورعملکرد
go build -o /tmp/durable-jobs .بیلد فایل اجرایی مرجع در solution
enqueue --store <dir> --input <file>افزودن وظایف. ارسال مجدد عیناً یکسان بدون خطر است
worker --store <dir> --max-jobs 100دریافت اجاره و اجرای حداکثر 100 وظیفه
status --store <dir>نمایش وظایف، اثرهای جانبی دردسترس و دامنه
--crash-after effectخروج با کد 86 پس از ثبت رسید
--crash-after claimخروج با کد 86 پیش از تولید خروجی
--now-ms 111 --lease-ms 10ساعت منطقی. اجاره‌ی قبلی منقضی شد
go run . demoاجرای توالی خرابی اثر جانبی

اجرای دموها

کار و کد
وظیفهکد
اجرای دموی درسpython3 code/main.py
نمره‌دهی به مرجع پروژه--all --solution --strict
اجرای خواننده‌ی ابریpython3 cli.py samples/input.json
خواندن مستقیم از AWS زندهpython3 cli.py <input> --mode aws
تثبیت نسخه‌ی SDK اختیاریstrands-agents==1.57.1

بازپخش اکتیویتی از لاگ رویدادها

کد
python
@activity("call_llm")         # هر فراخوانی LLM یک اکتیویتی است
def call_llm(doc_count: int) -> str:
    return f"summary({doc_count}_docs)"
hit = log.lookup(name, args)  # رویداد done با آرگومان‌های یکسان
if hit:
    return hit["result"]      # بازپخش، بدون اجرای جدید
log.append({"name": name, "args": list(args), "status": "started"})
result = fn(*args)            # فقط زمانی اجرا می‌شود که در لاگ نباشد
log.append({"name": name, "args": list(args),
            "status": "done", "result": result})

چک‌پوینت به ازای هر ابرگام

کد
python
store = CheckpointStore(db_path)                         # چک‌پوینت‌های جدول SQLite
store.write(thread_id, super_step, dict(state))          # یک سطر به ازای هر گام
restored = store.latest(thread_id)                       # ORDER BY super_step DESC
super_step, state = restored
super_step += 1                                          # ادامه پس از آخرین گام
run_agent_with_checkpoint(store, "t-1", crash_at=3, goal=5)
final = run_agent_with_checkpoint(store, "t-1", goal=5)  # ورکر 2
await asyncio.gather(*(sim_llm_call_async() for _ in range(n)))

قرارداد خواننده‌ی ابری محدود به دامنه

کد
python
ALLOWED = {"inventory.list", "metrics.read", "logs.read"}
validate_plan(raw, scope)      # یک تا ده اقدام، فقط-خواندنی، درون دامنه
execute(plan, provider, max_steps=5, max_chars=4000)
# بیش از سقف بودجه: وضعیت budget_exhausted
request_key(operation, resource) # sha256 of the JSON pair
cached_read(operation, resource, provider, cache, retries=2)
# اصابت به کش: 0 تلاش. تلاش مجدد فقط برای TimeoutError
run(payload, provider)         # افزودن رسیدها با مشخصات cached و attempts
parse_model_plan(text, scope)  # برنامه‌ی مدل به validate_plan ارسال می‌شود

پیش‌فرض‌ها

پیش‌فرض‌ها
تنظیمپیش‌فرضنکته
--lease-ms30000اجاره‌ی واگذاری به میلی‌ثانیه
--max-attempts3سپس وظیفه منتظر تطبیق دستی می‌ماند
--max-jobs1تعداد وظایف برای یک‌بار فراخوانی ورکر
--delay-ms0محدوده‌ی 0..60000
--now-ms-1-1 به معنی زمان واقعی جاری است
max_steps5بودجه‌ی گام. max_chars برابر 4000 است
retries2در cached_read. دستور run در CLI مقدار 1 را پاس می‌دهد

عیب‌یابی

عیب‌یابی
  • کاربران قطع می‌کنند، تلاش‌های مجدد انباشته می‌شوند

    علت
    استفاده از درخواست-پاسخ برای وظیفه‌ی 5 دقیقه‌ای
    راه‌حل
    استفاده از صف یا ساختار پایدار
  • ناپدید شدن وظایف ناموفق

    علت
    ورکرهای صف فاقد صف پیام مرده (DLQ)
    راه‌حل
    افزودن یک DLQ و پایش اندازه‌ی DLQ
  • خرابی‌ها تا پیش از گزارش کاربر دیده‌نمی‌شوند

    علت
    اجرای پس‌زمینه بدون صدور ردگیری محاسبات
    راه‌حل
    صدور اسپن‌های OpenTelemetry GenAI
  • کرش باعث اجرای مجدد ابزارها و هزینه‌ی دوباره برای LLM می‌شود

    علت
    حلقه‌ی ناپخته‌ی while True
    راه‌حل
    لاگ کردن هر فراخوانی به عنوان اکتیویتی و بازپخش
  • اتمام کار خطای تداخل برمی‌گرداند

    علت
    ورکر منسوخ: نسخه یا اجاره تغییر کرده است
    راه‌حل
    دریافت اجاره‌ی جدید وظیفه را به پایان می‌رساند
  • وظیفه در سقف تعداد تلاش متوقف می‌ماند

    علت
    --max-attempts پر شده است
    راه‌حل
    وظیفه‌ی قابل مشاهده را به صورت دستی تطبیق دهید
  • واگرایی در بازپخش

    علت
    استفاده از زمان واقعی داخل تصمیم‌گیری جریان کاری
    راه‌حل
    ثبت آن به عنوان یک اثر جانبی
  • مصرف 10 گیگابایت استک توسط 10,000 فراخوانی

    علت
    یک ترد به ازای هر فراخوانی LLM
    راه‌حل
    استفاده از async برای لایه‌ی I/O

پرسش‌ها

پرسش و پاسخ
کدام بک‌اند چک‌پوینت؟
PostgreSQL در برابر دیپلوی‌ها پایدار است. SQLite فقط برای توسعه محلی است. Redis ناپایدار است مگر اینکه AOF/snapshot پیکربندی شده باشد.
چه زمانی اجرای پایدار اشتباه است؟
اجراهای کوتاه‌تر از چند دقیقه بدون ورودی انسانی، یا بازیابی کاملاً فقط-خواندنی.
آیا پایداری افت کیفیت پس از 35 دقیقه را حل می‌کند؟
خیر. اضافه کردن HITL تازه در ورود مجدد و سوییچ‌های قطع اضطراری بودجه الزامی است.
آیا رسید عملکرد دقیقاً یک‌بار دارد؟
خیر. اجرا حداقل یک‌بار است. رسید فقط این اثر محلی را بی‌اثر در تکرار می‌کند.
چرا برای سه گام، دو خوانش از ارائه‌دهنده صورت گرفت؟
فراخوانی مکرر metrics.read از کش محلیِ درخواست استفاده می‌کند.
بازیابی چه چیزی را نشان می‌دهد؟
وظیفه‌ی incident-summary در نسخه‌ی v4 با 2 تلاش و reused_effect: true کامل شده است.

نکات کاربردی

نکته‌ها
  • با FastAPI + Postgres شروع کنید. هرگاه حین سنجش دچار شکست شد ارتقا دهید.
  • در هر فراخوانی اثر جانبی، یک کلید حذف تکرار قرار دهید.
  • برای پرداخت‌ها و فراخوانی APIهای خارجی از الگوی اوت‌باکس استفاده کنید.
  • از دیپلوی رنگین‌کمانی استفاده کنید. هرگز اجراهای در حال انجام ایجنت را حین دیپلوی نکشید.
  • برای I/O از async استفاده کنید. تردها را فقط برای پس‌پردازش وابسته به پردازنده به کار بگیرید.
  • مخزن وظایف را روی یک فایل‌سیستم محلی POSIX نگه دارید. آن را روی NFS قرار ندهید.
  • هنگام کار ورکرها، فایل‌های ذخیره‌سازی را ویرایش نکنید.