Новости ИИ

claude plugin eval: как измерить, что ваш плагин для Claude Code

Heli
Автор
Heli
Опубликовано 12.09.2026
0,0
Views 4

У автора плагина или навыка для Claude Code до сих пор был один способ проверить свою работу: открыть сессию, напечатать запрос, посмотреть на ответ и решить, что стало лучше. Способ рабочий, но у него есть два изъяна. Во-первых, вы проверяете на той формулировке, которую сами и придумали, а живой человек напишет иначе. Во-вторых, вы не знаете, справился бы Claude без вашего плагина.

Команда claude plugin eval закрывает обе дырки. Она прогоняет плагин на наборе реалистичных запросов, проверяет результат формальными критериями, а затем повторяет тот же набор с выключенным плагином и показывает разницу. Давайте разберемся, из чего эта разница считается, во что обходится и где в ней подводные камни.

Что нужно, чтобы команда вообще запустилась

Три условия:

1) Claude Code версии 2.1.269 или новее. Проверить, claude --version, обновить, claude update
2) каталог плагина с манифестом plugin.json или .claude-plugin/plugin.json. Подходит и плагин вида "каталог навыков"
3) та же авторизация, с которой вы обычно работаете. Прогоны и проверки идут на ваших учётных данных и на ваших лимитах

Отдельно стоит сказать, чем эта команда не является. claude plugin validate проверяет файлы плагина на синтаксис и схему, то есть отвечает на вопрос "собирается ли". claude plugin eval проверяет поведение, то есть отвечает на вопрос "помогает ли". Формат случаев тут свой и с файлом evals/evals.json из плагина skill-creator не пересекается.

Случай и проверка

Набор живёт в каталоге evals/ внутри плагина. Каждый случай, это своя папка, а в ней два вида файлов: prompt.md с запросом и папка graders/ с проверками.

Представьте приёмку квартиры. Запрос, это задание строителям ("поклейте обои в спальне"), а проверки, это лист приёмки: ровность стен мерят уровнем, а общий вид оценивает человек глазами. Уровень даёт одинаковый ответ каждый раз, а глаз приёмщика зависит от того, кто пришёл и в каком настроении. Оба способа нужны, но доверять им надо по-разному.

В claude plugin eval ровно та же развилка, и она называется типом проверки. Их шесть:

Тип Что проверяет Считается моделью
regex регулярное выражение в ответе, стенограмме или файле нет
tool_used инструмент был вызван, столько-то раз, с таким-то вводом нет
tool_order один инструмент вызван раньше другого нет
file_exists файл по маске создан или, наоборот, не создан нет
llm рубрику "PASS если..., FAIL если...", голосует модель-судья да
baseline что результат не хуже эталонной стенограммы .jsonl да

Четыре первых считаются по стенограмме и по созданным файлам, не ходят в модель и не стоят ничего. Токены тратят только llm и baseline: судья голосует трижды и засчитывает PASS, если за него хотя бы два голоса из трёх.

Отсюда практический вывод, которого нет в анонсе. Набор, который вы гоняете на каждую правку навыка, стоит собрать из бесплатных проверок, а llm держать для того, что формально не описывается. И держать его на коротких ответах: чем длиннее текст, который читает судья, тем сильнее его вердикт плавает от прогона к прогону.

Проверка, которая пригодится почти в каждом случае, выглядит так:

---
type: tool_used
tool: Skill
input_match: '"skill"\s*:\s*"(?:[\w-]+:)?your-skill-name"'
---

Она отвечает на самый частый вопрос автора навыка: а он вообще сработал, или Claude ответил сам и мимо.

Главная цифра, это не оценка

Один случай по умолчанию гоняется три раза, потому что агент недетерминирован и по одному запуску ничего не понять. Оценка прогона, это доля пройденных проверок, оценка случая, это среднее по прогонам. Случай считается пройденным, когда его оценка дотягивает до порога --threshold, а порог по умолчанию равен 1.0, то есть требует всех проверок.

А затем те же три прогона повторяются с выключенным плагином, и в таблице появляется вторая колонка:

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

Это контрольная группа, как в испытании лекарства: одной половине дают препарат, другой пустышку, и ценность препарата, это разница между половинами, а не самочувствие первой половины. Оценка 1.00 в колонке WITH сама по себе не говорит ни о чём. Если в колонке W/OUT тоже 1.00, случай проходит без вашего плагина, и плагин тут не при чём.

У этого механизма есть тонкость, из-за которой дельта иначе врала бы в вашу пользу. Проверка "навык был вызван" без плагина не может пройти никогда, и если её считать, прогон без плагина уедет к нулю, а Δ надуется. Поэтому такие проверки из счёта исключаются в обоих плечах и показываются только как индикатор. Это все проверки tool_used с инструментом Skill и всё, что вы сами помечаете arm: with-only. Обратный случай, проверка "навык НЕ должен вызываться" с min: 0 и max: 0, наоборот, должна считаться в обоих плечах, и для неё ставят arm: both.

Самая частая находка на первом же прогоне выглядит так: Δ около нуля, а проверка tool_used: Skill красная. Это значит, что модель не выбирает ваш навык на живой формулировке запроса. Лечится не текстом навыка, а его полем description во фронтматтере, и проверяется повторным прогоном.

Как это запускается

Сам набор писать руками не нужно, хотя можно. Из корня плагина:

claude plugin eval init

Откроется интерактивная сессия. Claude прочитает плагин, спросит вас, что считается хорошим и плохим результатом, предложит формулировки, которые должны вызывать плагин и которые вызывать его не должны, подберёт проверки, один раз прогонит их вживую и запишет по папке на каждый запрос. Дальше вы выходите из сессии и запускаете набор:

claude plugin eval .

Если хотите сначала посмотреть, из чего состоят файлы, есть пустой шаблон: claude plugin eval init --bare first-case. Он пишет заготовку и не запускает ничего.

Для итерации по одному случаю есть режим подешевле:

claude plugin eval . --case <case-name> --runs 1 --ablation none

Тут стоит остановиться, потому что в анонсе названа только половина экономии. --runs 1 снимает два прогона из трёх, а --ablation none убирает всё второе плечо, то есть ещё половину от остатка. Один случай с настройками по умолчанию, это шесть запусков модели. В таком режиме вместо WITH, W/OUT и Δ в таблице появятся колонки SCORE и PASS%, а Δ вы не увидите, её просто не с чем считать. И помните, что один прогон шумный: увидели улучшение на --runs 1, подтвердите его на трёх, прежде чем поверить.

Отчёт report.html пишется в evals/results/<время>/ и представляет собой один самодостаточный файл без внешних запросов, поэтому его можно приложить к сборке CI или открыть с диска. В нём видно вердикт по каждой проверке каждого прогона, а для проверок llm ещё и голоса судьи с тем куском текста, который он читал. Если вы вошли по подписке claude.ai и артефакты для аккаунта доступны, отчёт дополнительно публикуется приватным артефактом и в вывод добавляется строка Published:. Ключ --no-publish оставляет отчёт только на диске.

Чего прогон не видит

Каждый запуск получает свой одноразовый домашний каталог, рабочий каталог и конфигурацию, и агент работает там дочерним процессом claude -p с одним только вашим плагином.

Это экзамен в чужом кабинете, а не работа за своим столом. Внутрь не попадает ничего вашего: настройки пользователя, хуки, файлы CLAUDE.md, серверы MCP, другие установленные плагины, память, навыки. Из переменных окружения проходит только разрешённый список и переменные с префиксом EVAL_. Каталог с самими случаями агенту тоже не виден, поэтому подсмотреть свои проверки он не может.

Практических следствий два. Первое: рабочий каталог пустой, значит всё, что нужно задаче, либо кладётся в текст запроса, либо создаётся скриптом scaffold_script, либо передаётся переменной EVAL_*. Упоминания вида @path в запросе в файлы не разворачиваются. Второе: если ваш навык работал только потому, что рядом лежал нужный CLAUDE.md, в прогоне это вылезет наружу.

Инструменты в прогоне тоже урезаны, и разрешения никто не спрашивает. Доступен набор только для чтения: Read, Glob, Grep, NotebookRead, Skill, Agent, TodoWrite и инструменты задач. Всё, что пишет или ходит в сеть, надо выдавать явно:

claude plugin eval . --allow-tools Write Edit "Bash(npm test *)"

Тут есть ограничение, которое стоит знать до того, как вы соберёте набор. Любая выдача Bash включает песочницу уровня операционной системы, а на нативной Windows движка песочницы нет. Такой набор там не запустится: Claude Code откажет каждому прогону, вместо того чтобы выполнить его без изоляции, и случай получит ноль. Выход, это WSL2, а на Linux надо поставить bubblewrap и socat.

Сколько это стоит

Стоимость в таблице и в отчёте, это оценка по прайсовым ценам сделанных вызовов, а не счёт. Объём считается прикидкой: примерно "случаи умножить на прогоны" запусков агента с плагином, столько же без плагина, и плюс три коротких вызова судьи на каждую проверку llm или baseline в каждом прогоне.

Способы удержать расход:

1) --max-cost-usd <usd> ставит потолок, который проверяется перед стартом каждого запуска. Запущенное добивает до конца, поэтому итог может немного превысить потолок, а команда выйдет с кодом 2 и частичными результатами

2) --ablation none там, где Δ не нужна

3) бесплатные проверки в быстром наборе, llm только там, где без судьи не обойтись

4) -j, или --concurrency, от 1 до 8 запусков одновременно. На стоимость не влияет и предел вашего аккаунта не обходит, сокращает только время ожидания

5) --judge-model по умолчанию указывает на небольшую быструю модель. Для тонких рубрик её меняют на sonnet, и вот это уже влияет на счёт

Запуск в 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, что какой-то случай ушёл ниже порога, или файл случая не загрузился, или случаев не нашлось, или каталог не доверенный. Код 2, это частичный прогон: упёрлись в потолок стоимости или отвалились учётные данные, но results.json всё равно записан с partial: true и причиной. Код 130, это прерывание, 143, это завершение извне, например по таймауту сборки. Проблемы с публикацией отчёта на код выхода не влияют.

Две мелочи, которые экономят день отладки. Первая: --trust-plugin нужен, потому что при первом запуске команда спрашивает "Trust this plugin directory?", а под --json или без терминала спросить не может и падает с кодом 1. Вторая: закрепляйте обе модели, и рабочую, и судью. Иначе через месяц выкатится новая версия модели, набор просядет, и вы будете искать регресс в своём плагине, которого там нет.

Честное "но"

Как всегда есть НО, и тут их несколько.

Проверки llm недетерминированы. Судья, это модель, и на длинном тексте её вердикт плавает. Документация прямо советует: если tool_used: Skill проходит, а Δ отрицательная, сначала подозревайте судью, а не плагин. Небольшая модель вполне может зарубить правильный ответ за то, что он оформлен не так, как описано в рубрике.

Порог по умолчанию 1.0 строгий. Он требует, чтобы прошли все проверки во всех прогонах, и на живом наборе это скорее повод настроить порог осознанно, чем оставлять как есть.

И главное, про безопасность, которое в анонсе сказано одной строкой. claude plugin eval грузит навыки и хуки проверяемого плагина и выполняет их на вашей машине от вашего имени. Это то же решение о доверии, что и claude --plugin-dir. Изоляция, описанная выше, ограничивает агента под тестом, а не код самого плагина. Хуки и реальные серверы MCP работают вне песочницы агента, поэтому теоретически способны дотронуться до тех самых файлов, которые потом читают проверки. Пройденный набор говорит о поведении плагина и ничего не говорит о том, безопасен ли он. Чужой плагин с хуками, которые вы не писали, стоит гонять в контейнере или на раннере CI, а его оценки до тех пор считать справочными.

Вывод

Ценность этой команды не в том, что появилась оценка, а в том, что появилась вторая колонка. Навык, который выглядел полезным, довольно часто набирает единицу и с ним, и без него, и это значит, что модель справлялась и сама, а вы месяц полировали текст, который ни на что не влиял.

Начинать стоит с одного случая и двух проверок: одна на результат, вторая на то, каким путём результат получен. Дальше смотреть не на общий счёт, а на строки с Δ около нуля, потому что именно там ваш плагин не работает.

Авторизуйтесь, чтобы оставить комментарий.

Комментариев: 0

Нет комментариев.

Тут может быть ваша реклама

Пишите info@aisferaic.ru

Похожие новости