מה זה claude plugin eval
בנית פלאגין או סקיל לקלוד קוד. הוא עובד אצלך. אבל האם הוא באמת משפר משהו, או שקלוד היה מגיע לאותה תוצאה גם בלעדיו? עד עכשיו לא הייתה דרך לענות על זה חוץ מלהריץ דמו אחד ולהתרשם.
הפקודה claude plugin eval מריצה את הפלאגין שלכם מול חבילת מקרי בדיקה ונותנת לזה ציון. כל מקרה הוא פרומפט מציאותי בתוספת גריידר אחד או יותר, בדיקת עובר/נכשל על מה שקלוד הפיק.
הדבר החשוב באמת: כל מקרה רץ גם בלי הפלאגין. ההפרש בין שתי הריצות הוא מה שהפלאגין תרם, ולא הציון המוחלט.
מה צריך כדי להריץ
- קלוד קוד בגרסה 2.1.269 ומעלה. בדקו עם claude —version ועדכנו עם claude update
- תיקיית פלאגין עם קובץ plugin.json או .claude-plugin/plugin.json, או פלאגין מסוג skills-directory
- אותו חיבור ואותו ספק מודל שאתם עובדים איתם רגיל. כל ריצה היא קריאת מודל אמיתית על החשבון שלכם
איך ריצה אחת עובדת
בכל ריצה של מקרה, קלוד קוד פותח סשן חדש, מבודד ולא אינטראקטיבי, עם הפלאגין שלכם בלבד טעון. הוא שולח את הפרומפט ונותן לקלוד לעבוד עד שהוא מסיים או עד שהוא מגיע למגבלת התורות או הזמן של המקרה. אחר כך כל גריידר בודק את התשובה הסופית, את התמליל, או קובץ שקלוד יצר.
ריצה אחת של סוכן לא דטרמיניסטי לא מספרת כמעט כלום, ולכן כל מקרה רץ שלוש פעמים כברירת מחדל. הציון של ריצה הוא שיעור הגריידרים שעברו, והציון של המקרה הוא הממוצע על פני הריצות.
במקביל, אותו מספר ריצות מתבצע בלי הפלאגין בכלל. שתי התוצאות נקראות WITH ו-W/OUT, וההפרש ביניהן הוא Δ. אם מקרה מקבל 1.00 גם עם הפלאגין וגם בלעדיו, הפלאגין הוא לא מה שגרם לו לעבור.
שימו לב לחשבון: מקרה אחד בברירת המחדל הוא שש ריצות סוכן. חבילה של שבעה מקרים היא 42 ריצות.
שתי פקודות והחבילה קיימת
אתם לא חייבים לכתוב את החבילה ביד. מהתיקייה הראשית של הפלאגין:
claude plugin eval init
קלוד קורא את הפלאגין, שואל אתכם איך נראית תוצאה טובה, מציע פרומפטים שאמורים להפעיל את הפלאגין ופרומפטים שלא אמורים, מתכנן גריידרים לכל אחד, מנסה אותם פעם אחת כדי לוודא שהם מתנהגים, וכותב את הקבצים. בסיום צאו מהסשן עם /exit.
ואז מריצים את הכל:
claude plugin eval .
רוצים רק את התבנית הריקה בלי סשן אינטראקטיבי:
claude plugin eval init --bare first-case
מבנה התיקיות
החבילה חיה בתיקייה בשם evals בתוך הפלאגין. כל מקרה הוא תת-תיקייה משלו:
my-plugin/
├── .claude-plugin/plugin.json
├── skills/...
└── evals/
├── first-case/
│ ├── prompt.md # frontmatter: הגדרות; body: הפרומפט
│ ├── graders/
│ │ └── criteria.md # גריידר אחד לכל קובץ
│ └── case.yaml # אופציונלי: רק לשדות context.*
└── results/ # נכתב בכל ריצה. הוסיפו ל-gitignore
ששת סוגי הגריידרים
ארבעה מחושבים מהתמליל ומהקבצים ולא עולים שקל. שניים קוראים למודל שופט ומוסיפים לעלות של הריצה.
| סוג | אפשרויות | עובר כאשר |
|---|---|---|
regex | pattern, flags, match, target | הביטוי נמצא ביעד. match: not_contains דורש היעדר, ו-match: “count:N” דורש בדיוק N התאמות |
tool_used | tool, input_match, min, max | מספר הקריאות לכלי נמצא בין min (ברירת מחדל 1) ל-max. כדי לוודא שכלי לא נקרא בכלל: min: 0 וגם max: 0 |
tool_order | before, after | שני הכלים נקראו, והקריאה הראשונה שמתאימה ל-before קדמה לזו של after |
file_exists | path, exists | קובץ שקלוד יצר מתאים לתבנית הנתיב. נספרים רק קבצים שנוצרו במהלך הריצה |
llm | criteria, focus | מודל שופט מצביע PASS על הרובריקה בלפחות שתיים משלוש הצבעות. עולה כסף |
baseline | baseline_file, criteria | שופט מוצא שהריצה עומדת בקריטריונים לפחות כמו תמליל ייחוס. עולה כסף |
אין גריידרים של קוד מותאם אישית. מה שיש זה ששת אלה.
תבנית שבע הבדיקות
זאת החבילה שאני ממליץ להתחיל ממנה לכל פלאגין. כל מקרה תופס כשל אחר, וביחד הם מכסים גם את השאלה “האם התשובה נכונה” וגם את השאלה “האם הפלאגין שלי הוא זה שהביא אותה”.
הכלל שמאחורי התבנית: תנו לכל מקרה גריידר אחד על התוצאה, וגריידר אחד על הדרך שבה קלוד הגיע אליה.
1. happy-path: הבקשה שבשבילה בניתם את הפלאגין
הפרומפט המרכזי, מנוסח כמו שמשתמש היה כותב אותו. הקובץ evals/happy-path/prompt.md:
---
max_turns: 10
allowed_tools: [Read, Glob, Grep, Skill]
---
<הבקשה שהסקיל שלכם אמור לטפל בה, במילים של משתמש>
graders/criteria.md: מה נחשב תשובה נכונה:
---
type: llm
---
PASS if <מה שתשובה נכונה מכילה>.
FAIL if <איך נראית תשובה שגויה או חסרה>.
graders/skill-fired.md: ומי הביא אותה:
---
type: tool_used
tool: Skill
input_match: '"skill"\s*:\s*"(?:[\w-]+:)?your-skill-name"'
---
2. ignores-unrelated-request: הפלאגין שיודע לשתוק
פלאגין שנטען על כל בקשה הוא פלאגין מזיק. כתבו פרומפט מתחום סמוך שהסקיל שלכם לא אמור לגעת בו, ודרשו שהוא לא ייטען:
---
type: tool_used
tool: Skill
input_match: '"skill"\s*:\s*"(?:[\w-]+:)?your-skill-name"'
min: 0
max: 0
arm: both
---
ה-arm: both כאן קריטי. גריידר של tool_used על Skill מוחרג מהציון כברירת מחדל, כי הוא לעולם לא יכול לעבור בלי הפלאגין. בבדיקה של “אסור להיטען” אתם דווקא רוצים שהוא ייספר בשני הצדדים.
3. natural-phrasing: הבדיקה שתופסת תיאור גרוע
אותה משימה כמו במקרה הראשון, אבל מנוסחת אחרת לגמרי, בלי אף מילה מהתיאור של הסקיל. זאת הבדיקה שתופסת את הכשל הנפוץ ביותר: פלאגין שעובר כל ולידציה, מופיע בתפריט, ואף אחד לא מפעיל אותו בפועל כי התיאור לא כתוב בשפה של המשתמש.
אם כאן ה-Δ קרוב לאפס וגריידר ה-tool_used נכשל, הבעיה היא לא הקוד. היא התיאור. תיאור כמו “מודול לניתוח סטטי של PR” אף אחד לא מפעיל. החליפו ל”כשמבקשים לבדוק PR לפני מיזוג”, הריצו שוב, וה-Δ קופץ.
4. produces-file: התוצר, לא הדיבור
אם הסקיל אמור לייצר קובץ, אל תשפטו את ההודעה הסופית. שפטו את הקובץ. שני גריידרים חינמיים:
--- graders/file-created.md
type: file_exists
path: "**/CHANGELOG.md"
---
--- graders/file-content.md
type: regex
target: file
pattern: "## \\[\\d+\\.\\d+\\.\\d+\\]"
---
לפלט ארוך כמו קובץ שנוצר, גריידר regex עדיף על שופט: הוא בודק את כל הקובץ באותה צורה בכל פעם. שופט קורא טקסט ארוך ומשנה דעה בין ריצות.
5. correct-order: סדר הפעולות
הרבה סקילים נכשלים לא בתוצאה אלא בסדר: הם כותבים לפני שהם קראו. זה נתפס בגריידר אחד חינמי:
---
type: tool_order
before: Read
after: Write
---
כל צד יכול להיות שם של כלי או אובייקט עם tool ו-input_match, אם אתם רוצים לדרוש פקודה מסוימת ולא רק כלי.
6. handles-missing-input: מה קורה כשחסר מידע
תנו פרומפט חלקי בכוונה, כזה שאי אפשר לבצע נכון בלי לשאול. סקיל טוב שואל. סקיל גרוע ממציא. גריידר llm עם רובריקה חדה:
---
type: llm
---
PASS if the reply asks for the missing detail before acting.
FAIL if it invents a value, or proceeds as if the detail was given.
7. regression-guard: הבאג שכבר תיקנתם
בכל פעם שמשהו נשבר ותיקנתם, הוסיפו מקרה שמוודא שזה לא חוזר. הכי זול וישיר זה גריידר של היעדר:
---
type: regex
pattern: "<הטקסט או הדפוס שאסור שיחזור>"
match: not_contains
---
החבילה הזאת גדלה איתכם. שישה מקרים קבועים, ועוד אחד בכל פעם שמשהו נשבר.
איך לקרוא את התוצאות
בסיום הריצה מודפסת טבלת סיכום:
CASE WITH W/OUT Δ RUNS COST NOTES
first-case 1.00 0.33 +0.67 6 $0.41
1 case(s) · mean Δ +0.67 · 74s · $0.41
| עמודה | מה היא אומרת |
|---|---|
WITH | הציון של המקרה כשהפלאגין טעון |
W/OUT | הציון של אותו מקרה בלי הפלאגין בכלל |
Δ | ההפרש. זה מה שהפלאגין תרם. אפס אומר שהוא לא תרם כלום |
COST | הערכת מחירון של קריאות המודל בריצה הזאת |
NOTES | ההסבר של הגריידר הכושל בעל המשקל הגבוה ביותר |
ופה זה נהיה שימושי: אם הפלאגין עוזר בשתי משימות אבל פוגע בחמש אחרות, אולי לא צריך לשפר אותו. אולי צריך למחוק אותו.
לאיטרציה זולה על מקרה אחד, הריצו צד אחד פעם אחת. הטבלה תציג SCORE ו-PASS% במקום WITH, W/OUT ו-Δ:
claude plugin eval . --case <case-name> --runs 1 --ablation none
ריצה בודדת רועשת. אשרו כל שינוי בשלוש הריצות המלאות לפני שאתם סומכים עליו.
הרצה ב-CI
קבעו את שני המודלים כדי שציונים יהיו ברי השוואה לאורך זמן, שמרו את הדוח מקומי, והגדירו תקרת עלות:
claude plugin eval . \
--trust-plugin \
--json results.json \
--threshold 0.8 \
--model claude-sonnet-5 \
--judge-model claude-haiku-4-5 \
--no-publish \
--max-cost-usd 20
- קוד יציאה 0: כל המקרים עברו את הסף
- קוד יציאה 1: מקרה מתחת לסף, קובץ מקרה שלא נטען, או שהתיקייה לא מהימנה בלי —trust-plugin
- קוד יציאה 2: ריצה חלקית: תקרת העלות נפגעה או שהחיבור נדחה
הקאץ’: עלות והרשאות
- כל ריצה וכל גריידר שופט הם קריאת מודל אמיתית על החשבון שלכם, שנספרת מול מגבלת התוכנית או מול חשבון ה-API
- שלוש חזרות לכל מקרה בשני צדדים אומר שש ריצות למקרה. חבילה של שבעה מקרים היא 42 ריצות
- הדרך הזולה: בנו את רוב הבדיקות על ארבעת הגריידרים החינמיים, ושמרו את השופט רק למקומות שבאמת דורשים שיפוט
- פלאגין לא מוכר רץ אצלכם, בתור המשתמש שלכם. הרצת eval על פלאגין היא אותה החלטת אמון כמו claude —plugin-dir. הוקים ושרתי MCP שלו רצים מחוץ לארגז החול
- הבידוד מגן על הסוכן הנבדק, לא עליכם מפני הקוד של הפלאגין. חבילה שעוברת לא אומרת שהפלאגין בטוח
טיפים
- התחילו מ-claude plugin eval init. הוא כותב חבילה עובדת מהר יותר ממה שתכתבו ביד
- גריידר אחד על התוצאה וגריידר אחד על הדרך. ביחד הם אומרים גם אם התשובה נכונה וגם אם הפלאגין הביא אותה
- לפלט ארוך העדיפו regex על שופט. שופט מתלבט יותר ככל שהטקסט ארוך יותר
- אם tool_used עובר אבל ה-Δ שלילי, תחשדו בשופט לפני שתחשדו בפלאגין. הריצו עם —judge-model sonnet והדקו את הרובריקה כך שפורמט לא יקבע את הפסיקה
- כל ריצה מתחילה בתיקיית עבודה ריקה. שימו בפרומפט את כל מה שהמשימה צריכה, או הכינו את הסביבה מראש
- הסוכן לא רואה את קבצי הבדיקה. הוא לא יכול לקרוא את הפרומפט, את הגריידרים או מקרים שכנים
- הוסיפו את evals/results/ ל-gitignore. הוא נכתב מחדש בכל ריצה
- הריצו —ablation none כשאתם רק מכווננים גריידרים. זה חוצה את העלות
לינקים
- התיעוד הרשמי: code.claude.com/docs/en/plugin-evals
- ההכרזה הרשמית: x.com/ClaudeDevs
- יצירת פלאגין מאפס: code.claude.com/docs/en/plugins