اجرای بادوام در واقع چه چیزی را تضمین میکند
موتورهای اجرای بادوام — Restate، Temporal و سیستمهای مشابه — یک مسئلهٔ واقعی و دشوار را حل میکنند: آنها باعث میشوند یک workflow از مرگ فرایند، پارتیشنشدن شبکه و deploy جان سالم به در ببرد. تضمینها دقیقاند و ارزش دارد که صریح بیان شوند.
- اجرای دقیقاً یکبارِ هر گام. گامی که کامل شده است در بازپخش دوباره اجرا نمیشود. نتیجهٔ آن از یک log بادوام خوانده میشود.
- قابلیت ازسرگیری پس از crash. یک worker میتواند در میانهٔ اجرا بمیرد؛ دیگری journal را برمیدارد و از آخرین مرز commitشده ادامه میدهد.
- بازپخش قطعیِ کار انجامشده. با داشتن همان journal، runtime همان توالی side effectها را بازسازی میکند.
اینها ویژگیهای runtime هستند. هیچ چیزی دربارهٔ استدلال agent نمیگویند. یک workflow که بهطور تمیز از سر گرفته میشود ثابت کرده است که runtime میتواند یک call graph را بازسازی کند — نه اینکه اقدام بعدی هنوز مطلوب است، هنوز مجاز است، یا هنوز با هدفی که اجرا را آغاز کرد سازگار است.
این اشتباه آسان است چون واژگان همپوشانی دارند. «بادوام» شبیه «قابلاعتماد» به نظر میرسد. «دقیقاً یکبار» شبیه «درست» به نظر میرسد. در یک workflow متعارف — شارژ یک کارت، ارسال یک ایمیل، بهروزرسانی یک سطر — قصد در زمان نگارش ثابت شده و در خود گراف کدگذاری شده است. گراف همان قصد است. در یک اجرای agent، گراف در زمان اجرا از استدلال یک مدل روی یک هدف تولید میشود. journal ثبت میکند که agent چه کرد، نه اینکه چرا مجاز بود آن را انجام دهد.
شکاف قصد در زمان ازسرگیری
در نظر بگیرید که یک اجرا در آغاز واقعاً چه چیزی در دست دارد. یک هدف («حل درخواست بازپرداخت این مشتری»)، یک plan (توالی فراخوانیهای ابزار که agent پیشنهاد داده)، مجموعهای از محدودیتهای پذیرفتهشده (سقف بازپرداخت، ابزارهای مجاز، دادهای که agent میتواند بخواند)، و یک بودجه (tokenها، زمان واقعی، تعداد فراخوانیهای خارجی).
یک checkpoint معمولاً متغیرها را سریالایز میکند: شاخص گام فعلی، خروجیهای ابزار، محتوای scratchpad، شاید یک شیء plan. اما اختیاری که تحت آن این متغیرها تولید شدهاند را سریالایز نمیکند. سقف بازپرداخت توسط سیاستی اعطا شده بود که ممکن است تغییر کرده باشد. دامنهٔ ابزار برای نشستی تأیید شده بود که ممکن است منقضی شده باشد. دستور کاربر — «تا مبلغ روی فاکتور بازپرداخت کن» — ممکن است با پیام بعدیای که اجرای ازسرگرفتهشده هرگز نمیبیند، منسوخ شده باشد.
بین crash و ازسرگیری، دنیا حرکت میکند. قیمتها تغییر میکنند. موجودی بازتخصیص مییابد. مجوزها لغو میشوند. یک نهاد نظارتی راهنما منتشر میکند. کاربر نظرش را عوض میکند. هیچیک از این رویدادها در journal نیست، چون journal فقط میداند agent قبل از توقف چه چیزی را مشاهده کرده است.
این یک حالت شکست مشخص و بدخیم تولید میکند: یک اجرای ازسرگرفتهشده که با موفقیت کامل میشود در حالی که کاری را انجام میدهد که مسیر اصلی هرگز مجاز نکرده بود. تکمیل محتمل به نظر میرسد. logها تمیزند. توالی گامها بهطور قطعی بازپخش میشود. و اقدام اشتباه است، چون قصدی که آن را توجیه میکرد کهنه شده است.

این یک باگ درستی است، نه یک باگ دسترسپذیری. در تستهای بازیابی از crash ظاهر نمیشود. در production ظاهر میشود، هفتهها بعد، وقتی کسی میپرسد چرا یک agent بازپرداختی صادر کرده که سیاست قبلاً آن را ممنوع کرده بود.
ثبت زمینهٔ تصمیم
راهحل این است که زمینهٔ تصمیم را در کنار وضعیت پایدار نگه داریم. بهطور مشخص، یک checkpoint باید حمل کند:
- هدف را همانطور که در آغاز اجرا بیان شده، همراه با hash دستور منبع؛
- نسخهٔ plan را که agent در حال اجرای آن است، نه فقط گام بعدی؛
- اعطای دامنهٔ ابزار — کدام ابزارها، تحت کدام سیاست، با کدام انقضا؛
- بودجهٔ باقیمانده را در واحدهایی که اهمیت دارند (فراخوانیها، tokenها، محدودیتهای معادل ارزی که بهعنوان مرزهای سیاست بیان شدهاند، نه مبالغ)؛
- دلیل گام بعدی را، به شکلی که یک validator بتواند بررسی کند.
در زمان ازسرگیری، runtime این زمینه را پیش از ادامه در برابر سیاست فعلی دوباره اعتبارسنجی میکند. این اعتبارسنجی مجدد یک تشریفات نیست. میپرسد: آیا این هدف هنوز مجاز است؟ آیا این دامنهٔ ابزار هنوز اعطا شده است؟ آیا بودجهٔ باقیمانده هنوز با plan سازگار است؟ آیا دلیل گام بعدی هنوز توسط هدف پشتیبانی میشود؟
یک اعتبارسنجی مجددِ ناموفق یک حالت پایانی است، نه یک retry. retry کردن یک شکست سیاست فقط بودجه را میسوزاند و همان رد را تولید میکند. اجرا باید متوقف شود، اختلاف بین قصد اصلی و فعلی را آشکار کند، و به یک انسان یا orchestrator سطح بالاتر بازگرداند.
این یک trade-off واقعی است. اعتبارسنجی مجدد در هر ازسرگیری latency اضافه میکند و نیاز دارد که سیاست بهعنوان یک سرویس قابلکوئری باشد، نه جاسازیشده در کد. همچنین به این معناست که برخی اجراها که میتوانستند بهدرستی کامل شوند، برای بازبینی متوقف میشوند. جایگزین — تکمیل بیصدا تحت اختیار منقضیشده — بدتر است، اما هزینه صفر نیست و باید صادقانه بیان شود.
Idempotency رضایت نیست
کلیدهای Idempotency یک مکانیزم خوبفهمشده هستند: تضمین میکنند که یک فراخوانی خارجیِ retryشده د
یک کلید idempotency از تأثیر دوبارهٔ همان فراخوانی جلوگیری میکند. هیچ کاری دربارهٔ یک فراخوانی واحد که تحت یک mandate منقضیشده انجام شده، نمیکند. اگر اختیار agent برای صدور بازپرداختها در ساعت ۱۴:۰۰ منقضی شده باشد و اجرا در ساعت ۱۴:۰۵ از سر گرفته شود، یک فراخوانی بازپرداخت idempotent دقیقاً یکبار اجرا میشود — و غیرمجاز خواهد بود.

این دو مفهوم باید در runtime از هم جدا شوند:
- کلید idempotency عملیات را شناسایی میکند، بنابراین retryها ایمن هستند؛
- توکن اختیار mandate را شناسایی میکند، بنابراین اجرا مجاز است.
هر دو باید در زمان اجرا معتبر باشند. یک اجرای طولانیمدت به اختیاری نیاز دارد که منقضی شود و بهصراحت تمدید گردد، نه توکنی که در آغاز ضرب شده و برای تمام عمر workflow حمل میشود. تمدید یک نقطهٔ تصمیم است: میتواند اعطا، رد، یا با دامنهٔ محدودتر اعطا شود. آن نقطهٔ تصمیم جایی است که قصد دوباره به سیستم وارد میشود.
قواعد طراحی برای اجراهای افقبلند
چند قاعده از موارد بالا نتیجه میشود. رایگان نیستند، اما از یک شکست خاموشِ درستی ارزانترند.
مدت اجرا را با طول عمر اختیار محدود کنید، نه با صبر زیرساخت. اگر mandate برای یک ساعت معتبر است، اجرا یک ساعت دارد. اجازه ندهید یک workflow سه روز اجرا شود چون صف آن را تحمل کرده است. وقتی اختیار منقضی میشود، اجرا متوقف میشود و درخواست تمدید میکند.
در زمان ازسرگیری plan را دوباره استخراج کنید، نه اینکه یک plan کهنه را بازپخش کنید. plan یک پیشنهاد است، نه یک اسکریپت. در زمان ازسرگیری، باید به agent هدف، وضعیت فعلی دنیا، و بودجهٔ باقیمانده داده شود و از او خواسته شود گام بعدی را دوباره پیشنهاد دهد. journal محدود میکند که چه چیزی قبلاً رخ داده است؛ نباید دیکته کند که چه چیزی بعداً رخ میدهد.
هر رویداد ازسرگیری را با اختلاف بین قصد اصلی و قصد دوبارهاعتبارسنجیشده ثبت کنید. اختلاف، مصنوع جالب است. ثبت میکند که چه چیزی تغییر کرده — سیاست، بودجه، دامنه، وضعیت دنیا — و چرا اجرا ادامه یافت یا متوقف شد. بدون آن، بازبینی پس از حادثه هیچ دستاویزی ندارد.
یک مکانیزم مشخص که کار میکند: یک رکورد زمینهٔ تصمیم که در کنار journal ذخیره میشود، نسخهبندی میشود، و در هر مرز ازسرگیری توسط یک سرویس validator کوچک بررسی میشود. validator رکورد و snapshot سیاست فعلی را میگیرد و continue، pause، یا terminate را برمیگرداند. journal همچنان دغدغهٔ runtime است؛ زمینهٔ تصمیم دغدغهٔ agent است. جدا نگه داشتن آنها شکاف قصد را قابلمشاهده میکند بهجای اینکه آن را داخل یک stack سریالایزشده پنهان کند.
نکتهٔ گستردهتر این است که موتورهای اجرای بادوام دربارهٔ آنچه ادعا میکنند درست هستند. آنها باعث میشوند workflowها از شکست جان سالم به در ببرند. آنها باعث نمیشوند agentها بر اساس دلایل درست عمل کنند. آن ویژگی دوم باید روی آن مهندسی شود، و با پذیرش این شروع میشود که یک checkpoint بدون قصد فقط یک راه بسیار قابلاعتماد برای اشتباه بودن است.
