🇷🇺 Русский · 🇬🇧 English
Самостоятельный харнесс, чтобы гонять модели против MCP-тулз askads (Яндекс Директ / VK Ads / Метрика) и бенчить их между собой на нашем домене (русская рекламная аналитика + многошаговый tool-use), а не на чужих кодинг-бенчах.
Два режима:
fixed— детерминированные фикстуры (замороженный фейк-кабинет какtool_result). Воспроизводимое сравнение моделей, гоняется в CI без сети/ключей кабинета.live— спавн РЕАЛЬНЫХ MCP-серверов по stdio (mcp-yandex-directи т.д.) с токенами из env. Интеграционные тесты самих тулов на живом кабинете.
Движок и MCP-клиент развязаны от askads (вынесены в llmbench/), репозиторий автономен.
Как читать таблицу результатов:
| Метрика | Что | Кто считает |
|---|---|---|
| Accuracy | точность чисел (CTR/CPC/CPA/расход) + верная привязка к кампании (entity-анкоринг), без выдумок | Оценивается кодом |
| Tools Use | нужные тулы вызваны успешно, в нужном порядке, без лишних/запрещённых | Оценивается кодом |
| Edge Cases | поведение в краевых случаях (пустой отчёт, отказ менять ставку, уточнение) | Оценивается LLM-судьями |
| Lang quality | естественность и ясность русского | Оценивается LLM-судьями |
| Score | сводный балл прогона = среднее доступных компонент (см. «Как считается Score») | — |
| Cost per Answer | средняя стоимость одного ответа, USD | — |
| Score per USD | «качество на доллар» (Score ÷ цена); выше = выгоднее | — |
| Stability | 5 − разброс Score между повторами кейса; выше = стабильнее |
— |
| ⭐ | лучший баланс «качество/цена»: нет варианта, который был бы и качественнее, и дешевле одновременно | — |
Score одного прогона — среднее доступных компонент (не всех четырёх колонок сразу):
- Tools Use — всегда;
- Accuracy — если у кейса есть golden-факты (числовые кейсы);
- Edge Cases и Lang quality — если работали судьи.
Состав компонент зависит от кейса, поэтому:
- Score сравним между вариантами (кейсы у всех одни), но не равен среднему четырёх колонок отчёта;
- упавшие прогоны (ошибки API, обрезка лимитом токенов) в метрики не входят — они в отдельной колонке
Err; Stability = 5 − средний разброс (σ) Score между повторами одного кейса— ловит шум модели, а не разницу сложности кейсов.
results/2026-07-03/ (+ англ. results.en.md) — свежий полный грид (16 вариантов × 9 кейсов × 3 повтора = 432 прогона, 0 ошибок, ≈ $18) на исправленном скоринге.
Топ-3 по балансу «качество/цена» (⭐):
| LLM | Thinking | Score | Cost/ответ | Чем берёт |
|---|---|---|---|---|
| GLM-4.6 | нет | 4.62 | $0.003 | лучший «качество/цена», ~27× дешевле Opus |
| GPT-4.1 | нет | 4.93 | $0.013 | неожиданно силён и дёшев |
| Opus 4.8 | adaptive/high | 4.96 | $0.081 | потолок качества |
Sonnet 4.6 (текущий прод) просел на краевых кейсах (Edge ~3.3 — выдумывает причины на пустом срезе, не уточняет неясный вопрос). Прогон results/2026-06-29/ — исторический, до правок скоринга.
llmbench/
core.py # allowlists, конвертеры тулов, обрезка, ставки, system-prompt, retry, таймауты
fixtures.py # замороженный кабинет + FIXTURE_VERSION (единый источник golden-фактов)
mcp.py # live stdio-клиент + реестр серверов + fake-сессия + preflight_live
engines.py # агентные loop'ы: run_anthropic (Claude/GLM), run_openai (GPT); ретраи, таймауты
scoring.py # numeric (entity-анкоринг) + toolcheck (учёт is_error) + cost
judges.py # панель {Claude, GPT, GLM, (опц.) Gemini}, нейтральность, детерминизм
cases.py # кейсы (вопрос + trace-спека + golden_facts с entity + рубрика)
report.py # агрегация записей, Stability/Score/Pareto, сборка markdown (тестируется в CI)
runner.py # сетка вариантов × кейсы × repeat, JSONL-персист, отчёт
tests/ # офлайн self-test: скоринг + агрегация + конвейер ранера (всё в CI)
results/ # per-date папки: results.ru.md + results.en.md + сырой runs.jsonl (всё под VCS для fixed)
Нужен Python ≥ 3.10 (в CI — 3.11).
Офлайн self-test (без сети/денег; CI):
pip install -r requirements-dev.txt
pytest -qДетерминированный model-бенч (нужны ключи моделей):
RUN_BENCH=1 ANTHROPIC_API_KEY=… ZAI_API_KEY=… OPENAI_API_KEY=… \
python -m llmbench.runner --mode fixed --repeat 2Опц. GOOGLE_API_KEY — добавляет Gemini-судью (нейтрального, когда GPT — кандидат).
Против РЕАЛЬНЫХ тулов (нужны npm-серверы + токены кабинета):
npm install # ставит mcp-yandex-direct и др.
RUN_BENCH=1 ANTHROPIC_API_KEY=… YANDEX_DIRECT_TOKEN=… \
python -m llmbench.runner --mode live --variants "GLM-4.6 disabled" --judges offEnv токенов кабинета (для --mode live):
| Env | Назначение |
|---|---|
YANDEX_DIRECT_TOKEN (+ опц. YANDEX_DIRECT_LOGIN) |
токен Яндекс Директа — обязателен для live; LOGIN нужен, если токен агентский |
YANDEX_METRIKA_TOKEN |
токен Метрики (для metrika-кейсов) |
VK_ADS_TOKEN |
токен VK Ads |
MCP_PATH_YANDEX_DIRECT |
опц. — переопределить путь к MCP-серверу (/path/to/dist/index.js) |
Live-режим делает префлайт (токены + наличие серверов) ДО первого платного вызова.
Флаги ранера:
| Флаг | Что делает |
|---|---|
--mode fixed|live |
фикстуры (дефолт) или реальные MCP-серверы |
--variants <подстроки…> |
какие варианты гнать (опечатка в фильтре — ошибка, а не молчаливый полный грид) |
--cases <id…> |
какие кейсы гнать (та же защита от опечатки) |
--repeat N |
повторов на кейс (дефолт 2) |
--judges panel|neutral|off |
панель судей / только нейтральные / без судей |
--concurrency N |
параллельных прогонов внутри варианта (дефолт 4) |
--dry-run |
показать смету (число прогонов/судейских) без ключей и трат |
--out <dir> |
каталог отчёта (дефолт results/<date>/) |
--report-from <jsonl> |
пересобрать отчёт (ru+en) из runs.jsonl бесплатно |
--resume <jsonl> |
догнать прерванный прогон (только недостающие/упавшие ключи) |
Список вариантов (модель × thinking/effort/reasoning) — в llmbench/runner.py; добавить модель = одна строка (не забудь тариф в core.MODEL_RATES, иначе ранер предупредит).
Каждый прогон складывается в дата-папку results/<date>/: сырой runs.jsonl (по записи на прогон — ответ, tool-трейс, usage, все оценки, ошибки) и двуязычный авто-отчёт results.ru.md + results.en.md. runs.jsonl — источник правды: отчёт (обе версии) пересобирается из него бесплатно, без повторных вызовов моделей —
python -m llmbench.runner --report-from results/2026-07-03/runs.jsonlruns.jsonl под VCS для fixed-прогонов (фейк-кабинет, приватных данных нет; ~230 КБ в паке). runs.jsonl не коммить (локально/приватный S3). Отчёты .md — под VCS. Топ-3, прозу и выводы дописывают руками поверх сгенерированного грида в той же дата-папке. Второй прогон за день не затирает первый (при коллизии по дате к папке добавляется время).
Прервался (обнулился баланс, Ctrl-C)? Готовые прогоны уже в runs.jsonl (пишется построчно по мере готовности) — долей баланс и догони остаток, платя только за него:
RUN_BENCH=1 …ключи… python -m llmbench.runner --resume results/2026-07-03/runs.jsonl--resume пропускает уже успешные (вариант, кейс, повтор), гоняет только упавшие/недостающие, дописывает в тот же файл и пересобирает отчёт (при дублях успех побеждает). Можно и добавить ключ (напр. OPENAI_API_KEY) и догнать варианты, пропущенные в исходном прогоне.
- Потолок кейсов: топ-модели упираются в 5.0 по Tool/Numeric → «паритет» здесь = «оба отлично решают ЭТИ задачи». Для строгого различения качества нужны более трудные кейсы.
- Судьи вторичны: без нейтрального вендора первичный мягкий балл = среднее панели (advisory, возможна self-preference). Вес сравнения — на ключевых метриках.
- Ставки/кэш-множители моделей — по прайс-листам; сверить с биллингом.
glm-5/gpt-5: доступность ≠ идентичность ожидаемой модели — сверить.--repeat— грубый флаг шума; «неверное число == пропущенное» в numeric — упрощение.fixed-режим не ловит robustness на грязном API-выводе (для этого--mode live).system-promptвcore.py— доменный (аналитик Директа); замени под свой кейс.