تصور کنید بازبینی کد در تیم شما در ژانویه تمام خطاهای بحرانی را میگرفت، اما در ژوئن نیمی از آنها را نادیده میگیرد. خطرناکترین بخش این است که مدل همچنان با همان اعتمادبهنفس و فرمت همیشگی پاسخ میدهد، اما در واقعیت، کیفیت تشخیص آن سقوط کرده است. این شکست در سکوت رخ میدهد.
به نقل از گزارشی که در ۲۵ اوت ۲۰۲۶ در وبسایت dev.to منتشر شد، یک هشدار جدی دربارهی شکاف امنیتی خطرناک در خط لولههای (Pipeline) مدرن استقرار کد داده شده است. در حالی که هر مرحله از تحویل نرمافزار بر اساس تأکیدات (Assertions) و تستها استوار است، بازبینهای هوش مصنوعی زاینده (Generative AI) — که خودشان نقش داور کد را دارند — معمولاً بدون هیچ آزمونی مورد اعتماد قرار میگیرند. این موضوع باعث میشود که بازبین AI احتمالاً به بزرگترین سطح تأییدنشده در کل فرآیند توسعه تبدیل شود.
این پدیده که «رانش مدل» (Model Drift) نامیده میشود، تا زمانی که یک باگ بحرانی به محیط عملیاتی نرسد، نامرئی است. همانطور که در تحلیلهای قبلی ما دربارهی امنیت مدلهای بازمتن اشاره کردیم، اعتماد کورکورانه به خروجیهای مدل بدون داشتن یک معیار سنجش، ریسک سیستمیک ایجاد میکند. در کدنویسی، وقتی یک تست میشکند، سیستم با صدای بلند فریاد میزند، اما وقتی یک پرامپت به دلیل بهروزرسانی مدل دیگر درست عمل نمیکند، شکست در سکوت رخ میدهد. این چالش با مفاهیم گستردهتری از رانش هدف در مدلها مرتبط است که در بررسیهای ما پیرامون استفاده از جلسات (Sessions) برای جلوگیری از تغییرات ناخواسته در قصد مدل به تفصیل مورد بحث قرار گرفته است.
در بحثهای اخیر در جامعه DEV، این سؤال مطرح شده است که «چه کسی بازبین را تست میکند؟» و پاسخ صادقانه این است: تقریباً هیچکس. ریشه مشکل در نبود یک «اوراکل» یا مرجع حقیقت است. یک ابزار Linter مجموعهای از قوانین دارد و یک تست واحد (Unit Test) یک ادعای مشخص را بررسی میکند، و یک بازبین انسانی نیز توسط انسان دومی در فرآیند Code Review نظارت میشود. اما یک بازبین هوش مصنوعی تنها یک پرامپت دارد، و این پرامپت توسط مدلی ارزیابی میشود که در لایههای زیرین مدام در حال تغییر است. اگر نتوانید به طور دقیق بیان کنید که بازبین «باید» چه چیزی را شناسایی کند، هرگز نمیفهمید چه زمانی دیگر قادر به شناسایی آن نیست.
بسیاری از تیمها تصور میکنند با «پین کردن» (Pinning) یا تثبیت نسخه مدل، از این رانش جلوگیری میکنند. اما این گزارش استدلال میکند که تثبیت پیکربندی (Configuration) لازم است اما کافی نیست. ارائهدهندگان مدلها اغلب بهروزرسانیهایی را ارسال میکنند، کوانتش (Quantization) را تغییر میدهند — شبیه به فشردهسازی یک فایل حجیم برای اشغال فضای کمتر بدون از دست دادن زیاد کیفیت — یا پارامترهای پیشفرض را بدون تغییر در رشتهی نسخه (Version String) که شما ثبت کردهاید، تغییر میدهند.
بنابراین، شناسهای که شما تثبیت کردهاید، در واقع یک هدف متحرک است. در حالی که پیکربندی شما ثابت میماند، رفتار مدل دچار رانش میشود. این بدان معناست که مجموعه تستهای رگرسیون شما باید بر روی «خروجیها» تأکید کنند، نه بر روی «نسخهها». برای حل این مشکل، تیمها باید با بازبین کد مانند یک وابستگی (Dependency) برخورد کنند که دارای «قراردادهای رفتاری» است، نه یک فایل تنظیمات ایستا. این همان شکاف میان توصیه رایج برای پین کردن تنظیمات AI و واقعیت استقرار مدلهاست.
پین کردن نسخه تنها یک نقطه شروع تکرارپذیر به شما میدهد، اما وقتی مدل تغییر میکند، هیچ معیاری برای مقایسه در اختیار شما قرار نمیدهد. شما به یک خط پایه (Baseline) از رفتار مورد انتظار و یک روش ارزان برای اندازهگیری منظم آن نیاز دارید.
راهکار عملی، ساخت یک «مجموعه داده باگهای کاشتهشده» (Planted-bug corpus) است. این مجموعه شامل تعداد کمی تغییرات کد (Pull Requestهای مصنوعی) است که هر کدام حاوی یک نقص تزریقشده با یک دستهبندی باگ مشخص و یک حکم (Verdict) مورد انتظار هستند. شما این مجموعه را یکبار بر اساس تاریخچه حوادث (Incident History) واقعی تیمتان میسازید و سپس بازبین را در بازههای زمانی مشخص روی آن تست میکنید.
برای پیادهسازی این سیستم، باید استانداردهای فنی زیر را دنبال کنید:
- ترکیب: ساخت مجموعهای از ۱۰ تا ۲۰ باگ کاشتهشده که از حوادث اخیر تیم استخراج شدهاند. هر مورد باید دقیقاً شامل یک نقص باشد.
- موارد سالم: گنجاندن کدهای «سالم» (Clean Cases). بازبینی که همه چیز را باگ تشخیص دهد، به اندازه بازبینی که هیچ چیز را نمیبیند، بیفایده است.
- آستانه پذیرش: تعریف یک نرخ حداقل برای تشخیص (مثلاً ۰.۸ یا ۸۰٪) برای اینکه مجموعه تست پاس شود.
- فیلدهای داده: هر ورودی به یک
corpus_version(مثلاً "2026-08")، یکbug_class(مثلاً "null_dereference") و یک مقدار Boolean برایshould_catchنیاز دارد.
به عنوان مثال، برای یک خطای null dereference در فایل src/cache.js یک Diff مصنوعی ایجاد میشود. در حالت «قبل»، کد ممکن است به این صورت باشد: const entry = cache.get(key); if (entry.expiresAt < Date.now()) {. اما در حالت «بعد»، باگ تزریق میشود: const entry = cache.get(key) || null; if (entry.expiresAt < Date.now()) {.
برای خودکارسازی این فرآیند، یک اسکریپت ساده پایتون میتواند این موارد را از طریق API بازبین اجرا کند. این اسکریپت پرامپتی میسازد که از AI میخواهد تغییرات را بررسی کرده و فقط نقصهای concrete (عینی) را همراه با شماره فایل و خط گزارش کند.
سیستم امتیازدهی در اینجا عمداً ساده (Naive) طراحی شده است: اسکریپت بررسی میکند که آیا case['id'] یا bug_class در خروجی ظاهر شده است یا خیر. اگرچه در یک پیادهسازی واقعی باید خروجیهای ساختاریافته (Structured Output) تجزیه شوند، اما این قالب به گونهای است که وابسته به فروشنده خاصی نیست تا مجموعه داده بتواند حتی پس از تغییر ابزار بازبین، باقی بماند. اگر نرخ تشخیص از آستانه تعیینشده پایینتر بیاید، اسکریپت با یک کد غیرصفر (non-zero code) خارج میشود و اجازه میدهد اجرای رگرسیون مستقیماً به CI متصل شود.
برای عملیاتی کردن شناسایی رانش، این گردشکار پنجمرحلهای پیشنهاد میشود:
۱. ساخت: ایجاد ۱۰ تا ۲۰ باگ کاشتهشده از تاریخچه حوادث به همراه Diffهای سالم.
۲. خط پایه: اجرای یک دور اولیه و ثبت نرخ تشخیص برای هر دستهبندی باگ تا مشخص شود بازبین امروز چه چیزی را تشخیص میدهد.
۳. زمانبندی: تبدیل این مجموعه داده به یک Cron Job هفتگی که در صورت افت نرخ تشخیص به زیر آستانه، با شکست (Fail) مواجه شود.
۴. تحلیل: در صورت شکست، خروجی فعلی را با خط پایه مقایسه (Diff) کنید تا تصمیم بگیرید که آیا پرامپت تغییر کرده است یا خودِ مدل.
۵. هرس کردن: بهروزرسانی فصلی مجموعه داده. دستهبندیهایی از باگها که تیم شما دیگر نمینویسد، تنها باعث ایجاد اعتماد کاذب میشوند.
نگهداری این سیستم حیاتی است. مجموعهای که هرگز تغییر نکند، تاریخ را اندازه میگیرد نه ریسکهای فعلی را؛ و موارد قدیمی نرخ تشخیص reassuring (اطمینانبخشی) ایجاد میکنند در حالی که بازبین روی باگهایی که واقعاً در حال ارسال آنها به محیط عملیاتی هستید، دچار رانش شده است.
البته هر تیمی به این سیستم نیاز ندارد. گزارش اشاره میکند که باگهای کاشتهشده، باگهای واقعی نیستند و یک مجموعه کوچک ۱۵ موردی، درصدهایی با حاشیه خطای زیاد تولید میکند. بنابراین باید به آن به عنوان یک «شاخص روند» نگریست، نه یک بنچمارک دقیق ریاضی.
به طور خاص، اگر شرایط زیر را دارید، از این هزینه اضافی اجتناب کنید:
- اگر هنوز مرحله بازبینی AI در خط لوله خود ندارید؛ اندازهگیری بازبینی که از آن استفاده نمیکنید، صرفاً اتلاف وقت است.
- اگر مخزن (Repository) کوچکی با تعداد PRهای هفتگی بسیار کم مدیریت میکنید، جایی که یک بازبین انسانی دوم سیگنال بیشتری فراهم میکند.
- اگر تنها به دنبال شکست در «قضاوت» هستید نه شکست در «تشخیص»، زیرا این یک محدودیت واقعی در هرگونه بررسی مبتنی بر خروجی است. این ضعف در تشخیص دقیق، با پژوهشهای اخیر درباره ناتوانی مدلهای زبانی در تولید اسکریپتهای بازگشتی (Rollback) کد همسو است که نشان میدهد مدلها در درک دقیق قراردادهای فنی کدنویسی دچار مشکل هستند.
در نهایت، عادتهای تست توسط «هزینه نهایی» (Marginal Cost) تعیین میشوند. یک مجموعه رگرسیون تنها زمانی به عادت تبدیل میشود که هزینه نهایی آن صفر باشد، زیرا تیمها در هفتههایی که بودجه محدود است، بررسیهای پولی را نادیده میگیرند.
پلتفرم MonkeyCode با ارائه دسترسی رایگان به مدلها و گزینههای سرور رایگان، این بهانه بودجه را حذف کرده است تا شناسایی رانش به یک فرآیند پسزمینه تبدیل شود، نه یک تصمیم خرید. اقتصاد در اینجا اهمیت دارد زیرا رانش بازبین کند است؛ یک ممیزی پولی فصلی، هفتهای را که نرخ تشخیص در آن به طور بیصدا نصف شده است، از دست خواهد داد.
با تبدیل ممیزیهای فصلی به چکهای هفتگی خودکار، تیمها میتوانند افت کیفیت را قبل از رسیدن نقص به دست کاربر متوجه شوند. بازبین کد شما را قضاوت میکند؛ حالا زمان آن است که چیزی بازبین را قضاوت کند.
گام بعدی شما
- لیست ۱۰ مورد از رایجترین باگهای سه ماه اخیر تیمتان را استخراج کنید.
- یک مجموعه داده کوچک از PRهای مصنوعی (سالم و معیوب) بر اساس این لیست بسازید.
- یک اسکریپت ساده برای اجرای هفتگی این مجموعه روی API بازبین خود تنظیم کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو