فاز 19 · درس 27

طراحی بستر ارزیابی ایجنت‌های هوش مصنوعی با وظایف آزمایشی ثابت

نوع
ساختنی
زمان
حدود 90 دقیقه
زبان‌ها
Python (stdlib)
پیش‌نیاز
فاز 19 · درس 25 (گیت‌های اعتبارسنجی)، فاز 19 · درس 26 (اجراکننده‌ی ساندباکس)، فاز 14 · درس 30 (توسعه‌ی ایجنت مبتنی بر ارزیابی)، فاز 14 · درس 19 (بنچمارک‌های SWE-bench و GAIA)
یک ترازو و ابزار دقیق اندازه‌گیری فلزی که در کنار برگه‌های چک‌لیست و قطعات کد برای سنجش خودکار قرار گرفته است
فهرست مطالب
  1. اهداف یادگیری
  2. صورت مسئله
  3. مفاهیم پایه
  4. معماری سیستم
  5. پیاده‌سازی از صفر
  6. چرا pass@k به جای اکتفا به pass@1؟
  7. هماهنگی با سایر بخش‌های مسیر A
  8. اجرای پروژه

توسعه‌ی ایجنت‌های کدنویسی بدون یک چارچوب سنجش دقیق، شبیه برنامه‌نویسی بدون تست واحد است. وقتی یک پرامپت یا مدل زبانی را تغییر می‌دهید، چطور مطمئن می‌شوید که عملکرد کلی سیستم بهبود یافته و دچار افت کیفیت (Regression) نشده است؟ تکیه بر بررسی دستی کدها یا ادعای خود ایجنت مبنی بر حل مسئله، به‌سرعت به خطاهای پنهان در محیط عملیاتی ختم می‌شود.

در این درس یک بستر ارزیابی (Eval Harness) کامل می‌سازید که مجموعه‌ای از وظایف آزمایشی ثابت (Fixture Tasks) را روی ایجنت اجرا می‌کند، با اعتبارسنج‌های قطعی نتیجه را می‌سنجد و معیارهای کلیدی مانند pass@1، pass@k، تاخیر زمانی و هزینه‌ی توکن‌ها را استخراج می‌کند تا منبع حقیقت پایداری برای سنجش تغییرات داشته باشید.

یک ایجنت کدنویسی دقیقاً به همان اندازه‌ای خوب است که مجموعه‌ی وظایف سنجش آن خوب باشد. در این درس، یک بستر ارزیابی (Evaluation Harness) می‌سازیم که پوشه‌ای از وظایف ثابت (Fixture Tasks) را می‌گیرد، هرکدام را روی یک ایجنت کاندید اجرا می‌کند، قبولی یا رد شدن را با یک مدل اعتبارسنج (Verifier) قطعی می‌سنجد و نتایج را در قالب شاخص‌های pass@1، pass@k، میانگین تاخیر (Latency) و میانگین هزینه تجمیع می‌کند. این بستر آزمایشی همان منبع حقیقت (Source of Truth) شماست که تفاوت بین یک افت کیفیت (Regression) و یک بازآفرینی کد (Refactor) را مشخص می‌کند.

اهداف یادگیری

  • تعریف وظیفه‌ی ثابت به‌صورت سه‌گانه‌ای (Triple) از هدف (Goal)، راه‌اندازی (Setup) و اعتبارسنج (Verifier).
  • امتیازدهی به چندین اجرای نمونه برای هر وظیفه و محاسبه‌ی pass@1 و pass@k.
  • تجمیع تاخیر و هزینه در قالب معیارهای میانگین و صدک 95ام.
  • اتصال اعتبارسنج‌های قطعی (تفاوت فایل، کد خروجی، تطابق رگکس) به توابعی با قابلیت استفاده‌ی مجدد.
  • ارائه‌ی یک گزارش ساختاریافته‌ی JSON که اسکریپت‌های رهگیری افت کیفیت بتوانند آن را دریافت و پردازش کنند.

صورت مسئله

سه حالت شکست (Failure modes) گریبان‌گیر بنچمارک‌های ایجنتی می‌شود که بدون بستر ارزیابی ساخته شده‌اند:

اولی قبولی تاییدنشده است. ایجنت ادعا می‌کند باگ را برطرف کرده، انسان نگاهی گذرا به تفاوت فایل‌ها (Diff) می‌اندازد، تست‌ها سبز ثبت می‌شوند و سه هفته بعد، تست‌های ارزیابی افت کیفیت همان باگ را دوباره رو می‌کنند. ایجنت استدلالی به‌ظاهر موجه ارائه داده بود، بدون اینکه در عمل چیزی را درست کرده باشد.

دومی افت کیفیت پنهان است. تغییری در قالب پرامپت (Prompt template) ایجنت را روی وظیفه‌ای پرسرصدا 4% بهتر و روی وظیفه‌ای بی‌سرصدا 14% بدتر می‌کند. بدون یک مجموعه‌ی مرجع و معتبر (Goldset) و نمره‌ی مجزا برای هر وظیفه، این افت کیفیت راهی شاخه‌ی اصلی پروژه (Main) می‌شود و فقط وقتی صدای مشتری درآمد خودش را نشان می‌دهد.

سومی انحراف معیارهای مقایسه در طول زمان است. ارزیابی روز دوشنبه با 100 وظیفه اجرا شده و روز جمعه با 95 تا، چون یک نفر نام پنج وظیفه‌ی ثابت را عوض کرده است. در ظاهر، نرخ قبولی (Pass Rate) نشان‌دهنده‌ی 5% بهبود است؛ اما در واقعیت این‌طور نیست.

بستر آزمایشی همان برنامه‌ای است که این ناکامی‌ها را به داده‌های واقعی و مستند تبدیل می‌کند. این بستر تک‌تک وظایف ثابت را، هر بار با ترتیبی تکرارپذیر، در برابر اعتبارسنجی اجرا می‌کند که بر اساس یک بررسی قطعی، فقط درست یا غلط برمی‌گرداند.

مفاهیم پایه

fixtures/task_001/task.json + expected/بستر آزمایشیبرای هر وظیفه:راه‌اندازی / اجرای ایجنت k نمونه /اعتبارسنجی هر نمونه /ثبت تاخیر و هزینهfixtures/task_002/...EvalReportpass@1 / pass@kمیانگین ms / صدک p95 msمیانگین هزینه

یک FixtureTask شامل یک فایل JSON کوچک به‌همراه یک پوشه‌ی اختیاری به نام expected/ است. فایل JSON مواردی چون id، بخش goal (همان پرامپت ارائه‌شده به ایجنت)، بلوک setup (فایل‌هایی که باید در دایرکتوری کاری موقت قرار گیرند) و بلوک verifier را تعریف می‌کند. بلوک اعتبارسنج نام تابعی را در رجیستری اعتبارسنج‌های بستر مشخص کرده و آرگومان‌هایش را به آن می‌رساند.

سه نوع اعتبارسنج بخش اعظم وظایف کاربردی را پوشش می‌دهند:

اولین مورد file_equals است. پس از اجرای ایجنت، فایل مشخصی را با محتوای مورد انتظار مقایسه می‌کند. این اعتبارسنج مخصوص وظایف از نوع «این باگ را دقیقاً به همین شیوه برطرف کن» است.

دومین مورد regex_match است. محتوای فایل مشخص‌شده با یک عبارت منظم (Regex) سنجیده می‌شود. این حالت وظایف از نوع «تابع باید وجود داشته باشد و مقدار X را برگرداند» را پوشش می‌دهد که در آن‌ها راه‌حل‌های متعددی قابل‌قبول هستند.

سومین مورد shell_exit_zero است. بستر آزمایشی دستوری را در شل (از طریق ساندباکسِ درس 26) اجرا می‌کند و تنها در صورتی وظیفه را قبول در نظر می‌گیرد که کد خروجی دستور صفر باشد. این اعتبارسنج به درد وظایف از نوع «تست‌ها باید پاس شوند» می‌خورد.

بستر آزمایشی هر وظیفه را k بار اجرا می‌کند. فرمول pass@k برابر است با 1 - (1 - p)^k که در آن p نرخ قبولی تجربی است؛ بستر برای بررسی واریانس، تعداد دفعات خام را هم گزارش می‌دهد. تاخیر، زمان واقعی اجرای هر نمونه است. هزینه هم همان مقداری است که خود ایجنت گزارش می‌دهد (تعداد توکن، دلار یا هر دو)؛ بستر آزمایشی این هزینه را روی نمونه‌ها جمع می‌زند و اعداد تجمیعی و مجزای هر وظیفه را ارائه می‌کند.

معیار PASS @ Kp و k را بکشید
PASS @ KPass@k asks whether at least one of k independent samples solves the task. If each try succeeds with probability p, all k fail with probability (1-p)^k, so pass@k is one minus that. Even a weak model climbs steeply with more samples, which is why best-of-k is such a cheap lever and why pass@1 and pass@k tell different stories.
معیار pass@k بررسی می‌کند که آیا حداقل یکی از k نمونه‌ی مستقل، وظیفه را حل می‌کند یا خیر. اگر هر تلاش با احتمال p موفق شود، تمام k تلاش با احتمال k^(p-1) شکست می‌خورند؛ بنابراین pass@k برابر است با یک منهای آن مقدار. حتی یک مدل ضعیف نیز با افزایش تعداد نمونه‌ها جهش چشمگیری پیدا می‌کند؛ به همین دلیل است که رویکرد best-of-k راهکاری بسیار ارزان بوده و pass@1 و pass@k حقایق متفاوتی را بازگو می‌کنند.

معماری سیستم

بارگذاریتجمیعEvalHarnessFixtureTaskهدف / راه‌اندازی / مدل اعتبارسنجبرای هر وظیفه:آماده‌سازی دایرکتوری موقت از setupبه ازای هر نمونه در بازه k:اجرای وظیفه کاندیدا، scratch_dir ->SampleResultاعتبارسنجی نمونه، task -> boolثبت تجمیعی به ازای هر وظیفهTaskReporttask_id / k / قبولی‌ها / نرخ قبولیمیانگین تاخیر / میانگین هزینهEvalReportکل وظایف / pass@1 / pass@k / تاخیرp95

کاندید یک موجودیت قابل‌فراخوانی است: Callable[[FixtureTask, str], SampleResult]. بستر آزمایشی دایرکتوری کاری موقت را با tempfile.mkdtemp() می‌سازد و مسیرش را در قالب یک رشته ساده تحویل می‌دهد. بستر کاری ندارد که کاندید پشت صحنه چطور کار می‌کند. این کاندید می‌تواند یک اعمال‌کننده‌ی قطعیِ تکه کدها (Patch) باشد (که برای خودآزمایی بستر مفید است)، یک ایجنت واقعیِ مبتنی بر مدل زبانی، یا یک فازر (Fuzzer). آنچه بین آن‌ها برقرار است صرفاً قرارداد SampleResult است.

پیاده‌سازی از صفر

فایل main.py شامل این بخش‌هاست:

  1. دیتاکلاس FixtureTask.
  2. دیتاکلاس SampleResult: شامل success_self_reported، latency_ms، cost_units و edits.
  3. دیتاکلاس‌های TaskReport و EvalReport با متد to_dict().
  4. کلاس VerifierRegistry برای نگاشت نام اعتبارسنج به تابع مربوطه. اعتبارسنج‌های پیش‌فرض: file_equals، regex_match و shell_exit_zero.
  5. کلاس EvalHarness که یک دایرکتوری از وظایف را در برابر یک کاندید اجرا می‌کند و خروجی EvalReport می‌دهد.
  6. پنج وظیفه‌ی آزمایشی ثابت که در پوشه‌ی tasks/ قرار دارند:
    • خطای مرتبه‌ی یک (Off-by-one) در fizzbuzz
    • نبود return در تابع factorial
    • غلط املایی در پیام خطا
    • بدنه‌ی خالی یک تابع
    • خطای مرتبه‌ی یک در پیمایش لیست پیوندی
  7. یک کاندید مرجعِ قطعی (apply_known_fixes) که بستر آزمایشی برای اثبات عملکرد و کسب pass@1 معادل 1.0 از آن استفاده می‌کند.
  8. دمویی که گزارش نهایی EvalReport را به شکل JSON چاپ کرده و با کد صفر خارج می‌شود.

وظایف ثابت به‌شکل فایل‌های JSON درون tasks/ و فایل‌های منبع متناظر درون tasks/<id>/buggy/ و tasks/<id>/expected/ سازمان‌دهی شده‌اند. بستر آزمایشی پوشه‌ی buggy را در یک دایرکتوری کاری موقت کپی می‌کند، آن را تحویل کاندید می‌دهد و نتیجه را در برابر expected اعتبارسنجی می‌کند.

چرا pass@k به جای اکتفا به pass@1؟

ایجنت‌های واقعیِ مبتنی بر مدل‌های زبانی رفتاری تصادفی دارند. کسب pass@1 معادل 0.6 در نگاه اول شکست به نظر می‌رسد. اما pass@5 معادل 0.95 نشان می‌دهد که ایجنت در اکثر مواقع به پاسخ درست می‌رسد، فقط در تلاش‌های اولیه انتخاب اشتباهی می‌کند. راه‌حل این مشکل استفاده از روش‌های نمونه‌گیر (Sampler) و رتبه‌بندی (Rank) است، نه لزوماً آموزش بیشتر مدل. معیار pass@k این موضوع را شفاف می‌کند.

شاخص pass@k همیشه در کنار pass@1 گزارش می‌شود؛ زیرا pass@k می‌تواند روی یک نقص واقعی سرپوش بگذارد: اگر مدلی در هر بیست بار تلاش فقط یک بار جواب درست بدهد، با یک ایجنت کاربردی طرف نیستید. بستر آزمایشی هر دو زاویه را نشان می‌دهد.

هماهنگی با سایر بخش‌های مسیر A

در درس 25 زنجیره‌ی گیت‌های کنترلی (Gates) را ساختیم. درس 26 ساندباکس (Sandbox) را اضافه کرد. بستر آزمایشی برای هر اعتبارسنج shell_exit_zero از این ساندباکس استفاده می‌کند. در درس 28 هر بار اجرای بستر را درون یک ردگیری محاسبات (Trace) مربوط به OTel قرار می‌دهیم. در نهایت درس 29 دموی سرتاسری (End-to-end) را در برابر یکی از وظایف ثابت موجود اجرا می‌کند و pass@1 = 1.0 را برای کاندید مرجع اعتبارسنجی خواهد کرد.

اجرای پروژه

cd phases/19-capstone-projects/27-eval-harness-fixture-tasks
python3 code/main.py
python3 -m pytest code/tests/ -v

این دمو گزارش نهایی EvalReport را به‌صورت JSON چاپ می‌کند که شامل pass@1، pass@5، میانگین تاخیر و تفکیک عملکرد در هر وظیفه است. کد خروجی برنامه صفر خواهد بود. تست‌ها توابع اعتبارسنج، محاسبات ریاضی pass@k، بارگذاری وظایف ثابت و اجرای سرتاسری بستر ارزیابی در برابر کاندید مرجع را پوشش می‌دهند.

خودآزمایی

به سؤال‌ها جواب بدهید تا ببینید چقدر از درس در ذهنتان مانده است.

  1. پیش از درسپیش از مطالعه درس: یک مدل اعتبارسنج خوب برای ارزیابی ایجنت بیش از هر چیز به چه ویژگی‌ای نیاز دارد؟
  2. حین درسیک کاندیدا در یک وظیفه منفرد در 5 نمونه موفق به کسب 3 قبولی می‌شود. فرمول pass@5 ارائه شده در درس چه مقداری را بازمی‌گرداند (گردشده تا دو رقم اعشار)؟
  3. حین درسچرا در گزارش درس، هر دو معیار pass@1 و pass@k گنجانده شده‌اند؟
  4. حین درسبستر آزمایشی (harness) قبل از هر نمونه متد _prepare_scratch را صدا می‌زند. چرا این کار برای pass@k > 1 حیاتی است؟
  5. پس از درسشما یک مدل اعتبارسنج جدید با نام 'pytest_passes' اضافه می‌کنید که pytest را در دایرکتوری موقت اجرا می‌کند. باید آن را بر پایه کدام مدل اعتبارسنج موجود بسازید؟
  6. پس از درسیک بازبین می‌پرسد: «آیا این پس‌رفت ناشی از مدل است یا ناشی از بستر آزمایشی؟» کدام دست‌سازه به این پرسش پاسخ می‌دهد؟

سؤالات متداول

چرا در ارزیابی ایجنت‌ها به pass@k نیاز داریم و pass@1 کافی نیست؟

مدل‌های زبانی رفتاری تصادفی و غیرقطعی دارند؛ ممکن است یک مدل با pass@1 پایین، در تلاش‌های بعدی پاسخ درست را بیابد (pass@k بالا). این معیار مشخص می‌کند آیا مشکل مدل با نمونه‌گیری و رتبه‌بندی حل می‌شود یا نیازمند بازآموزی اساسی است.

یک وظیفه‌ی ثابت (Fixture Task) از چه بخش‌هایی تشکیل شده است؟

هر وظیفه‌ی ثابت شامل سه‌گانه‌ی هدف (پرامپت ارائه شده به ایجنت)، راه‌اندازی (فایل‌های اولیه‌ی محیط آزمایشی) و بلوک اعتبارسنج قطعی برای تایید درستی پاسخ است.

اعتبارسنج‌های قطعی در بستر ارزیابی چگونه کار می‌کنند؟

این اعتبارسنج‌ها بر اساس بررسی‌های مشخص و بدون اتکا به قضاوت احتمالی مدل کار می‌کنند؛ مانند تطابق دقیق فایل با پاسخ مرجع (file_equals)، تطبیق الگو با عبارات منظم (regex_match) یا موفقیت در اجرای دستورات شل و تست‌ها با کد خروجی صفر (shell_exit_zero).

ما رو توی گوگل بیشتر ببین

با افزودن نکست ادمین به «منابع ترجیحی» گوگل، درس‌ها و مطالب ما را در بخش اخبار برتر جستجو بیشتر می‌بینید.