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

اجرای پایدار، استدلال پایدار نیست: چک‌پوینت‌کردن وضعیت عامل بدون از دست دادن قصد

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

نمای نزدیک از یک رک سرور که LEDهای وضعیت و کابل‌های شبکه‌ی برچسب‌دار متصل به یک سوییچ را نشان می‌دهد.

دو چیز که وضعیت نامیده می‌شوند

یک چک‌پوینت در رانتایم یک عامل معمولاً مکانیک‌های یک اجرا را ثبت می‌کند: کدام گره از گراف اجرا شد، کدام ابزار فراخوانی شد، ابزار چه چیزی برگرداند، کدام یال در انتظار است. این وضعیت اجراست. برای پاسخ به این پرسش کافی است: «ماشین کجا بود؟»

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

موتورهای اجرای پایدار در مکان‌نما خوب هستند. آن‌ها ژورنالی از گام‌ها را بازپخش می‌کنند، کارهای انجام‌شده را رد می‌کنند، و کنترل را در نخستین گام ناتمام بازمی‌گردانند. این رفتار درست برای گردش‌کاری است که معنایش در زمان تعریف ثابت شده است. یک عامل چنین نیست. معنایش در هر گام از تاریخچه‌ای که می‌بیند بازساخته می‌شود، و تاریخچه همان چیزی نیست که آن را تولید کرده است. مکان‌نما را بدون قرارداد بازیابی کنید و اجرا کرش نمی‌کند. روان ادامه می‌یابد، در جهت اشتباه، با همان لحن مطمئنی که پیش از وقفه داشت.

بازبرنامه‌ریزی از یک هدف کهنه

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

اثرات جانبی تکراری

مورد کلاسیک: آخرین فراخوانی ابزار موفق شد اما تأییدیه گم شد. موتور اجرای پایداری که در نخستین گام ناتمام بازمی‌گردد، فراخوانی را دوباره صادر می‌کند. اگر فراخوانی charge_card یا send_email یا create_ticket باشد، اجرا اکنون دو نسخه دارد. این شکست استدلال نیست؛ شکست قرارداد چک‌پوینت است. ژورنال قصد فراخوانی را ثبت کرده، نه واقعیت اثر را، و این دو تنها در صورتی قابل تفکیک‌اند که خود اثر کلیدی داشته باشد که سیستم پایین‌دستی آن را بشناسد.

Close-up of a modern building facade with geometric design and reflective windows

رانش فرض

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

یک قرارداد چک‌پوینت کارآمد

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

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

مکانیزمی که این را در عمل کارآمد می‌کند یک کلید idempotency در دامنه‌ی اجراست که از ورودی‌های پایدار مشتق می‌شود، نه از ساعت دیواری یا توالی:

key = hash(run_id, step_name, canonical_args)

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

مکانیزم دوم امتناع است. یک چک‌پوینت نسخه‌ی اسکیما را حمل می‌کند، و رانتایم از بازگشت در میان نسخه‌های ناسازگار امتناع می‌کند به‌جای تلاش برای مهاجرت با بهترین تلاش. مهاجرت قصد یک بازبرنامه‌ریزی است، و بازبرنامه‌ریزی باید یک عملیات صریح و لاگ‌![Colorful absIridescent swirls in a soap bubble texture, resembling an oil slickCircuit board macro

چه زمانی بازنگردیم

اجرای پایدار یک پیش‌فرض است، نه یک خیر جهانی. سه مورد به نفع ورود مجدد به‌جای ادامه استدلال می‌کنند.

اجراهایی که از یک مرز مجوز عبور کرده‌اند. اگر اجرا مجوزی گرفته، بودجه‌ای خرج کرده، یا به نمایندگی از یک principal عمل کرده که مجوزش به یک نشست محدود بود، ادامه‌دادن اختیاری را ادامه می‌دهد که ممکن است دیگر وجود نداشته باشد. این اجراها باید دوباره وارد تأیید شوند. چک‌پوینت می‌تواند به‌عنوان شواهد حفظ شود؛ نباید به‌عنوان یک اعتبارنامه استفاده شود.

شکاف‌های طولانی. واقعیت‌های بیرونی نیمه‌عمر دارند. یک قیمت، یک وضعیت تیکت، یک وضعیت دیپلوی، یک شمارش موجودی — هرکدام یک مشاهده‌ی کش‌شده با انقضای ضمنی است که چک‌پوینت ثبت نمی‌کند. اجرایی که پس از شکافی طولانی‌تر از کوتاه‌ترین نیمه‌عمر در مجموعه‌ی کاری‌اش بازمی‌گردد، از واقعیت‌های کهنه استدلال می‌کند در حالی که آن‌ها را به‌عنوان جاری ارائه می‌دهد. حرکت صادقانه این است که کهنگی را به‌عنوان محرک بازبرنامه‌ریزی ببینیم: مشاهدات کش‌شده را باطل کنید، آن‌هایی را که گام بعدی به آن‌ها وابسته است دوباره واکشی کنید، و تنها سپس ادامه دهید.

مجموعه‌های فرضی که دیگر برقرار نیستند. اگر هر محدودیت پذیرفته‌شده‌ای در منبعش پس گرفته شده باشد، اجرا ادامه‌ی معتبری ندارد. یک ری‌استارت معتبر دارد.

معامله

پایدارکردن قصد رایگان نیست. یعنی چک‌پوینت بزرگ‌تر می‌شود، یعنی هر محدودیت به یک فیلد منشأ نیاز دارد، و یعنی رانتایم باید بتواند «هدف آن‌گونه که راه‌اندازی شد» را از «هدف آن‌گونه که اصلاح شد» تفکیک کند — که به‌نوبه‌ی خود یعنی اصلاح هدف باید یک عملیات درجه‌یک با یک ورودی لاگ باشد، نه یک اثر جانبی ویرایش پرامپت. همچنین یعنی برخی بازگشت‌ها رد خواهند شد که یک موتور ساده‌لوحانه آن‌ها را کامل می‌کرد، و اجراهای ردشده شکست‌های قابل‌مشاهده‌ای هستند در حالی که ادامه‌های خاموش چنین نیستند.

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

چه چیزی ثبت کنیم

یک قاعده‌ی عملی: پیش از نوشتن تابع چک‌پوینت، بنویسید که یک اپراتور جدید برای تحویل‌گرفتن اجرا در میانه‌ی مسیر بدون پرسیدن چیزی از اپراتور اصلی به چه چیزهایی نیاز دارد. آن فهرست وضعیت قصد است. شاخص گام روی آن نیست. هر چیزی که روی آن است باید در چک‌پوینت باشد، نسخه‌بندی‌شده، و همراه با یک کلید idempotency برای هر اثری که اجرا می‌تواند بر جهان بیرون داشته باشد. استدلال پایدار خاصیتی است که از ری‌استارت جان سالم به در می‌برد؛ اجرای پایدار تنها مکانیزمی است که ری‌استارت را ممکن می‌سازد.

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

خواندن مرتبط

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

What is the difference between execution state and intent state in an agent run?

Execution state is the cursor: which step ran, which tool returned what, what is pending. Intent state is the goal, the accepted constraints, the assumptions committed to, and the unresolved obligations. A checkpoint that stores only the cursor can resume the machine but not the reasoning.

Why do resumed agents produce duplicate side effects?

Because the journal records the intent to call a tool, not the fact of the effect. If the call succeeded but the acknowledgement was lost, replay re-issues it. Run-scoped idempotency keys derived from stable inputs let the downstream system recognise the replay and return the prior result instead of repeating the effect.

When should a run not be resumed?

When it crossed an authorisation boundary, when the gap since the last checkpoint exceeds the half-life of the external facts it depends on, or when an accepted constraint has been withdrawn at its source. These cases call for re-approval or re-planning, not continuation.

Should checkpoints be migrated across schema versions?

No. Migration of intent is a re-plan and should be an explicit, logged operation. The runtime should version the checkpoint schema and refuse to resume across incompatible versions rather than attempting a silent best-effort migration.