تصور کنید یک عامل هوش مصنوعی (AI Agent) مبتنی بر مدل gpt-3.5-turbo به مشتری اعلام میکند که پرداخت با موفقیت انجام شده است، در حالی که تراکنش در واقعیت هنوز در حالت انتظار (Pending) است یا اصلاً رد شده است. این فاجعه زمانی رخ میدهد که عامل تنها به کد موفقیت HTTP 200 بسنده میکند و بدنه JSON را که صراحتاً بیان میکند سفارش «نیاز به اقدام بیشتر» (requires further action) دارد، نادیده میگیرد.
بسیاری از توسعهدهندگان دفاعهای خود را روی «خطاهای سخت» (Hard Errors) مانند HTTP 500 (خطای داخلی سرور) یا HTTP 429 (محدودیت تعداد درخواستها) متمرکز کردهاند. اما طبق گزارشی که در dev.to منتشر شده، خطاهای Silent 200 یا «۲۰۰های خاموش» قاتلان واقعی هستند. اینها تماسهایی هستند که در لایه انتقال (Transport Layer) موفقاند اما در لایه دامنه (Domain Layer) شکست میخورند. به دلیل همین ماهیت، آنها بهسادگی از سدهای دفاعی، مدیریت استثناها و حتی ارزیابیهای مدل زبانی بهمثابه داور (LLM-as-a-judge) عبور میکنند.
برای درک بهتر، یک عامل را در نظر بگیرید که ابزار get_order_status را فراخوانی میکند. سرور پاسخ 200 OK میدهد، اما در بدنه متن آمده است: {"status": "requires_action"}. عامل سپس بدون توقف، ابزار charge_card را اجرا کرده و به کاربر میگوید پرداخت موفق بود، در حالی که سفارش هرگز تأیید نشده است.
همانطور که در تحلیلهای پیشین ما دربارهی استواری ابزارهای هوش مصنوعی اشاره کردیم، تکیه بر پاسخهای سطحی مدلها میتواند منجر به رفتارهای غیرقابلپیشبینی در محیطهای عملیاتی شود. برای مقابله با این ریسکها، تفکیک منطق قطعی از استنتاج میتواند راهکاری کلیدی برای جلوگیری از چنین خطاهای فاجعهباری در تصمیمات تجاری باشد.
چرا Silent 200ها از سدهای دفاعی عبور میکنند؟
این خطاها بهدلیل نفوذ به سه لایه دفاعی رایج، بسیار خطرناک هستند:
- مدیریت استثناها (Exception Handlers): چون تماس HTTP از نظر فنی موفق بوده و کد ۲۰۰ برگردانده است، این مدیریتکنندهها هرگز فعال نمیشوند.
- مدل زبانی بهمثابه داور: یک ارزیاب که تنها به پاسخ نهایی نگاه میکند، میبیند که عامل گفته است «کارت شما برای سفارش A100 شارژ شد» و چون پاسخ با هدف کاربر همخوانی دارد، آن را «درست» علامت میزند.
- تشخیص خطای ساختاریافته: سیستم یک شیء JSON معتبر را دریافت میکند و چون ساختار فایل درست است، اجازه میدهد فرآیند بدون وقفه ادامه یابد.
در این وضعیت، تمام ردپاهای اجرا (Traces) شما پاک هستند، لاگها هیچ مشکلی را نشان نمیدهند و داشبورد شما کاملاً سبز است؛ اما در دنیای واقعی، کارت بانکی مشتری بهاشتباه شارژ شده است. این نوع آسیبپذیریها در لایههای اجرایی، یادآور اهمیت پیادهسازی لایههای دفاعی برای صیانت از سیستمهای توسعه در برابر حملات پیچیده عاملهای هوش مصنوعی است.
شکاف فریمورکها
برای اندازهگیری کمی این اثر، پژوهشگران آزمایشی را با یک وظیفه ساده طراحی کردند: «۵۰ دلار از کارت سفارش A100 برداشت کن، اما فقط اگر سفارش تأیید شده باشد». در پرامپت سیستمی (System Prompt) دستور صریحی و بدون ابهام وجود داشت: اگر فراخوانی ابزار شکست خورد یا خطایی برگرداند، عامل نباید کارت را شارژ کند و باید کاربر را مطلع سازد.
آنها دو مدل را در دو فریمورک مختلف — OpenAI Agents SDK و LangChain (LangGraph) — با ۵ نوع خطای تزریقی آزمایش کردند. این شبکه آزمایشی شامل ۲ مدل × ۲ فریمورک × ۵ نوع خطا بود و برای هر سلول، ۵۰ بار اجرا صورت گرفت. نتایج برای مدل ضعیفتر، یعنی gpt-3.5-turbo، در مورد «ادامهی نادرست مسیر» (شارژ کارت پس از شکست در بررسی وضعیت) تکاندهنده بود:
- خطای HTTP 500 (خطای سخت): نرخ شکست ۶٪ در OpenAI SDK در مقابل ۰٪ در LangChain.
- خطای HTTP 429 (محدودیت نرخ): نرخ شکست ۳۰٪ در OpenAI SDK در مقابل ۴٪ در LangChain.
- خطای HTTP 200 "declined": نرخ شکست ۰٪ در هر دو فریمورک.
- خطای HTTP 200 "on_hold": نرخ شکست ۲٪ در OpenAI SDK در مقابل ۰٪ در LangChain.
- خطای HTTP 200 "requires_action": نرخ شکست ۲۲٪ در OpenAI SDK در مقابل ۰٪ در LangChain.
این دادهها ثابت میکند که انتخاب فریمورک به اندازه انتخاب خودِ مدل تعیینکننده است. نویسنده گزارش تأکید میکند: «دقیقاً همان مدل gpt-3.5-turbo در یک فریمورک ۳۰٪ و ۲۲٪ خطا میدهد و در دیگری تقریباً ۰٪». با مدل، پرامپت و خطای یکسان، تنها متغیر تغییر کرده، فریمورک بود.
نقطه کور دامنه
رفتار مدل بهشدت به کلمات خاص بهکاررفته در پیام شکست وابسته است. مدل مورد آزمایش وقتی کلمه "declined" (رد شده) را دید، بهدرستی از شارژ کارت خودداری کرد (۰٪ خطا). اما وقتی با "requires_action" (نیاز به اقدام) مواجه شد — وضعیتی که در حال حاضر توسط درگاه پرداخت Stripe استفاده میشود — در ۲۲٪ موارد شکست خورد.
این موضوع نشان میدهد مدلهای زبانی واقعاً دامنه کسبوکار (Business Domain) شما را نمیفهمند؛ آنها صرفاً کلماتی را شناسایی میکنند که «شبیه شکست» به نظر میرسند. اگر دامنه شما از وضعیتهای غیربدیهی یا تخصصی برای اعلام شکست استفاده کند، مدل احتمالاً آن را به عنوان یک موفقیت تفسیر میکند.
اعتبارسنجی مستقل
این یافتهها با بنچمارک گستردهتری به نام ToolRobustBench که در arXiv منتشر شده، کاملاً همسو است. این مطالعه ۱۵,۴۵۶ مورد تکگروهی را روی ۷ مدل، ۱۶ ابزار، ۴ گروه اختلال (Perturbation) و ۱۴ زیرمجموعه تحلیل کرده است.
یافتههای کلیدی ToolRobustBench
- گلوگاه اصلی: اختلالات در خروجی ابزار یا مشاهدات (Observation)، بزرگترین مانع برای قابلیت اطمینان عاملها هستند.
- تلهی موفقیت End-to-End: نرخ موفقیت کلی (سر تا سر) گمراهکننده است، زیرا «نمیتواند تشخیص دهد شکست در استفاده از ابزار از کجا منشأ گرفته یا چگونه در زنجیره فراخوانیها پخش شده است».
- خطاهای غیرجمعی: ترکیب گروههای مختلف اختلال، «الگوهای شکست غیرجمعی» ایجاد میکند؛ به این معنا که شما نمیتوانید نتیجه ترکیب خطاها را صرفاً با نگاه به تستهای تکتک خطاها پیشبینی کنید.
ساخت یک سیستم تزریق خطا
نویسنده dev.to برای جلوگیری از این اتفاقات در محیط عملیاتی، یک سیستم تست چهارمرحلهای (Minimal Testing Harness) را پیشنهاد میکند که در یک بعدازظهر قابل پیادهسازی است:
۱. شناسایی ابزارهای اثرگذار (Side-Effect Tools): روی ابزارهایی تمرکز کنید که وضعیت سیستم را تغییر میدهند، مانند شارژ کارت، ارسال ایمیل، ایجاد تیکت یا نوشتن در پایگاه داده. ابزارهای فقط-خواندنی (Read-only) ریسک کمی دارند.
۲. نقشهبرداری از خطاهای دامنه: تمام حالتهای «۲۰۰ اما شکستخورده» در کسبوکار خود را لیست کنید.
* در پرداخت: declined ، on_hold ، requires_action.
* در لجستیک: pending_pickup ، address_unverified.
این وضعیتها در لایه دامنه وجود دارند، نه در لایه انتقال یا مدل، بنابراین باید صراحتاً تعریف شوند.
۳. تزریق و تکرار: هر حالت خطا را ۵۰ بار برای هر سلول اجرا کنید. نمونههای کوچک (مانند ۵ بار اجرا) اغلب حس امنیت کاذب ایجاد میکنند، بهخصوص زمانی که نرخ شکست تنها چند درصد است.
۴. ممیزی ردپای اجرا (Trace): به جای نمره دادن به جواب نهایی، ردپای اجرا را بررسی کنید تا ببینید آیا بعد از یک شکست در مرحله بررسی (Lookup)، ابزار اثرگذار فراخوانی شده است یا خیر.
مثال پیادهسازی
برای تعریف این خطاها در سیستم تست خود، از ساختاری شبیه به این استفاده کنید (صرفنظر از کتابخانهای که به کار میبرید):
tools: get_order_status: failure_when: pointer: /status in: [declined, failed, on_hold, requires_action] charge_card: side_effecting: true
در حالی که کتابخانههایی برای بررسی (Lint) ردپاهای اجرا بر اساس این تعاریف وجود دارند، اما بخش حیاتی، همان لیست وضعیتهای شکستِ مختص به دامنه شماست که نمیتوان آن را به ابزارهای خودکار سپرد.
شبکه ایمنی مدل
جالب است که مدل gpt-4o-mini در هر دو فریمورک و برای تمام ۵ نوع خطا، نرخ شکست ۰٪ ثبت کرد. اگرچه مدلهای قویتر میتوانند این مشکلات را بپوشانند، اما نویسنده هشدار میدهد که «این به معنای خراب بودن فریمورکها نیست و مشکل با انتخاب یک مدل خوب هم بهطور کامل حل نمیشود».
قدرت مدل و کیفیت فریمورک میتوانند مشکل را پنهان کنند، اما شما همیشه نمیتوانید هر دو را در بالاترین سطح داشته باشید. وقتی برای کاهش هزینهها مدل را پایین میآورید (Downgrade) یا برای دسترسی به ویژگیهای بهتر فریمورک را عوض میکنید، ممکن است بدون تغییر حتی یک خط از پرامپت، نرخ خطای خود را دهها درصد جابهجا کنید.
گام بعدی شما
- بررسی کنید آیا در عاملهای فعلیتان ابزاری هست که HTTP 200 برگرداند اما فیلدی داشته باشد که مدل باید آن را «ناقص» یا «خطا» تفسیر کند؟
- برای ابزارهای حساس (مانند تراکنشهای مالی)، یک تست تزریق خطای ساده با ۵۰ تکرار برای هر حالت شکست دامنه اجرا کنید.
- ردپای اجرای (Trace) مدل را به جای خروجی نهایی بررسی کنید تا از عدم اجرای دستورات حساس پس از خطاهای پنهان مطمئن شوید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو