تصور کنید برنامهنویسی را استخدام کردهاید که بهجای اجرای یک تست ساده برای بررسی سلامت کد، ساعتها وقت صرف مطالعهی دفترچه راهنمای تست میکند تا حدس بزند نتیجه چه خواهد بود. این رفتار غیرمنطقی، دقیقاً همان نقطهای است که بسیاری از عاملهای کدنویسی پیشرفته در آن شکست میخورند.
یک عامل کدنویسی (Coding Agent) — ابزاری که مثل یک دستیار برنامهنویس، میتواند بهطور مستقل کد بنویسد و تغییرات را اعمال کند — اغلب توکنهای بیشتری را صرف پیشبینی نتیجهی یک اسکریپت بررسی میکند تا هزینهای که برای اجرای واقعی آن میپردازد. این رفتار منجر به یک شکست خاص و هزینهبر میشود: عامل منطق پیادهسازی را تحلیل میکند تا نتیجه را حدس بزند و در بسیاری از موارد، به پاسخی کاملاً غلط میرسد.
این پدیده نشاندهندهی تضاد بنیادین در جریانهای کاری عاملمحور است. وقتی یک عامل کدنویسی به سورسکد اسکریپتهایی که یک مخزن (Repository) را نظارت میکنند دسترسی دارد، متن کد را مسیری ارزانتر برای رسیدن به پاسخ میبیند تا اقدام به اجرا. از آنجا که این مدلها اساساً تولیدکنندههای احتمالی متن هستند، با کد مانند متنی برخورد میکنند که باید مصرف شود، نه ابزاری قطعی (Deterministic) که باید به کار گرفته شود. برای یک مدل، «خواندن» کاری است که تمام روز انجام میدهد؛ بنابراین خواندن یک اسکریپت برای فهمیدن آنچه خواهد گفت، ارزانتر از اجرای آن و انتظار برای نتیجه به نظر میرسد. اما در واقعیت، این مسیر اصلاً ارزان نیست. مدل توکنهای خود را روی استدلالی میسوزاند که خودِ اسکریپت بهطور قطعی و رایگان انجام میدهد و در نهایت پاسخی ضعیفتر تولید میکند، چون مدل رفتار را از روی پیادهسازی استنتاج میکند، بهجای اینکه آن را مشاهده کند.
این چالش زمانی رخ میدهد که توسعهدهندگان به سمت سامانههای خودگردان و متراکم از نظر دامنه (Domain-dense) حرکت میکنند. در این محیطها، «گیتها» یا اسکریپتهای بررسی برای اعتبارسنجی دستورات کوتاه بهصورت ارزان استفاده میشوند. هدف این است که دستورات کوتاه داده شود و گیتها آنها را تایید کنند و در صورت شکست، بافت (Context) اضافی ارائه دهند. اما تا زمانی که سورسکد این گیتها در درخت کاری (Working Tree) قابل مشاهده باشد، عاملها وسوسه میشوند رابط طراحیشده — یعنی خروجی اجرا — را دور بزنند و به جای آن، باستانشناسی دستی روی سورسکد انجام دهند. تحلیل کدِ گیتها برای جلوگیری از فعال شدن آنها، یک الگوی ضدبنیاد (Anti-pattern) و هزینهبر است.
کالبدشکافی یک شکست در پیشبینی
در ۳ آگوست ۲۰۲۶، یک جلسه گزارششده با یک عامل کدنویسی، این الگوی غلط را در حین ویرایش یک پیکربندی برجسته کرد. عامل باید تصمیم میگرفت آیا یک «گارد» (Guard) اختیاری را فعال کند یا خیر؛ گاردی که جلسات تفویضشده را به سمت یک شکل تصمیمگیری خاص سوق میدهد. این گارد در حالت پیشفرض خنثی است؛ در مستندات مربوط به آن در یک جمله ذکر شده است که فعالسازی آن بر عهدهی مصرفکننده است و در غیر این صورت، به صورت متن خنثی باقی میماند (که پیشفرض اعلامشده برای این مخزن است).
عامل هرگز آن جمله را در مستندات نخواند. در عوض، مراحل زیر را طی کرد:
- تلاش کرد بخش خاصی از مستندات را بازخوانی کند، اما نتیجه خالی بود. بهجای اینکه پرسوجو را با یک عنوان بهتر تکرار کند، به سراغ سورسکد رفت.
- پیادهسازی گارد را باز کرد و تمام ۲۸ خط کد را خواند.
- به این نتیجه رسید که کد در مسیرهای رایج بهطور پاکیزه خارج میشود و فعال کردن آن بیضرر است.
- گارد را در یک فایل پیکربندی تحت مدیریت قرار داد.
- در استدلال خود، پیشبینی کرد که چون این چکها فایلهای ردیابی شده را کنترل میکنند و این فایل خاص (
settings.local.json) ردیابی نمیشد، پس هیچ چکی فعال نخواهد شد.
وقتی توسعهدهنده مداخله کرد، چکها واقعاً اجرا شدند. هر دو سبز بودند، چه با ویرایش و چه بدون آن. هیچ چکی در این مجموعه نمیتوانست اشتباه را بگیرد چون یک گارد مشورتی ذاتاً بیضرر است. تنها مرجع معتبر در مورد این سوال، همان مستندات بود؛ تنها منبع ارزانقیمتی که جلسه در طی مسیر نادیده گرفت تا به باستانشناسی سورسکد بپردازد.
تحلیل نهایی (Post-mortem) خودِ عامل، قانون دقیقی را برای این شکست ارائه داد: «نشانه برای متوجه شدن اشتباه من این است: اگر دارم استدلال میکنم که آیا یک گیت فعال میشود یا نه، یعنی همین حالا از ریل خارج شدهام».
هزینه «پیشمحاسبه» احکام
این یک اتفاق تصادفی نیست؛ نویسنده این مورد را آنقدر دیده است که دیگر آن را یک لغزش ساده نمیبیند. شش روز پیش از ویرایش پیکربندی، در جلسه دیگری که وظیفه اعزام یک مرحله تفویضی را داشت، مشکل مشابهی رخ داد. یک گارد بودجه روی هر فراخوانی اعزام بهعنوان یک هوک پیش-ابزار (Pre-tool hook) اجرا میشود — همان نقطه رهگیری که نویسنده پیشتر درباره آن نوشته بود — و در لحظه تلاش، حکمی مقتدرانه صادر میکند.
عامل بهجای تلاش برای اعزام و اجازه دادن به گارد برای ارائه حکم، یک حلقه انتظار ساخت تا نتیجه را «پیشمحاسبه» کند. این منجر به دو هزینه متمایز شد:
- اتلاف توکن: مدل توکنهای زیادی را در یک حلقه صرف محاسبه اطلاعاتی کرد که هوک در هر صورت آن را تحویل میداد. جلسه بعداً اعتراف کرد که «تلاش برای اجرا قطعاً ارزانتر از پیشمحاسبه است» و اشاره کرد که یک گارد با رویکرد Fail-closed، پیشبینی را غیرضروری میکند.
- ناپایداری: عامل یک حکم مشورتی را بهعنوان «مسدودکننده» (Blocking) خواند، در حالی که مستندات مالک صراحتاً میگفت این حکم هرگز مسدود نمیکند. مدل یک هشدار ساخت که در مستندات وجود نداشت.
این ثابت میکند که پیشبینی، صرفاً مسیری کندتر برای رسیدن به همان نتیجه نیست؛ بلکه نتیجهای متفاوت و غیرقابلاعتماد است که با هزینه زیاد به دست میآید. این دقیقاً مشابه بیاعتمادی به گزارشهای عاملهاست: همانطور که ادعای یک عامل مبنی بر اینکه «کارش را درست انجام داده» نیاز به تایید دارد، مدل ذهنی عامل از اینکه یک مکانیسم «چه میگفت»، یک اثر مشکوک است. این همان بیاعتمادی است که اکنون متوجه شیء دیگری شده است: مدلِ عامل در مقابل گزارشِ عامل.
شکست ساختاری نردههای متنی
وقتی عامل پیشنهاد داد که این رفتار را «یادداشت و اصلاح» کند، نویسنده اشاره کرد که این اولین بار نیست. جلسه پذیرفت که «یادداشت و اصلاح» بیفایده است چون این اصلاح با پایان جلسه از بین میرود.
دستوری که باید در هر جلسه دوباره اعمال شود، در حالی که با یک جایگزین خواندنی و همیشه در دسترس (سورسکد) رقابت میکند که «ارزانتر» به نظر میرسد، بیشتر شبیه یک پیشنهاد است تا یک نرده. اگر نثر (Prose) نتواند در برابر دامنهی واژگان تخصصی اثر کند، در اینجا هم شکست میخورد. وسوسه برای خواندن پیادهسازی، یک مشکل ساختاری است که با تغییر پرامپت حل نمیشود. این یک رقابت بین یک «پیشنهاد» و یک «وسوسه» است.
راهکار: کدپنهانی (Opacity) بهعنوان یک ویژگی طراحی
اگر سورسکد همان چیزی است که عامل را به پیشبینی دعوت میکند، تنها راه باقیمانده حذف سورسکد است. این موضوع در جریان ارزیابی این بحث مطرح شد که آیا یک مجموعه چکهای مبتنی بر شل (Shell) به یک فایل باینری کامپایلشده تبدیل شود یا خیر. در حالی که دلایل مهندسی سنتی — مانند قابلیت حمل به فراتر از لینوکس، ابزارهای مستقل با چرخههای انتشار مجزا و استفاده از یک کامپایلر واقعی بهجای لینتر (Linter) — در نظر گرفته شدند، اما عامل تعیینکننده، رفتار عامل (Agent) بود.
وجود سورسکد اسکریپتها باعث اتلاف توکن میشود چون عاملها را دعوت میکند بهجای اجرای عملیات چرخه حیات (Lifecycle)، نتایج را پیشبینی کنند. انتقال به باینریهای کامپایلشده، ماهیت چک را تغییر میدهد. عامل نمیتواند سورسکد یک باینری را بخواند؛ بنابراین مجبور است با رابط تعامل کند: ابزار را اجرا کند و حکم را مشاهده کند. این کار باعث میشود رفتار «اول-اوراکل» (Oracle-first) بهصورت ساختاری اجباری شود، نه یک دکترین که مدل بتواند مخفیانه آن را دور بزند.
به زبان ساده، خروجی طراحیشدهی یک چک، همان حکم و متن اصلاحی آن است. سورسکد، پیادهسازی است، نه رابط. پنهان کردن پیادهسازی، اعتراف به ضعف چک نیست، بلکه یک انتخاب طراحی مشروع برای جلوگیری از مصرف سطح اشتباه توسط یک تولیدکنندهی احتمالی متن است. برای چنین خوانندهای (AI)، پیادهسازی خواندنی، کانالی است که با کانال طراحیشده رقابت میکند و در هزینهی ظاهری پیروز میشود اما در دقت شکست میخورد.
تعریف مرزها
برای جلوگیری از اصلاح بیشازحد، بسیار حیاتی است که بین آنچه باید پنهان شود و آنچه باید باقی بماند تمایز قائل شد. نویسنده در ابتدا پیشنهاد کرد دسترسی به هر دو موردِ «سندهای مشخصات» (Specification documents) و «سورسکد» مسدود شود. با این حال، جلسه نیمی از این پیشنهاد را رد کرد و اشاره کرد که مسدود کردن دسترسی به SPEC، اصل «سند-بر-سوابق» (Spec-over-precedent) را میشکند. بدون سند مالک به عنوان حقیقت بنیادین (Ground Truth)، عامل از فکر کردن زیاد دست نمیکشد، بلکه صرفاً شروع به حدس زدن از روی سوابق میکند.
مدل پیشنهادی از سه سطح مجزا استفاده میکند:
- خلاصه (The Brief)
- ماهیت: مکانیسم برای چیست و آیا باید به آن دست زد یا خیر.
- دسترسی: بله — حداکثر خوانایی داشته باشد. این حقیقت بنیادین است.
- پیادهسازی (The Implementation)
- ماهیت: حکم چگونه محاسبه میشود.
- دسترسی: خیر. این سطح باعث استنتاج در جایی میشود که مشاهده در دسترس بود.
- حکم و متن اصلاحی (The Verdict and Correction Text)
- ماهیت: کانال بازخورد طراحیشده.
- دسترسی: بله. این رابط اصلی است.
حذف خلاصه، مشکل عامل را حل نمیکند، بلکه فقط نوع شکست را تغییر میدهد. عامل بهجای پیشبینی چک، شروع به تقلید از آخرین تغییر مشابهی میکند که دیده است؛ یعنی تبدیل یک شکست گرانقیمت و آشکار به یک شکست ارزان و نامرئی. همانطور که در تحلیل نهایی یک جلسه ذکر شد: «سورسکد به شما میگوید یک چیز چه میکند، خلاصه به شما میگوید برای چه ساخته شده است، و تنها مورد دوم پاسخ میدهد که آیا باید به آن دست بزنید یا خیر».
تمایز از اصول دیگر
این استدلال را باید از سه مفهوم رایج مهندسی متمایز کرد:
۱. اصل کرکوفز (Kerckhoffs's Principle): این اصل میگوید یک سیستم باید حتی اگر طراحی آن عمومی باشد، امن بماند. اینجا بحث امنیت در برابر یک مهاجم خصمانه نیست، بلکه بحث هزینه برای یک خوانندهی همکار است. عامل در حال حمله به چک نیست، بلکه دارد کمکآورترین مسیر ظاهری را میگیرد. کدپنهانی در اینجا، یک مسیر غلط و وسوسهانگیز را از پیش روی یک همکار برمیدارد، نه یک آسیبپذیری را از یک مهاجم. این یک کدپنهانی سطحی است؛ سورسکد لازم نیست از دنیا مخفی باشد، فقط باید از درخت کاری که عامل میخواند حذف شود.
۲. قانون گودهارت (Goodhart's Law): مریلین استراترن این را چنین بیان کرد: «وقتی یک معیار تبدیل به هدف شود، دیگر معیار خوبی نیست». این توصیفِ بهینهسازی یک متریک بهجای خودِ آن چیزی است که متریک اندازهگیری میکند. اگر عاملی پیکربندی را ویرایش میکرد تا پیشدستی کند و چک را دور بزند، این یک شکست گودهارت بود. اما اینجا، عامل استنتاج را جایگزین مشاهده کرده است. معیار بهطور بد کیفیت شبیهسازی شده، نه اینکه بازی (Game) شود.
۳. منطق کامپایلر: هیچکس سورسکد یک کامپایلر را نمیخواند تا پیشبینی کند بیلد شکست میخورد یا نه؛ آنها کامپایلر را اجرا میکنند. تشخیص (Diagnostic) همان رابط است. اگرچه اکثر کامپایلرها متنباز هستند، اما کدپنهانیِ باینری در حین اجرا، مسیر وسوسهانگیز استنتاج را حذف میکند.
برگیتای بوکلر در گزارش خود درباره حسگرهای قابلیت نگهداری (Maintainability sensors)، خروجی یک چک را بهعنوان خودِ مکانیسم میبیند — بازخوردی که به عامل اجازه میدهد خودش را اصلاح کند، که او آن را «نوع خوبی از تزریق پرامپت» مینامد. نکته تکمیلی نویسنده این است که این کانال طراحیشده، رقیبی دارد: خودِ پیادهسازی حسگر که در همان مخزن کد قرار دارد.
موازنههای مهندسی و عملکرد
انتقال به باینریهای کامپایلشده مزایای ثانویهای هم دارد، هرچند در ابتدا هزینهها اشتباه تخمین زده شدند. توجیهات اولیه روی زمان واقعی (Wall-clock time) متمرکز بود، اما اندازهگیریها نشان داد که شروع پردازشهای چک تنها حدود یک درصد از کل زمان اجرا را میگیرد. حتی یک اصلاح دستهای در سطح شل (Shell-level batch fix) برای چکی که در هر صفحه یک مفسر تازه اجرا میکرد، از مدلهای اولیه باینری سریعتر بود.
با این حال، رویکرد کامپایلشده سه اهرم عملکردی قابل توجه ایجاد میکند که اسکریپتهای شل در پیادهسازی بهینه آنها مشکل دارند:
- موازیسازی: اجرای مجموعه چکها روی چندین هسته پردازنده (CPU cores).
- کشینگ (Caching): ذخیره نتایج یک چک بر اساس ورودیهایی که قبلاً اعلام کرده است.
- پیمایش مشترک (Shared Traversal): یک بار پیمایش مشترک از درخت ردیابی شده که دادهها را به nhiều خواننده میرساند، بهجای اینکه هر چک بهتنهایی درخت را پیمایش کند.
تنها هزینه، سد اعتماد برای پذیرندگان انسانی است. درخواست «این باینری مبهم را روی هر کامیت اجرا کن» سختتر از یک اسکریپت شل خواندنی است. راهکار این است که سورسکد عمومی و بیلد بازتولیدپذیر (Reproducible) باقی بماند و چکسامها (Checksums) منتشر شوند. اینگونه انسانها میتوانند کد را در یک مخزن عمومی بازرسی کنند یا خودشان آن را بیلد کنند تا آرتیفکت را تایید نمایند، در حالی که عامل در محیط کاری محدود به دریافت حکم است. این ادعای نازکتری نسبت به عبارت «باینری مبهم» است — این یک اصطکاک است، نه یک دیوار.
وضعیت فعلی و محدودیتها
انتقال به باینریهای کامپایلشده در حال حاضر یک ورودی به تعویق افتاده در نقشه راه است (ثبت شده در اواخر جولای) و با برچسب «در انتظار طراحی» (Design-pending) علامتگذاری شده است. بخشی از دلیل این است که این انتقال، درِ قابلیت گسترش سادهی اسکریپتهای شل را میبندد، جایی که کاربران میتوانند بهsimplicity یک اسکریپت جدید اضافه کنند.
تشخیص این الگوی غلط پیشبینی بر اساس چهار جلسه در بازه سه هفته از رونوشتها (Transcripts) است. اگرچه راهکار کدپنهانی ساختاری، اصطکاک را برای توسعهدهندگان انسانی افزایش میدهد، اما یک شکست تکرارشونده و خاص را حذف میکند: جایی که عاملها پیادهسازی را بهجای رابط میبینند، توکن میسوزانند و در این مسیر خطا ایجاد میکنند. برای پروژههای مشتری، این امر باعث میشود رفتار «اول-اوراکل» بهصورت ساختاری اجباری شود.
گام بعدی شما
- اگر از عاملهای کدنویسی برای نظارت بر مخازن خود استفاده میکنید، دسترسی آنها به سورسکد اسکریپتهای تست را محدود کنید.
- خروجیهای ابزارهای تست را بهگونهای طراحی کنید که حاوی «متن اصلاحی» دقیق باشد تا مدل نیاز به حدس زدن نداشته باشد.
- برای ابزارهای حیاتی، بهجای اسکریپتهای متنی، از ابزارهای کامپایلشده استفاده کنید تا مدل را مجبور به تعامل با رابط (Interface) کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو