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

Какие проблемы в LLM-продакшене важно поймать раньше жалоб
LLM в продакшене похож на обычный API только снаружи. Внутри есть три особенности: стоимость зависит от токенов, ответы не всегда предсказуемы, а качество и доступность часто завязаны на внешнего провайдера и его лимиты. Поэтому мониторинг здесь отвечает не на один вопрос "жив ли сервис", а сразу на несколько: не стало ли хуже, дороже или рискованнее.
Жалобы пользователей почти всегда запаздывают. Сначала растет очередь, потом увеличивается задержка, позже появляются таймауты, и только затем человек пишет в поддержку: "бот завис". С качеством похожая история: модель чаще уходит в сторону, путает факты или отвечает слишком общо, а заметно это становится после десятков диалогов.
Полезно заранее договориться, что для вас значит "работает". Обычно это сочетание нескольких критериев: скорость (ответы приходят вовремя даже в пик), стабильность (без всплесков ошибок и обрывов), качество (ответ решает задачу, а не просто звучит правдоподобно), стоимость (токены и расходы предсказуемы) и безопасность (нет утечек данных и опасных подсказок в логах).
Еще один частый сюрприз: проблема может быть не у вас. Провайдер меняет модель, вводит новые лимиты, где-то по сети растут потери, и вы получаете деградацию без единого релиза со своей стороны.
Чтобы ловить это раньше жалоб, заранее определите роли и реакции. Продукт отвечает за качество и конверсию в решенную задачу. Поддержка видит рост повторных обращений и "непонятных" диалогов. Безопасность следит за персональными данными и промпт-инъекциями. Инфраструктура отвечает за очереди, задержки и ошибки. В крупных организациях (например, в банке или госструктуре) именно согласованность этих ролей делает алерты полезными, а не шумными.
Карта сигналов: что измерять и как связывать данные
Чтобы мониторинг не превращался в набор разрозненных графиков, разложите наблюдаемость по слоям. У каждой проблемы есть след сразу в нескольких местах: железо и сеть дают задержки, приложение - ошибки и таймауты, модель - неожиданный текст и рост токенов, а бизнес видит падение конверсии или рост обращений в поддержку.
Ключ к связи этих следов - единый request_id. Он должен появляться на входе (фронт, API-шлюз, бот-платформа) и проходить до ответа модели и обратно. Тогда по одному запросу вы быстро поймете, был ли он в очереди, сколько занял вызов провайдера, какая модель ответила и что именно вернулось.
Для каждого запроса стоит фиксировать минимум: request_id и временные метки (вход, старт/конец LLM-вызова, выход), session_id и канал (веб, мессенджер, внутренняя система), модель/версию и параметры (температура, max_tokens, инструменты), результат (успех/ошибка, причина, ретраи, обрезка ответа). Тексты промпта и ответа тоже полезны, но храните их с маскированием персональных данных.
Хранить это обычно удобнее в трех местах: метрики для чисел и алертов (задержки, ошибки, токены), логи для деталей (тексты, причины, контекст), трейсы для цепочки вызовов (фронт -> бэкенд -> LLM -> внешние сервисы). Важно, чтобы везде был один и тот же request_id.
Простой пример: пользователи жалуются "бот стал тупее". С request_id вы можете увидеть, что качество просело не у модели, а из-за таймаутов: часть ответов обрезается, потому что очередь выросла, и приложение режет max_tokens, чтобы уложиться в лимит времени.
Очереди и задержки: метрики, которые показывают перегрузку
Перегрузка почти всегда проявляется одинаково: медленные ответы, таймауты и "плавающее" время отклика. Если ждать жалоб, вы будете тушить пожар. Поэтому в первую очередь держите метрики очередей и задержек: они раньше других показывают, что система не успевает.
Начните с очереди: длина, среднее и p95 время ожидания, скорость обработки (сколько запросов в секунду реально уходит на выполнение). Смотрите не только "сколько ждут", но и "почему": очередь растет из-за всплеска трафика, падения пропускной способности модели или ограничений провайдера.
Чтобы быстрее находить узкое место, разбивайте латентность по этапам и считайте p50/p95/p99 для каждого: pre-processing (валидация, подготовка контекста, RAG), вызов модели (время до ответа и время генерации), post-processing (фильтры, форматирование, запись в БД), сетевые задержки. Таймауты и ретраи лучше учитывать как отдельные события.
Если инфраструктура своя (например, on-prem в дата-центре), добавьте concurrency и утилизацию ресурсов: CPU/GPU, память, диск, сеть. Частый сценарий: p50 остается нормальным, а p99 растет, потому что GPU упирается в память, и часть запросов попадает в "хвост".
Не забывайте про лимиты провайдера: rate limit, throttling, остаток квот. Их лучше считать отдельными ошибками, иначе они будут выглядеть как "случайные таймауты".
Для стриминга нужны отдельные сигналы: время до первого токена и скорость токенов в секунду. Пользователь часто готов ждать дольше, если первый токен приходит быстро, а поток идет ровно.
Токены и стоимость: как не пропустить рост расходов
Если сервис стабилен, но счета растут, причина почти всегда видна в токенах. Поэтому мониторинг должен показывать не только "сколько запросов", но и "сколько текста вы гоняете через модель" - по пользователям, сценариям и времени.
Какие метрики по токенам собирать
Для каждого запроса фиксируйте input tokens, output tokens и tokens per request. Дальше смотрите распределения: медиана, 90-й и 99-й перцентили. Среднее часто обманывает: рост расходов обычно дают редкие, но очень длинные запросы.
Полезные разрезы: сценарии (поддержка, поиск по базе знаний, генерация письма), типы пользователей (внутренние сотрудники, внешние клиенты), источник контекста (история чата, документы, системный промпт), модель/версия (после переключения часто меняется длина ответа).
Следующий слой - деньги. Если тарификация по токенам, считайте estimated cost на запрос и суммарную стоимость по сценарию за час/день. Так быстро видно, что, например, 10% трафика "съедает" 60% бюджета.
Что обычно раздувает токены
Чаще всего виноваты длинный контекст и разрастающаяся история чата. Отдельно измеряйте долю запросов с длинным промптом (например, выше 90-го перцентиля за неделю) и фиксируйте причины: добавили больше документов, стали прикладывать логи целиком, не обрезаете историю.
Считайте, сколько запросов упираются в max context (или близко к нему). Это и про стоимость, и про качество: модель теряет часть полезного контекста или вы вынуждены резать данные вслепую.
Если есть кеширование (ответов, эмбеддингов, извлеченных документов), держите cache hit rate и оценку "сэкономленных токенов". В чатботе поддержки повторяемые вопросы быстро превращаются в ощутимую экономию: падает tokens per request при том же числе обращений.
Ошибки и надежность: что логировать и считать
Надежность LLM-сервиса начинается не с дашбордов, а с дисциплины логов. Важно уметь ответить на простой вопрос: что именно сломалось - модель, ваш код или зависимость.
Собирайте ошибки в двух разрезах: ответы провайдера (например, 4xx и 5xx) и ошибки приложения (валидация входа, сбой парсинга, ошибка сборки промпта). Отдельно учитывайте таймауты: они часто выглядят как "непонятные" падения, но на деле это перегрузка или зависшая зависимость.
Полезный минимум для каждого запроса: request_id, user_id/tenant (если есть), сценарий (чат, поиск, суммаризация), код результата (ok, provider_4xx, provider_5xx, timeout, app_error), статус стриминга (completed/aborted/partial), число ретраев и причина повтора, какие зависимости вызывались (поиск, векторная база, хранилище документов, авторизация) и их статусы.
Ретраи считайте отдельной метрикой, а не как "повторили и все хорошо". Смотрите долю запросов с повтором, среднее число ретраев и прибавку к задержке. Рост ретраев часто появляется раньше роста явных 5xx.
Есть и тихие сбои: пустые ответы, обрыв стрима на середине, частичный ответ без финальной части. Их легко пропустить, если смотреть только на HTTP-коды. Добавьте счетчики empty_output и stream_aborted.
Если используете circuit breaker и фолбэки (например, без RAG, с упрощенным промптом или запасным провайдером), измеряйте долю запросов, ушедших в запасной режим. Так можно увидеть деградацию зависимости до того, как польются жалобы: поиск в векторной базе начал отдавать таймауты, система чаще включает фолбэк, и пользователи получают более общие ответы.
Качество ответов: метрики без сложной науки
Качество проще начинать мерить не "умностью", а понятными исходами. Добавьте счетчики по типам ответа: успешный (помог и довел до результата), отказ (модель не ответила или сослалась на политику), предупреждение (ответ с оговорками, неполный, просит уточнить). Уже это показывает, где пользователи застревают.
Дальше подключите простую автооценку по сигналам, которые легко посчитать в логах и которые часто коррелируют с проблемами: длина ответа (слишком коротко или "простыня"), повторяемость (циклы и одни и те же фразы), соблюдение формата (просили 3 шага или JSON, пришел обычный текст), язык (пользователь на русском, модель внезапно отвечает на другом), токсичность и грубость.
Смотрите и бизнес-сигналы. Для внутреннего помощника ИТ-службы тревожными будут повторный вопрос сразу после ответа, рост эскалаций в поддержку, отказ от операции (начал оформление заявки и бросил), падение доли решенных запросов за сессию.
Автоматика не заменяет людей, поэтому нужна проверка по выборке. Выберите 20-50 диалогов в неделю и оцените по 3-5 простым критериям: "ответил по сути", "не выдумал факты", "дал следующий шаг", "тон нормальный". Критерии должны быть одинаковыми у всех проверяющих.
Чтобы замечать регрессии после обновлений промптов или модели, держите небольшой тестовый набор (golden set) из типовых задач. Прогоняйте его регулярно и сравнивайте с базовой версией по тем же критериям и авто-сигналам.
Деградации и дрейф: как замечать ухудшения вовремя
Деградация в LLM редко выглядит как "все сломалось". Чаще это постепенный рост отказов, падение полезности ответов или больше галлюцинаций. При этом графики задержек и ошибок могут оставаться зелеными, а пользователи уже недовольны. Поэтому мониторинг должен включать сигналы качества и изменения входных данных.
Что считать дрейфом и как его мерить
Сравнивайте "сегодня" с базовой неделей, когда все работало хорошо. Дрейф чаще видно по тому, как меняются запросы: темы и намерения (закупки, техподдержка, безопасность), языки и доля смешанного языка, длина промпта и ответа, доля сложных случаев (файлы, таблицы, специфичная терминология), доля запросов на обход правил и чувствительные темы.
Если растет доля сложных кейсов, качество может упасть даже без изменений модели. Это нормально, но должно включать другой режим: больше контекста, другой промпт или маршрутизацию на человека.
Канареечные релизы и сравнение версий
Любое изменение (новая версия модели, правка промпта, новый источник контента, новая аудитория) выпускайте как канарейку: 1-5% трафика на новую версию, затем расширение.
Алерты удобно строить как "новая версия хуже старой" на окне 30-60 минут. Например: отказов (policy/refusal) стало больше на X%, доля низкой оценки от пользователей выросла на X пунктов, увеличилась доля ответов, где модель не нашла нужное в базе и "додумала", выросли инциденты безопасности (PII, чувствительные данные, попытки обхода).
Пример: после обновления промпта чатбота для внутренней поддержки растет доля запросов "сделай исключение из правил" и одновременно падает полезность ответов. Это сигнал не "подкрутить температуру", а проверить, не ослабили ли вы ограничения и не изменили ли тон инструкций.
Как настроить мониторинг по шагам: от нуля до контроля качества
Чтобы мониторинг реально спасал, начните не с графиков, а с простого договора с командой: что считаем нормой и когда будим дежурного.
1) Зафиксируйте SLO, а не "все подряд"
Выберите 2-3 показателя, которые отражают пользовательский опыт. Например: 95-й перцентиль времени ответа, доля ошибок (5xx, таймауты) и один показатель качества (хотя бы доля "принято без правок" или оценка оператором).
Дальше добавляйте слой за слоем:
- Опишите путь запроса целиком и поставьте тайминги на этапах: очередь, препроцессинг, вызов модели, постобработка, запись в базу.
- Приведите логи к одному формату: имя модели, версия промпта, параметры (температура, max_tokens), входные и выходные токены, статус, причина ошибки.
- Соберите дашборды под реальные сценарии, а не "общий": чат поддержки, поиск по документам (RAG), генерация отчетов.
- Добавьте регулярный прогон тестового набора и короткий отчет по качеству (хотя бы раз в день).
- Привяжите каждую метрику к действию: что делает дежурный, если порог превышен.
2) Сделайте качество измеримым без сложной науки
Простой вариант: один и тот же набор 50-200 типовых запросов и ожидаемые признаки ответа (нашел нужный документ, не выдумал факты, соблюдает формат). Если "поплыл" только один сценарий, это часто указывает на конкретную причину: новый промпт, обновление индекса, смена модели.
Пример: пользователи начали жаловаться на "длинные ответы". Если у вас есть разметка этапов и токены в логах, вы быстро увидите, где рост: увеличилось время в очереди или модель стала генерировать на 30% больше токенов. Это разные решения: масштабирование воркеров против ограничения max_tokens и правки промпта.
Алерты, которые работают: пороги, окна и понятные действия
Хороший алерт отвечает на два вопроса: что сломалось и что делать дальше. Если после пейджера нужно полчаса разбираться, где искать проблему, алерт будут либо игнорировать, либо он начнет раздражать.
Удобно держать алерты в трех группах. Первые ловят симптомы, то есть то, что уже видно пользователю: p95 задержки, рост очереди, всплеск 5xx, увеличение ретраев. Вторые ловят причины, которые еще не обязательно проявились наружу: rate limit у провайдера, приближение к квоте по токенам или деньгам, деградация зависимостей (векторное хранилище, база, сеть). Третьи следят за качеством: просадка на golden set, рост доли отказов, рост эскалаций на оператора.
Чтобы алерты не шумели, задавайте не только пороги, но и окно. Например, "p95 > 4 сек 10 минут" почти всегда лучше, чем "p95 > 4 сек 1 минуту". Помогают и двухступенчатые правила: предупреждение при мягком пороге, критический при жестком, плюс дедупликация, чтобы один инцидент не создавал десятки уведомлений.
Пример: у чатбота поддержки растет очередь, а p95 ползет вверх. Первый алерт (симптом) говорит "перегрузка", второй (причина) показывает "уперлись в лимит запросов", третий (качество) пока молчит. Тогда действие простое: временно снизить нагрузку (ограничить параллелизм или включить деградацию ответа), а потом разбираться с лимитами и емкостью.
Для каждого алерта нужен короткий runbook, иначе команда будет действовать наугад. Достаточно 5 пунктов:
- Где смотреть подтверждение: графики, логи, трассировки.
- Что проверить в первую минуту: очереди, 5xx, лимиты, здоровье зависимостей.
- Как быстро снизить ущерб: фича-флаг, понижение температуры, отключение тяжелых инструментов, возврат к кешу.
- Как откатить или переключиться на запасной режим.
- Когда и кому эскалировать (с четким временем и критериями).
Это особенно важно, если LLM-сервис работает 24/7 и завязан на инфраструктуру и поддержку, как в крупных интеграционных проектах и дата-центрах.
Частые ошибки в мониторинге LLM и как их избежать
Первая ловушка - смотреть на одну красивую цифру и думать, что все под контролем. Чаще всего это среднее время ответа. Среднее прячет редкие, но болезненные хвосты: пользователю важны не "в среднем 2 секунды", а "иногда 30". Поэтому рядом со средним держите p95 и p99, а еще отдельно время в очереди и время выполнения модели.
Вторая ошибка - смешивать разные сценарии в одну метрику. Поддержка, поиск по базе знаний и генерация письма живут по разным правилам: разные промпты, разные лимиты токенов, разная терпимость к задержке. Разделяйте метрики хотя бы по типу задачи, каналу (чат, API), языку и критичным клиентам. Так вы увидите локальные провалы, а не "среднюю температуру по больнице".
Третья ошибка - не фиксировать, что именно было развернуто. Без версии модели, версии промпта, параметров (temperature, max_tokens) и контекста (источник данных, включенные инструменты) вы не сможете честно сравнить до/после и быстро откатиться.
Еще один типовой провал - алерты без владельца и без понятного действия. Если уведомление не отвечает на вопрос "кто и что делает в первые 10 минут", его будут игнорировать.
Набор привычек, который обычно спасает:
- Делайте дашборды и алерты раздельно по сценариям и сегментам.
- Храните версионность: модель, промпт, параметры, фичи и дату релиза.
- Настраивайте алерты с коротким описанием шага проверки и ответственного.
- Следите не только за ошибками, но и за токенами на запрос.
- Проверяйте p95/p99, а не только среднее.
Отдельно про стоимость: рост токенов выглядит как "мелочь", пока счет не удваивается. Держите лимиты и алерты на токены/запрос и токены/пользователя, и отдельно на "стоимость за 1k запросов" по каждому сценарию.
Быстрый чеклист и следующие шаги
Если мониторинг уже есть, раз в неделю полезно честно ответить на вопрос: вы узнаете о проблеме по алерту или по жалобе?
Минимальный набор сигналов, который стоит держать под рукой каждый день:
- Очередь и задержки: длина очереди, p95 (и лучше p99) латентности, время ожидания до начала генерации.
- Ошибки и ретраи: доля 5xx, таймауты, отмены, процент повторных попыток, ошибки лимитов провайдера.
- Токены и стоимость: входные и выходные токены на запрос, стоимость на 1k запросов, топ самых дорогих промптов.
- Качество по выборке: регулярная проверка ответов (например, 50-100 реальных диалогов в неделю) и простая оценка "ок/не ок" с причиной.
Дашборды лучше держать простыми: один для "здоровья сервиса" (трафик, p95, ошибки), второй для "денег" (токены, стоимость, самые дорогие сценарии), третий для "качества" (доля плохих ответов по выборке и основные причины).
Когда срабатывает алерт, важнее всего быстро стабилизировать сервис и не ухудшить ситуацию релизами:
- Заморозьте релиз и откатите последние изменения, если они совпали по времени.
- Включите фолбэк (шаблонные ответы, поиск по базе знаний, более простая модель) для критичных сценариев.
- Ограничьте контекст: режьте историю диалога, вложения и слишком длинные промпты.
- Снизьте нагрузку: rate limit, очереди, временное отключение второстепенных функций.
Дальше планируйте улучшения по причинам: раз в неделю разбирайте несколько самых дорогих запросов и несколько типовых провалов качества, фиксируйте действие и ожидаемый эффект.
Если вы внедряете LLM на собственной инфраструктуре (в том числе on-prem и в дата-центрах), полезно сразу закладывать наблюдаемость, SLO и процессы реакции на инциденты. В таких проектах GSE.kz (gse.kz) часто подключается как системный интегратор: от железа и серверов до инфраструктуры для AI и поддержки 24/7, чтобы эксплуатация не держалась на ручных догадках.
FAQ
Какие метрики в LLM-сервисе чаще всего первыми показывают проблему?
Начните с очереди и латентности по перцентилям (p95/p99), доли таймаутов и 5xx, а также ретраев. Эти сигналы обычно растут раньше, чем пользователи успеют пожаловаться, и хорошо показывают перегрузку и проблемы с провайдером.
Зачем нужен единый request_id и что он дает на практике?
Единый `request_id` позволяет связать метрики, логи и трассировки для одного запроса: сколько он ждал в очереди, как долго вызывалась модель, какая версия промпта и модели была, где случился таймаут и был ли ответ обрезан. Без этого вы видите «среднюю температуру», но не понимаете причину конкретных сбоев.
Как выбрать SLO для LLM, чтобы не утонуть в метриках?
Зафиксируйте 2–3 SLO, которые отражают пользовательский опыт: например, p95 времени ответа, долю ошибок/таймаутов и один простой показатель качества. Остальные метрики добавляйте как диагностику, иначе дашборды будут «все обо всем» и не помогут в инциденте.
Как быстро заметить рост расходов на токены и найти причину?
Фиксируйте `input_tokens`, `output_tokens` и `tokens_per_request` для каждого запроса и смотрите распределения, а не среднее. Добавьте оценку стоимости на запрос и по сценариям, чтобы быстро увидеть, какой тип запросов «съедает» бюджет и из-за чего вырос контекст или длина ответа.
Как отличить проблемы провайдера LLM от проблем вашего приложения?
Считайте ошибки лимитов отдельно: rate limit, throttling, исчерпание квоты, а также время ожидания у провайдера. Если смешать их с обычными таймаутами, будет казаться, что «просто сеть плавает», и вы потратите время не на то место.
Какие метрики нужны, если ответы идут стримингом?
Для стриминга важны две метрики: время до первого токена и скорость токенов в секунду. Пользователь часто терпит длинный ответ, если поток начинается быстро и идет ровно, поэтому эти сигналы лучше коррелируют с ощущением «бот завис» чем общий тайминг ответа.
Как мерить качество ответов без сложных моделей-оценщиков?
Начните с простых исходов: помог/не помог, отказ, просьба уточнить, плюс технические сигналы вроде слишком короткого ответа, повторов и несоблюдения формата. Затем добавьте регулярную ручную проверку небольшой выборки диалогов по единым критериям, чтобы видеть регрессии, которые не поймаешь по задержкам и 5xx.
Что такое golden set и как он помогает ловить деградации после обновлений?
Соберите небольшой набор типовых запросов и прогоняйте его регулярно, сравнивая текущую версию с базовой. Если выпускать изменения канарейкой на 1–5% трафика и смотреть разницу в отказах, стоимости и качестве на коротком окне, регрессии видно до массовых жалоб.
Как настроить алерты, чтобы они были полезными, а не шумными?
Хороший алерт говорит, что ухудшилось, за какой период, и что проверить в первую минуту. Используйте окна (например, 10 минут), разделяйте симптомы (p95, очередь, 5xx) и причины (лимиты, квоты, деградация зависимостей), и держите короткий runbook, чтобы действия не были «наугад».
Как логировать промпты и ответы, не создавая рисков с персональными данными?
Храните тексты промптов и ответов только если они реально нужны для расследований, и сразу применяйте маскирование персональных данных. В логах достаточно оставить идентификаторы, версии промптов, параметры генерации и технические признаки качества, чтобы разбирать инциденты без риска утечек.