Offline vs online оценка

Два режима измерения качества дополняют друг друга. Важно не путать, какой на что отвечает.

OfflineOnline
КогдаДо релиза, в CIПосле релиза, на проде
На чёмФиксированный датасет (golden)Живой трафик пользователей
Отвечает на«Стал ли билд лучше?»«Как система ведёт себя в реальности?»
ПлюсПовторяемо, безопасно, дёшевоНастоящее поведение, реальные кейсы
МинусДатасет ≠ вся реальностьОшибку видят пользователи

Offline — это «лабораторный анализ на образце», online — «наблюдение за пациентом». Этот урок — про offline: как построить повторяемое измерение, которое ловит регрессию до того, как её увидит пользователь. Оно опирается на связку dataset + evaluator + experiment из урока про LangSmith — здесь мы наполняем часть «evaluator» конкретными метриками.

ℹ️ Почему у LLM нет одной «accuracy»

У классификатора есть эталонный ответ и метрика точности. У LLM-системы выход — свободный текст, «правильных» формулировок много, а «качество» распадается на измерения: фактическая верность, релевантность, полнота, тон, формат, отсутствие галлюцинаций. Поэтому offline-оценка LLM — это не одно число, а набор метрик, часто сконструированных под конкретную задачу. Отсюда три подхода ниже.

Три типа offline-метрик

Метрики offline-оценки удобно разложить по тому, как они считают «хорошо/плохо» — от простого к гибкому.

100%
колёсико — масштаб  ·  зажать и тянуть — перемещение
Три способа посчитать «качество» offline ① Детерминированные код сравнивает с эталоном • exact / fuzzy match • JSON valid, есть поле X • regex, длина, число • task completion rate ✓ быстро, дёшево, стабильно ✗ только чёткие ответы «ответ буквально верный?» структурированный выход, tool success, финальный факт ② Специализированные готовые метрики под задачу • RAGAS (для RAG): — faithfulness — answer relevancy — context precision/recall • BLEU/ROUGE (текст) ✓ проверены, под домен ✗ не под всякую задачу RAG-пайплайны, суммаризация, перевод ③ Custom scorers свои критерии, часто LLM-judge • «тон вежливый?» • «покрыл все пункты?» • «нет запретных тем?» • рубрика 1–5 по критерию ✓ гибко, под любой критерий ✗ дороже, судья сам шумит «ответ хорош ПО СМЫСЛУ?» субъективное качество, многокритериальность

Правило выбора: иди слева направо и бери самое простое, что ловит нужное. Детерминированная проверка дешевле и стабильнее LLM-судьи — если ответ можно проверить кодом (валидный JSON, точное число, успех инструмента), не зови LLM. Судью (③) — только там, где нужен смысл, который кодом не ухватить.

Task completion rate

Для агента (не просто «ответчика») главная offline-метрика — task completion rate: доля задач, которые агент довёл до успешного результата. Это верхнеуровневый показатель «работает ли агент вообще», в отличие от метрик отдельного ответа.

Ключевой вопрос — как определить «успешно выполнил». Варианты по возрастанию гибкости:

  • По конечному результату — детерминированная проверка: агент вернул правильное число / создал файл / выполнил транзакцию. Если исход проверяем кодом — идеально.
  • По достижению цели — для нечётких задач цель проверяет LLM-судья: «решил ли ответ задачу пользователя?» (да/нет).
  • Составной success — задача считается выполненной, если пройдены несколько под-условий (нашёл информацию И правильно оформил И уложился в шаги).
✅ Task completion — про исход, а не про путь

Важное различие: task completion rate оценивает результат («задача решена?»), а не то, как агент к нему шёл. Оценка самой траектории (правильные ли шаги, не было ли лишних вызовов) — это отдельная метрика, trajectory evaluation, ей посвящён урок в разделе «Тестирование агентов». Начинай с исхода: если агент не решает задачу, анализировать путь рано.

RAGAS: метрики для RAG

Если твой агент использует RAG (модуль 04), у оценки появляется специфика: качество зависит и от retrieval (нашли ли нужные документы), и от генерации (использовал ли ответ найденное без выдумок). Писать эти метрики с нуля не надо — есть RAGAS, специализированный фреймворк оценки RAG. Его метрики (считаются с помощью LLM) разложены по стадиям пайплайна:

Метрика RAGASЧто измеряетСтадия
faithfulnessОтвет опирается на контекст, не выдумывает (анти-галлюцинация)Генерация
answer relevancyОтвет по существу вопроса, без водыГенерация
context precisionНайденные документы релевантны (мало мусора)Retrieval
context recallНайдено всё нужное для ответа (ничего не упущено)Retrieval

Ценность разбивки — в локализации проблемы. Низкий faithfulness → модель галлюцинирует, чини промпт/генерацию. Низкий context recall → retriever не находит нужное, чини поиск/чанкинг/эмбеддинги. Одна метрика «плохой ответ» этого не разделила бы.

Оценка RAG через RAGAS (концептуально)
python
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall
from datasets import Dataset

# датасет: вопрос, ответ системы, найденный контекст, эталон (ground truth)
data = Dataset.from_dict({
    "question":     ["Какая столица Франции?"],
    "answer":       ["Столица Франции — Париж."],
    "contexts":     [["Париж — столица и крупнейший город Франции."]],
    "ground_truth": ["Париж"],
})

result = evaluate(data, metrics=[
    faithfulness,        # не галлюцинирует?
    answer_relevancy,    # по существу?
    context_precision,   # retrieval точный?
    context_recall,      # retrieval полный?
])
print(result)   # {'faithfulness': 1.0, 'answer_relevancy': 0.98, ...}
# низкий faithfulness → чини генерацию; низкий recall → чини retriever
⚠️ RAGAS считает метрики через LLM — это стоит денег и шумит

Большинство метрик RAGAS вычисляются самой LLM (оценка faithfulness — это LLM, сверяющая ответ с контекстом). Отсюда следствия: оценка стоит токенов, не мгновенна и сама по себе имеет разброс (та же природа, что у LLM-as-judge — следующий урок). Точный набор метрик и API RAGAS меняются между версиями — сверяйся с актуальной документацией. Используй RAGAS на репрезентативной выборке, а не на каждом запросе прода.

Custom scorers по критериям

Готовые метрики покрывают типовое, но у твоего продукта свои критерии: «ответ в фирменном тоне», «не обещает того, чего компания не делает», «покрыл все пункты вопроса», «уложился в формат». Для этого пишут custom scorers — функции, возвращающие оценку по твоему критерию. Форма — та же, что у evaluator из LangSmith: на вход выход системы (и эталон), на выходе score.

Два вида по механике:

  • Кодовые — критерий проверяется программно: длина, наличие обязательных секций, валидность формата, отсутствие стоп-слов. Дёшево и стабильно.
  • LLM-based — критерий субъективный, судит LLM по рубрике: «оцени вежливость 1–5», «покрывает ли ответ все аспекты?». Гибко, но дороже и с разбросом.
Два custom scorer'а: кодовый и LLM-based
python
# ① Кодовый scorer — проверяем формат детерминированно (дёшево, стабильно)
def has_required_sections(run, example) -> dict:
    answer = run.outputs["answer"]
    ok = all(section in answer for section in ["## Итог", "## Источники"])
    return {"key": "format_ok", "score": 1.0 if ok else 0.0}

# ② LLM-based scorer — субъективный критерий через судью по рубрике
JUDGE_PROMPT = """Оцени ответ по критерию ВЕЖЛИВОСТЬ по шкале 1-5.
Верни ТОЛЬКО число.
Ответ: {answer}"""

def politeness(run, example) -> dict:
    answer = run.outputs["answer"]
    score = int(llm(JUDGE_PROMPT.format(answer=answer)))   # 1..5
    return {"key": "politeness", "score": score / 5}       # нормируем к 0..1

# оба подключаются к experiment как обычные evaluators (см. урок LangSmith)
# evaluate(system, data="my-dataset", evaluators=[has_required_sections, politeness])
✅ Правило: критерий → самый дешёвый scorer, который его ловит

Прежде чем писать LLM-судью, спроси: «можно ли проверить критерий кодом?». Формат, длина, наличие полей, валидный JSON, стоп-слова — всё это кодовые scorers: быстрее, бесплатно, без разброса. LLM-судью береги для смысловых критериев (тон, полнота, релевантность), которые программно не выразить. Хороший набор offline-метрик — это смесь: много дешёвых кодовых + несколько дорогих LLM-based.

Типичные ошибки

❌ Ошибка 1: одна метрика на всё

«Правильность» не покрывает релевантность, тон, формат и галлюцинации. Оценивай по нескольким измерениям — иначе улучшишь одно, не заметив, как просело другое.

❌ Ошибка 2: LLM-судья там, где хватит кода

Проверять валидный JSON или точное число через LLM — дорого, медленно и менее надёжно, чем json.loads или ==. Детерминированное — кодом.

❌ Ошибка 3: нерепрезентативный датасет

Offline-метрика хороша ровно настолько, насколько датасет похож на реальный трафик. 10 лёгких примеров дадут ложные 95% — а прод развалится на кейсах, которых в датасете не было. Наполняй датасет реальными трудными случаями (в т.ч. из прод-трейсов).

❌ Ошибка 4: слепо доверять числу

RAGAS/LLM-scorers сами шумят и могут ошибаться. Не принимай решение по одному прогону на 5 примерах; смотри на размер выборки, разброс и глазами проверяй спорные оценки судьи.

Шпаргалка

Offline-метрики — всё в одном месте
text
OFFLINE = оценка на фиксированном датасете ДО релиза (повторяемо, безопасно, в CI)
  online = после релиза на живом трафике · offline ловит регрессию заранее
  опирается на dataset + evaluator + experiment (урок LangSmith)

у LLM НЕТ одной accuracy: качество многомерно (верность/релевантность/тон/формат/...)
  → набор метрик, часто под задачу

3 ТИПА МЕТРИК (бери самое простое, что ловит нужное):
  ① детерминированные — код vs эталон: exact/fuzzy, JSON valid, regex, TASK COMPLETION
     ✓ быстро/дёшево/стабильно · «буквально верно?»
  ② специализированные — готовые под задачу: RAGAS (RAG), BLEU/ROUGE (текст)
  ③ custom scorers — свои критерии, часто LLM-judge · «хорош по смыслу?» · гибко/дорого

TASK COMPLETION RATE (главная для АГЕНТА): доля доведённых до успеха задач
  успех: по результату (код) / по цели (judge) / составной
  про ИСХОД, не про путь (путь = trajectory evaluation, др. урок)

RAGAS (для RAG, метрики через LLM):
  faithfulness (не галлюцинирует) · answer_relevancy (по существу)   ← генерация
  context_precision (retrieval точный) · context_recall (полный)     ← retrieval
  разбивка ЛОКАЛИЗУЕТ проблему: низкий recall→retriever, низкий faith→генерация

CUSTOM SCORERS: кодовые (формат/длина/поля — дёшево) + LLM-based (тон/полнота — дорого)
  правило: критерий → самый дешёвый scorer, который его ловит

ГРАБЛИ: одна метрика на всё · LLM-судья где хватит кода · нерепрезентативный датасет ·
        слепо верить числу (шум judge, размер выборки)

Практическое задание

Задание: собери offline-оценку агента

  1. Для агента из модулей 03–05 определи task completion rate: как ты формализуешь «задача выполнена успешно»? Проверяемо ли это кодом или нужен судья?
  2. Разложи качество своего агента на 3–4 измерения (например: правильность, релевантность, формат, тон). Для каждого выбери тип метрики (① / ② / ③) и обоснуй.
  3. Если у агента есть RAG — прогони RAGAS на 5–10 примерах. Где метрика ниже: генерация (faithfulness) или retrieval (recall)? Что чинить?
  4. Напиши один кодовый custom scorer (формат/наличие полей) и один LLM-based (субъективный критерий по рубрике). Подключи оба как evaluators.
  5. Найди в своём наборе критерий, который ты сначала хотел отдать LLM-судье, но можно проверить кодом. Перепиши на кодовый scorer.
  6. Оцени датасет: репрезентативен ли он? Добавь 2–3 трудных реальных кейса (например, из прод-трейсов LangSmith/Langfuse). Как изменились метрики?
  7. Со звёздочкой: собери всё в один offline-прогон (experiment) для двух версий промпта и сравни по всем метрикам сразу. Какая версия победила и по каким измерениям проиграла?

Что дальше

Мы дважды упёрлись в «а тут судит LLM» — в RAGAS и в custom scorers. Но у автоматических метрик есть предел: некоторые вещи может оценить только человек. Следующий урок — про human evaluation: процесс разметки, согласованность оценщиков и как избегать предвзятости.