مسئله تلاش دوم: تکرار امن هوش مصنوعی بدون اقدام تکراری

ت

تیم ژرف ای‌آی

۱۶ مرداد ۱۴۰۵۱۴ دقیقه مطالعه
مسئله تلاش دوم: تکرار امن هوش مصنوعی بدون اقدام تکراری

یک عامل تدارکات سفارش خرید را به سامانه ERP می‌فرستد. فراخوانی ابزار ده ثانیه منتظر می‌ماند و با پایان مهلت روبه‌رو می‌شود. هماهنگ‌کننده این وضعیت را شکست فرض می‌کند، ارائه‌دهنده را عوض می‌کند، فرمان را دوباره می‌سازد و بار دیگر می‌فرستد. فراخوانی اول قبلاً ثبت شده بود؛ فقط پاسخ آن گم شد. اکنون کسب‌وکار دو سفارش خرید، دو ردپای تأیید و یک بررسی ناشی از سازوکار بازیابی دارد.

هر جزء رفتاری معقول داشت: timeout، retry، failover و پذیرش دو فرمان معتبر در ERP. چیزی که وجود نداشت تعریف مشترک یک نیت تجاری بود.

این راهنما درباره تصمیم پس از یک تلاش نامطمئن است: سامانه باید دوباره تلاش کند، درخواست موازی بفرستد، مسیر را عوض کند، نتیجه را تطبیق دهد یا متوقف شود؟ قاعده مرکزی ساده است: شکست انتقال، نتیجه تجاری نیست. یک نیت منطقی باید مالک همه تلاش‌ها باشد و هر عملی که می‌تواند جهان بیرون را تغییر دهد، پیش از تکرارپذیرشدن باید قابل شناسایی و تطبیق باشد.

پایان مهلت، وضعیت ناشناخته می‌سازد نه شکست قطعی

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

این فشرده‌سازی در گردش‌کار هوش مصنوعی خطرناک‌تر است، چون یک نوبت ظاهری می‌تواند چند عملیات داشته باشد:

عملیاتاثر معمولبازیابی پیش‌فرض
بازیابی نسخه تغییرناپذیر سندفقط خواندنیتلاش دوباره در مهلت کلی
تولید پیش‌نویس از شاهد ثابتمحاسباتی اما متغیرتلاش یا تغییر مسیر فقط در صورت پذیرش تفاوت خروجی
پیشنهاد فرمانهنوز بدون تغییر بیرونیتولید مجدد با زمینه نسخه‌دار
رزرو موجودی یا ایجاد رکوردتغییر بیرونیتطبیق بر اساس نیت؛ تکرار فقط با ایدِمپوتنسی
ارسال پیام یا آغاز پرداختپیامد انسانی یا مالیتا زمان تأیید، وضعیت نامعین
تأیید نتیجه ثبت‌شدهبررسی فقط خواندنیتلاش مستقل با بودجه محدود

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

نیت منطقی را از تلاش‌های اجرایی جدا کنید

کاربر یک نتیجه می‌خواهد: «سفارش تأییدشده را ایجاد کن.» سامانه ممکن است برای رسیدن به آن چند فراخوانی شبکه انجام دهد. این دو سطح را جدا مدل کنید:

  • intent_id یک نتیجه مجازشده از سوی کاربر یا سیاست را مشخص می‌کند؛
  • attempt_id یک تلاش اجرایی درون همان نیت است؛
  • provider_request_id فراخوانی ارائه‌دهنده یا زیرساخت را ثبت می‌کند؛
  • action_key شناسه پایدار ایدِمپوتنسی برای سرویس تغییردهنده است؛
  • receipt_id نتیجه معتبر و ثبت‌شده را مشخص می‌کند.

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

نیت مالک مهلت، مجوز، پارامتر canonical، بودجه تلاش و وضعیت نهایی است؛ تلاش‌ها حق گسترش آن‌ها را ندارند.

پروتکل‌ها چه می‌گویند و این راهنما چه می‌افزاید

چند منبع معتبر این مرز را روشن می‌کنند. RFC 9110 روش را زمانی ایدِمپوتنت می‌داند که اثر موردنظر درخواست‌های یکسان تکراری با یک درخواست برابر باشد. این استاندارد علیه retry خودکار درخواست غیرایدِمپوتنت هشدار می‌دهد، مگر معنا یا شاهد اجرا نشدن اجازه دهد؛ و Retry-After را از جمله همراه 503 Service Unavailable تعریف می‌کند.

Builders’ Library آمازون مهلت، retry محدود، backoff، jitter و مهار تلاش را به هم متصل می‌کند. راهنمای API ایدِمپوتنت شناسه نیت اعلام‌شده از سوی فراخوان را بر حدس تکرار ترجیح می‌دهد و رکورد رفع تکرار را اتمیک به تغییر داده می‌بندد.

گوگل نشان می‌دهد retry آبشاری اضافه‌بار را تقویت می‌کند؛ retry در سه لایه حتی یک درخواست را به ۶۴ تلاش backend می‌رساند. gRPC تلاش‌های هم‌پوشان محدود با deadline مشترک، pushback و throttling را تعریف می‌کند. Stripe کلید پایداری را نشان می‌دهد که نتیجه نخست را بازپخش و پارامتر تغییرکرده را رد می‌کند.

معماری زیر تحلیل ژرف بر پایه این منابع است. هیچ‌یک از HTTP، AWS، گوگل، gRPC یا Stripe یک استاندارد جهانی retry برای هوش مصنوعی تعریف نکرده‌اند. هر API پایین‌دستی دامنه ایدِمپوتنسی، مدت نگهداری، رفتار ذخیره خطا و معنای reconciliation خود را دارد؛ اصل را بگیرید، نه فرض مستندنشده یک سرویس دیگر را.

عدم قطعیت را در ماشین حالت آشکار کنید

برای نیت منطقی ماشین حالت صریح بسازید:

new → prepared → authorized → executing → committed

حالت‌های پایانی rejected، cancelled و expired را اضافه کنید و حالتی را که بسیاری حذف می‌کنند نیز نگه دارید: indeterminate. وقتی فراخوان نمی‌تواند ثابت کند یک اثر مهم رخ داده یا نه، تلاش نامعین است. نباید فقط برای ساده‌ماندن داشبورد، آن را failed نامید.

فقط هماهنگ‌کننده نیت اجازه حرکت از authorized به executing دارد. پیش از ارسال، تلاش را ثبت می‌کند، در هر تکرار مجاز همان کلید اقدام را می‌فرستد و فقط یک رسید معتبر می‌پذیرد. اگر پاسخ گم شود، به indeterminate می‌رود، سامانه مرجع را می‌پرسد، event یا webhook را مصرف می‌کند یا پرونده را به تطبیق انسانی می‌فرستد. تلاش تازه فقط وقتی مجاز است که قرارداد، امن‌بودن بازپخش را تضمین کند.

لغو یک مشاهده است نه rollback؛ بستن stream ثابت نمی‌کند ابزار یا تراکنش هیچ کاری نکرده است.

بازیابی را بر اساس کلاس عملیات انتخاب کنید

پیش از نوشتن کد retry از جدول تصمیم استفاده کنید:

وضعیت مشاهده‌شدهکلاس اثرحرکت درست
رد اعتبارسنجی، مجوز یا سیاستدائمیتوقف، نمایش دلیل و بدون retry
اضافه‌بار صریح همراه دستور انتظارخواندن یا نوشتن ایدِمپوتنتانتظار طبق دستور، افزودن jitter در جای لازم و مصرف یک واحد بودجه
قطع اتصال پیش از اثبات ارسال درخواستهرکدامتکرار فقط با اثبات ارسال‌نشدن یا ایدِمپوتنت‌بودن اقدام
پایان مهلت در بازیابی تغییرناپذیرفقط خواندنیتلاش در deadline کلی
پایان مهلت در استنتاج خالص و بدون ابزارمحاسباتیتلاش یا failover در صورت پذیرش هزینه و تفاوت خروجی
پایان مهلت پس از احتمال شروع ابزار تغییردهندهنوشتن پرپیامدوضعیت نامعین؛ پرس‌وجو با کلید اقدام یا تطبیق event
خرابی ارائه‌دهنده پیش از مرز اقدامکار پیشنهادیتغییر مسیر فقط به انتشار ارزیابی‌شده و هم‌ارز سیاستی
سیاست نامعلوم، مجوز کهنه یا خروجی ناسازگارهرکدامتوقف یا ارجاع به بازبینی پاسخ‌گو

«قابل retry» ویژگی ذاتی یک کد خطا نیست؛ حاصل برخورد شاهد شکست، معنای عملیات، زمان باقی‌مانده، بودجه تلاش و پیامد است.

یک پاکت ایدِمپوتنسی دور نیت تجاری بسازید

کلید ایدِمپوتنسی باید نیت اعلام‌شده فراخوان را نمایندگی کند؛ نه تلاش تصادفی انتقال و نه صرفاً hash متن پرامپت. این پاکت را کنار آن ذخیره کنید:

فیلدهدف
intent_id و actor_scopeاتصال یک نتیجه به مستأجر، عامل و هدف مجاز
operation و canonical_args_hashکشف استفاده دوباره از کلید با معنای تغییرکرده
authorization_versionاثبات تأیید و محدودیتی که اقدام را مجاز کرده
release_idاتصال مدل، پرامپت، شِمای ابزار، سیاست ایمنی و router
action_key و دامنه پایین‌دستیاعلام اینکه کدام فراخوانی‌ها متعلق به یک اثرند
created_at، deadline و retentionمحدودکردن اعتبار تلاش‌های دیررس و رفع تکرار
max_attempts و retry_ownerجلوگیری از تکثیر retry در چند لایه
receipt_locatorیافتن نتیجه ثبت‌شده بدون تکرار تغییر

release_id را به گذرنامه انتشار هوش مصنوعی متصل کنید؛ تغییر ارائه‌دهنده یا شِما نباید فرمان تأییدشده را گسترده‌تر کند.

گیرنده باید کلید اقدام را به‌شکل اتمیک claim و تغییر را اعمال کند یا قراردادی تراکنشی و هم‌ارز ارائه دهد. در بازپخش، معنای نتیجه قبلی را برگرداند، همان کلید با پارامتر canonical متفاوت را رد کند و دانش رفع تکرار را بیش از هر تأخیر محتمل نگه دارد. داده شخصی یا راز را داخل کلید قابل مشاهده نگذارید.

اگر گیرنده ایدِمپوتنسی ندارد، فراخوان به الگوی محدودتری نیاز دارد: ایجاد شرطی با مرجع تجاری یکتا، compare-and-set بر نسخه، رزرو و سپس confirm، اجرای سریالی یا status lookup با مرجع کلاینت. اگر هیچ بازپخش امن یا تطبیق قابل اتکایی وجود ندارد، retry خودکار پرپیامد در دسترس نیست.

یک لایه را مالک بودجه retry کنید

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

برای تأیید زمان کنار بگذارید؛ مهلت ۲۰ ثانیه‌ای که تقریباً صرف تولید دوباره شود فرصتی برای بررسی اقدام ندارد. خواندن کم‌پیامد شاید یک retry داشته باشد؛ تغییر حفاظت‌نشده هیچ‌کدام. از backoff نمایی محدود با jitter استفاده کنید، دستور انتظار را رعایت کنید و با تعویض ارائه‌دهنده بودجه مصرف‌شده را صفر نکنید.

این بودجه مکمل مهندسی تأخیر استنتاج است. با ساختن آن‌قدر کار تکراری که سرویس کند را overload کند، تأخیر دنباله بهتر نمی‌شود.

خواندن را hedge کنید، نه اثر تجاری را

در hedging تلاش دوم پیش از شکست تلاش نخست ارسال می‌شود. این روش می‌تواند تأخیر دنباله یک خواندن امن را کم کند، اما عمداً بار هم‌زمان را بالا می‌برد. فقط برای عملیاتی به‌کارش ببرید که اجرای کامل هر دو نسخه بی‌ضرر است: بازیابی تغییرناپذیر، پرس‌وجوی سلامت یا استنتاج خالصی که خروجی‌اش خودِ اقدام نیست.

حتی در این حالت، «اولین پاسخ برنده است» برای هوش مصنوعی شرط دارد. سریع‌ترین جواب روان لزوماً مستندترین جواب نیست. deadline مشترک را حفظ کنید، تلاش هم‌پوشان را محدود کنید، بازنده‌ها را لغو و هزینه‌شان را ثبت کنید و خروجی برنده را از همان کنترل شاهد و ایمنی بگذرانید. عامل مجهز به ابزار را hedge نکنید، مگر اینکه صفحه اقدام در همه نسخه‌ها به‌صورت فیزیکی غیرفعال باشد.

مدل‌ها ممکن است دستور، شِما، ابزار و ایمنی را متفاوت تفسیر کنند. کنترل‌های صلاحیت مسیریابی مدل را اعمال کنید؛ failover نباید انتشار بررسی‌نشده یا افزایش دسترسی باشد.

مرز اقدام را تراکنشی کنید

گردش‌کار عامل قابل اتکا، فکر را از ثبت جدا می‌کند:

  1. آماده‌سازی: شاهد جاری را بگیرید و بدون تغییر، فرمان پیشنهادی بسازید.
  2. مجوز: سیاست، دسترسی، سقف، شِما، تازگی و تأیید انسانی لازم را بررسی و پارامتر canonical را ثابت کنید.
  3. ثبت: نیت مجاز و یک ردیف outbox را در سامانه مرجع برنامه به‌شکل اتمیک بنویسید.
  4. ارسال: ردیف outbox را با کلید اقدام پایدار بفرستید و شناسه درخواست و رسید پایین‌دستی را ذخیره کنید.
  5. تطبیق: وضعیت معتبر کسب‌وکار را تأیید کنید، سپس نیت را committed بنامید و یک بار به کاربر اطلاع دهید.

تحویل دوباره صف، ردیف outbox را بازپخش می‌کند نه نوبت استدلال را. webhook پیش از تغییر state رفع تکرار می‌شود. مدل می‌تواند نتیجه نامعین را توضیح دهد، اما تصمیم نمی‌گیرد نبود پاسخ یعنی نبود اثر. مجوز ابزار مستقل می‌ماند؛ همان اصلی که در امنیت دسترسی ابزار هوش مصنوعی توضیح داده شده است.

این طراحی تحویل جادویی «دقیقاً یک بار» نیست؛ انتقال حداقل یک‌بار را با اثر ایدِمپوتنت، رسید پایدار و تطبیق ترکیب می‌کند.

مثال عملی: یک دستور خرید دوزبانه

کارمند به فارسی سفارش تأییدشده را می‌خواهد؛ سرپرست بعداً آن را به انگلیسی باز می‌کند. هر دو نما یک intent_id دارند: زبان نمایش را عوض می‌کند، نه هویت تجاری را.

دستیار درخواست تأییدشده و رکورد جاری تأمین‌کننده را می‌گیرد و پیشنهاد ساختاریافته می‌سازد. کد سیاست، تأییدکننده، مبلغ، مرکز هزینه، وضعیت تأمین‌کننده و قاعده خرید جاری را بررسی می‌کند. پس از مجوز، برنامه فرمان ERP را ثابت و ردیف outbox را با کلید po:<tenant>:<intent> ثبت می‌کند.

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

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

مسیر شکستی را بیازمایید که دمو نشان نمی‌دهد

پیش از انتشار fault injection اجرا کنید:

  • پس از ثبت سرویس پایین‌دستی، پاسخ را حذف کنید؛
  • تلاش نخست را تا پس از بازگشت retry به تأخیر بیندازید؛
  • همان پیام صف و webhook را چند بار تحویل دهید؛
  • هم‌زمان به همه لایه‌های retryکننده خطای overload بدهید؛
  • لغو کلاینت را نادیده بگیرید و بگذارید hedge بازنده تمام شود؛
  • هنگام اجرای تلاش، مجوز را منقضی کنید؛
  • همان نیت را از رابط فارسی و انگلیسی بازپخش کنید؛
  • کلید اقدام را با پارامتر تغییرکرده تکرار و ردشدن آن را تأیید کنید.

نتیجه منطقی را بسنجید، نه فقط موفقیت RPC:

  • ضریب تلاش: تعداد کل تلاش به ازای هر نیت منطقی؛
  • نرخ اثر تکراری: اقدام تجاری تکراری به ازای هر نیت ثبت‌شده؛
  • نرخ و سن وضعیت نامعین: تعداد و زمان تا reconciliation؛
  • واگرایی failover: تفاوت مهم پیشنهادها میان انتشارهای واجد شرایط؛
  • نرخ نتیجه دیررس: تلاش‌های کامل‌شده پس از deadline یا لغو؛
  • goodput: نتیجه مفید و سازگار با سیاست به ازای ظرفیت محدود.

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

شکست‌هایی که شبیه تاب‌آوری‌اند

  • کلید تازه برای هر retry: هر تلاش یکتا دیده می‌شود و رفع تکرار بی‌اثر است.
  • یک کلید برای فرمان اصلاح‌شده: مبلغ یا گیرنده تازه، نیت تازه است نه بازپخش.
  • retry در همه لایه‌ها: SDK، gateway، workflow و UI بار را تکثیر می‌کنند، درحالی‌که هرکدام سقف محلی کوچکی گزارش می‌دهند.
  • hedge عامل ابزارمند: هر دو مسیر می‌توانند پیش از انتخاب برنده از مرز اقدام بگذرند.
  • failover بدون برابری انتشار: بازیابی، سیاست، دسترسی ابزار، الزام شاهد یا شِما را پنهانی عوض می‌کند.
  • رفع تکرار مولد: مدل حدس می‌زند دو اقدام «یکی» هستند، به‌جای اجرای هویت تجاری canonical.
  • retention کوتاه‌تر از بازپخش: تلاش دیررس پس از فراموش‌شدن کلید به اقدام تازه تبدیل می‌شود.

دروازه پذیرش

retry یا failover خودکار را تا زمانی که پاسخ همه پرسش‌های زیر مثبت نیست فعال نکنید:

  1. آیا نیت منطقی از هر تلاش اجرایی جداست؟
  2. آیا مرز اقدام صریح است و هنگام تولید پیشنهاد به‌شکل فیزیکی غیرفعال می‌ماند؟
  3. آیا هر خطا به دائمی، گذرا، اضافه‌بار یا نامعین طبقه‌بندی می‌شود؟
  4. آیا یک لایه مالک deadline سراسری و بودجه retry است؟
  5. آیا سرویس تغییردهنده کلید اقدام پایدار یا جایگزین شرطی امن می‌پذیرد؟
  6. آیا نتیجه معتبر بدون تکرار تغییر قابل یافتن است؟
  7. آیا جایگزین ارائه‌دهنده از نظر سیاست، شِما، مجوز و کیفیت ارزیابی‌شده هم‌ارز است؟
  8. آیا نتیجه دیررس، event تکراری، لغو و بازپخش دوزبانه آزموده شده است؟
  9. آیا اپراتور می‌تواند retry را متوقف، همه تلاش‌ها را بازرسی و نتیجه حل‌نشده را تطبیق دهد؟
  10. آیا هشدارها اثر تکراری، ضریب تلاش، سن وضعیت نامعین و goodput را می‌بینند، نه فقط availability را؟

با تغییر رفتار retry ارائه‌دهنده، اضافه‌شدن تلاش خودکار به SDK، پیداشدن اثر تازه در ابزار، تغییر مدت نگهداری کلید یا جابه‌جایی مرز اقدام در انتشار مدل و router، این دروازه را دوباره بررسی کنید. امن‌ترین تلاش دوم سریع‌ترین تلاش نیست؛ تلاشی است که ثابت کند هنوز همان نیت نخست را نمایندگی می‌کند و نمی‌تواند پیامد دوم بسازد.

یادداشت منابع — بازبینی ۷ اوت ۲۰۲۶

#قابلیت اطمینان هوش مصنوعی#ایدِمپوتنسی#سامانه‌های توزیع‌شده#عامل هوش مصنوعی#پیشگیری از رخداد

مطالب مرتبط

آماده شروع پروژه هوش مصنوعی خود هستید؟

با تیم ما تماس بگیرید و درباره نحوه کمک به کسب‌وکار خود صحبت کنید.