تصور کنید کدی مینویسید که در تمام محیطهای آزمایشی سبز است، اما به محض استقرار در دنیای واقعی، برای هر کاربر کرش میکند. این دقیقاً همان اتفاقی است که برای یک توسعهدهنده در پیادهسازی سرور Google Gemini رخ داد؛ جایی که نرخ موفقیت ۱۰۰ درصدی در تستهای واحد، هیچ تضمینی برای عملکرد صحیح در محیط عملیاتی نبود. یک توسعهدهنده فاش کرد که یک اسکریپت دمو ساده توانست در کمتر از یک دقیقه زمان اجرا، یک شکست بحرانی را پیدا کند که یک مجموعه کامل از تستها از دیدن آن غافل مانده بودند.
به گزارش وبسایت dev.to، این اتفاق تلهای رایج در توسعه هوش مصنوعی زاینده (Generative AI) — شبیه به آشپزی با دستورالعمل روی کاغذ که در واقعیت با مواد موجود در یخچال همخوانی ندارد — را آشکار میکند: شکاف عمیق میان محیطهای شبیهسازیشده (Mocked) و قراردادهای زنده API. این چالش دقیقاً همان نقطهای است که بسیاری از پروژهها در آن دچار لغزش میشوند و شکاف میان دموی موفق و تولید واقعی میتواند به چهار دلیل اصلی منجر به شکست پروژههای هوش مصنوعی شود. در دنیای ادغام مدلهای زبانی بزرگ (LLM)، توسعهدهندگان اغلب برای کاهش هزینه و افزایش سرعت از «موکها» یا شبیهسازها استفاده میکنند تا پاسخهای API را تقلید کنند. در حالی که این روش ثابت میکند کد شما پاسخ را «درست مدیریت میکند»، اما هرگز نمیتواند ثابت کند که API در واقعیت آن پاسخ را «ارسال خواهد کرد».
در این پروژه، سرور یک پیادهسازی از پروتکل زمینهٔ مدل (Model Context Protocol یا MCP) بود که مدل gemini-3.1-flash-lite-image را در بر میگرفت. این سرور چهار ابزار برای تولید تصویر و ویرایش حالتمند فراهم میکرد که توسط عاملهایی مانند Claude Code (یک رابط خط فرمان یا CLI نوشته شده با زبان Rust) و یک عامل Google ADK (مدل LlmAgent بر پایه gemini-2.5-flash) با استفاده از MCPToolset مصرف میشدند.
جزئیات فنی و معماری
این سرور یک پیادهسازی فشرده از زبان پایتون است که تقریباً ۳۰۰ خط کد دارد. این سیستم از Interactions API برای فعالسازی جلسات حالتمند (Stateful Sessions) از طریق پارامترهای store=True و previous_interaction_id بهره میبرد. این معماری اجازه میدهد ویرایشهای چندمرحلهای روی تصاویر انجام شود؛ برای مثال، کاربر میتواند یک تابلوی نئونی با متن «RAMEN» را به تصویری که پیشتر تولید شده اضافه کند، در حالی که تداوم پیکسلها در سطح دقیق حفظ شود.
قبل از کشف باگ، پروژه کاملاً سالم به نظر میرسید. وضعیت سیستم به شرح زیر بود:
- ۱۰ از ۱۰ تست واحد با موفقیت پاس شده بودند.
- گزارشهای ابزارهای تحلیل کد مانند
ruffوmypyکاملاً پاک و بدون خطا بود. - سرور برای چندین روز توسط عاملهای هوش مصنوعی بدون هیچ مشکلی استفاده شده بود.
- حتی پروژه به صورت یک ایمیج داکر با نام (xbill9/nb2lite-mcp) برای استفاده عمومی در دسترس قرار گرفته بود.
مکانیسم شکست: انحراف قرارداد
باگ در پارامتر thinking_level ابزار تولید تصویر نهفته بود. اعتبارسنجی محلی سرور، چهار مقدار «minimal»، «low»، «medium» و «high» را به عنوان مقادیر مجاز میپذیرفت. اما در واقعیت، API زنده Gemini تنها مقادیر «low» و «high» را قبول میکرد.
وقتی توسعهدهنده اسکریپت دمو (demo.sh) را برای تولید تصویر یک «آشپز رباتیک کوچک در حال پختن رامن» با استفاده از سطح «minimal» اجرا کرد، سیستم کرش کرد. API گوگل یک کد خطای ۴۰۰ بازگرداند با این پیام: {'error': {'message': "'minimal' is not a supported thinking level for this model. Allowed values are: low, high.", 'code': 'invalid_request'}}.
مشکل بزرگتر این بود که مقدار پیشفرض در فایل server.py روی «medium» تنظیم شده بود. این یعنی هر فراخوانی زنده که به طور صریح این پارامتر را تغییر نمیداد، به طور خودکار منجر به خطای HTTP 400 میشد. توسعهدهنده اشاره کرد که لیست مجاز محلی در واقع یک «کپی کششده» از حقیقتی بود که مالکیت آن در اختیار API است و این کپیها بهطور اجتنابناپذیری دچار انحراف (Drift) میشوند.
چرا تستها سبز ماندند؟
تستهای واحد از یک کلاینت شبیهسازیشده (Mock Client) استفاده میکردند که برای هر ورودی ارسالی، یک پیام موفقیت برمیگرداند. به طور مشخص، تابع test_generate_image_success متد server._get_client را پچ (Patch) کرده بود تا بدون توجه به مقدار thinking_level ارسالی، یک تعامل ساختگی موفق بازگرداند.
این وضعیت منجر به سه شکاف اصلی شد:
- شکاف شبیهسازی (The Mock Gap): تستها ثابت کردند سرور مقدار «medium» را صادقانه به مقصد میفرستد، اما نمیتوانستند تشخیص دهند که API واقعی، مقدار «medium» را نامعتبر میبیند.
- شکاف کاربر (The User Gap): کاربران قبلی که عمدتاً عاملهای هوش مصنوعی بودند، برای تصاویر خود کیفیت «high» را درخواست میکردند و بنابراین باگ فعال نمیشد.
- شکاف پیشفرض (The Default Gap): چون عاملها مقدار پیشفرض را بازنویسی (Override) میکردند، تنظیمات معیوب «medium» و مقدار شبحوار «minimal» هرگز در محیط عملیاتی آزمایش نشدند.
راهکار و رفع مشکل
توسعهدهنده با بهروزرسانی دو خط از کد عملیاتی، سرور را با قرارداد API همراستا کرد:
- بهروزرسانی لیست مجاز: تغییر متغیر
SUPPORTED_THINGING_LEVELSاز{"minimal", "low", "medium", "high"}به{"low", "high"}. - تغییر پیشفرض: تغییر مقدار پیشفرض
thinking_levelاز «medium» به «low».
برای جلوگیری از بازگشت باگ (Regression)، یک تست جدید اضافه شد تا اطمینان حاصل شود که مقدار «medium» اکنون در همان لایه محلی با یک خطای خوانا («Unsupported thinking level 'medium'») رد شود، پیش از آنکه درخواستی به API ارسال گردد. همچنین توسعهدهنده یک بازبینی کامل روی امضای سه ابزار، Docstringها و تابع get_help سرور انجام داد تا تمام مقادیر نادرست حذف شوند.
این اصلاحات در کمتر از ۱۰ دقیقه پس از اولین شکست، از طریق بازسازی و پوش کردن ایمیج داکر مستقر شد. این سرعت واکنش به دلیل صراحت پیام خطای ۴۰۰ بود که مقادیر مجاز را دقیقاً نام برده بود و راه حل را در متن خطا ارائه داد.
گام بعدی شما
این تجربه نشان میدهد که تستهای شبیهسازیشده منطق داخلی را تایید میکنند، اما نمیتوانند قراردادهای خارجی را تایید کنند. توسعهدهنده توصیههای زیر را پیشنهاد میکند:
- پیادهسازی Smoke Tests زنده: حداقل یک فراخوانی ارزان و واقعی از API را در چرخه تستهای خود نگه دارید (مثلاً با دستور
DEMO_FAST=1 ./demo.sh) تا انحراف قراردادها را سریعاً شناسایی کنید. - تست دقیق مقادیر پیشفرض: مقادیر پیشفرض مواردی هستند که کاربران به ندرت تغییر میدهند و بنابراین اصلیترین مکان برای پنهان شدن باگها هستند.
- حذف لیستهای مجاز محلی: داشتن یک کپی محلی از مقادیری که توسط یک سرور خارجی مدیریت میشود، مانند یک «بمب ساعتی از انحراف» است.
- ارزش دادن به اسکریپتهای دمو: یک اسکریپت دمو، ارزانترین تست End-to-End موجود است که از اعتبارنامههای واقعی و مسیر موفقیت (Happy Path) واقعی استفاده میکند.
با افزایش استفاده از MCP به عنوان استانداردی برای ارتباط میان عامل و ابزار، بار اعتبارسنجی از دوش عامل به دوش سرور منتقل میشود؛ موضوعی که در تحلیلهای آینده بررسی خواهیم کرد.




گفتگو