Перейти к содержимому
22 дек. 2024 г.·7 мин чтения

Оффлайн и онлайн метрики LLM: как свести их в дашборд

Оффлайн и онлайн метрики LLM не всегда совпадают. План статьи о том, как собрать дашборд, где рядом видны eval score, сбои и бизнес-эффект.

Оффлайн и онлайн метрики LLM: как свести их в дашборд

Почему оффлайн и онлайн дают разную картину

Оффлайн-тесты почти всегда чище реальной жизни. Команда берет набор промптов, фиксирует модель, один раз настраивает рубрику и получает понятный eval score. В продакшене все иначе: люди пишут с опечатками, меняют тему на полпути, вставляют куски писем, возвращаются через час и ждут ответ сразу.

Поэтому высокий eval score не гарантирует хороший результат после релиза. Оценка часто смотрит только на текст ответа, а пользователь оценивает весь путь: дождался ли он ответа, понял ли следующий шаг, пришлось ли повторять вопрос, сработал ли сценарий до конца. Модель может отвечать точно, но слишком долго. Для человека это уже плохой опыт.

Реальный трафик ломает аккуратные оффлайн-тесты еще и потому, что в нем больше переменных. Меняется длина контекста, retrieval приносит лишние документы, часть запросов идет с пустыми полями, часть попадает на другую модель или к другому провайдеру из-за нагрузки. Если команда использует единый шлюз и маршрутизацию между моделями, как в RU LLM, расхождение видно особенно хорошо: один и тот же промпт ведет себя по-разному при смене маршрута, лимитов и очередей.

Задержка и сбои меняют поведение пользователя сильнее, чем кажется по графику. При p95 в 7-8 секунд люди чаще жмут повтор, упрощают вопрос или просто уходят. После этого вы видите больше коротких запросов, больше обрывов сессий и хуже бизнес-метрику, хотя качество отдельных ответов на ручной проверке могло даже вырасти.

Есть и обратная история. Модель может получить средний балл на оффлайн-наборе, но в онлайне принести лучший результат для бизнеса. Так бывает, когда она отвечает короче, яснее и быстрее. Для саппорта это означает меньше переводов на оператора. Для внутреннего ассистента - меньше времени на поиск ответа. Для продаж - больше завершенных заявок, даже если формулировки у модели не идеальны по рубрике.

Оффлайн и онлайн метрики LLM нельзя читать отдельно. Если eval score растет, а конверсия, удержание или доля завершенных сценариев падают, проблема часто не в самой модели. Сначала проверьте задержку, ошибки, таймауты, фолбэки и долю повторных запросов. Без этого связь между eval score и бизнес-метриками почти всегда выглядит лучше на тестовом стенде, чем в живом трафике.

Какие метрики держать рядом

Одна цифра почти всегда врет. Модель может дать высокий eval score на тестовом наборе и при этом терять пользователей из-за таймаутов, длинных ответов или частых переключений на fallback. Поэтому на одном экране стоит держать не "лучшую модель", а связку качества, надежности и результата для бизнеса.

Удобнее смотреть на метрики как на один срез трафика: по интенту, модели, провайдеру, каналу и версии промпта. Тогда оффлайн и онлайн метрики LLM начинают спорить предметно, а не абстрактно.

Обычно рядом держат пять показателей: eval score по задачам и интентам, долю ошибок и таймаутов, p95 latency, fallback rate между моделями и провайдерами и одну бизнес-метрику на сценарий. Это может быть конверсия, удержание, доля решенных обращений или снижение переводов на оператора. Важно выбрать один главный сигнал на сценарий, иначе дашборд быстро расползается.

Такой набор лучше всего читать по строкам. Например, для интента "проверка статуса заявки" можно увидеть 0,89 по eval, 4,2% таймаутов, p95 в 11 секунд, fallback 18% и долю решенных обращений 62%. Этот срез говорит куда больше, чем любой один график.

Есть простое правило: если растет eval score, но вместе с ним растут p95, ретраи и fallback, улучшение сомнительное. Пользователь не чувствует оффлайн-победу, если ответ пришел поздно или только со второй попытки. Обратная ситуация тоже встречается часто: latency стала ниже, а доля решенных обращений просела, потому что модель начала отвечать слишком коротко и чаще уходит в безопасный отказ.

Если команда маршрутизирует трафик между несколькими моделями и провайдерами через единый шлюз, fallback и retry лучше резать по каждой ветке маршрута. Тогда видно, спасает ли отказоустойчивость сценарий или просто прячет проблему одной модели за счет другой.

Хороший дашборд не ищет победителя. Он показывает, где именно расходятся качество, стабильность и бизнес-эффект.

Как договориться о единых определениях

Обычно спор начинается не с графика, а с разных смыслов за одной и той же цифрой. Для ML-команды "качество" может быть средним eval score по тестовому набору, для продукта - долей сессий, где пользователь дошел до цели, а для платформы - долей запросов без таймаута. Если не свести это к общему словарю, дашборд быстро превращается в витрину для споров.

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

Для каждой метрики полезно зафиксировать пять вещей: точную формулу, источник данных, окно времени, уровень агрегации и владельца. Это скучно только на старте. Потом именно эти детали экономят часы споров.

Окна времени нужно сверять отдельно. Частая ошибка: оффлайн-оценка считается по стабильному набору раз в неделю, а онлайн-график смотрят за последние 24 часа во время акции, релиза или сбоя у провайдера. После этого команда делает вывод, что модель "просела", хотя сравнивает разные периоды и разный трафик. Лучше сразу договориться, какие окна считаются сопоставимыми: день к дню, неделя к неделе или релиз к релизу.

Еще один обязательный слой - идентификаторы. request_id связывает конкретный вызов модели с логами и трассировкой. session_id показывает цепочку в рамках одного сценария. user_id помогает связать ответ модели с продуктовым событием: заявка отправлена, диалог брошен, оператор подключился. Без этой связки eval score и бизнес-метрики живут в разных мирах.

Средние значения тоже часто мешают. Один и тот же дашборд должен уметь резать данные по модели, маршруту и продуктовой фиче. Иначе хороший результат на FAQ скроет провал в онбординге, а стабильный провайдер - сбои на резервном маршруте. Если вы работаете через шлюз вроде RU LLM, удобно тянуть request_id, маршрут и провайдера из одного слоя, а продуктовые события - из своей аналитики.

И последнее: у каждого блока дашборда должен быть хозяин. Платформа отвечает за задержку и ошибки, ML - за eval и деградацию модели, продукт - за конверсию сценария. Если у графика нет формулы, окна времени и владельца, ему рано появляться на первом экране.

Как связать запрос, ответ и бизнес-событие

Если у запроса нет общего идентификатора, дашборд быстро начинает врать. Одна команда смотрит на eval score, другая на конверсию, третья на ошибки API, и каждый видит свою правду. Связка начинается с одного request_id, который проходит через вызов модели, ответ и действие пользователя после ответа.

Для каждого продакшен-запроса полезно хранить не только текст и latency. Нужен и контекст маршрута: какая модель ответила, через какого провайдера прошел вызов, какой маршрут выбрал шлюз и сколько было ретраев. Если трафик идет через RU LLM, это особенно важно: один и тот же OpenAI-совместимый вызов может уйти на разных провайдеров или на собственный хостинг модели, а без этого поля вы не поймете, почему вчера качество выросло, а сегодня просело.

Минимальный набор полей обычно такой: request_id, user_id или session_id, model, provider, route, retries, prompt_version, policy_version, response_id, latency, cost, cache_hit, eval_score, eval_source и business_event.

Версию промпта и набор защитных правил лучше хранить как отдельные поля, а не в комментарии к релизу. Иначе через две недели никто не вспомнит, какой system prompt стоял в проде и какая проверка блокировала ответ. Для спорных случаев это важнее самого текста ответа.

Источник оценки тоже нужен рядом с запросом. Есть большая разница между offline eval на размеченном датасете, автооценкой другой моделью и ручной жалобой оператора. Если свести все в одно поле "score", команда начнет делать ложные выводы. Лучше хранить и само значение, и source: offline_batch, online_judge, user_feedback, human_review.

Бизнес-событие стоит добавлять не в момент ответа модели, а после него, когда пользователь что-то сделал. Для чат-ассистента это может быть "заявка отправлена", "диалог брошен", "перевод на оператора" или "повторный вопрос через 30 секунд". Тогда видно не просто хороший ответ по внутренней оценке, а ответ, после которого человек дошел до нужного действия.

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

На одном экране хорошо уживаются три линии: eval score, доля ошибок и бизнес-метрика. Например, качество по автооценке выросло на 6%, но вместе с этим выросли ретраи и доля переводов на оператора. Это не успех, а повод открыть сырые запросы по конкретному маршруту и версии промпта.

Как собрать первый экран дашборда

Снизьте шум в интеграции
Оставьте код и промпты как есть, если уже работаете с OpenAI или OpenRouter.

Первый экран должен отвечать на три вопроса за 10 секунд: сервис жив, ответы не просели по качеству, бизнес не теряет пользователей. Если для этого нужно листать ниже, экран перегружен.

Сверху обычно хватает трех чисел: доступность, error rate и p95. Показывайте их сразу в двух окнах, например за 15 минут и за сутки. Короткое окно ловит инцидент, длинное помогает не дергаться из-за шума.

Рядом ставьте eval score по свежему трафику, а не по старому тестовому набору. Иначе дашборд покажет спокойную картину там, где пользователи уже ждут дольше, чаще жмут повтор и уходят в операторский канал.

Следом нужна одна бизнес-метрика на сценарий. Для поддержки это может быть доля решенных обращений без оператора. Для поиска по базе знаний - доля сессий без повторного вопроса. Для продаж - доля завершенных заявок. Главное, чтобы эта метрика обновлялась с понятным лагом и была привязана к request_id или session_id.

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

Пример: чат-ассистент банка

Банк поменял модель в чат-ассистенте для типовых обращений: лимит по карте, статус перевода, блокировка, условия тарифа. На оффлайн-наборе новая версия выглядела лучше. Eval score вырос, редакторы чаще выбирали ее ответы, а на коротких диалогах текст казался точнее и спокойнее.

Проблемы начались после выката. Новая модель отвечала медленнее, особенно когда клиент задавал второй или третий уточняющий вопрос. Средняя задержка выросла умеренно, но p95 ушел сильно вверх. Часть сессий упиралась в таймаут, и клиент нажимал кнопку перевода на оператора раньше, чем получал ответ.

Сначала команда решила, что дело в качестве ответов, и начала править промпт. Но ручная проверка показала другое: ответы действительно стали лучше по формулировке, а падение шло из-за хвоста задержки. Когда трафик разрезали по маршрутам, выяснилось, что длинные диалоги чаще уходили на запасную ветку с более медленным провайдером. Оффлайн-оценка этого просто не видела.

Этот пример хорошо показывает, почему eval score и бизнес-метрики нельзя читать отдельно. Если смотреть только на качество текста, новая модель победила. Если смотреть только на долю переводов на оператора, модель будто бы проиграла. Полная картина появилась только после того, как рядом поставили качество, p95, retry rate, fallback rate и результат сценария.

Где команды чаще ошибаются

Смотрите маршрут каждого запроса
Используйте аудит-трейлы и единый API-поток для разбора сбоев и фолбэков.

Когда оффлайн и онлайн метрики LLM расходятся, проблема часто не в самой модели. Команда просто смотрит на данные слишком грубо и получает красивую, но ложную картину.

Первая частая ошибка - смотреть только среднюю задержку. Среднее скрывает хвост, а пользователи обычно чувствуют именно его. Если 90% ответов приходят за 2 секунды, а 10% висят по 18 секунд, среднее может выглядеть терпимо, но в чате, поиске или поддержке это уже ломает сценарий.

Вторая ошибка появляется после смены маршрута или провайдера. Команда переводит часть трафика на новую модель, а потом сравнивает общий поток за неделю с прошлой неделей. В такой смеси теряется причина изменения: где сработала новая модель, где повлиял другой тип запросов, а где выросла нагрузка.

Это особенно часто случается в схемах с единым API-шлюзом, когда маршрут до модели можно поменять без правок в коде. Удобно для запуска, но опасно для аналитики, если вы не помечаете каждый запрос версией маршрута, провайдером и политикой ретраев.

Третья ошибка еще банальнее: модели сравнивают на разных наборах запросов. Одну проверили на коротких FAQ-вопросах, другую - на сложных диалогах с историей и таблицами. Потом удивляются, почему высокий eval score не дал роста в проде.

Тревожные признаки обычно такие:

  • средняя задержка падает, а жалоб в поддержке становится больше;
  • success rate растет, но скрытые ретраи тоже растут;
  • новая модель "лучше" только на свежей, неравной выборке;
  • бизнес-метрика меняется раньше, чем это вообще могло произойти.

Со скрытыми ретраями команды ошибаются особенно часто. Шлюз может прозрачно повторить запрос к другому провайдеру, и пользователь все же получит ответ. На графике это выглядит как успех, хотя система уже дала сбой, потратила больше токенов и добавила несколько секунд ожидания. Если не вынести retry rate и failover rate рядом с quality score, отказоустойчивость LLM начнет маскировать проблему, а не решать ее.

Отдельная ловушка - делать вывод по бизнес-метрике без временного лага. Если банк запустил новую модель в понедельник, а в тот же день увидел сдвиг по конверсии заявок, это еще не доказательство. Часть эффектов приходит через часы, часть - через дни: пользователь мог вернуться позже, оператор мог закрыть тикет только на следующий день, а продажа могла доехать до CRM еще позже.

Хороший дашборд LLM не спорит о том, какая метрика "главнее". Он показывает цепочку: какой маршрут выбрали, какой eval score был у этого типа запросов, сколько было ретраев, какой хвост задержки получили пользователи и что случилось с бизнес-событием через нужный лаг.

Быстрый чек-лист перед выводами

Сравнивайте 500 плюс моделей
Подайте реальные запросы в единый шлюз и выберите маршрут под свой сценарий.

Один красивый график легко уводит не туда. Перед тем как говорить, что модель стала лучше или хуже, проверьте не саму метрику, а условия, в которых она появилась. Расхождение между eval score и онлайном часто объясняется не качеством ответа, а сменой маршрута, окна отчета или состава трафика.

Если выборка маленькая, скачок может быть обычным шумом. Для редкого сценария 20-30 диалогов почти ничего не доказывают. Для массового потока даже падение на 2-3% уже похоже на сигнал, но только если вы смотрите на один и тот же сегмент: канал, тип запроса, устройство и время суток.

Перед выводом полезно быстро проверить пять вещей:

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

Последние два пункта команды часто недооценивают. Допустим, оффлайн-оценка стабильна, но в онлайне растет доля повторных попыток. Тогда пользователи ждут дольше, чаще бросают сессию, а конверсия проседает. На графике качества все выглядит спокойно, а проблема сидит в отказоустойчивости.

С окном отчета та же история. Пользователь может задать вопрос сейчас, а оформить заявку через час или на следующий день. Если дашборд связывает ответ модели только с текущей сессией, вы увидите слабую или ложную связь с бизнес-метрикой. Нужна аккуратная привязка по request_id, session_id и времени бизнес-события.

В инфраструктуре вроде RU LLM это особенно важно, потому что один и тот же клиентский код может пойти через другой маршрут или к другому провайдеру без изменений в SDK. Поэтому в дашборде стоит хранить рядом provider, model, route_id, prompt_version и флаг fallback для каждого запроса.

Если хотя бы на один вопрос нет ясного ответа, вывод лучше отложить. Сначала выровняйте условия сравнения. Потом уже решайте, виновата модель, маршрут или сам способ измерения.

С чего начать на следующей неделе

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

Для старта хватит 5-7 метрик. Больше не нужно: команда утонет в цифрах и снова начнет спорить по ощущениям. Обычно достаточно offline eval score на небольшом стабильном наборе примеров, доли плохих ответов по ручной проверке, p95 latency, доли hard errors, доли фолбэков или переключений на запасной маршрут и одной бизнес-метрики сценария.

Такой набор уже связывает eval score и бизнес-метрики с надежностью. На одном экране видно, что модель может пройти оффлайн-тест, но просесть в онлайне из-за таймаутов, длинных ответов или роста фолбэков.

Потом проживите с этим набором одну неделю вручную. Каждый день берите 20-30 реальных запросов, где оффлайн-оценка и онлайн-результат расходятся, и разбирайте их руками. Обычно причина находится быстро: плохой роутинг, неучтенный тип запроса, деградация у одного провайдера или сломанная разметка бизнес-события.

Сразу задайте пороги реакции. Если error rate выше выбранного уровня, система шлет алерт. Если p95 latency уходит за предел, трафик частично переводится на запасной маршрут. Если ручная проверка показывает рост плохих ответов, команда откатывает промпт или модель, даже если средний eval score пока выглядит нормально.

Если трафик идет через RU LLM, в дашборд полезно добавить срезы по провайдерам, маршрутам и аудит-трейлам из единого API-потока. Это экономит время на разборе: не нужно собирать картину из разных логов, а расхождения между качеством, задержкой и отказами видны по каждому маршруту отдельно.

В конце недели зафиксируйте правила разбора инцидентов. Кто смотрит на eval, кто отвечает за latency, кто подтверждает влияние на бизнес-метрику, кто принимает решение об откате. Без владельцев даже хороший дашборд LLM быстро превращается в красивую, но бесполезную стену графиков.

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

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

Почему высокий eval score не гарантирует хороший результат после релиза?

Потому что оффлайн-набор почти всегда чище живого трафика. В проде люди пишут с ошибками, меняют тему, ждут быстро и часто попадают в длинные диалоги.

Смотрите не только на текст ответа, но и на p95 latency, таймауты, ретраи и долю завершенных сценариев. Если модель отвечает точнее, но дольше, пользователь все равно получает плохой опыт.

Какие метрики смотреть рядом с eval score?

Держите рядом пять сигналов: eval score, error rate, p95 latency, fallback или retry rate и одну бизнес-метрику на сценарий. Для саппорта это может быть доля решенных обращений без оператора, для продаж — доля завершенных заявок.

Так вы сразу видите, где расходятся качество текста, стабильность сервиса и итог для бизнеса.

Что обычно ломает аккуратные оффлайн-тесты в онлайне?

Чаще всего картину ломают длинный хвост задержки, скрытые ретраи, таймауты, лишние документы из retrieval и смена маршрута между моделями или провайдерами. Еще мешают пустые поля и разный состав трафика по дням.

Проверяйте эти вещи раньше, чем начинаете переписывать промпт или менять модель.

Как понять, что проблема в задержке, а не в качестве ответа?

Сравните качество ручной проверки с поведением пользователей после ответа. Если формулировки стали лучше, а люди чаще жмут повтор, бросают сессию или уходят к оператору, ищите причину в задержке и сбоях.

Особенно полезно смотреть p95, а не среднее. Среднее часто прячет проблемы, которые пользователь чувствует сильнее всего.

Зачем хранить request_id и session_id?

Без общего идентификатора команды видят разные куски одной истории. request_id связывает вызов модели с логами и трассировкой, а session_id показывает цепочку в рамках сценария.

Если добавить user_id и время события, вы сможете проверить, к какому ответу привели перевод на оператора, повторный вопрос или отправка заявки.

Как связать ответ модели с бизнес-событием?

Не привязывайте бизнес-событие только к факту ответа модели. Привязывайте его к действию после ответа: пользователь отправил заявку, задал повторный вопрос, ушел или запросил оператора.

Так вы увидите не просто хороший score, а реальный эффект ответа на сценарий.

Что стоит вывести на первый экран дашборда?

Покажите три вещи, которые отвечают на вопрос за несколько секунд: сервис жив, качество не просело, бизнес не теряет пользователей. Обычно для этого хватает доступности, error rate, p95 latency, свежего eval score и одной бизнес-метрики.

Ниже добавьте разрез по интентам и разрез по маршрутам. Этого хватит, чтобы быстро понять, где искать причину.

Как не запутаться при маршрутизации между моделями и провайдерами?

Помечайте каждый запрос моделью, провайдером, route_id, числом ретраев и флагом fallback. Иначе смена ветки замаскирует реальную причину просадки.

Если вы работаете через единый шлюз вроде RU LLM, тяните эти поля из одного слоя и режьте графики по каждой ветке маршрута отдельно.

Когда можно доверять сравнению двух моделей?

Сначала выровняйте условия. Сравнивайте один и тот же интент, близкий объем трафика, одинаковые окна времени, одну версию промпта и один маршрут вызова.

Если в тот же день сменился провайдер или выросли ретраи, не делайте вывод по общему графику. Такое сравнение даст красивую, но ложную картину.

С чего начать, если дашборда еще нет?

Начните с одного сценария, где ошибка заметна и пользователю, и бизнесу. На первую неделю хватит небольшого набора: offline eval score, доля плохих ответов по ручной проверке, p95 latency, hard errors, fallback rate и одна бизнес-метрика.

Потом каждый день разбирайте несколько реальных запросов, где метрики расходятся. Так вы быстро поймете, что именно ломает результат: модель, маршрут, провайдер или разметка событий.