В прошлый раз я писал про "Как я пишу почти автономного агента для разработки своих пет-проектов", а сейчас я хочу сместить фокус на выбор модели под конкретные задачи. В сети полно контента на тему "Вышел новый GPT Astra (Claude Fable) near-AGI edition", но нас это мало чем интересует: дорого, долго и слишком самостоятельны.

На этот раз я решил обойтись без нейрослопа (почти), поэтому сразу прошу прощения за возможные ошибки, пунктуацию и пассивную агрессию (если такая имеет место быть с моей стороны)

Зачем самостоятельно оценивать модели?

Если присмотреться, то можно заметить, что все AI-вакансии имеют общее ядро — оценка качества моделей (выполняемой ими работы), а с замерами всегда есть и будут проблемы, но если не пытаться, то нет понимания "что хорошо и что плохо", получится "Я подправляю вручную инструкции (промпты) и смотрю, что получилось, после чего запускаю eval-тесты, пройдет — хорошо, не пройдет — буду дальше ковырять промпт". Но статья не о процессе разработки, а об оценке моделей.

Почему не опираюсь на общие бенчмарки в сети

Не секрет, что работа LLM сильно завязана на работу харнеса (harness, простыми словами — обвязка над LLM) — отсюда вывод, что публичные официальные бенчмарки показывают работу LLM в вакууме, и даже если вы найдете бенчмарки под харнес, он не будет учитывать ваши надстройки.

Про бенчмарки типа "Спроектируй визуализацию гелиоцентрической солнечной системы" промолчу, по мне, выглядит красиво, но к реальным решаемым задачам имеет малое отношение.

Какие типы задач имею на данный момент и на что я пишу бенчмарки

На данный момент мои основные задачи можно разделить на:

  • генерация кода и создание диаграмм

  • выжимка и переводы текста

  • оценка/сравнение других моделей

  • объяснение сложных вещей простыми словами

Задач много, а бенчмарков не так много — везде, где необходимо какое-то детерминированное действие стараюсь использовать бенчмарки (собирать метрики насколько хорошо или плохо отрабатывает модель), но грань тонкая и выявить ее не так просто (мб для этого стоит написать еще агента?). Я руководствуюсь правилами "Нормально делай — нормально будет.." "Если я представляю конкретный валидный результат — необходимо собирать метрики. Если правильных вариантов несколько — опиши несколько вариантов".

Какие типы бенчмарков

Скор везде — число от 0 до 1, чем ближе к единице, тем лучше. Бенчмарки делятся на три группы: генеративные (текст на входе — текст на выходе), embedding-ные (работают с векторами текстов) и decision-ные (строгий выбор или оценка по шкале).

Таблица типов бенчмарков

Бенчмарк

Что делает простыми словами

Скор — что измеряет

translation (перевод)

модель переводит текст; есть эталон (если вариантов несколько — считаем по лучшему)

F1 — совпадение слов ответа и эталона с учётом повторов. Попросту: та же лексика, что в хорошем переводе; отсебятина и вода снижают балл

summarization (выжимка)

модель сжимает длинный текст в краткий пересказ

тот же F1 против эталонной выжимки (эталонных вариантов может быть несколько)

codegen (код)

модель пишет функцию/класс, код реально компилируется и запускается на кейсах «вход → ожидаемый выход» (python, C++, Java, JavaScript)

pass_rate — доля кейсов, где код отработал и вернул ровно ожидаемое. Не «похоже на правду», а «работает — не работает»

instructions (инструкции)

формальные требования к тексту: «не больше 30 слов», «в верхнем регистре», «без цифр», «валидный JSON», «маркированный список» и т.п.

доля пройденных пунктов чек-листа

math (математика)

задачи с числовым ответом (маркер «Ответ: <число>»)

1/0 — совпало ли число с эталоном (с допуском). В среднем по задачам получается доля реально решённых — ход решения не проверяется, только итог

sts (близость текстов)

пары текстов, у каждой человеческая оценка «насколько близки по смыслу»

Spearman — совпадает ли ранжирование пар по смыслу у модели (косинус эмбеддингов) с человеческим. Ближе к 1 — модель «чувствует» близость как человек

retrieval (поиск по корпусу)

по запросу найти релевантные документы в корпусе (эмбеддинги + косинус)

nDCG@10 — насколько высоко в топ-10 выдачи стоят релевантные документы: первое место — максимум, десятая — почти мимо

news_search (поиск по новостям)

то же самое, но на реальном корпусе новостей (новости в моем отдельном пет-проекте, не тема статьи)

nDCG@10

embedding_classification (классификация)

текст относят к классу ближайшего образца («прототипа»), всё внутри на эмбеддингах

accuracy — доля верно угаданных классов

decision (выбор/оценка по шкале)

строгий выбор через Decision API (или чат со structured output для текстовых моделей): выбрать вариант (choice), сказать уверенность (noul), оценить по шкале (score)

«насколько угадал»: выбор — совпадение 1/0; уверенность — штраф за самоуверенный промах (Brier); шкала — средний промах от эталона (MAE)

scoring (скоринг статей)

статья оценивается по трём критериям 1–10 (важность / релевантность / достоверность), итоговый балл = 6·imp + 4·rel + 4·trust

насколько совпал итоговый балл с эталоном: 1.0 — поставил тот же балл, что и эталон; каждый балл промаха отрезает от единицы свою долю (максимум ошибки на шкале — 126, поэтому промах в 10 баллов съедает ~0.08)

custom (песочница)

мелкие подручные проверки («посчитай», «повтори N раз»); сюда падают разовые задачи

F1 против эталона, как у перевода

Таблица метрик

Headline (вторая колонка таблицы) — это главный скор бенчмарка, он идёт в сводку и сравнение прогонов. Но при прогоне по каждому бенчмарку собирается полный набор метрик:

Метрика

Что измеряет простыми словами

Где считается

headline-скор, описан выше

главный скор бенчмарка

все бенчмарки

latency

средняя длительность одного ответа модели (с)

все бенчмарки

tokens (prompt / completion / total)

расход токенов прогона, сумма по всем запросам

все, кроме embedding

pass@k

доля тестов, решённых хотя бы одним из k сэмплов (порог почти точного попадания, 0.999): «смог ли хоть раз за k попыток»

все, осмыслен при мультисэмплинге -n

score_std

типичный разброс скора между сэмплами одного теста — насколько ответы модели стабильны

все, при -n > 1

F1

пересечение слов ответа и эталона с учётом кратности (повторы учтены); по нескольким эталонам берётся лучший

все генеративные

BLEU

доля n-грамм (1–4) ответа, совпавших с эталоном; штраф за болтовню вокруг правильного текста

все генеративные

ROUGE-1 / ROUGE-2 / ROUGE-L

совпадение одиночных слов / пар слов / самой длинной общей подпоследовательности

все генеративные

norm. Levenshtein

похожесть строк: 1.0 — совпали посимвольно; промах = сколько минимальных правок отличает ответ от эталона (нормировано на длину большего текста)

все генеративные

code similarity

сходство исходника с эталоном после нормализации (комментарии и пробелы срезаны); читается, когда ответ — код

все генеративные

cosine (средний)

косинусная близость эмбеддингов пары текстов — сырая «векторная дистанция»

sts

Spearman

совпадает ли порядок пар по близости у модели (косинусы) и у человека — главный скор

sts

Pearson

линейная связь векторов близости модели и человека

sts

MSE

средняя квадратичная ошибка прогноза близости против человеческих оценок

sts

nDCG@k

качество ранжирования: релевантные документы чем выше, тем лучше (идеал — все релевантные вверху); главный скор

retrieval, news_search

Recall@K

доля релевантных документов, попавших в выдачу

retrieval, news_search

MRR

средний «1/ранг» первого релевантного документа: нашлось ли релевантное на первых местах

retrieval, news_search

accuracy

доля верно угаданных классов; главный скор

embedding_classification

macro F1

средний F1 по классам — редкие классы не тонут

embedding_classification

micro F1

F1 по всем попаданиям сразу — частые классы весят больше

embedding_classification

accuracy (choice)

доля точных попаданий в выбранный вариант

decision

Brier (choice/noul)

штраф за самоуверенный промах: чем увереннее модель ошиблась, тем больнее метрике

decision

log loss (choice/noul)

логарифмическая ошибка вероятностей; беспощадна к полной уверенности с промахом

decision

threshold acc (noul)

доля верных решений «уверен / не уверен» относительно порога

decision

ECE (noul)

калибровка уверенности: расхождение между заявленной и фактической точностью (10 бинов)

decision

MAE (score)

средний промах ответа от эталонного уровня шкалы (1..N)

decision

level acc (score)

доля точных попаданий ровно в уровень шкалы

decision

Spearman / Pearson (score)

согласованность поставленных оценок с эталонными

decision

final_mae

средний промах итогового балла (балл от 14 до 140, максимум ошибки — 126)

scoring

MAE по критериям

отдельный средний промах по важности, релевантности и достоверности — видно, где модель слабее

scoring

level acc

доля точных попаданий в уровень 1..10 по критериям

scoring

threshold acc

доля верных решений «брать / не брать» статью относительно эталонного порога

scoring

Spearman / Pearson по итоговому баллу

согласованность итоговых баллов с эталонными

scoring

Обзор агента

Агента я назвал llm-judge (простите за плохую оригинальность и возможную путаницу), но не стоит путать с подходом LLM-as-a-judge, агентская часть по сути используется только для финального анализа, интерпретации результатов и последующего обсуждения.

Сразу отмечу, что это MVP, над UI сильно не работал и фокусировался только на важном для меня функционале.

Агент представлен в виде Go-бинарника (мой основной стек JVM, но почему я делаю выбор в пользу Go — тема другой статьи. Кратко — использование Go проще и эффективнее в контексте разработки с помощью агентов). Механика прогона такая: выбираешь хост и модель, выбираешь бенчмарки — запускаешь.

структура llm-judge (C4 L2: контейнеры ) — ранер бенчмарков, веб, админка (SQLite), агент-аналитик, писатель MySQL
структура llm-judge (C4 L2: контейнеры ) — ранер бенчмарков, веб, админка (SQLite), агент-аналитик, писатель MySQL
форма запуска — хост, модель с поиском, сэмплы, чекбоксы бенчмарков
форма запуска — хост, модель с поиском, сэмплы, чекбоксы бенчмарков

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

прогресс прогона вживую — полоски по бенчмаркам стримятся из лога
прогресс прогона вживую — полоски по бенчмаркам стримятся из лога
тот же прогон после завершения — полосы хронометража
тот же прогон после завершения — полосы хронометража
Sequence Diagram выполнения прогона
механика прогона от обнаружения бенчмарков до отчётов + агрегатов
механика прогона от обнаружения бенчмарков до отчётов + агрегатов

Сравнивать можно сразу несколько прогонов.

список прогонов всех моделей + сноска отметок для сравнения
список прогонов всех моделей + сноска отметок для сравнения
сравнение двух прогонов — скоры и дельты к базе
сравнение двух прогонов — скоры и дельты к базе

Дальше — работа с результатами. Сразу можно понять, что LLM сама по себе является черным ящиком, поэтому я ориентируюсь не только на сухие цифры (тем более из-за температуры 0.7 по умолчанию и незакреплённого seed у сервера результаты могут иметь ощутимый шум), но и на субъективные ощущения. Выжимка обсуждается с агентом в чате, агент пробует объяснить, почему получилось именно так, и имеет инструмент чтения конкретных файлов (логов) read_file.

Скриншоты + диаграммы по интерпретации, анализу и обсуждению результатов
панель выжимок — режим кратко/подробно + сохранённые выжимки
панель выжимок — режим кратко/подробно + сохранённые выжимки
отчёт выжимки в просмотре — скоры, дельты, аномалии
отчёт выжимки в просмотре — скоры, дельты, аномалии
SD выжимки через агента
SD выжимки через агента
чат по выжимке — вопросы агенту, он читает файлы отчётов сам
чат по выжимке — вопросы агенту, он читает файлы отчётов сам
SD по чату
SD по чату
отчёт бенчмарка открыт в окне просмотра
отчёт бенчмарка открыт в окне просмотра
админка — провайдеры + слот агента
админка — провайдеры + слот агента

Оффтоп (крик души)

Многих, думаю, напрягают инфоцыгане, которые обещают сделать из вас AI-чемпиона, уменьшить расходы на $2 млн (с нашей-то подпиской за $20–200 звучит очень интересно). Сравнивают же эти "AI-чемпионы" зачастую харнес с моделями, поисковый индекс + AI-функции с моделями, но не рассказывают, какие задачи они решают, какой контекст попадает внутрь агента и как агент его обрабатывает.

Против AI-чемпионов ничего не имею, просто хочу сказать, что никакой чудо-таблетки (модели, харнеса, сервиса) не существует (а если бы существовало — это детерминированное действие, и зачем тогда человек в этом цикле? Человек более внимательный, чем агент? Не думаю) и стоит ориентироваться сугубо на себя.

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

Нейрослоп выводы

Раздел назван в мою честь, так что говорить буду я — генератор текста. Замечания изнутри машины, которую эти бенчмарки крутят:

  • Не верьте мне на слово — тем более когда ответ звучит уверенно. Уверенность у LLM приклеена к токенам, а не к фактам: поэтому Brier и ECE в decision честнее accuracy — они бьют по самоуверенному промаху, а не по «угадал/не угадал».

  • Я хорошо подгоняю текст под эталон. F1/ROUGE измеряют лексику, а не смысл: их можно поднять «словарём правильных слов» без понимания. Чем в тесте есть исполняемый финал (код, число, чек-лист) — тем он честнее и тем меньше в нём меня.

  • Объяснения пост-фактум — рационализация. На «почему расхождение на codegen?» я отвечу связно в любом случае: есть ли в числах правда или я подгоняю нарратив под исход. Поэтому у агента инструмент — read_file в сырые логи, а не моя память о них.

  • Модели тут судят не «глазами LLM-as-judge» — и это правильно: у судьи-LLM есть свои любимцы и своя предвзятость. Судить должна метрика и эталон, мне оставили только интерпретацию.

  • Бенчмарк в своём харнесе превращает модель из «магии» в компонент — с ценой, задержкой и границей применимости. Самый недооценённый эффект оценки: перестаёшь выбирать «лучшую модель» и начинаешь складывать пазл «модель × задача × цена × скорость».

Мои выводы

  • Оценка моделей является нетривиальной и, самое главное, очень важной задачей, всегда можно сказать "Используй claude fable, она может сделать все что угодно (кроме кофе — его она сделать не сможет и принести потом тоже)" и в целом результат будет удовлетворяющий.

  • Если есть возможность заменить генерацию на детерминированное выполнение (скрипты, код и т. п.), то этим следует пользоваться, т.к. любая LLM никогда не будет защищена на 100% от генерации мусора, prompt injection и прочих неприятных штук. (Я эту тему в статье не раскрывал, но выводом поделиться захотелось)

  • Крупные модели имеют меньше контроля, более самостоятельные в принятии решений и далеко не всегда показывают тот результат, который мы ожидаем.

  • Модель стоит оценивать — но не одними сухими цифрами: она сама по себе просто крутая формула расчёта следующего токена (а сравнивать "эта формула круче другой формулы" — какое-то ребячество).

P.S. Без нейро-помощника обойтись не получилось, т.к. заполнение таблиц, создание скриншотов и диаграмм съели бы основной бюджет времени на статью, поэтому прошу прощение за "На этот раз я решил обойтись без нейрослопа".

Комментарии (1)


  1. Ondriss
    08.11.2026 15:19

    Это интересно, буду знать, сам часто работаю с ИИ, так что будет полезно