SSD Nodes Learn 🎉 VPS החל מ־$5.50/חודש
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-13

בניית מערכת הערכה עצמית (Evals) לסוכני AI

למדו כיצד להקים לולאת הערכה עצמאית לסוכני AI ללא תלות בספקים חיצוניים. המדריך מפרט שימוש ב-golden cases, בדיקות דטרמיניסטיות, שופט LLM ומעקב אחר שיעורי הצלחה בכל commit.

מהן הערכות (evals) עצמיות לסוכני AI

הערכות עצמיות לסוכני AI הן ארבעה רכיבים שאתם שומרים במאגר הקוד שלכם: קובץ עם מקרי בוחן שמורים, סקריפט שמריץ את הסוכן מולם, סט בדיקות שמדרג כל תשובה, וטבלה של תוצאות שניתן לבצע עליה שאילתות. אף אחד מהרכיבים הללו אינו מחייב ספק חיצוני. כל הלולאה מורכבת מכמה מאות שורות של Python וקובץ SQLite אחד.

הסוכן עבד בהדגמה כי בחרתם את חמשת הקלטים בעצמכם. הוא הפסיק לעבוד בשבוע השני כי שורת prompt השתנתה, או שהמודל השתנה, או שתיאור של כלי השתנה, ואף מדידה לא כיסתה זאת. לולאת הערכה הופכת את התחושה ש"זה מרגיש פחות טוב עכשיו" לנתון מדויק: "שיעור ההצלחה ירד מ-58 מתוך 60 ל-51 מתוך 60 ב-commit 4f1c9ab".

בלולאה יש ארבעה שלבים, ומדריך זה מוקדש לכל שלב בסעיף נפרד: איסוף עקבות (traces) אמיתיים, קידום המקרים המעניינים למקרי בוחן, דירוג כל מקרה בכל שינוי, ושמירת שיעור ההצלחה לצד ה-commit שיצר אותו. אותה לולאה עובדת ללא קשר למה שמריץ את הסוכן, ו-מסגרות העבודה לסוכנים בהתקנה עצמית ששווה להריץ נבדלות בעיקר בכמות העקבות שהן מספקות לכם ללא מאמץ.

מדוע הסוכן מפסיק לעבוד בשבוע השני

סוכן מורכב מ-prompt, מודל, קבוצת הגדרות של כלים, וכל הקשר (context) שנשלף בזמן הריצה. כל ארבעת המרכיבים הללו יכולים להשתנות מבלי שקוד היישום ישתנה, לכן סקירת קוד רגילה לא תזהה בעיות.

הסיבה הנפוצה ביותר היא עריכת ה-prompt. אתם מוסיפים משפט אחד כדי למנוע תשובה גסה. המשפט הזה משנה את ההתנהגות עבור קלטים שאף אחד לא בדק מחדש, והעקבות (traces) מראים זאת בבירור: העקבה של השבוע שעבר עבור אותה שאלה מכילה קריאת כלי create_refund, בעוד שהעקבה של השבוע הנוכחי אינה מכילה דבר, והתשובה היא התנצלות מנומסת במקום זאת. שום דבר לא הפיק שגיאה, לכן לא הופעלה התראה.

הסיבה השנייה היא המודל. תעדו את מחרוזת המודל המדויקת ששלחתם בכל הרצה, claude-haiku-4-5-20251001 במקום קיצור שאתם שומרים בראש, כיוון ששיעור הצלחה שיורד ביום שבו החלפתם מודלים ניתן לאבחון רק כאשר המודל מתועד בשורה המתאימה.

הסיבה השלישית היא כלים. ניסוח מחדש של תיאור כלי משנה את המועד שבו המודל מחליט לקרוא לו. אם הכלים שלכם מגיעים דרך שרתי MCP שרצים על VPS, הסכימה נמצאת בתהליך אחר, כך שהיא יכולה להשתנות מתחת לאפכם ללא כל הבדל (diff) במאגר הקוד שלכם. הסיבה הרביעית היא שליפה: אותה שאלה פוגעת באינדקס שנבנה מחדש במהלך הלילה, והתשובה עוקבת אחר המסמך החדש.

בניית סט בדיקות איכותי (Golden Set) מתוך עקבות (traces) קיימים

אל תמציאו מקרי בוחן. הפיקו אותם מתעבורת אמת. אם אתם כבר מריצים Langfuse לתיעוד עצמי של הסוכן שלכם, כל בקשה נשמרת יחד עם הקלט, קריאות הכלים והפלט שלה – אלו בדיוק חומרי הגלם הדרושים ליצירת מקרה בוחן.

ייצאו טווח של תצפיות שורש (root observations) דרך ה-API הציבורי. הגישה מתבצעת באמצעות אימות בסיסי (basic authentication), כאשר ה-public key שלכם משמש כשם משתמש וה-secret key כסיסמה.

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]'

קראו רשומה אחת לפני שאתם כותבים לוגיקת עיבוד (parsing). השורות מוחזרות תחת data, אך שמות השדות המכילים את השאלה והתשובה תלויים באופן שבו הסוכן שלכם מבצע אינסטרומנטציה ל-spans שלו; לכן, בצעו מיפוי למה שאתם רואים בפועל במקום להסתמך על מה שציפיתם לראות. לאחר מכן, כתבו את המקרים ידנית, אובייקט 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 נקודות, ומספר שקופץ ללא סיבה ברורה יזכה להתעלמות.
  • כל באג בסביבת הייצור שאתם מתקנים חייב להפוך למקרה בוחן ביום התיקון. הרגל זה הוא שגורם לסט לצמוח בכיוון הנכון.
  • התנהגות אחת לכל מקרה. מקרה בוחן שבודק בו-זמנית גם את סכום ההחזר וגם את הטון של התשובה לא יספק לכם מידע מועיל כאשר הוא ייכשל.
  • ה-id לעולם אינו משתנה, כיוון שה-id הוא הדרך שבה ההרצה של היום מושוות להרצה של החודש שעבר.
  • בצעו הסתרה (redaction) לפני ה-commit. קובץ זה נכנס ל-git, לכן הסירו שמות לקוחות ומספרי הזמנות שאינם בבעלותכם.

בצעו הערכה באמצעות בדיקות דטרמיניסטיות תחילה, כיוון שהן אינן כרוכות בעלות

כל רכיב בעל תשובה חד-משמעית צריך להיבדק באמצעות assertion פשוט. ללא קריאה למודל, ללא עלות וללא עמימות. בדיקות דטרמיניסטיות מאתרות רגרסיות מבניות, ואלו הן הבעיות שמשבשות את המערכות סביב ה-agent שלכם: ה-JSON אינו מתפענח, הכלי מעולם לא נקרא, ביטוי אסור הופיע בתגובה, או שהתשובה אינה מצטטת מקור.

פונקציה אחת בלבד מכירה את ה-agent שלכם. כל שאר רכיבי ה-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

שמרו על תקציב השימוש בכלים בתוך הרשימה הזו. agent שפותר מקרה ב-3 קריאות היום וב-11 קריאות מחר חווה רגרסיה, גם אם התשובה הסופית נכונה, כיוון שאתם משלמים על כל קריאה שהוא מבצע.

שימוש ב-LLM כשופט, וארבע הדרכים שבהן זה משתבש

כל מה ששורד את הבדיקות האוטומטיות זקוק למעריך אנושי או ממוכן שיקרא אותו. שופט מבוסס LLM הוא קריאה שנייה למודל: הוא מקבל את השאלה, את תשובת הסוכן וקריטריון אחד, ואז מחזיר פסק דין. זו הדרך המעשית היחידה לדרג האם התשובה אכן עונה על מה שהמשתמש ביקש.

ארבעה כללים הופכים שופט לשימושי:

  • פסק דין בינארי, לעולם לא ציון מ-1 עד 10. סקאלה נוטה להחזיר 7 או 8 כמעט על הכל, כך שהמספר לעולם לא משתנה ולא ניתן ללמוד ממנו דבר.
  • קריטריון אחד לכל קריאה. שאלו על סכום ההחזר, או על הטון, אך לא על שניהם בבת אחת.
  • ספקו לשופט את התשובה המצופה בכל מקרה שבו קיימת כזו. דירוג מול תשובת ייחוס הוא משימה קלה בהרבה מדירוג מופשט.
  • כפו את מבנה הפלט ונתחו אותו בקפדנות.
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)

כעת, מצבי הכשל. לכל אחד מהם יש בדיקה שניתן להריץ עוד היום, והרצת הבדיקות הללו חשובה, כיוון ששופט ללא פיקוח מייצר מספרים שנראים מדויקים אך חסרי משמעות.

הטיית אורך. תשובות ארוכות עוברות לעיתים קרובות יותר. בדקו זאת: קחו עשר תשובות שהשופט פסל, הוסיפו לכל אחת שתי פסקאות של מלל ביטחוני שאינו מוסיף עובדות חדשות, ושפטו אותן שוב. כל פסק דין שמשתנה ל"עובר" מעיד על הטיית אורך, והדבר שיש לתקן הוא ה-rubric.

העדפה עצמית. שופט נוטה לעיתים קרובות לדרג פלט ממשפחת המודלים שלו בצורה חיובית יותר מאשר פלט ממשפחה אחרת. בדקו זאת: דרגו את אותן 30 תשובות עם שופטים משתי משפחות שונות והשוו את פסקי הדין מקרה מול מקרה. במקומות שבהם הם אינם מסכימים, קראו את המקרה בעצמכם.

הטיית מיקום. אם אתם משתמשים בשופט כדי להשוות בין שתי תשובות, A ו-B, החליפו את הסדר והריצו שוב. פסק דין שמשתנה בעקבות ההחלפה מעיד על כך שהשוואה זוגית אינה בטוחה עדיין עבור ה-rubric הזה.

זליגת ה-rubric. קריטריונים מעורפלים מייצרים שופטים נוחים מדי. "האם התשובה מועילה" תעביר כמעט הכל. "האם התשובה מציינת את סכום ההחזר בדולרים" תעביר רק את מה שהתכוונתם אליו. שכתבו כל קריטריון עד שהוא יציין במפורש את העובדה הנבדקת.

הגנה אחת מכסה את כל הארבעה. שמרו 30 מקרים שתייגתם ידנית, ודרגו את השופט מול התיוגים שלכם בכל פעם שאתם משנים את מודל השופט או את ה-prompt של השופט. אם הוא אינו מסכים איתכם ביותר ממקרה אחד מתוך עשרה, תקנו את ה-rubric לפני שתסמכו על שיעור המעבר שהוא מפיק. השופט הוא קוד, לכן יש לנהל לו גרסאות ולבצע לו סקירה בדיוק כמו לקוד.

דירוג זול, הסלמה למודל מתקדם

שימוש במודל היקר ביותר לכל בדיקה בכל commit הוא הדרך שבה עלות ה-eval עולה על עלות הסוכן שאותו הוא בודק. סדרו את המדרגים לפי מחיר, ועצרו ברגע שהתשובה ברורה.

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 אסימוני קלט (tokens) ו-120 אסימוני פלט לכל קריאת מדרג, גודל ריאלי עבור שאלה אחת, תשובה אחת וקריטריון אחד. דירוג של 1,000 מקרים עולה 1.80 דולר ב-Claude Haiku 4.5 ו-9.00 ב-Claude Opus 5. הפער נראה זניח עד שמכפילים אותו. סט של 60 מקרים, הנבדק בכל commit, ב-40 commits בשבוע, מגיע ל-2,400 קריאות מדרג בשבוע עוד לפני שהרצנו את ה-job הלילי.

שתי הנחות חלות בצורה נקייה על עבודת eval, והן מצטברות. הרצות eval אינן אינטראקטיביות, לכן ה-Batch API מקצץ בחצי את מחירי הקלט והפלט בתמורה למסירה אסינכרונית, כפי שמופיע בשורה הראשונה בטבלה. ה-rubric וההנחיות זהים בייט-ל-בייט בכל קריאה, לכן prompt caching מתאים כאן: קריאה מה-cache עולה עשירית ממחיר הקלט הבסיסי, וכתיבה ל-cache של חמש דקות עולה פי 1.25 ממחיר הקלט הבסיסי, כך שה-cache מחזיר את עלותו כבר לאחר פגיעה אחת. אלו מחירי המחירון של Anthropic נכון לאוגוסט 2026, ו-Sonnet 5 נמצא במחיר השקה עד ה-31 באוגוסט 2026, לכן העמודה השלישית תעלה לאחר תאריך זה.

סולם הדירוג, לפי הסדר:

  • בדיקות דטרמיניסטיות על כל מקרה. ללא עלות 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"]

גישה זו מקריבה מעט מדיוק הדירוג לטובת חיסכון בעלויות, לכן יש למדוד את הפשרה במקום להניח אותה. פעם בחודש, דרגו את כל הסט גם עם המדרג המחמיר והשוו בין שתי העמודות. אם הם חלוקים בדעתם ביותר ממספר קטן של מקרים, ה-rubric שלכם רופף מדי עבור המודל הקטן, ואת ה-rubric יש לתקן. שליטה בהוצאות הסוכן עצמו היא משימה נפרדת, המכוסה ב-בקרת עלויות עבור סוכן AI על גבי 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 בסביבת production על גבי VPS מכסה את ההגדרות שמתחילות להיות משמעותיות אם הקובץ משותף בין מכונות.

ה-runner מדפיס את אותו המידע עבור משתמש:

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

הרץ את ה-suite על שינויים שעלולים לשבור סוכן (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

הרצות מלאות הן איטיות יותר ושייכות ללוח זמנים. שירות ו-timer של systemd ב-VPS המופעלים מדי לילה מריצים את כל הסט מול ה-prompt הפרוס, וזה מה שתופס שינויים שמגיעים מחוץ למאגר שלך, כגון כלי חיצוני שהתנהגותו השתנתה.

סקירה אנושית, מבוססת דגימה ולא בדיקה ממצה

השופט מכויל מול תוויות אנושיות, לכן מישהו חייב לייצר אותן. קראו דגימה בכל שבוע: כל מקרה שבו השופט נכשל, בתוספת עשרה מקרים שעברו בהצלחה שנבחרו באקראי. המקרים שעברו בהצלחה הם החצי החשוב, כיוון ששופט שהחל בשקט לאשר תשובות שגויות ייראה מושלם בכל לוח בקרה המבוסס על הפסיקות של עצמו.

חמישה-עשר מקרים, שלוש דקות לכל אחד, מסתכמים ב-45 דקות בשבוע. תהליך זה מניב תיקונים למדריך הדירוג במקומות שבהם אתם והשופט אינכם מסכימים, וכן מקרים חדשים לסוגי כשלים שאף אחד לא העלה על דעתו. רשמו את הפסיקה האנושית באותה טבלה עם graded_by מוגדר ל-human, כך שההסכמה בין השופט לאדם תהפוך לשאילתה במקום לזיכרון.

מה משתבש בתוך ה-eval harness עצמו

anthropic.RateLimitError בהרצה המלאה הראשונה. הרצה של 60 מקרים במקביל חורגת ממכסת הבקשות או הטוקנים של ה-tier שלכם. הגבילו את ה-concurrency ל-4 עובדים, והעבירו את ההרצה הלילית ל-Batch API.

json.JSONDecodeError: Expecting value: line 1 column 1 (char 0) מה-judge. המודל השיב בטקסט חופשי, או עטף את ה-JSON בתוך code fence. בצעו ניסיון חוזר אחד, ולאחר מכן רשמו את המקרה כשגיאה. לעולם אל תתנו לכשל ב-parse להיחשב כהצלחה, כיוון שחבילת בדיקות שהופכת שגיאות להצלחות תתקרב ל-100% בעוד שה-agent הופך גרוע יותר.

מקרים לא עקביים (Flaky cases). אותו קלט עובר בהרצה אחת ונכשל בבאה אחריה, כיוון שה-agent דוגם את הפלט שלו. הריצו את המקרה הלא-עקבי 3 פעמים ורשמו את השבר במקום למחוק את המקרה. מקרה שעובר 2 מתוך 3 הרצות הוא באג אמיתי בחוסן המערכת, ולקוח ייתקל בו.

שחיקה של ה-golden set. מישהו עורך תשובה צפויה כדי להפוך את ה-suite לירוק. בדקו diffs ל-evals/cases.jsonl בזהירות רבה כמו diffs ל-agent, כיוון שקובץ זה הוא ההגדרה הכתובה שלכם למה שנכון.

חבילת בדיקות שלעולם לא נכשלת. שיעור הצלחה שעומד על 100% במשך חודש אומר שה-set הפסיק לעקוב אחרי המוצר. משכו 10 עקבות (traces) אחרונים, מצאו את אלו שה-agent טיפל בהם בצורה גרועה, והוסיפו אותם.

FAQ

כמה מקרים נדרשים עבור סט הערכה של סוכן AI?

התחילו עם 40 עד 80 מקרים והרחיבו את הסט על בסיס כשלים אמיתיים. מתחת ל-20 מקרים, תוצאה לא עקבית אחת משנה את אחוז ההצלחה ב-5 נקודות, ולכן הנתון מפסיק להיות בעל משמעות. מעבר לכמה מאות מקרים, כל הרצה עולה כסף וזמן, בעוד שהערך המוסף של כל מקרה נוסף הוא זניח. המדד הקובע אינו הכמות, אלא שיעור סוגי הכשלים הידועים שלכם מה-production שמופיעים בסט לפחות פעם אחת.

האם ניתן לסמוך על שופט LLM שיעריך את הסוכן שלי?

רק לאחר שמדדתם אותו מול התיוגים שלכם. שמרו 30 מקרים שתייגתם ידנית, ובדקו את השופט מולם בכל פעם שאתם משנים את מודל השופט או את ה-prompt שלו. שופטים מראים הטיה לאורך (תשובות ארוכות עוברות יותר) והטיה עצמית (תשובות ממשפחת המודלים שלהם מקבלות ציון גבוה יותר). ניתן לבדוק את שניהם: הוסיפו תוכן לתשובה שנכשלה ובדקו אותה שוב, או דרגו את אותן תשובות עם שופט ממשפחה אחרת. אם השופט חולק על התיוגים שלכם ביותר ממקרה אחד מתוך עשרה, ה-rubric מעורפל מדי לשימוש.

באיזה מודל כדאי להשתמש לדירוג ה-evals?

דרגו בזול והסלימו לפי הצורך. טענות דטרמיניסטיות אינן עולות דבר, לכן הן מורצות ראשונות על כל מקרה. מודל קטן מטפל במקרים הברורים. רק כשלים ופסקי דין בעלי ביטחון נמוך מועברים למודל מתקדם (frontier model). לפי מחירון אוגוסט 2026, דירוג של 1,000 מקרים עולה כ-1.80 דולר עם Claude Haiku 4.5 וכ-9.00 עם Claude Opus 5. מכיוון שהרצות ה-eval הן אסינכרוניות, ה-Batch API מקצץ את שני המחירים בחצי.

האם ה-evals מחליפים ניטור ב-production?

לא, כיוון שהם עונים על שאלות שונות. חבילת eval אומרת לכם אם שינוי שאתם עומדים להפיץ משפר או מרע סט קבוע של מקרים. מעקב (tracing) וניטור אומרים לכם באילו מצבים נתקלים משתמשים אמיתיים כרגע, כולל קלטים שאף מקרה לא מכסה. הם מזינים זה את זה: ה-traces מספקים מקרים חדשים, וחבילת ה-eval קובעת אם התיקון שלכם אכן עבד.