הערכת סוכנים (Evals)
למה קשה לבדוק סוכן
בדיקה רגילה של קוד מריצה פונקציה ומשווה לתוצאה צפויה. סוכן לא עובד ככה: אותה משימה יכולה לעבור בכל הרצה מסלול אחר — כלים אחרים, סדר אחר, מספר צעדים אחר — ולפעמים כמה מסלולים שונים נכונים כולם. וטעות בצעד שלישי עלולה להתגלות רק בצעד העשירי.
לכן "עבד לי בדמו" לא אומר הרבה. Evals הם הדרך למדוד את זה באופן שיטתי: סט קבוע של משימות, קריטריון הצלחה ברור לכל אחת, והרצה חוזרת שמראה באיזה אחוז מהמקרים הסוכן באמת מצליח — ומה קרה כשהוא נכשל.
תוצאה מול מסלול
הערכת תוצאה (outcome) בודקת את המצב הסופי: האם הבדיקות עוברות אחרי התיקון, האם התשובה נכונה, האם הרשומה הנכונה נוצרה במסד הנתונים. זו השאלה החשובה ביותר, והיא לא מענישה את הסוכן על כך שבחר דרך אחרת מזו שציפינו לה.
הערכת מסלול (trajectory) בודקת איך הוא הגיע לשם: כמה צעדים לקח, כמה עלה, האם השתמש בכלים הנכונים, והאם ביצע פעולה אסורה בדרך — גם אם בסוף הצליח. סוכן שמתקן את הבאג אבל מוחק בדרך קובץ שלא היה צריך לגעת בו לא עבר את הבדיקה.
בונים סט משימות
לא צריך מאות משימות כדי להתחיל. 20 עד 50 משימות מייצגות, שנלקחו משימוש אמיתי, כבר מגלות את רוב הבעיות. לכל משימה צריך קריטריון הצלחה שאפשר לבדוק — לא "תשובה טובה", אלא "הבדיקות ב-auth עוברות" או "התשובה כוללת את מספר ההזמנה הנכון".
המקור הטוב ביותר למשימות הוא כישלונות אמיתיים: כל פעם שהסוכן טועה בשימוש אמיתי, המקרה הופך למשימה חדשה בסט. כדאי לכלול גם מקרי קצה, וגם מקרים שבהם התשובה הנכונה היא לסרב או לעצור ולשאול.
ובגלל שהסוכן לא דטרמיניסטי, מריצים כל משימה כמה פעמים ומודדים אחוז הצלחה ולא "עבר / נכשל". סוכן שמצליח ב-3 מתוך 5 הרצות הוא לא אותו סוכן כמו אחד שמצליח ב-5 מתוך 5, גם אם שניהם "עוברים" בהרצה בודדת.
Graders: מי קובע אם הסוכן הצליח
בדיקה בקוד היא הבחירה הראשונה בכל מקום שאפשר: הרצת בדיקות, השוואה מדויקת, בדיקת מצב של קובץ או מסד נתונים. היא מהירה, זולה וחד-משמעית.
לפלט פתוח — סיכום, תשובה ללקוח, דוח — משתמשים ב-LLM-as-judge: מודל שני מקבל את הפלט ורובריקה מפורשת ("האם התשובה מזכירה את מדיניות ההחזרים? האם הטון מנומס?") ומחזיר ציון. זה עובד, אבל לשופט יש הטיות מוכרות: הוא נוטה להעדיף תשובות ארוכות, תשובות בסגנון שלו, ולפעמים את התשובה שמוצגת ראשונה. רובריקה ספציפית ושאלות כן/לא מצמצמות את זה.
בדיקה אנושית היא עדיין הסטנדרט: יקרה ואיטית, אבל משמשת לכייל את השופט האוטומטי (האם הוא מסכים עם בני אדם?) ולדגום מדי פעם את מה שהבדיקות האוטומטיות מפספסות.
Evals כבדיקות רגרסיה
הערך האמיתי של סט evals מגיע כשמשנים משהו. כל שינוי בפרומפט, במודל, בתיאור של כלי או בהגדרות ה-harness יכול לשפר מקרה אחד ולשבור שלושה אחרים. מריצים את הסט לפני כל שינוי ואחריו, ומשווים אחוזי הצלחה ועלות מול הגרסה הקודמת — בדיוק כמו בדיקות רגרסיה בקוד רגיל.
interface EvalCase {
task: string;
check: (result: AgentResult) => Promise<boolean>; // grader: קוד או LLM-as-judge
}
async function runEvals(cases: EvalCase[], runsPerCase = 5) {
const report = [];
for (const evalCase of cases) {
let passed = 0;
for (let run = 0; run < runsPerCase; run++) {
const result = await runAgent(evalCase.task); // כולל trace מלא: כלים, צעדים, עלות
if (await evalCase.check(result)) passed++;
}
report.push({ task: evalCase.task, passRate: passed / runsPerCase });
}
return report;
}
// grader מבוסס קוד: מריצים את בדיקות הפרויקט אחרי שהסוכן סיים
const fixLoginBug: EvalCase = {
task: "בדיקות ההתחברות נכשלות. מצא ותקן את הבאג.",
check: async (result) => (await runTests(result.workspace, "auth")).allPassed,
};Tracing: לראות מה הסוכן באמת עשה
trace הוא תיעוד מלא של הרצה אחת: כל קריאה למודל, כל קריאת כלי עם הקלט והפלט שלה, טוקנים, זמן ועלות — אותו לוג ביקורת שה-harness שומר (פרק 5). מספרים מצרפיים אומרים לכם שמשהו נכשל; ה-trace אומר למה.
הרבה מהתובנות החשובות מגיעות פשוט מקריאת traces: איפה הסוכן בחר כלי לא נכון, איפה פירש לא נכון הודעת שגיאה, איפה בזבז עשרה סיבובים על חיפוש. זה גם המקום שבו רואים אם כלי מתוכנן טוב (פרק 8).
בפרודקשן אותו מנגנון הופך לניטור: אחוזי הצלחה, עלות ממוצעת למשימה, לולאות שנעצרו על מגבלת צעדים. וכל כישלון שמתגלה שם חוזר לסט ה-evals כמשימה חדשה — וכך המעגל נסגר.