Оценка производительности (Eval): Метрики и тестовые наборы
Введение: Почему «на глаз» больше не работает
Добро пожаловать в шестой модуль. До сих пор мы учились создавать и интегрировать. Теперь пришло время научиться сомневаться в том, что мы создали.
В классической разработке программного обеспечения у нас есть роскошь детерминизма. Если функция сложения возвращает 2 + 2 = 4, она работает. Если она возвращает 5, она сломана. Все черно-белое.
В разработке на базе LLM (Large Language Models), таких как Gemini, мы работаем в серой зоне. Если вы попросите модель написать саммари статьи, и она сделает это хорошо, но пропустит одну деталь — это баг или фича? А если она напишет саммари в стихах, хотя вы этого не просили? А если ответ верный, но тон слишком агрессивный?
Раньше разработчики использовали подход, который в шутку называют «Vibe Check»: прогнали пару промптов, вроде выглядит нормально, можно деплоить. В продакшене это путь к катастрофе. Когда вы обновляете промпт, меняете температуру или переходите на новую версию Gemini (например, с Flash на Pro), вы не можете вручную перепроверять 1000 кейсов.
В этом уроке мы построим систему систематической оценки (Evaluation или Evals). Мы разберем, как создавать «золотые датасеты», какие метрики использовать (и почему BLEU/ROUGE устарели для чат-ботов) и как заставить Gemini оценивать саму себя.
Анатомия тестового набора (The Golden Dataset)
Прежде чем что-то измерять, нам нужно знать, на чем измерять. Тестовый набор (Test Set) в LLMOps отличается от юнит-тестов.
Хороший тестовый кейс для LLM обычно состоит из трех компонентов:
- Input (Вход): Промпт или контекст, который подается модели.
- Expected Output (Ожидаемый результат / Ground Truth): Идеальный ответ, написанный человеком.
- Context (Контекст): Дополнительные данные (например, фрагменты документов для RAG), если они нужны.
Где брать данные?
- Реальные логи: Самый ценный источник. Возьмите 50-100 запросов из истории общения пользователей с вашим ботом.
- Синтетические данные: Используйте более мощную модель (например, Gemini 1.5 Pro), чтобы сгенерировать примеры вопросов и ответов на основе вашей документации.
- Ручное написание: Необходимо для покрытия «краевых случаев» (edge cases) — попыток взлома, нецензурной лексики или вопросов не по теме.
Совет: Не пытайтесь сделать тысячи тестов сразу. Начните с 50-100 качественных примеров. Качество важнее количества.
import json
# Пример структуры тестового набора (JSONL формат часто используется в LLMOps)
test_dataset = [
{
"id": "case_001",
"input": "Как сбросить пароль в системе?",
"context": "Для сброса пароля перейдите в настройки профиля и нажмите кнопку 'Безопасность'.",
"expected": "Перейдите в настройки профиля, выберите раздел 'Безопасность' и следуйте инструкциям для сброса."
},
{
"id": "case_002",
"input": "Какая погода на Марсе?",
"context": "Мы продаем облачное ПО для бухгалтерии.",
"expected": "К сожалению, я не могу ответить на этот вопрос, так как я консультирую только по нашему бухгалтерскому ПО."
}
]
# Сохранение для использования в пайплайне
with open('golden_dataset.jsonl', 'w', encoding='utf-8') as f:
for entry in test_dataset:
f.write(json.dumps(entry, ensure_ascii=False) + '\n')
Типы метрик: От простых к умным
Когда у нас есть данные и ответы модели, как понять, насколько они хороши? Метрики делятся на три больших класса.
1. Детерминированные метрики (Deterministic Metrics)
Самые быстрые и дешевые. Они проверяют наличие конкретных слов или формат.
- Exact Match: Ответ модели байт-в-байт совпадает с эталоном. Редко применимо для чат-ботов, но полезно для задач экстракции (например, извлечь дату).
- Valid JSON/XML: Если вы просили модель вернуть JSON, парсится ли он?
- Regex Check: Содержит ли ответ email, телефон или запрещенные слова.
- Length Check: Не слишком ли длинный/короткий ответ.
2. Статистические метрики (N-gram based)
Пришли к нам из классического NLP (машинного перевода). Самые известные — BLEU, ROUGE, METEOR.
Суть: Они считают перекрытие слов между ответом модели и эталоном.
Проблема: Они не понимают смысла.
Фраза «Я люблю кофе» и «Я обожаю эспрессо» имеют почти нулевое пересечение слов, поэтому ROUGE покажет плохой результат, хотя смысл идентичен. В эпоху LLM эти метрики используются всё реже, в основном для задач суммаризации.
3. Метрики на основе моделей (Model-Based / LLM-as-a-Judge)
Золотой стандарт современного LLMOps. Мы используем другую, обычно более мощную LLM, чтобы оценить ответ нашей рабочей модели.
Это работает так: вы даете Судье (например, Gemini 1.5 Pro) промпт: «Сравни ответ А и ответ Б. Оцени по шкале от 1 до 5, насколько ответ А соответствует истине, описанной в контексте».
import google.generativeai as genai
import os
# Предполагается, что API ключ уже настроен
# genai.configure(api_key=os.environ["GOOGLE_API_KEY"])
def llm_as_a_judge(input_text, actual_output, expected_output):
"""
Использует Gemini для оценки семантической близости и корректности.
"""
judge_model = genai.GenerativeModel('gemini-1.5-pro')
evaluation_prompt = f"""
Ты — строгий арбитр. Оцени качество ответа ИИ-ассистента.
ВВОД ПОЛЬЗОВАТЕЛЯ: {input_text}
ЭТАЛОННЫЙ ОТВЕТ (ИСТИНА): {expected_output}
ОТВЕТ АССИСТЕНТА: {actual_output}
ЗАДАЧА:
1. Оцени, содержит ли ответ ассистента всю ключевую информацию из эталона.
2. Проверь, нет ли в ответе ассистента галлюцинаций (информации, противоречащей эталону).
3. Оцени тон ответа.
ВЫВОД:
Верни ТОЛЬКО JSON с полями:
- "score": число от 1 до 10,
- "reasoning": краткое объяснение оценки.
"""
response = judge_model.generate_content(
evaluation_prompt,
generation_config={"response_mime_type": "application/json"}
)
return json.loads(response.text)
# Пример использования
result = llm_as_a_judge(
input_text="Как сбросить пароль?",
actual_output="Идите в настройки и жмите Безопасность.",
expected_output="Перейдите в настройки профиля, выберите раздел 'Безопасность' и следуйте инструкциям."
)
print(f"Оценка: {result['score']}/10")
print(f"Причина: {result['reasoning']}")
RAG-триада: Специфические метрики для поиска
Если вы разрабатываете RAG (Retrieval Augmented Generation) приложение, вам нужно оценивать не только финальный ответ, но и работу поискового механизма. Здесь применяется концепция «RAG-триады».
- Context Relevance (Релевантность контекста): Насколько найденные документы действительно относятся к вопросу пользователя? Если пользователь спросил про цены, а вы нашли документы про миссию компании — это провал на этапе поиска (Retrieval).
- Faithfulness (Верность контексту): Действительно ли ответ модели основан только на найденных документах, или она «додумала» что-то из своего обучения? Это проверка на галлюцинации.
- Answer Relevance (Релевантность ответа): Отвечает ли финальный текст на вопрос пользователя? Модель может выдать верный по контексту факт, который, однако, не является ответом на заданный вопрос.
Для реализации этих метрик также идеально подходит подход LLM-as-a-Judge. Вы подаете судье тройку: (Вопрос, Найденный_Контекст, Ответ) и просите оценить связи между ними.
Тонкости реализации и подводные камни
Внедрение Evals — это не просто написание скрипта. Это изменение процесса разработки.
1. Проблема «Смещения судьи» (LLM Bias)
Модели-судьи часто имеют свои предпочтения:
- Verbosity Bias: Они часто ставят более высокие оценки более длинным ответам, даже если они «льют воду».
- Position Bias: При сравнении двух ответов (A и B), модели чаще выбирают первый (A). Решение: меняйте ответы местами и усредняйте результат.
- Self-Preference: Модели GPT-4, как правило, выше оценивают тексты, сгенерированные GPT-4, а Gemini — тексты Gemini.
2. Стоимость и скорость
Запуск LLM-as-a-Judge на 500 тестов с использованием Gemini 1.5 Pro может стоить денег и занимать время.
Стратегия:
- При локальной разработке (
git push) запускайте малый набор (smoke tests) из 10-20 примеров. - Полный прогон (full regression) делайте на CI/CD перед деплоем в прод или ночью.
3. Инструментарий
Вам не обязательно писать все с нуля. Существуют фреймворки, такие как DeepEval, Ragas (для RAG), Promptfoo. Они уже содержат готовые промпты для судей и логику подсчета метрик. Однако понимание того, как это работает «под капотом» (как в коде выше), критически важно для настройки под ваши нужды.
Создайте класс `ToxicityEvaluator` на Python, используя Gemini API. Задача класса — принять список сообщений и вернуть долю (процент) токсичных ответов. Критерий токсичности: наличие грубости, оскорблений или угроз. Протестируйте его на наборе из 3 фраз (одна из которых должна быть явно грубой).
Вы разрабатываете чат-бота для юридической консультации. Какая метрика будет НАИБОЛЕЕ важна для предотвращения юридических рисков и почему?
Заключение
Оценка производительности LLM — это переход от магии к инженерии. Вы не можете улучшить то, что не можете измерить.
Внедряя Evals, вы начинаете цикл:
- Изменение промпта -> 2. Запуск Evals -> 3. Анализ провалов -> 4. Повтор.
Это дает уверенность. Вместо страха «что он там скажет клиенту», вы получаете метрику: «Наш бот корректен в 98% случаев». Оставшиеся 2% — это ваша зона роста.
В следующем уроке мы поговорим о том, как задеплоить всё это в высоконагруженный продакшн и настроить мониторинг в реальном времени.