Перейти к содержимому

6.1 · Статьи про evals

Неделя 6 · Evals · ⏱ ~4 ч · Теория

Evals (оценки качества) отличают продукт на LLM от демо, которое «вроде работает». Без них непонятно, стало ли лучше после смены промпта, модели или чанкинга, и систему нельзя безопасно менять. На собеседованиях вопрос «как вы оцениваете качество своей системы?» звучит почти всегда, и ответ «посмотрел глазами» сразу выдаёт новичка. С этой главы начинается Проект 3: evals для ассистента поддержки «Полки» из проекта 2.

Почему «проверил руками на 5 примерах» — не оценка

Заголовок раздела «Почему «проверил руками на 5 примерах» — не оценка»

В проекте 2 мы оценивали ответы ассистента вручную на 13 вопросах. Чтобы понять, чего такой проверке не хватает, начнём с обычного кода без LLM. Допустим, мы поменяли формулу order_total в коде магазина (скидка, промокод, доставка) и проверили её на пяти заказах. Все пять сошлись. Значит ли это, что формула верна? Нет:

  1. Выборка мала. Пять примеров не покрывают краевые случаи: чай на развес (unit = 'g', цена за 100 г), промокод TEA15 вместе со скидкой, отменённый или возвращённый заказ.
  2. Выборка смещена. В проверку попадают примеры, которые пришли в голову, а это обычно «типичные» случаи, на которых всё и так работает.
  3. Нет повторяемости. Через неделю после следующей правки те же пять примеров тем же способом никто не прогонит и не сравнит.
  4. Нет числа. «Вроде лучше» нельзя сравнить с «вроде лучше» другой версии.

С LLM всё ещё хуже: модель недетерминирована, ответ зависит от формулировки, и улучшение на одном типе вопросов часто ломает другой. Eval — это повторяемый прогон фиксированного набора примеров с автоматическим подсчётом метрик. По сути, это набор тестов (pytest, JUnit, npm test) для недетерминированной системы: вместо assert x == y — проверки, которые выдают долю успешных ответов.

Как устроить такой прогон на практике, подробно объясняет Hamel Husain, ML-инженер и консультант по LLM-продуктам. В статье «Your AI Product Needs Evals» (первый пункт маршрута) он описывает три уровня, от дешёвых к дорогим:

Уровень Что это Когда запускать Пример для ассистента поддержки «Полки»
1. Unit-тесты / assertions Детерминированные проверки кодом На каждое изменение, в CI Ответ содержит ссылку [1]; отказ начинается с фразы REFUSAL; среди источников нет kb/returns-2025.md
2. Человеческая оценка и LLM-as-judge Человек или модель-судья оценивает ответ Регулярно, перед релизом «Ответ верный и опирается на найденные куски?»
3. A/B-тесты Сравнение на живых пользователях Когда продукт зрелый Для учебного проекта не нужно: живых клиентов нет

Главная мысль статьи: начинать с первого уровня и с просмотра данных. Уровни 2–3 строятся поверх, а не вместо.

Уровни отвечают на вопрос «чем проверять», а цикл — на вопрос «откуда берутся проверки»:

┌───────────────┐
│ смотреть на │◄──────────────────────┐
│ данные │ │
└──────┬────────┘ │
▼ │
┌───────────────┐ ┌──────────────┐ │
│ найти типы │──►│ написать │ │
│ ошибок │ │ eval на них │ │
└───────────────┘ └──────┬───────┘ │
▼ │
┌──────────────┐ │
│ изменить │ │
│ систему │────┘
└──────────────┘

Evals не придумываются из головы: их выводят из реальных ошибок. Сначала читаем трейсы (вопрос → что нашлось → что ответила модель), замечаем повторяющиеся проблемы и на каждую пишем проверку. Этот приём (error analysis) мы проделаем руками в 8.4.

Часть этих метрик мы уже считали в неделях 4–5 (hit@k, MRR) или проверяли руками (корректность, цитаты, отказы). Теперь соберём их в одну систему. Для RAG-системы (наш ассистент поддержки по kb/ из проекта 2) оценивать нужно отдельно поиск и отдельно генерацию, иначе непонятно, где сломалось.

Метрики поиска (retrieval):

  • hit rate@k — доля вопросов, у которых нужный кусок попал в топ-k найденных.
  • MRR (Mean Reciprocal Rank) — средняя величина 1/позиция первого правильного куска; награждает за то, что правильный кусок стоит выше.
  • recall@k / precision@k — если правильных кусков несколько (вопрос про порог бесплатной доставки опирается и на delivery.md, и на promo.md).

Метрики ответа (generation):

  • correctness — ответ совпадает по смыслу с эталоном.
  • faithfulness / groundedness — каждое утверждение ответа подтверждается найденными кусками (нет галлюцинаций).
  • relevance — ответ отвечает на заданный вопрос, а не на соседний.
  • отказ там, где надо — на вопрос вне базы знаний («где мой заказ 1042?», «гарантия на кофемашины») система честно отвечает фразой отказа и предлагает оператора.

Плюс операционные метрики: стоимость прогона, латентность, доля ошибок API. Подробно метрики и их подсчёт — в 6.4.

Метрика говорит, что измерять, но не как. Одну и ту же correctness можно проверять разными способами — от регулярного выражения до человека:

Способ Плюсы Минусы
Точное совпадение / регулярки Быстро, бесплатно, детерминировано Подходит только для коротких или структурированных ответов
Метрики пересечения слов (BLEU, ROUGE) Дёшево Плохо коррелируют с качеством свободного текста; Eugene Yan подробно разбирает почему
Сходство эмбеддингов (BERTScore и т.п.) Ловит перефразы «Похоже» не значит «верно»: «вернуть в течение 14 дней» и «вернуть в течение 7 дней» почти идентичны по эмбеддингам
LLM-as-judge Понимает смысл, масштабируется Стоит денег, имеет свои смещения, его надо проверять
Человек Самый точный Медленно и дорого, не масштабируется

LLM-as-judge: как сделать судью, которому можно верить

Заголовок раздела «LLM-as-judge: как сделать судью, которому можно верить»

Из таблицы видно: для свободного текста реально масштабируется только LLM-судья, но его самого надо проверять. Как это сделать, объясняет вторая статья Hamel («Creating a LLM-as-a-Judge») — по сути инструкция. Ключевые идеи:

  1. Один эксперт задаёт стандарт. В нашем случае эксперт — мы сами (в настоящем магазине — владелец или старший сотрудник поддержки): мы написали kb/ и знаем, какой ответ про возврат вскрытого чая правильный.
  2. Бинарная оценка pass/fail + критика, а не шкала 1–10. Разницу между «6» и «7» не может объяснить ни человек, ни модель; зато «неверно, потому что указан срок возврата 30 дней вместо 14» — понятно и проверяемо.
  3. Few-shot примеры с критикой в промпте судьи: показываем судье свои размеченные случаи.
  4. Измеряем согласие судьи с собой. Размечаем руками 20–50 ответов, прогоняем судью, считаем, где он совпал. Смотрим отдельно на два типа ошибок: судья пропустил плохой ответ / судья забраковал хороший.
  5. Итерируем промпт судьи, пока согласие не станет приемлемым.

Известные смещения судей (о них пишут и Eugene Yan, и applied-llms.org):

  • Позиционное: при попарном сравнении судья чаще выбирает первый (или второй) вариант. Лечится перестановкой и двойным прогоном.
  • Многословие: длинный ответ кажется лучше.
  • Самопредпочтение: модель склонна выше оценивать тексты своего же семейства.
  • Дрейф критериев: Shreya Shankar с соавторами показали, что сами люди уточняют критерии, пока размечают ответы. Поэтому критерии судьи пишутся после просмотра данных, а не до.

Пример промпта судьи (иллюстративный, на английском, как удобнее модели):

JUDGE_PROMPT = """You are grading an answer from the customer support assistant of an online shop.
The assistant answers from the shop's knowledge base.
Question: {question}
Reference answer: {reference}
Assistant answer: {answer}
Is the assistant answer factually consistent with the reference answer?
Minor wording differences are fine. Wrong numbers, wrong product, outdated rules,
or missing the key fact is a FAIL.
Reply in JSON: {{"critique": "<one or two sentences>", "verdict": "PASS" | "FAIL"}}
"""

Важно: критика идёт до вердикта. Модель сначала рассуждает, потом выносит решение; обратный порядок даёт вердикт, под который подгоняется объяснение.

Статьи Hamel — основа главы; остальные из маршрута подтверждают те же идеи с других сторон:

  • applied-llms.org («What We Learned from a Year of Building with LLMs») — практические уроки: начинать с промптинга и простых assertion-тестов, смотреть на данные каждый день, предпочитать попарные сравнения и бинарные оценки, не доверять судье без проверки, «vibe checks» не заменяют evals, но и полностью без них нельзя.
  • Eugene Yan, «Patterns for Building LLM-based Systems» — evals идут первым паттерном из семи, не случайно. Там же разбор классических метрик (BLEU, ROUGE, BERTScore) и почему они плохо работают для открытых ответов, и идея о том, что для своей задачи нужен свой набор.
  • Chip Huyen, «Building LLM applications for production» — evals как часть инженерной дисциплины: неоднозначность естественного языка, сложность оценки, стоимость и латентность как полноправные метрики, версионирование промптов.
Термин Значение
Golden dataset Проверенный человеком набор вопросов с эталонами (у нас — eval/golden.jsonl)
Reference / эталон Правильный ответ, с которым сравнивают
Trace Полная запись одного запроса: вход, поиск, промпт, ответ, токены, время
Offline eval Прогон на фиксированном наборе до релиза
Online eval Оценка на живом трафике (мониторинг)
Regression Ухудшение метрики после изменения

Статьи этой главы от провайдера не зависят: уровни evals, бинарный судья с критикой, согласие судьи с нашей разметкой одинаковы для Claude, OpenAI, DeepSeek и локальной модели в Ollama. Меняется практическая сторона: кто будет судьёй, сколько стоит прогон и какие параметры судьи реально работают. Код судьи на DeepSeek и Ollama разобран в главе 6.4 · Скрипт оценки: retrieval + faithfulness (гл. 6.4); здесь — решения.

Факты ниже сверены в ноябре 2026 по api-docs.deepseek.com и docs.ollama.com. Модели и цены у DeepSeek меняются часто, актуальное стоит проверять перед работой.

Правило из статей Hamel и Eugene Yan: судья не слабее оцениваемой модели (лучше сильнее), и его согласие с человеком измерено. На нашем стеке это выглядит так:

Роль Основной вариант Почему Для сравнения
Оцениваемая система (ответчик RAG, ask()) deepseek-flash или локальная модель в Ollama дёшево или бесплатно, на них построен проект 2 Claude / OpenAI на том же наборе
Судья deepseek-v4-pro с выключенными рассуждениями и temperature=0 сильнее Flash, стабильнее при temperature 0, прогон стоит центы сильная модель Claude или OpenAI на подвыборке
Второе мнение наша ручная разметка и судья Claude или OpenAI на подвыборке (kb/ публичная, вопросы выдуманы) другое семейство; ловит перекос «DeepSeek судит DeepSeek» —
Личные данные (настоящие сообщения клиентов, снимок базы в проекте 4) облачный судья только на выдуманных вопросах и демо-базе; реальные случаи размечаем сами личные данные в облако не идут, а локальная модель на обычном ноутбуке слишком слаба для судьи —

Самопредпочтение здесь реально: Flash и Pro — одно семейство. Это не причина отказаться от Pro в роли судьи, а причина обязательно измерить его согласие с нашей разметкой и время от времени прогонять подвыборку через судью другого семейства. Локальный судья упирается в память: на 8 ГБ RAM реально модели класса 4B (qwen3:4b, выбор курса по умолчанию), на 16 ГБ — 7–8B, и только на 32 ГБ+ — 14B и крупнее. Модели 4B и 7–8B слишком слабы для судьи: судья должен быть сильнее ответчика, а они слабее даже deepseek-flash. 14B на 32 ГБ годится разве что в предварительный фильтр с измеренным согласием. Поэтому судья — deepseek-v4-pro (или более сильная облачная модель) на публичных данных, а Ollama у нас — локальный ответчик для вопросов с личными данными и сравнения, эмбеддинги и офлайн-эксперименты.

Что нужно судье Claude OpenAI DeepSeek Ollama
Повторяемость (temperature=0) есть; у части новых моделей ограничения на sampling-параметры, сверяем с докой модели есть у обычных моделей; reasoning-модели sampling-параметры не принимают работает только с выключенными рассуждениями: режим thinking включён по умолчанию, и в нём temperature молча игнорируется есть, плюс параметр seed
Структурированный вердикт structured outputs (JSON-схема) или tool use response_format с JSON-схемой только json_object: JSON валиден, но схема не проверяется; в промпте нужны слово «json» и пример структуры format с JSON-схемой в нативном API
Стоимость прогона на ~60 вопросов по странице цен Anthropic по странице цен OpenAI порядка десятков центов (расчёт в главе 6.4) $0 за API, платим временем и памятью компьютера
Куда уходят данные облако Anthropic облако OpenAI серверы DeepSeek в Китае никуда, всё локально

В Проекте 3 оценивается ассистент по публичной базе знаний kb/, и вопросы golden set выдуманы без личных данных, поэтому куски, вопросы и ответы можно отправлять в DeepSeek. Настоящие сообщения клиентов (телефоны, e-mail, номера заказов), outputs/handoff.jsonl, снимок базы магазина и ключи в DeepSeek и в бесплатные облачные тарифы (которые могут учиться на входных данных) не отправляются никогда: для них только Ollama или выдуманные данные. Правило касается любого облачного провайдера, не только DeepSeek. Это станет важно в главе 10.3 · Проект 4: evals агента на 20 случаях (гл. 10.3), где судья будет читать разборы проблемных заказов по снимку базы.

  1. Открываем Hamel Husain: Your AI Product Needs Evals → читаем целиком (≈60 мин). Обязательная статья. Обращаем внимание на три уровня evals, на раздел про просмотр данных и на пример с ассистентом по недвижимости (Rechat): как из ошибок рождаются конкретные тесты. Выписываем, какие assertions можно написать для нашего ассистента поддержки.
  2. Открываем Hamel Husain: Creating a LLM-as-a-Judge → читаем целиком (≈50 мин). Главное: почему бинарная оценка с критикой, как измерить согласие судьи с экспертом, почему критерии рождаются в процессе разметки.
  3. Открываем What We Learned from a Year of Building with LLMs → читаем в тактической части разделы про evaluation и monitoring (≈40 мин). Остальное пробегаем по заголовкам. Берём отсюда список ловушек LLM-as-judge и совет про попарные сравнения.
  4. Открываем Eugene Yan: Patterns for Building LLM-based Systems → раздел «Evals» (≈30 мин). Раздел про RAG мы уже читали в 4.2. Обращаем внимание на таблицу классических метрик и критику BLEU/ROUGE.
  5. Открываем Chip Huyen: Building LLM applications for production → часть 1, про проблемы продакшена: оценка, стоимость, латентность, промпт-версионирование (≈30 мин). Статья 2023 года: цены и модели устарели, принципы нет.
  6. (Опционально, для углубления) Hamel: A Field Guide to Rapidly Improving AI Products и Eugene Yan: Evaluating the Effectiveness of LLM-Evaluators. Вторая — обзор исследований о том, насколько судьи согласны с людьми. Справочник на будущее: Hamel: AI Evals FAQ — длинный, читается по вопросам, когда упрёмся.
  7. (Опционально) Anthropic: Define success criteria and build evaluations — как официальная документация формулирует критерии успеха и типы грейдеров.
  8. Открываем DeepSeek API Docs → Quick Start, страницы Models & Pricing и Thinking Mode (≈15 мин). Записываем: текущие id моделей, что thinking включён по умолчанию и что в нём temperature не действует. Это прямо влияет на стабильность судьи.
  9. Открываем Ollama: Structured outputs (≈10 мин): как format с JSON-схемой задаёт форму вердикта локального судьи. Если Ollama ещё не установлена: только с ollama.com; на macOS перед первым запуском приложения проверяем codesign -dv и spctl -a -vv, для других систем — по официальной инструкции на сайте.
  • Метрика без просмотра данных обманывает. 85% correctness ничего не говорит, пока не видно, что в оставшихся 15%: может, там все вопросы про одну категорию — например, про возвраты, где мешает архивная returns-2025.md.
  • Общие метрики «из коробки» (helpfulness, coherence) редко полезны. Метрики должны вытекать из реальных ошибок системы, а не из списка в библиотеке.
  • Судья — тоже модель, и он ошибается. Без измеренного согласия с человеком оценка судьи — просто ещё одно мнение.
  • Шкала 1–10 создаёт иллюзию точности. Средний балл «7,3 против 7,1» ни о чём не говорит.
  • Не смешиваем поиск и генерацию в одну цифру. Если упала correctness, надо понимать: модель не нашла кусок или нашла, но ответила неверно.
  • Набор, на котором долго тюнят систему, перестаёт быть честным. Про переобучение под набор подробно в 8.1.
  • Статьи 2023 года устарели в деталях (названия моделей, цены, конкретные инструменты), но не в принципах. Конкретику проверяем в текущей документации.
  • «temperature 0» на DeepSeek может ничего не делать. Режим thinking включён по умолчанию, и в нём temperature игнорируется без ошибки. Для судьи рассуждения выключаем явно или осознанно принимаем больший шум.
  • Судья того же семейства, что ответчик. DeepSeek судит DeepSeek — классический риск самопредпочтения. Лечится измеренным согласием с нашей разметкой и вторым судьёй другого семейства.
  • Создаём notes/evals.md в учебном репозитории.
  • Раздел «Виды evals»: таблица из трёх уровней Hamel; для каждого — 2 примера проверок для ассистента поддержки (например, «ответ про LAMP-LIGHT-MINI не ссылается на kb/products/lamp-light.md»).
  • Раздел «Метрики»: определения hit rate@k, MRR, correctness, faithfulness, relevance своими словами, по одному примеру на каждую.
  • Раздел «LLM-as-judge: подводные камни»: минимум 5 пунктов (смещения + как их лечить).
  • Раздел «Почему 5 примеров — не оценка»: объяснение в 5–7 предложениях, как ответ на собеседовании.
  • Набрасываем черновик промпта судьи для correctness нашего ассистента (бинарный, критика перед вердиктом). Пока не запускаем, он пригодится в 6.4.
  • Выписываем 5 вопросов к ассистенту из проекта 2, на которых он, по нашим наблюдениям, ошибается (кандидаты: старые правила возврата, порог бесплатной доставки, похожие лампы, вопрос на две страницы). Это пополнение к 20 вопросам eval/golden.jsonl для 6.3.
  • Добавляем в notes/evals.md раздел «Судьи на нашем стеке»: кто ответчик, кто судья, кто второе мнение и почему; таблицу Claude / OpenAI / DeepSeek / Ollama из теории пересказываем своими словами.
  • В черновике промпта судьи учитываем JSON mode DeepSeek: слово «JSON» и пример структуры прямо в промпте (в примере JUDGE_PROMPT выше они уже есть).
  • notes/evals.md есть и содержит все пять разделов.
  • Можем за 2 минуты устно объяснить, почему «проверил руками на 5 примерах» — не оценка, и чем hit rate отличается от faithfulness.
  • Есть черновик промпта судьи.

Вопрос 1

Какой уровень evals Hamel советует строить первым?

  • a) A/B-тесты
  • b) LLM-as-judge
  • c) unit-тесты/assertions и просмотр данных
  • d) человеческая разметка всех ответов.

c. Сначала дешёвые детерминированные проверки и чтение трейсов; судьи и A/B строятся поверх.

Вопрос 2

Чем hit rate@k отличается от MRR?

Hit rate@k смотрит только, попал ли правильный кусок в топ-k (да/нет). MRR учитывает позицию: правильный кусок на 1-м месте даёт 1, на 3-м — 1/3.

Вопрос 3

Модель ответила правильно, но факт взят не из найденных кусков, а «из головы». Какая метрика это поймает: correctness или faithfulness?

Faithfulness. Correctness будет «верно», но система не опиралась на найденное, и в следующий раз «голова» может ошибиться — например, назвать «обычный» для интернет-магазинов срок возврата вместо правила «Полки».

Вопрос 4

Почему бинарная оценка pass/fail обычно надёжнее шкалы 1–10?

Разницу между соседними баллами не может объяснить ни человек, ни модель, поэтому оценки шумят. Бинарное решение с критикой проверяемо и легко сравнивается с разметкой эксперта.

Вопрос 5

Что такое позиционное смещение судьи и как его снизить?

Склонность выбирать вариант на определённой позиции при попарном сравнении. Лечится прогоном в обоих порядках и учётом только согласованных решений.

Вопрос 6

Почему сходство эмбеддингов плохо подходит для проверки ответа «Невскрытую упаковку чая можно вернуть в течение 14 дней»?

Эмбеддинги «14 дней» и «7 дней» почти совпадают: смысл фразы одинаковый, отличается одно число. Для фактов с числами нужна точная проверка или судья, которому велено сверять числа.

Вопрос 7

Откуда должны браться критерии для evals?

  • a) из списка метрик в библиотеке
  • b) из анализа реальных ошибок системы
  • c) из бенчмарков вроде MMLU
  • d) из документации модели.

b. Критерии выводятся из просмотра данных и ошибок; общие метрики часто меряют не то.

Вопрос 8

Что не так в этом промпте судьи?

Rate the answer from 1 to 10. First give the score, then explain why.
Question: {question}
Answer: {answer}

Шкала 1–10 вместо бинарной оценки; оценка до объяснения, поэтому объяснение подгоняется под число; нет эталона или контекста, с которым сравнивать; не сказано, какие ошибки считаются критичными.

Вопрос 9

Зачем при оценке RAG разделять метрики поиска и метрики ответа?

Чтобы понимать причину: если нужный кусок не найден, менять промпт бесполезно, чинить надо поиск, и наоборот.

Вопрос 10

Как проверить, что LLM-судье можно доверять?

Разметить руками 20–50 ответов, прогнать судью, посчитать согласие и отдельно оба типа ошибок (пропуск плохих, браковка хороших), итерировать промпт судьи.

Вопрос 11

Correctness выросла с 80% до 84% после смены промпта. Достаточно ли этого, чтобы сказать «стало лучше»? Что ещё нужно посмотреть?

Нет. Нужно знать разброс между прогонами и размер набора (4 п.п. на 50 вопросах — это 2 вопроса, вполне шум), посмотреть, на каких вопросах изменилось, и не сломались ли другие метрики (faithfulness, доля уместных отказов, стоимость). Об этом 8.1.

Вопрос 12

Судье на deepseek-v4-pro поставили temperature=0 и больше ничего не меняли, а вердикты на тех же ответах всё равно мигают. Почему?

У DeepSeek по умолчанию включён режим thinking, а в нём temperature не действует (ошибки при этом нет). Нужно выключить рассуждения (thinking: disabled) или принять шум и измерить разброс повторными прогонами.

Вопрос 13

Почему deepseek-v4-pro в роли судьи для ответов deepseek-flash требует особой проверки и как её сделать?

Обе модели из одного семейства, судья может выше оценивать «свои» ответы. Проверка: согласие судьи с нашей ручной разметкой и прогон подвыборки через судью другого семейства (Claude или OpenAI; база знаний публичная, вопросы выдуманы, отправлять можно).

Вопрос 14

Ассистент отвечает на настоящие сообщения клиентов, где есть телефоны и номера заказов. Как оценивать эти ответы?

  • a) отправить сообщения судье deepseek-v4-pro, он сильнее
  • b) любой бесплатной облачной моделью
  • c) облачным судьёй только на выдуманных вопросах, а реальные случаи размечать вручную
  • d) локальной 4B-моделью как единственным судьёй.

c. Судья видит те же данные, что и ответчик, поэтому личные данные клиентов в облако (тем более на серверы в Китае) не уходят. А модель, которая помещается в память обычного ноутбука (4B на 8 ГБ, 7–8B на 16 ГБ), слишком слаба, чтобы ей верить как судье: максимум предварительный фильтр, решение за ручной разметкой.

Дальше строим сам набор: сначала учимся генерировать черновик вопросов моделью в 6.2 · Синтетические данные для evals, потом доращиваем eval/golden.jsonl с 20 вопросов до проверенного набора в 6.3 · Набор из 50–100 вопросов с эталонами.