SSD Nodes Learn 🎉 VPS از $5.50/ماه
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-08-13

پیاده‌سازی ارزیابی خودمیزبان برای ایجنت‌های هوش مصنوعی

با ساخت یک چرخه ارزیابی خودمیزبان، عملکرد ایجنت خود را با استفاده از SQLite و Python بسنجید. به جای حدس و گمان، نرخ قبولی دقیق را در هر commit مشاهده و تغییرات را ردیابی کنید.

ارزیابی‌های خودمیزبان (self-hosted) برای ایجنت‌های هوش مصنوعی چیست

ارزیابی‌های خودمیزبان برای ایجنت‌های هوش مصنوعی شامل چهار موردی است که در مخزن (repository) خود نگهداری می‌کنید: فایلی از نمونه‌های ذخیره‌شده، اسکریپتی که ایجنت را روی آن‌ها اجرا می‌کند، مجموعه‌ای از بررسی‌ها که به هر پاسخ نمره می‌دهد، و جدولی از نتایج که می‌توانید آن را پرس‌وجو کنید. هیچ‌کدام از موارد این لیست نیازی به فروشنده (vendor) ندارد. کل این چرخه تنها چند صد خط کد Python و یک فایل SQLite است.

ایجنت در دمو کار می‌کرد چون شما خودتان آن 5 ورودی را انتخاب کرده بودید. در هفته دوم از کار افتاد چون یک خط از prompt تغییر کرد، یا مدل عوض شد، یا توضیحات یک ابزار تغییر کرد و هیچ معیاری این موارد را پوشش نمی‌داد. یک چرخه ارزیابی، جمله «حس می‌کنم الان بدتر شده» را به «نرخ قبولی در commit 4f1c9ab از 58 از 60 به 51 از 60 کاهش یافت» تبدیل می‌کند.

این چرخه چهار مرحله دارد و این راهنما برای هر مرحله یک بخش در نظر گرفته است: جمع‌آوری ردپاهای (traces) واقعی، ارتقای موارد جالب به نمونه‌های آزمایشی، نمره‌دهی به هر نمونه در هر تغییر، و ذخیره نرخ قبولی در کنار commit که آن را ایجاد کرده است. همین چرخه فارغ از اینکه ایجنت را روی چه چیزی اجرا می‌کنید کار می‌کند و فریم‌ورک‌های ایجنت خودمیزبانی که ارزش اجرا دارند عمدتاً در میزان ردپایی که به‌صورت رایگان در اختیار شما قرار می‌دهند، با هم تفاوت دارند.

چرا ایجنت در هفته دوم از کار می‌افتد

یک ایجنت شامل پرامپت، مدل، مجموعه‌ای از تعاریف ابزار و هر نوع متنی است که در زمان اجرا بازیابی می‌شود. هر چهار مورد می‌توانند بدون تغییر در کد برنامه شما تغییر کنند؛ بنابراین در یک بازبینی کد معمولی، هیچ مورد مشکوکی دیده نمی‌شود.

شایع‌ترین علت، ویرایش پرامپت است. شما یک جمله اضافه می‌کنید تا از پاسخ‌های بی‌ادبانه جلوگیری کنید. آن جمله رفتار مدل را در ورودی‌هایی که کسی دوباره تست نکرده است تغییر می‌دهد و لاگ‌های ردیابی (traces) این موضوع را به‌وضوح نشان می‌دهند: ردیابی هفته گذشته برای همان سؤال شامل یک فراخوانی ابزار create_refund است، اما ردیابی این هفته هیچ فراخوانی‌ای ندارد و پاسخ فقط یک عذرخواهی مؤدبانه است. هیچ خطایی رخ نداده است، بنابراین هیچ هشداری فعال نمی‌شود.

علت دوم، مدل است. رشته دقیق مدل ارسالی در هر اجرا را ثبت کنید، یعنی claude-haiku-4-5-20251001 و نه نام اختصاری که در ذهن دارید؛ زیرا افت نرخ موفقیت در روزی که مدل را تغییر دادید، تنها زمانی قابل‌تشخیص است که نام مدل در ردیف داده‌ها موجود باشد.

علت سوم، ابزارها هستند. تغییر در شرح یک ابزار باعث می‌شود مدل در زمان متفاوتی تصمیم به فراخوانی آن بگیرد. اگر ابزارهای شما از طریق سرورهای MCP که روی یک VPS اجرا می‌شوند دریافت می‌شوند، طرحواره (schema) در یک پردازش دیگر قرار دارد و می‌تواند بدون هیچ تغییری در مخزن کد شما، تغییر کند. علت چهارم، بازیابی است: همان سؤال به اینکسی برخورد می‌کند که شبانه بازسازی شده است و پاسخ بر اساس سند جدید ارائه می‌شود.

ساخت مجموعه طلایی (golden set) از تریس‌هایی که قبلاً جمع‌آوری کرده‌اید

موارد ارزیابی را از خودتان ابداع نکنید. آن‌ها را از ترافیک واقعی استخراج کنید. اگر در حال حاضر از ردیابی Langfuse برای ایجنت خود به صورت self-hosted استفاده می‌کنید، هر درخواست به همراه ورودی، فراخوانی ابزارها و خروجی آن ذخیره می‌شود که دقیقاً همان ماده خام مورد نیاز برای یک مورد ارزیابی است.

یک بازه از root observationها را از طریق API عمومی خروجی بگیرید. این API از احراز هویت پایه (basic authentication) استفاده می‌کند که در آن کلید عمومی شما به عنوان نام کاربری و کلید مخفی شما به عنوان رمز عبور عمل می‌کند.

export LF_HOST="https://langfuse.example.com"
curl -sS -u "$LF_PUBLIC_KEY:$LF_SECRET_KEY" \
  "$LF_HOST/api/public/v2/observations?limit=50&isRootObservation=true&fromStartTime=2026-07-01T00:00:00Z" \
  | jq '.data[0]'

پیش از نوشتن هرگونه کد برای پارس کردن، یک رکورد را بخوانید. سطرها در data بازگردانده می‌شوند، اما نام فیلدهایی که پرسش و پاسخ را در خود نگه می‌دارند به نحوه ابزارگذاری (instrumentation) اسپن‌ها در ایجنت شما بستگی دارد؛ بنابراین به جای تکیه بر انتظارات قبلی، آنچه را که واقعاً مشاهده می‌کنید نگاشت کنید. سپس موارد ارزیابی را به صورت دستی، هر آبجکت JSON در یک خط، در evals/cases.jsonl بنویسید:

{"id": "refund-double-charge", "tags": ["smoke"], "input": "I was charged twice for order 41822.", "must_call": ["lookup_order", "create_refund"], "must_not_include": ["I cannot help"], "rubric": "The reply confirms exactly one refund for order 41822 and states the amount."}

پنج قانون برای حفظ کارایی این مجموعه وجود دارد:

  • 40 تا 80 مورد برای شروع کافی است. زیر 20 مورد، یک مورد ناپایدار (flaky) نرخ موفقیت را 5 واحد جابه‌جا می‌کند و عددی که بدون دلیل تغییر کند، نادیده گرفته می‌شود.
  • هر باگ عملیاتی (production bug) که رفع می‌کنید، باید در همان روز به یک مورد ارزیابی تبدیل شود. این عادت باعث می‌شود مجموعه در مسیر درست رشد کند.
  • هر مورد ارزیابی فقط یک رفتار را بررسی کند. موردی که همزمان مبلغ بازگشت وجه و لحن پاسخ را چک می‌کند، در صورت شکست، هیچ اطلاعات مفیدی به شما نمی‌دهد.
  • مقدار id هرگز تغییر نمی‌کند، زیرا این شناسه همان چیزی است که اجرای امروز را با اجرای ماه گذشته مقایسه می‌کند.
  • پیش از commit کردن، اطلاعات حساس را حذف (redact) کنید. این فایل در git ذخیره می‌شود، بنابراین نام مشتریان و هر شماره سفارشی که متعلق به شما نیست را پاک کنید.

ابتدا با بررسی‌های قطعی (Deterministic) ارزیابی کنید، زیرا هزینه‌ای ندارند

هر چیزی که پاسخ درست مشخصی دارد، باید با یک assertion ساده بررسی شود. بدون نیاز به فراخوانی مدل، بدون هزینه و بدون ابهام. بررسی‌های قطعی، رگرسیون‌های ساختاری را شناسایی می‌کنند؛ همان مواردی که باعث اختلال در سیستم‌های پیرامون عامل (Agent) شما می‌شوند: مثلاً JSON پارس نمی‌شود، ابزار فراخوانی نشده است، عبارت ممنوعه در پاسخ وجود دارد یا پاسخ هیچ منبعی را ذکر نکرده است.

تنها یک تابع از جزئیات عامل شما آگاه است. سایر بخش‌های چارچوب ارزیابی (Harness) باید عمومی باشند.

import json, os, urllib.request

def run_agent(case):
    req = urllib.request.Request(
        os.environ["AGENT_URL"],
        data=json.dumps({"input": case["input"]}).encode(),
        headers={"content-type": "application/json"},
    )
    with urllib.request.urlopen(req, timeout=120) as resp:
        return json.load(resp)


def deterministic(case, result):
    text = result.get("output", "")
    called = [c["name"] for c in result.get("tool_calls", [])]
    failures = []
    for tool in case.get("must_call", []):
        if tool not in called:
            failures.append(f"tool not called: {tool}")
    for phrase in case.get("must_not_include", []):
        if phrase.lower() in text.lower():
            failures.append(f"forbidden phrase: {phrase}")
    if len(called) > case.get("max_tool_calls", 12):
        failures.append(f"too many tool calls: {len(called)}")
    return failures

بودجه استفاده از ابزار را در آن لیست لحاظ کنید. عاملی که امروز یک مورد را با 3 فراخوانی حل می‌کند و فردا با 11 فراخوانی، حتی اگر پاسخ نهایی درست باشد، دچار رگرسیون شده است؛ زیرا شما برای هر فراخوانی که انجام می‌دهد هزینه پرداخت می‌کنید.

استفاده از LLM به عنوان داور و چهار روشی که در آن دچار خطا می‌شود

هر آنچه از بررسی‌های منطقی (assertions) عبور می‌کند، به یک ارزیاب نیاز دارد که محتوا را بخواند. داور مبتنی بر LLM در واقع یک فراخوانی مدل دوم است: این مدل پرسش، پاسخِ عامل (agent) و یک معیار را دریافت کرده و سپس نتیجه را اعلام می‌کند. این تنها روش عملی برای ارزیابی این موضوع است که «آیا پاسخ، پرسش کاربر را پوشش می‌دهد یا خیر».

چهار قانون، یک داور را قابل استفاده می‌کند:

  • نتیجه باید دودویی (Binary) باشد، هرگز از امتیاز 1 تا 10 استفاده نکنید. مقیاس عددی برای تقریباً همه چیز امتیاز 7 یا 8 را برمی‌گرداند، بنابراین اعداد تغییر نمی‌کنند و شما چیزی از آن‌ها نمی‌آموزید.
  • در هر فراخوانی فقط یک معیار را بررسی کنید. درباره مبلغ بازپرداخت بپرسید یا درباره لحن پاسخ، نه هر دو به صورت هم‌زمان.
  • هرگاه مورد آزمون دارای پاسخ مشخصی است، آن پاسخ مورد انتظار را به داور بدهید. ارزیابی بر اساس یک مرجع، بسیار آسان‌تر از ارزیابی انتزاعی است.
  • ساختار خروجی را اجباری کنید و آن را به دقت پارس (parse) نمایید.
from anthropic import Anthropic

client = Anthropic()  # reads ANTHROPIC_API_KEY from the environment


def judge_prompt(case, output):
    return (
        "You grade one answer against one criterion.\n"
        "Reply with JSON only, in this exact shape:\n"
        '{"verdict": "pass", "confidence": "high", "reason": "one short sentence"}\n'
        f"Criterion: {case['rubric']}\n"
        f"Question: {case['input']}\n"
        f"Answer: {output}\n"
        "Length is not a criterion. Judge only the criterion above."
    )


def judge(case, output, model):
    msg = client.messages.create(
        model=model,
        max_tokens=200,
        messages=[{"role": "user", "content": judge_prompt(case, output)}],
    )
    return json.loads(msg.content[0].text)

حال به حالت‌های شکست می‌پردازیم. برای هر کدام آزمونی وجود دارد که می‌توانید همین امروز اجرا کنید؛ اجرای این آزمون‌ها اهمیت دارد، زیرا داورِ کنترل‌نشده، اعدادی تولید می‌کند که دقیق به نظر می‌رسند اما فاقد معنا هستند.

سوگیری طول (Length bias). پاسخ‌های طولانی‌تر بیشتر تأیید می‌شوند. آن را تست کنید: ده پاسخی که داور رد کرده است را بردارید، هر کدام را با دو پاراگراف متن پرکننده (filler) که حاوی هیچ واقعیت جدیدی نیستند طولانی‌تر کنید و دوباره آن‌ها را قضاوت کنید. هر نتیجه‌ای که به «تأیید» تغییر کند، نشان‌دهنده سوگیری طول است و باید دستورالعمل (rubric) را اصلاح کنید.

خود-ترجیحی (Self-preference). داور اغلب خروجی‌های مدلِ خانوادهٔ خودش را نسبت به خروجی‌های مدل‌های دیگر با مهربانی بیشتری قضاوت می‌کند. آن را تست کنید: 30 پاسخ یکسان را با داورهایی از دو خانواده مدل متفاوت ارزیابی کنید و نتایج را مورد به مورد مقایسه کنید. در مواردی که اختلاف نظر دارند، خودتان آن مورد را بررسی کنید.

سوگیری موقعیت (Position bias). اگر از داور برای مقایسه دو پاسخ A و B استفاده می‌کنید، ترتیب آن‌ها را عوض کرده و دوباره اجرا کنید. نتیجه‌ای که با تغییر ترتیب عوض شود، به این معناست که مقایسه جفتی (pairwise) هنوز برای آن دستورالعمل ایمن نیست.

انحراف دستورالعمل (Rubric drift). معیارهای مبهم، داورهای سهل‌گیر تولید می‌کنند. «آیا پاسخ مفید است؟» تقریباً هر چیزی را تأیید می‌کند. «آیا پاسخ مبلغ بازپرداخت را به دلار بیان کرده است؟» فقط آنچه مد نظر شماست را تأیید می‌کند. هر معیار را تا زمانی که دقیقاً به واقعیتی که بررسی می‌شود اشاره کند، بازنویسی کنید.

یک محافظ، هر چهار مورد را پوشش می‌دهد. 30 موردی که شخصاً برچسب‌گذاری کرده‌اید را نگه دارید و هر بار که مدل داور یا پرامپت داور را تغییر می‌دهید، عملکرد داور را بر اساس برچسب‌های خود بسنجید. اگر داور در بیش از یک مورد از هر ده مورد با شما اختلاف نظر داشت، پیش از اعتماد به هر نرخ قبولی که تولید می‌کند، دستورالعمل را اصلاح کنید. داور در واقع کد است، بنابراین باید مانند کد، نسخه‌بندی و بازبینی شود.

رتبه‌بندی ارزان، ارتقا به مدل‌های پیشرفته

قضاوت کردن هر مورد با گران‌ترین مدل در هر commit، دلیلی است که هزینه ارزیابی از هزینه خودِ عاملی (agent) که در حال تست آن هستید، پیشی می‌گیرد. رتبه‌بندها را بر اساس قیمت مرتب کنید و به محض اینکه پاسخ مشخص شد، فرآیند را متوقف کنید.

ChartCost to judge 1,000 eval cases, list prices, August 2026
The data behind this chart
[
  {
    "label": "Haiku 4.5, Batch API",
    "usd_per_1000_judge_calls": "0.90"
  },
  {
    "label": "Haiku 4.5",
    "usd_per_1000_judge_calls": "1.80"
  },
  {
    "label": "Sonnet 5",
    "usd_per_1000_judge_calls": "3.60"
  },
  {
    "label": "Opus 5",
    "usd_per_1000_judge_calls": "9.00"
  }
]

این ارقام بر اساس حدود 1,200 توکن ورودی و 120 توکن خروجی در هر فراخوانی قضاوت محاسبه شده‌اند که اندازه‌ای واقع‌بینانه برای یک پرسش، یک پاسخ و یک معیار است. قضاوت 1,000 مورد با استفاده از Claude Haiku 4.5 هزینه 1.80 دلار آمریکا و با Claude Opus 5 هزینه 9.00 دلار خواهد داشت. این اختلاف تا زمانی که آن را ضرب نکنید ناچیز به نظر می‌رسد. یک مجموعه 60 موردی که در هر commit قضاوت شود، با 40 commit در هفته، پیش از آنکه کسی job شبانه را اجرا کند، به 2,400 فراخوانی قضاوت در هفته می‌رسد.

دو تخفیف به‌خوبی برای کارهای ارزیابی اعمال می‌شوند و با هم ترکیب می‌شوند. اجرای ارزیابی‌ها تعاملی نیست، بنابراین Batch API در ازای تحویل غیرهمزمان، قیمت ورودی و خروجی را نصف می‌کند که این موضوع در ردیف اول جدول دیده می‌شود. دستورالعمل‌ها و معیارها در هر فراخوانی بایت به بایت یکسان هستند، بنابراین prompt caching مناسب است: هزینه خواندن از حافظه کش یک‌دهم قیمت ورودی پایه است و هزینه نوشتن در حافظه کش برای پنج دقیقه، 1.25 برابر ورودی پایه است؛ بنابراین کش پس از یک بار استفاده، هزینه خود را جبران می‌کند. این‌ها قیمت‌های لیست Anthropic در اوت 2026 هستند و Sonnet 5 تا 31 اوت 2026 دارای قیمت‌گذاری مقدماتی است، بنابراین نوار سوم پس از آن تاریخ افزایش می‌یابد.

نردبان رتبه‌بندی به ترتیب:

  • بررسی‌های قطعی (Deterministic) روی همه موارد. بدون هیچ هزینه API.
  • یک مدل قضاوت کوچک برای مواردی که از آن بررسی‌ها عبور کرده‌اند.
  • یک قضاوت‌گر پیشرفته (frontier) فقط در مواردی که مدل کوچک اعلام شکست می‌کند یا با اطمینان پایین اعلام موفقیت می‌کند.
  • بررسی انسانی روی یک نمونه کوچک، یک بار در هفته.
CHEAP = "claude-haiku-4-5-20251001"
STRICT = "claude-opus-5"


def grade(case, result):
    hard = deterministic(case, result)
    if hard:
        return False, "deterministic", "; ".join(hard)
    first = judge(case, result["output"], CHEAP)
    if first["verdict"] == "pass" and first["confidence"] == "high":
        return True, CHEAP, first["reason"]
    second = judge(case, result["output"], STRICT)
    return second["verdict"] == "pass", STRICT, second["reason"]

این روش بخشی از دقت رتبه‌بندی را فدای هزینه می‌کند، بنابراین به‌جای فرض کردن، این توازن را اندازه‌گیری کنید. ماهی یک بار، کل مجموعه را با قضاوت‌گر سخت‌گیر نیز ارزیابی کنید و دو ستون را با هم مقایسه کنید. اگر آن‌ها در بیش از تعداد انگشت‌شماری از موارد اختلاف نظر داشتند، معیار شما برای مدل کوچک بیش از حد آزاد است و باید معیار را اصلاح کنید. کنترل هزینه‌های خودِ عامل (agent) یک وظیفه جداگانه است که در کنترل هزینه برای یک عامل هوش مصنوعی روی VPS پوشش داده شده است.

ردیابی نرخ موفقیت در طول زمان در سیستمی که مدیریت می‌کنید

نرخ موفقیتی که نتوانید آن را به یک commit خاص پیوند دهید، صرفاً یک برداشت ذهنی است. به ازای هر مورد در هر اجرا، یک ردیف در دیتابیس ذخیره کنید که شامل commit و مدل مورد استفاده در همان ردیف باشد.

CREATE TABLE IF NOT EXISTS results (
  run_id      TEXT NOT NULL,
  ran_at      TEXT NOT NULL,
  git_sha     TEXT NOT NULL,
  agent_model TEXT NOT NULL,
  case_id     TEXT NOT NULL,
  passed      INTEGER NOT NULL,
  graded_by   TEXT NOT NULL,
  reason      TEXT
);
SELECT run_id, git_sha, agent_model,
       count(*) AS cases,
       round(100.0 * sum(passed) / count(*), 1) AS pass_pct
FROM results
GROUP BY run_id
ORDER BY ran_at DESC
LIMIT 10;

طرح (schema) را با sqlite3 evals/results.db < evals/schema.sql بارگذاری کنید و سپس روند تغییرات را با sqlite3 -box evals/results.db < evals/passrate.sql بخوانید. یک سال اجرای روزانه برای 60 مورد، حدود 22,000 ردیف ایجاد می‌کند؛ بنابراین این مخزن داده هرگز به یک پروژه مستقل و سنگین تبدیل نخواهد شد. اجرای SQLite در محیط عملیاتی روی یک VPS تنظیماتی را پوشش می‌دهد که اگر این فایل بین چندین ماشین به اشتراک گذاشته شود، اهمیت پیدا می‌کنند.

ابزار اجراکننده، همان اطلاعات را برای مشاهده توسط انسان نیز چاپ می‌کند:

run 2026-08-05T09:14:22Z  sha 4f1c9ab  model claude-sonnet-5  58/60 pass (96.7%)
FAIL refund-double-charge  deterministic: tool not called: create_refund
FAIL pto-policy-question   judge(opus): reply gives no dollar amount

مجموعه تست‌ها را روی تغییراتی اجرا کنید که پتانسیل شکستن یک agent را دارند؛ این یعنی تغییرات در prompt، تغییرات مدل و تغییرات ابزارها، نه هر commit در هر جای مخزن کد. یک hook از نوع pre-push زیرمجموعه سریع تست‌ها را پوشش می‌دهد:

cat > .git/hooks/pre-push <<'EOF'
#!/bin/sh
python3 evals/run.py --set smoke || exit 1
EOF
chmod +x .git/hooks/pre-push

اجراهای کامل کندتر هستند و باید طبق زمان‌بندی انجام شوند. یک سرویس و تایمر systemd روی VPS به صورت شبانه کل مجموعه را روی prompt مستقر شده اجرا می‌کند؛ این همان روشی است که تغییرات ناشی از عوامل خارجی (مانند ابزارهای میزبانی‌شده‌ای که رفتارشان تغییر کرده است) را شناسایی می‌کند.

بازبینی انسانی، به‌صورت نمونه‌گیری و نه جامع

قضاوت‌کننده (judge) بر اساس برچسب‌های انسانی کالیبره می‌شود، بنابراین شخصی باید این برچسب‌ها را تولید کند. هر هفته یک نمونه را مطالعه کنید: تمام مواردی که قضاوت‌کننده در آن‌ها شکست خورده است، به‌علاوه ده مورد موفق که به‌صورت تصادفی انتخاب شده‌اند. موارد موفق تصادفی، نیمه مهم کار هستند؛ زیرا قضاوت‌کننده‌ای که به‌آرامی شروع به تأیید پاسخ‌های بد کرده است، در هر داشبوردی که بر اساس قضاوت‌های خودش ساخته شده باشد، عالی به نظر می‌رسد.

پانزده مورد با زمان سه دقیقه برای هر کدام، در مجموع 45 دقیقه در هفته زمان می‌برد و اصلاحاتی را برای دستورالعمل (rubric) در مواردی که شما و قضاوت‌کننده اختلاف نظر دارید، به همراه می‌آورد؛ همچنین موارد جدیدی از انواع شکست‌ها را که کسی تصور نمی‌کرد، آشکار می‌کند. قضاوت انسانی را در همان جدولی بنویسید که graded_by روی human تنظیم شده است، تا توافق بین قضاوت‌کننده و انسان به یک پرس‌وجو (query) تبدیل شود، نه یک خاطره.

چه چیزی در خودِ ابزار ارزیابی (eval harness) دچار اختلال می‌شود

anthropic.RateLimitError در اولین اجرای کامل. اجرای همزمان 60 مورد، از سقف درخواست یا توکنِ سطح کاربری شما فراتر می‌رود. تعداد workerها را روی 4 محدود کنید و اجرای شبانه را به Batch API منتقل نمایید.

json.JSONDecodeError: Expecting value: line 1 column 1 (char 0) از سمت داور (judge). مدل به صورت متنی پاسخ داده یا خروجی JSON خود را داخل code fence قرار داده است. یک‌بار دوباره تلاش کنید و سپس مورد را به عنوان خطا ثبت کنید. هرگز اجازه ندهید خطای پارس (parse failure) به عنوان موفقیت (pass) محسوب شود، زیرا مجموعه‌ای که خطاها را به موفقیت تبدیل می‌کند، در حالی که عملکرد عامل (agent) رو به افول است، به سمت 100% پیش می‌رود.

موارد ناپایدار (Flaky cases). ورودی یکسان در یک اجرا موفق و در اجرای بعدی ناموفق است، زیرا عامل خروجی خود را نمونه‌برداری (sample) می‌کند. مورد ناپایدار را 3 بار اجرا کنید و به جای حذف آن، کسر موفقیت را ثبت کنید. موردی که در 2 اجرا از 3 اجرا موفق می‌شود، یک باگ واقعی در پایداری است و مشتری حتماً آن را پیدا خواهد کرد.

فرسودگی مجموعه طلایی (Golden set rot). شخصی پاسخ مورد انتظار را ویرایش می‌کند تا وضعیت مجموعه سبز شود. تغییرات (diffs) در evals/cases.jsonl را به همان دقتی بررسی کنید که تغییرات کد عامل را بررسی می‌کنید، زیرا آن فایل، تعریف مکتوب شما از «صحیح بودن» است.

مجموعه‌ای که هرگز شکست نمی‌خورد. نرخ موفقیت 100% که برای یک ماه ثابت مانده است، یعنی آن مجموعه دیگر محصول را پایش نمی‌کند. 10 مورد از traceهای اخیر را استخراج کنید، مواردی که عامل در آن‌ها عملکرد ضعیفی داشته را بیابید و آن‌ها را به مجموعه اضافه کنید.

FAQ

یک مجموعه ارزیابی (eval set) برای ایجنت هوش مصنوعی به چند مورد نیاز دارد؟

با 40 تا 80 مورد شروع کنید و مجموعه را بر اساس شکست‌های واقعی گسترش دهید. زیر 20 مورد، یک نتیجه ناپایدار (flaky) نرخ موفقیت را تا 5 واحد تغییر می‌دهد، بنابراین این عدد دیگر حاوی اطلاعات مفیدی نیست. پس از چند صد مورد، هر اجرا هزینه مالی و زمانی واقعی دارد، در حالی که موارد حاشیه‌ای پوشش چندانی اضافه نمی‌کنند. معیاری که اهمیت دارد تعداد نیست، بلکه سهم انواع شکست‌های شناخته‌شده در محیط عملیاتی (production) است که حداقل یک بار در مجموعه ظاهر شده‌اند.

آیا می‌توان به یک LLM judge برای نمره‌دهی به ایجنت اعتماد کرد؟

فقط پس از آنکه آن را با برچسب‌های خودتان سنجیده باشید. 30 مورد را که با دست نمره‌دهی کرده‌اید نگه دارید و هر زمان که مدل یا پرامپت judge را تغییر دادید، عملکرد آن را نسبت به این موارد بسنجید. مدل‌های judge دچار سوگیری طول (length bias) هستند، که در آن پاسخ‌های طولانی‌تر بیشتر قبول می‌شوند، و همچنین سوگیری خود-ترجیحی (self-preference) دارند، که در آن خروجی‌های خانواده مدل خودشان را با ارفاق بیشتری نمره‌دهی می‌کنند. هر دو مورد قابل آزمایش هستند: یک پاسخ شکست‌خورده را طولانی‌تر کنید و دوباره آن را بسنجید، یا همان پاسخ‌ها را با یک judge از خانواده‌ای دیگر نمره‌دهی کنید. اگر judge در بیش از یک مورد از هر 10 مورد با برچسب‌های شما اختلاف داشت، دستورالعمل (rubric) بیش از حد مبهم است و قابل استفاده نیست.

کدام مدل باید ارزیابی‌ها را نمره‌دهی کند؟

ارزان نمره‌دهی کنید و در صورت نیاز ارتقا دهید. بررسی‌های قطعی (deterministic assertions) هزینه‌ای ندارند، بنابراین در هر مورد ابتدا اجرا می‌شوند. یک مدل کوچک موارد قبولی واضح را مدیریت می‌کند. فقط موارد شکست و نتایج با اطمینان پایین به یک مدل پیشرو (frontier model) ارجاع داده می‌شوند. با قیمت‌های لیست‌شده در اوت 2026، نمره‌دهی 1,000 مورد با Claude Haiku 4.5 حدود 1.80 دلار آمریکا و با Claude Opus 5 حدود 9.00 دلار هزینه دارد، و از آنجا که اجرای ارزیابی‌ها به‌صورت غیرهمگام (asynchronous) است، Batch API هر دو رقم را به نصف کاهش می‌دهد.

آیا ارزیابی‌ها جایگزین مانیتورینگ محیط عملیاتی (production) می‌شوند؟

خیر، زیرا به پرسش‌های متفاوتی پاسخ می‌دهند. یک مجموعه ارزیابی به شما می‌گوید که آیا تغییری که قصد انتشار آن را دارید، یک مجموعه ثابت از موارد را بهبود می‌بخشد یا بدتر می‌کند. ردیابی (tracing) و مانیتورینگ به شما می‌گویند که کاربران واقعی در حال حاضر با چه چیزی مواجه هستند، از جمله ورودی‌هایی که هیچ موردی آن‌ها را پوشش نمی‌دهد. این دو مکمل یکدیگرند: ردیابی‌ها موارد جدید را تأمین می‌کنند و مجموعه ارزیابی تعیین می‌کند که آیا اصلاح شما واقعاً مؤثر بوده است یا خیر.