تصور کنید در یک خط لوله استقرار مداوم (CI)، با یک امتیاز قرمز مواجه میشوید اما نمیدانید مشکل از کجاست. چرا یک امتیاز قرمز در خط لوله CI اغلب بیشتر شبیه به یک شایعه است تا یک تشخیص دقیق؟ وقتی یک ارزیابی شکست میخورد، معمولاً سه متغیر مستقل یعنی وزنهای مدل، بایتهای پرامپت و منطق داور بهطور همزمان تغییر کردهاند و شما نمیتوانید بفهمید کدامیک باعث افت کیفیت شده است. این سه ساعت مستقل بهطور نامحسوس با هم مخلوط میشوند و یک مقدار سادهی درست/غلط (Boolean) نمیتواند نام ببرد که کدامیک از این ساعتها باعث سقوط امتیاز شده است.
این ناپایداری، چالش اصلی تیمهایی است که مدلهای زبانی بزرگ (LLM) — مثل کتابخانهداری که میلیاردها صفحه را خوانده و حالا با همان لحن کتابها جواب میدهد — را وارد محیط عملیاتی میکنند. طبق گزارش MonkeyCode، اکثر تیمها از یک سیستم تست زنده استفاده میکنند که شبیه به تستهای واحد (Unit Test) است: پرامپت را میفرستند، یک شیء JSON را تحلیل میکنند و یک مقدار را بررسی میکنند. اما چون سیستم مورد آزمایش تصادفی (Stochastic) است، اوراکل (Oracle) در واقع کدی است که تغییر میکند و شبکه نیز بخشی از تجهیزات تست است، این رویکرد سه بخش متحرک را در یک فراخوانی واحد ادغام میکند. در واقع، تکیه بر خروجیهای ساده در تستهای واحد میتواند گمراهکننده باشد، چرا که کدهای سبز pytest لزوماً تضمینکنندهٔ صحت برنامههای تولیدشده توسط هوش مصنوعی نیستند و نیاز به تحلیلهای عمیقتری دارند.
همانطور که در تحلیلهای قبلی ما دربارهی امنیت و پایداری مدلهای بازمتن اشاره کردیم، حذف متغیرهای مزاحم تنها راه رسیدن به دقت است. به همین دلیل، پیشنهاد جدید MonkeyCode یک چرخش ساختاری است: بهجای ارزیابی فراخوانی زنده، «اسنپشات» (Snapshot) را ارزیابی کنید. در این روش، مرحله «ضبط» (Capture) از مرحله «نمرهدهی» (Grade) جدا میشود و داور بهعنوان یک تابع خالص عمل میکند که روی یک فایل باینری منجمد از پاسخ مدل اجرا میشود. راهکار عملی این است که ابتدا پاکت خام تکمیل (Completion Envelope) را ذخیره کنید و سپس آن اسنپشات را بهعنوان یک تابع خالص نمرهدهی کنید.
سازوکار پاکتهای منجمد
در این گردشکار، درخواستهای HTTP زنده با یک لاگ دائمی جایگزین میشوند. بهجای تولید پاسخ جدید در هر بار اجرای تست، سیستم خروجی خام را بهعنوان یک فایل JSON در کنار «مورد طلایی» (Golden Case) که آن پاسخ را تولید کرده است، ذخیره میکند. این رویکرد شباهت زیادی به الگوی Cassette دارد که با ضبط پاسخها، نشتهای مهندسی را در دموهای عاملهای هوش مصنوعی میبندد و از شکستهای لحظهای جلوگیری میکند.
برای دقت حداکثری، این سیستم از روشهای شناسایی خاص زیر استفاده میکند:
- پیشوند SHA-256: هر فایل بر اساس یک پیشوند ۱۶ کاراکتری از بایتهای درخواست استاندارد (Canonical) شناسایی میشود، نه بر اساس زمان ساعت سیستم.
- استانداردسازی (Canonicalization): درخواستها از طریق
json.dumpsبا تنظیمsort_keys=Trueو جداکنندههای خاص ( "," و ":" ) پردازش میشوند تا تضمین شود که یک پرامپت یکسان همیشه یک هش (Hash) یکسان تولید کند. - نمرهدهی آفلاین: مسیر نمرهدهی هرگز سوکت شبکه را باز نمیکند تا نوسانات و ناپایداریهای شبکه بهطور کامل از معادله حذف شود.
- ساختار ذخیرهسازی: تابع ضبط، پاکت را روی دیسک مینویسد و یک محموله (Payload) ایجاد میکند که شامل
case_id(شناسه مورد)،request_hash(هش درخواست)، خودِrequest(درخواست اصلی) وenvelope(پاکت پاسخ) است.
تشخیص «سه ساعت» متناقض
با جداسازی ضبط و نمرهدهی، توسعهدهندگان میتوانند بالاخره علت دقیق شکست را نام ببرند. اگر تست روی یک اسنپشات منجمد شکست بخورد، مشکل درونی است و به منطق داور یا یافتههای مورد انتظار مربوط میشود. اما اگر شکست فقط پس از ضبط یک اسنپشات جدید ظاهر شود، مشکل از سمت مدل یا پرامپت است.
بهعنوان مثال، دستیاری را در نظر بگیرید که از ابزارها استفاده میکند و باید از اختراع یک شناسه سفارش (Order ID) خودداری کند. ممکن است در روز دوشنبه، یک سیستم تست زنده پاس شود چون مدل در آن نمونهبرداری خاص، فیلد شناسه را بهطور کامل حذف کرده است. اما در روز سهشنبه، ممکن است تست شکست بخورد چون داور حالا مقدار null در JSON و نبودِ کلید را بهعنوان دو اتفاق متفاوت میبیند. بدون اسنپشات، داشبورد شما «تغییر رفتار مدل» (Model Drift) را مقصر میکند، اما یک پاکت منجمد اجازه میدهد خروجی روز دوشنبه را با داور روز سهشنبه مجدداً نمرهدهی کنید و ثابت کنید که در واقع داور تغییر کرده است.
جزئیات پیادهسازی فنی
این پیشنهاد شامل یک ماژول پایتون به نام replay_eval.py است که الزامات ساختاری را برای این سیستم تعریف میکند:
- GoldenCase Dataclass: یک کلاس داده منجمد (Frozen Dataclass) شامل
case_id(شناسه مورد)، دیکشنریrequest(درخواست) و یکfrozensetازexpected_findings(یافتههای مورد انتظار). - توابع یافته (Finding Functions): داورها بهعنوان
FindingFnتعریف میشوند (یک تابع فراخوانیپذیر که یک پاکت را میگیرد و مجموعهای از رشتهها برمیگرداند). برای مثال، تابعinvented_order_idبررسی میکند که آیا فراخوانی ابزارget_orderحاوی یکorder_idاست که مقدار آن None، خالی یا "UNKNOWN" باشد یا خیر. - کدهای یافته: سیستم از کدهای خاصی مانند
invented_argument(آرگومان اختراعی)،missing_argument(آرگومان مفقود) وok_refusal(امتناع صحیح) برای دستهبندی رفتار مدل استفاده میکند. - گزارشهای Diff: تابعی به نام
diff_reportsدو مجموعه از نتایج را مقایسه میکند تا شناسایی کند که آیا داور روی یک هش منجمد تغییر کرده است یا اینکه خودِ هش ضبطشده جابهجا شده است.
حفاظها و محدودیتها
برای جلوگیری از ادعاهای ناپایدار (Flaky Assertions)، داورها باید «شفافیت ارجاعی» (Referential Transparency) داشته باشند. این بدان معناست که آنها نمیتوانند ساعت سیستم، دایرکتوری کاری یا یک کاتالوگ باز را بخوانند. اگر داور وضعیت محیطی پروسه را بخواند، اسنپشاتهای منجمد را ناپایدار میکند. تمام وضعیتهای لازم — مانند برچسبهای زمانی منجمد یا کاتالوگهای شناسههای معتبر — باید درون خودِ مورد طلایی ذخیره شوند.
با این حال، محدودیتهای مشخصی برای این رویکرد وجود دارد:
- ورودی بد، خروجی بد (GIGO): یک اسنپشات نمیتواند موردی را که از همان لحظه ضبط در بعدازظهر اشتباه بوده است، نجات دهد. نمرهدهی مجدد یک لاگ بد، فقط باعث میشود پاسخ اشتباه، پایدار به نظر برسد.
- انطباق با PII: این روش برای تیمهایی که با دادههای حساس شخصی (PII) سروکار دارند مناسب نیست. اگر دادههای شبکه حاوی اطلاعات حساس باشد، ذخیره لاگهای خام تبدیل به یک حادثه نقض حریم خصوصی (Compliance Incident) میشود. در این راستا باید به یاد داشت که لاگهای CI میتوانند به نقشههای مخفی زیرساخت برای مهاجمان تبدیل شوند، لذا مدیریت امن این فایلها حیاتی است.
- پیشپردازشهای غیرقطعی: اگر یک پیشپردازشگر هر بار پرامپت را بازنویسی کند، هش درخواست مدام تغییر میکند (Thrash). تیمها باید پیشپردازشگر را پایدار کنند یا ضبط را بعد از آن انجام داده و پرامپت بازنویسیشده را در کنار پاکت ذخیره کنند.
- کمبود اوراکل: دایرکتوری نمیتواند اوراکلی را اختراع کند که محصول شما قادر به بیان آن نباشد. اگر کدهای یافتهی قابل بررسی وجود ندارند، تیمها باید ابتدا قراردادهای کوچکتری بنویسند.
مزیت ساختاری
این رویکرد مشابه نحوه تکامل زنجیره ابزارهای کامپایلر است. توسعهدهندگان در هر بار کلیک روی تست، یک کامپایلر را از نو نمیسازند؛ بلکه فایل Object را روی دیسک نگه میدارند و تستها را روی آن باینری منجمد اجرا میکنند. ارزیابی پرامپتها نیز به همین سطح از سختگیری نیاز دارد.
با داشتن یک لاگ دائمی، تیمها میتوانند «پسرفتهای خاموش» (Silent Regressions) را شناسایی کنند؛ مثلاً یک دستور trailing که در یک ادغام (Merge) نامرتبط در شاخه main اضافه شده است، یا تغییر در اسکیمای ابزار که یک آرگومان سابقاً اختیاری را به اجباری تبدیل کرده است. این اتفاقات وقتی در یک فراخوانی HTTP ادغام میشوند، شبیه به این به نظر میرسند که مدل یکشبه ضعیف شده است. اما وقتی به ضبط و نمرهدهی تقسیم شوند، آرتیفکتهای متفاوتی تولید میکنند که CI میتواند آنها را نام ببرد.
جداسازی و اعتبارسنجی
اتصال به محیط (Environment Coupling) یک حالت شکست خاموش است. برای شناسایی خطاهایی که به یک پروسه خاص گره خوردهاند، میتوان از محیط ضبط دوم استفاده کرد. اجرای یک درخواست استاندارد روی یک نقطه انتهایی (Endpoint) قابل دسترس دیگر، یک اسنپشات همزاد با هش مخصوص به خود تولید میکند.
بر اساس مستندات MonkeyCode، هدف عبور از شعارهای تبلیغاتی فروشندگان و حرکت به سمت مقایسه ساختاری است: بایتهای درخواست یکسان، دو پاکت، دو هش و یک داور. هیچ رتبهبندی صادقانهای بدون یک شناسه مدل پینشده (Pinned Model Identifier) و یک مجموعه پرامپت ثابت وجود ندارد. اگر هر دو هش جدید نمره تمیزی بگیرند اما اسنپشات دیروز اکنون شکست بخورد، یعنی کاربر داور را تغییر داده است.
افشای رابطه: این مقاله به عنوان بخشی از فعالیتهای ترویجی محصولات MonkeyCode تهیه شده است؛ دسترسی رایگان به مدل و گزینه سرور رایگان میتواند این پاکتها را بنویسد. شما همچنان نمرهدهی را بهصورت محلی و بهعنوان کد معمولی انجام میدهید و بهجای شعارهای فروشندگان، لیست یافتهها و هشها را مقایسه میکنید.
گام بعدی شما
- بررسی کنید آیا در خط لوله CI شما، شکستهای تستها به دلیل تغییر مدل است یا تغییر در منطق ارزیابی (Grader).
- برای موارد حساس، خروجیهای مدل را در قالب فایلهای JSON با هش SHA-256 ذخیره کنید تا بتوانید آنها را مجدداً ارزیابی کنید.
- توابع داور خود را به توابع خالص (Pure Functions) تبدیل کنید که هیچ وابستگی به محیط یا زمان ندارند.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو