اگر ساعتها وقت خود را صرف اسکرول کردن در هزاران خط خروجی استاندارد (stdout) برای یافتن دلیل شکست یک عامل هوش مصنوعی میکنید، باید بدانید که جستجو در این حجم از داده شبیه به گشتن به دنبال سوزنی در انبار کاهی است که مدام در حال رشد است. شکستهای این سیستمها بهندرت با یک خطای واضح (Exception) اعلام میشوند. طبق پیشنهادی که در ۴ سپتامبر ۲۰۲۶ در وبسایت dev.to منتشر شد، این خطاها در قالب پدیدهای به نام «رانش» (Drift) ظاهر میشوند.
بسیاری از توسعهدهندگان با لاگهای عاملها مانند یک دفترچه خاطرات برخورد میکنند، اما یک دفترچه خاطرات، ابزار تشخیص (Diagnosis) نیست. وقتی یک عامل فراخوانی یک ابزار حیاتی را نادیده میگیرد یا بهجای اصلاح (Patch) یک فایل، کل آن را بازنویسی میکند، لاگها همچنان متنی عادی به نظر میرسند. این موضوع یک شکاف دیدهشدگی ایجاد میکند؛ بهطوری که یک اجرا ممکن است گزارش «موفقیت» بدهد، اما اثرات جانبی واقعی — یعنی فایلهای تغییریافته و ابزارهای فراخوانیشده — با مسیر موردنظر متفاوت باشد. در این حالت، ممکن است در نوبت دوم مدل، محدودیتی را ابداع کند که در نوبت اول هرگز بیان نشده بود. این چالش دقیقاً همان نقطهای است که در آن لاگهای ابزاری صرفاً ادعاهایی توخالی هستند و نه مدرکی بر اجرای واقعی. اگر شما فقط خروجی استاندارد (stdout) را دنبال کنید، این اتفاقات نامرئی هستند، اما اگر کارتهای ساختاریافته را با هم مقایسه (Diff) کنید، این خطاها شبیه به یک تست شکستخورده ظاهر میشوند.
برای حل این مشکل، مفهوم «کارت اجرا» (Run Card) معرفی شده است. این سیستم بهجای ذخیره رمانهای طولانی از لاگها، یک خلاصه داستان (Plot Summary) ذخیره میکند. در واقع، هر اجرای عامل مانند یک کامیت در گیت (Git) در نظر گرفته میشود و اجرای فعلی با یک اجرای مرجع یا «فیکسچر والد» (Parent Fixture) مقایسه میشود تا دقیقاً نقطه انحراف منطق مشخص شود. این رویکرد حیاتی است زیرا ماهیت غیرقطعی (Non-determinism) مدلها، اهمیت اجرای مرجع را دوچندان میکند. دو اجرا میتوانند هر دو گزارش موفقیت بدهند، اما در ترتیب ابزارها، مسیرهای دسترسی یا هش فایلهای تغییریافته با هم متفاوت باشند. در اینجا، سیگنال «موفقیت» یک سیگنال ضعیف است، اما «توافق کانالها» سیگنالی قدرتمند است. سیگنالهای ضعیف باعث اتلاف زمان در تلاشهای مجدد (Retries) میشوند، در حالی که سیگنالهای قوی به شما میگویند که کدام تلاش مجدد واقعاً ارزش اجرا کردن دارد.
همانطور که در تحلیلهای پیشین ما دربارهی چالشهای مشاهدهپذیری در سیستمهای عاملمحور اشاره کردیم، تکیه بر خروجیهای متنی برای سیستمهای پیچیده یک ریسک است. این ریسک زمانی بحرانی میشود که عاملها دستورات ایمنی حیاتی را نادیده بگیرند، اتفاقی که در چارچوبهای فعلی مدیریت پرداخت مشاهده شده است.
معماری چهارکاناله
روش کارت اجرا بر چهار کانال داده مجزا متکی است که هر کدام به یک اثر انگشت SHA-256 تبدیل میشوند تا مقایسه بین ماشینهای مختلف ممکن شود. فلسفه اصلی این است که هیچ کانالی نباید جایگزین کانال دیگر شود. اگر یک کانال مفقود باشد، کارت ناقص است و مقایسه باید با شکست مواجه شود (Fail Closed). یک لاگ سبز بدون ردپای ابزار، یک موفقیت نیست، بلکه یک شکاف در ابزارگذاری است که لباس موفقیت پوشیده است.
- لاگها: یک خلاصه پایدار شامل نام لاگر، سطح خطا و رویداد، به همراه یک کلاس خطای اختیاری. این بخش حجم توکنها را نادیده میگیرد و روی نقاط کلیدی داستان تمرکز میکند. حجم لاگ با تلاشهای مجدد، استریم توکنها و چاپهای کمکی رشد میکند، اما علیت (Causality) رشد نمیکند. یک کپچر ۴۰۰۰ خطی میتواند یک اشتباه تکخطی را پنهان کند: مثلاً عامل دو بار
read_fileرا فراخوانی کرده، هرگزapply_patchرا اجرا نکرده، اما در نهایت عبارت «انجام شد» را چاپ کرده است. - فراخوانی ابزارها: توالی نام ابزارها، اثر انگشت آرگومانها و وضعیت خروجی. این کانال متوجه میشود چه زمانی منطق عامل از توالی ابزارهای پایه منحرف شده است.
- تغییرات سیستم فایل: فهرستی از مسیرها و هش محتوا. این بخش معمولاً خروجی
git diff --rawاست (زمانی که درخت کاری از قبل یک گیت چکاوت است) و تشخیص میدهد که آیا فایلی خارج از محدوده ثبتشده ابزارهای عامل تغییر کرده است یا خیر. در واقع، استفاده از هشها برای محافظت از محتوا، مشابه روشی است که هشهای blob برای جلوگیری از بازنویسی ناخواسته روایتهای انسانی توسط AI به کار میروند. - نوبتهای مدل: سوابقی از نقش (Role)، هش SHA-256 محتوا و تعداد کاراکترها. این کار باعث میشود تکمیلهای خارج از کنترل (Runaway completions) بدون نیاز به ذخیره کل متن پرامپت، قابل شناسایی باشند.
زمینه: منطق مقایسه (Diff)
انسانها حجم زیاد لاگها را با اسکرول کردن جبران میکنند، اما ماشینها نمیتوانند. استعاره بهتر، کنترل نسخه است. هیچکس یک کامیت را با خواندن تکتک بایتهای درخت کاری بررسی نمیکند، بلکه تغییرات را نسبت به والد بررسی میکند. اجراهای عامل نیز به همین والد نیاز دارند؛ در غیر این صورت، شما در حال خواندن یک کامیت یتیم هستید و آن را مشاهدهپذیری مینامید.
اختلاف بین کانالها بسیار آموزندهتر از یک شکست کلی است. تبدیل این الگوها به عبارت سادهی «عامل شکست خورد»، باعث اتلاف زمان در اجرای بعدی میشود. با جداسازی کانالها، میتوان ماهیت دقیق باگ را شناسایی کرد.
زمینه: چرا حجم به معنای علیت نیست
حجم لاگ یک معیار فریبنده است. یک فایل لاگ حجیم به معنای عملیات پیچیده یا موفق نیست. در بسیاری از موارد، حجم زیاد صرفاً نتیجه استریم توکنها یا چاپهای تکراری کمکی است.
علیت — یعنی زنجیره واقعی رویدادها که منجر به یک نتیجه میشود — اغلب در یک خط نهفته است. وقتی توسعهدهندهای ۴۰۰۰ خط را برای یافتن یک فراخوانی گمشده apply_patch میگردد، در واقع در حال انجام یک Diff دستی است. کارت اجرا این فرآیند را با تبدیل اجرا به یک شیء ساختاریافته بهجای یک جریان متنی، خودکار میکند.
جزئیات: الگوهای شکست
وقتی کانالها از هم فاصله میگیرند، ترکیب خاص این حرکات دقیقاً میگوید چه چیزی خراب شده است:
- کار روایتشده (Narrated Work): لاگها موفقیت را اعلام میکنند اما فایلها ثابت ماندهاند. عامل کاری را روایت کرده که در واقع انجام نداده است.
- شکست توزیعکننده (Dispatcher Failure): ابزارها تغییر کردهاند اما فایلها ثابت ماندهاند. توزیعکننده اجرا شده اما اصلاحیه (Patch) اعمال نشده است.
- تغییر خارجی (External Mutation): فایلها تغییر کردهاند اما ابزارها هیچ عملیات نوشتنی ثبت نکردهاند. چیزی خارج از محدوده ثبتشده، درخت فایل را تغییر داده است.
جزئیات: مکانیزم کارت
برای پیادهسازی این سیستم، از یک ساختار دادهای خاص استفاده میشود. RunCard حاصل پیوند چهار کانال است و حکم نهایی، حاصل Diff دو کارت است.
- اثر انگشتگیری: سیستم از
_sha(SHA-256) برای محتوا و_fingerprint(هش SHA-256 مرتبشده در JSON) برای اشیاء استفاده میکند. - مهر و موم کردن (Sealing): قبل از ذخیره در دیسک، کارت «مهر و موم» میشود. این فرآیند چهار هش کانال را تولید میکند که به عنوان شاخص اصلی برای مقایسه عمل میکنند.
- شواهد در مقابل هویت: کارت شواهد دقیق (مانند میلیثانیههای اجرای ابزار) را ذخیره میکند اما این دادهها را از «هویت» کانال حذف میکند. این کار تضمین میکند که تغییر جزئی در سرعت اجرا باعث تحریک یک شکست منطقی نشود.
تبدیل مشاهدهپذیری به تست
با هش کردن این کانالها، توسعهدهنده میتواند با ابزاری مانند diffcard.py دو اجرا را مقایسه کند. اگر هش ابزارها تغییر کند، منطق عامل تغییر کرده است. اگر هش فایلها تغییر کند، نتیجه تغییر کرده است. این رویکرد اجازه «رانش مجاز» (Allowed Drift) را میدهد؛ مثلاً توسعهدهنده میتواند تغییر در هش نوبتهای مدل (متن تولید شده توسط مدل) را بپذیرد اما اصرار کند که هش ابزارها و فایلها دقیقاً یکسان بماند. این کار، تولید توکنهای نویزی را از اثرات جانبی حیاتی جدا میکند. متن توکنها نویزی است، اما اثرات جانبی نیستند.
پیادهسازی و محدودیتها
این چارچوب بهگونهای طراحی شده که وابستگیهای کمی داشته باشد و با هر نقطه انتهایی (Endpoint) سازگار با OpenAI کار کند. این یک ابزار محلی (Local Harness) است، نه یک مطالعه موردی تولیدی، و هدف این است که در یک مخزن کپی شده و به یک Endpoint موجود متصل شود. این سیستم دادهها را در چهار مرز ثبت میکند: فیلتر لاگ، توزیعکننده ابزار، درخت کاری و کلاینت چت.
برای جلوگیری از «شکستهای کاذب»، سیستم پیشنهاد میکند کلیدهای پایدار در آرگومانهای ابزار در لیست سفید قرار گیرند. اگر یک فراخوانی ابزار شامل برچسب زمانی (Timestamp) یا ID تصادفی درخواست باشد، هش کردن کل دیکشنری باعث میشود هر اجرا متفاوت به نظر برسد. کلاس RunRecorder با حذف کلیدهایی مانند ts یا request_id قبل از اثر انگشتگیری، این مشکل را حل میکند.
تأخیر (Latency) به عنوان شاهد ذخیره میشود اما از هویت کارت حذف میگردد. این تفکیک در استفاده از سرویسهای رایگان که تأخیر صف بالاست، حیاتی است؛ در غیر این صورت، شما بهجای عیبیابی منطق عامل، در حال عیبیابی زمانبند (Scheduler) سرور خواهید بود که این یک حادثه متفاوت است.
پروژه MonkeyCode این منطق را در محصولات خود ادغام کرده و دسترسی رایگان به مدلها و سرورهایی برای میزبانی این حلقههای ثبت فراهم کرده است. با این حال، نویسنده هشدار میدهد که تکیه بر صفهای رایگان، کارتهایی درباره تأخیر صف تولید میکند، نه منطق عامل. این موارد باید در دسته «ظرفیت» (Capacity) ثبت شوند، نه منطق عامل. این روش به جایی ارزانقیمت برای تولید کارت دوم نیاز دارد، اما یک باکس میزبانیشده، ردپاها را علّی نمیکند. اگر از قبل یک Endpoint سازگار با OpenAI دارید، میتوانید همین ثبتکننده را به آن متصل کنید؛ فایل حکم نهایی اهمیتی نمیدهد که کدام فروشنده نوبتها را هش کرده است.
گردش کار عملی و مثالها
فرآیند شامل ایجاد یک نمونه مرجع (Fixture) و مقایسه اجراهای کاندید با آن است. یک توالی دستورات در خط فرمان به این شکل است:
mkdir -p fixtures artifacts worktreepython -m agent_runner --worktree ./worktree --out fixtures/run_base.jsonpython -m agent_runner --worktree ./worktree --out artifacts/run_cand.jsonpython diffcard.py fixtures/run_base.json artifacts/run_cand.json
یک کارت مرجع بهقدری کوچک است که در جریان بررسی کد (Code Review) قابل خواندن باشد. یک شکل JSON معمولی شامل run_id، چهار هش کانال، فهرستی از فراخوانیهای ابزار (با args_fp و ms) و عملیات فایل (مسیر، نوع عملیات و content_fp) است.
سپس انسان میتواند یک حکم تکخطی کنار JSON بنویسد، مثلاً: run_id=cand-014 verdict=FAIL unexpected=files tools=read_file,read_file,apply_patch files=src/app.py:mod notes=assistant claimed patch applied; worktree hash unchanged on first attempt.
محدودیتهای روش
این سیستم یک راهکار جادویی نیست. این روش پرامپتها را بازسازی نمیکند، صحت عملکردی را اثبات نمیکند و جایگزین Spanهای والد-فرزند نمیشود. همچنین برای عاملهایی که بدون تغییر در فایلها رفتار میکنند (مانند طبقهبندیکنندههای متنی که فقط چت میکنند)، نامناسب است زیرا کانال فایلها ساختاری خالی میماند و داشبورد در حالی که عامل شکست خورده، سبز میماند.
سایر محدودیتهای فنی عبارتند از:
- ریسک تصادم (Collision Risk): اگر دو اصلاحیه متفاوت در یک خلاصه کوتاه تصادم کنند، ممکن است شکست به اشتباه «پاس» شود؛ بنابراین هشهای کامل SHA-256 باید در مخازن نهایی ذخیره شوند.
- دامنه (Scope): فرض بر یک درخت کاری و یک فرآیند است. جابهجایی بین چندین عامل به
run_idوالد نیاز دارد که در این طرح فعلی پیاده نشده است. - امنیت: نباید در جایی استفاده شود که اسنپشات فایلها ممکن است اسرار (Secrets) را در کارت کپی کند.
- تحلیلها (Analytics): این سیستم برای تغذیه تحلیلهای محصول (Product Analytics) در نظر گرفته نشده است.
علاوه بر این، این روش یک مدل غیرقطعی را قطعی نمیکند، بلکه صرفاً آن غیرقطعی بودن را در کانالهای انتخابی مرئی میکند. هدف این است که با یک هش تغییریافته در ابزارها، همانگونه برخورد شود که توسعهدهنده با تغییر در یک lockfile برخورد میکند: یا تغییر را توضیح دهد یا آن را بازگرداند.
این تغییر، توسعه عاملها را از تستهای «حسی» (Vibes-based) به یک تمرین مهندسی دقیق و تحت کنترل نسخه منتقل میکند. با تمرکز بر اثرات جانبی بهجای جریان توکنها، توسعهدهندگان میتوانند اسکرول کردن را متوقف کرده و مقایسه (Diff) را آغاز کنند.
گام بعدی شما
- اگر در حال توسعه عاملهای پیچیده هستید، بهجای تکیه بر لاگهای متنی، یک سیستم ثبت اثر انگشت (Fingerprinting) برای خروجیهای فایل و ابزارها پیاده کنید.
- برای هر قابلیت جدید، یک «اجرای مرجع» (Golden Run) ایجاد کنید و هر تغییر در مدل یا پرامپت را با آن Diff کنید تا رانش منطقی را شناسایی کنید.
- در ابزارهای ثبت خود، متغیرهای نویزی مانند Timestamp را فیلتر کنید تا نرخ شکستهای کاذب کاهش یابد.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو