Наблюдаемость LLM‑системы: логи, трассировка, quality metrics и…
  • LLMOps
  • Автор: Команда CrmAI
  • Опубликовано:
Инженер смотрит на дашборд наблюдаемости LLM-системы

История, которую я слышал не раз: компания запустила AI-ассистента, отпраздновала успех, а через неделю поддержка прибегает с круглыми глазами — бот начал хамить клиентам. Или, того хуже, рекомендовать продукты конкурентов. CTO открывает логи, а там... ничего. Буквально пустота. Или наоборот — терабайты нечитаемого текста, в котором невозможно найти тот самый злополучный диалог.

Мы в CrmAI через это проходили сами. И теперь, когда к нам приходят клиенты с похожими проблемами, первый вопрос всегда один: «А что у вас с наблюдаемостью?» Обычно следует неловкая пауза.

LLM‑продукт без observability — это классический «черный ящик». Вы не знаете, почему модель ответила именно так, какие данные она увидела, где начала «галлюцинировать» и почему решила, что клиенту обязательно нужно знать про ваших конкурентов. Для технического директора это состояние постоянной фоновой тревоги: всё работает, но непонятно почему, и совершенно неясно, когда сломается.

В этой статье я хочу поделиться тем, что мы узнали за годы работы с LLM-системами. Построим вместе «прожектор» для вашего черного ящика: разберем, что конкретно стоит логировать (и, что не менее важно, чего логировать не надо — чтобы не утонуть в данных), как защитить всё это богатство от утечек, и на какие графики смотреть за утренним кофе, чтобы спать спокойно.

Что логировать: собираем пазл из улик

Когда я впервые столкнулся с логированием LLM-систем, думал: ну что тут сложного? Записал вопрос, записал ответ, готово. Как же я ошибался.

Логирование в LLM — это не просто «текст вошел, текст вышел». Это детективная работа. Когда что-то идет не так (а оно обязательно пойдет), вам нужно восстановить полную картину происшествия. Представьте: клиент жалуется, что бот посоветовал ему отменить заказ вместо того, чтобы помочь его оформить. Чтобы понять, что случилось, недостаточно увидеть ответ бота — нужно знать, что он «видел» и как «думал».

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

  • 1. Контекст — кто и откуда? User ID (обязательно хэшированный!), тип пользователя (VIP или обычный), канал связи (Telegram, веб-чат, голосовой помощник), версия приложения. Это помогает сразу отсечь: проблема у всех или только на Android? Жалуются платные клиенты или тестировщики?
  • 2. Входные данные — что спросили? Здесь важны две вещи: сырой запрос пользователя и финальный промпт, который ушел в модель (уже со всеми шаблонами, историей переписки и контекстом). Часто выясняется, что модель-то ответила корректно — просто в промпт подтянулся какой-то мусор из предыдущих сообщений.
  • 3. Процесс — как модель «думала»? Какие документы нашел поиск и с каким score релевантности, параметры модели (температура, seed), какие инструменты вызвал агент. Однажды мы полдня искали баг, а потом увидели: поиск упорно выдавал инструкцию 2020 года вместо актуальной, потому что в старой было больше ключевых слов.
  • 4. Результат — что ответили? Текст ответа (очевидно), но также время генерации, количество токенов (это ваши деньги), сработал ли safety-фильтр и почему.
  • 5. Обратная связь — что думают люди? Лайк или дизлайк от пользователя, текстовый комментарий если есть, факт эскалации на живого оператора. Это единственный по-настоящему честный сигнал качества — всё остальное косвенное.

Важный момент: не пытайтесь логировать всё и сразу на старте. Начните с базовых вещей — запрос, ответ, время, user_id. Потом добавляйте слои по мере необходимости. Иначе утонете в настройке инфраструктуры вместо того, чтобы улучшать продукт.

Безопасность: как не стать героем новостей об утечках

Вот о чем редко думают на старте: логи LLM-систем — это минное поле. Пользователи пишут ботам всё подряд. Пароли («забыл пароль, мой текущий — qwerty123, помоги восстановить»), номера карт, адреса, иногда даже интимные подробности. Если вы просто пишете это в файл или обычную базу данных — вы сидите на пороховой бочке. Рано или поздно она взорвется.

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

Что делать, чтобы не оказаться на их месте:

  • Чистите данные на входе. Вырезайте телефоны, email, номера карт ещё до того, как они попадут в лог. А в идеале — до отправки в OpenAI или Claude. Регулярные выражения для базовых паттернов + специализированные библиотеки для PII-detection. Это не сложно, но спасает репутацию.
  • Разделяйте метаданные и контент. Время запроса, количество токенов, user_id — это в быструю базу для аналитики, храните сколько нужно. А вот тексты промптов и ответов — в отдельное защищенное хранилище (S3 с шифрованием подойдет) с коротким сроком жизни. 30-90 дней обычно достаточно для разбора инцидентов, а потом — автоматическое удаление.
  • Контролируйте доступ жестко. Инженерам не нужно видеть переписки пользователей в повседневной работе. Доступ к текстам — только через обоснованный запрос с логированием: кто, когда и зачем открыл конкретный диалог. Звучит параноидально, но когда придет аудит или (не дай бог) суд — вы скажете себе спасибо.

Отдельная боль — соответствие 152-ФЗ и GDPR. Если пользователь попросит удалить свои данные, вы должны найти и удалить ВСЕ его логи за всё время. Если у вас логи разбросаны по файлам на разных серверах — удачи. Поэтому продумывайте структуру хранения заранее, пока данных немного.

Трассировка: путеводная нить в хаосе

Знаете, что больше всего бесит при разборе инцидентов? Когда у вас есть кусочки пазла, но они из разных коробок. Логи бэкенда отдельно, логи базы знаний отдельно, логи модели где-то в облаке — и никак их не связать между собой.

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

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

Что должно быть в каждой записи:

Идентификаторы

trace_id связывает весь запрос, span_id маркирует отдельный шаг, user_id — чей это запрос.

Шаги (спаны)

Поиск документов (Retrieval), ранжирование (Rerank), вызов модели (LLM Call), проверка безопасности (Guardrails).

Контекст шага

Какая версия промпта использовалась, с какой температурой, какой score релевантности у найденных документов.

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

Метрики качества: на что смотреть каждое утро

Когда мы только начинали работать с LLM, коллеги из ML-команды предлагали мониторить perplexity и прочие академические метрики. Звучало умно. На практике оказалось бесполезно — эти цифры никак не коррелировали с тем, довольны пользователи или нет.

Бизнесу не нужна наука. Бизнесу нужно знать три вещи: бот помогает или мешает? Сколько это стоит? Пользователи довольны? Всё остальное — для диссертаций.

Вот метрики, которые реально работают:

  • Groundedness (обоснованность ответа)

    Ключевой вопрос: модель взяла ответ из вашей базы знаний или придумала из головы? Если бот отвечает «наш офис находится на Марсе», а в базе такого нет — это галлюцинация. Цель — держать показатель выше 0.85. Если падает ниже 0.8 — срочно разбирайтесь с поиском или промптом, ваш бот превращается в фантазера.

  • Deflection Rate (процент решенных без человека)

    Какая доля обращений закрывается ботом без эскалации на оператора. Здоровый диапазон — 30-60%. Меньше 30% — бот практически бесполезен, вы просто платите за лишний слой между клиентом и поддержкой. Больше 80%? Тоже красный флаг. Возможно, вы сделали кнопку «позвать человека» слишком незаметной, и люди просто уходят недовольными.

  • CSAT (удовлетворенность пользователя)

    Простой вопрос после диалога: помог ли бот? Палец вверх или вниз. Это единственная метрика, которая показывает реальность, а не наши фантазии о качестве. Цель — 4.6 из 5 и выше. Всё, что ниже 4.0 — повод для серьезного разговора с командой.

  • Latency (время ответа, p95)

    Сколько пользователь ждет ответа. Для текстового чата психологический порог — 3-4 секунды. Дольше — раздражает. Для голосового помощника всё жестче: больше 1.2 секунды паузы — и человек думает, что связь оборвалась. p95 означает, что 95% запросов укладываются в этот лимит. Оставшиеся 5% — это ваши проблемные случаи, которые тоже нужно понимать.

Совет из практики: не пытайтесь отслеживать всё сразу. Начните с CSAT и Latency — это можно настроить за день. Deflection и Groundedness требуют больше инфраструктуры, добавите потом.

Дашборд: кабина пилота для вашего AI

Хороший дашборд должен отвечать на вопрос «всё в порядке?» за пять секунд. Серьезно, засеките время. Если вам нужно что-то искать, скроллить, переключать вкладки — дашборд плохой. Утром вы открываете его с чашкой кофе, бросаете взгляд — и либо спокойно идете на стендап, либо срочно пишете в чат команды.

Мы перепробовали много вариантов и пришли к простой структуре из трех блоков: здоровье системы (работает ли вообще?), качество ответов (работает ли хорошо?), бизнес-метрики (работает ли выгодно?). Вот как это выглядит:

Пример дашборда наблюдаемости LLM с метриками качества, задержками и расходами

Здоровье

  • Latency (p95): 3.9s OK
  • Errors (5xx): 0.3% OK

Качество

  • Groundedness: 0.87 High
  • CSAT: 4.7/5 High

Бизнес

  • Cost/Issue: 20 ₸
  • Deflection: 48%

Когда всё идет не так: анатомия инцидента

Вот вам честная правда: рано или поздно ваш бот «сойдет с ума». Это не вопрос «если», это вопрос «когда». Модель обновится, поиск сломается, кто-то загрузит в базу знаний документ с ошибками — вариантов масса. Важно не избежать инцидентов (это невозможно), а быстро их обнаружить и исправить.

В три часа ночи вы не хотите разбираться в логах. Вы хотите, чтобы система сама сказала: «проблема здесь, вот что случилось». Для этого нужны правильные алерты.

Три алерта, которые спасут вам сон
  • Качество ответов рухнуло. Groundedness упал ниже 0.8 или резко снизился за час. Первое действие — проверить поиск по базе знаний. В 80% случаев проблема там: либо индекс сломался, либо кто-то удалил важные документы.
  • Люди массово зовут оператора. Эскалации выросли на 20%+ за последний час. Значит, бот перестал справляться. Возможные причины: провайдер модели обновил её без предупреждения (да, такое бывает), промпт перестал работать, или появился новый тип запросов, который вы не предусмотрели.
  • Атака на бота (jailbreak). Больше 1% запросов выглядят как попытки взлома — специфические паттерны вроде «ignore previous instructions» или «you are now DAN». Либо кто-то целенаправленно атакует, либо в TikTok завирусилось видео «как взломать чат-бота». И то, и другое требует немедленной реакции.

Важно: алерты должны приходить не только на почту (её никто не читает ночью), но и в мессенджер дежурного. И у каждого алерта должен быть runbook — краткая инструкция «что делать», написанная так, чтобы понял человек, которого разбудили в три ночи.

Чеклист: можно ли спать спокойно?

Перед тем как уйти в отпуск (или просто на выходные), пройдитесь по этому списку. Если хотя бы один пункт не выполнен — у вас будет тревожный отдых.

  • Единый trace_id во всех системах. Вы можете взять любой запрос и проследить его путь от момента отправки до получения ответа? Если нет — первый приоритет.
  • Персональные данные не попадают в логи. Проверьте прямо сейчас: откройте случайные 10 записей в логах. Видите телефоны, email, имена? Если да — срочно добавляйте санитайзинг.
  • Дашборд показывает бизнес-метрики. Не только «токены в секунду», но и CSAT, стоимость на запрос, deflection rate. То, что волнует CEO, а не только инженеров.
  • Есть дежурный, который получает алерты. И этот дежурный знает, что делать. И у него есть доступы. И он не в отпуске одновременно с вами.
  • Существует кнопка «всё выключить». Emergency stop или мгновенный откат на предыдущую версию. Когда бот начинает творить дичь в три ночи — вам нужна возможность остановить его за 30 секунд, а не за 30 минут.

Этот чеклист мы прогоняем перед каждым крупным релизом и перед длинными выходными. Рекомендую делать то же самое.

Частые вопросы (и честные ответы)

Эти вопросы нам задают на каждой второй встрече. Собрал ответы в одном месте.

Нужно ли логировать весь диалог целиком?

Да, но с умом. Полный текст диалогов храните 30-90 дней — этого хватит для разбора любых инцидентов и жалоб клиентов. Для долгосрочной аналитики (год и более) оставляйте только обезличенные метаданные: длина сообщений, время ответа, результат (решено/эскалация), эмбеддинги для кластеризации. Так вы и тренды увидите, и под статью не попадете.

Как измерять Groundedness, не нанимая армию разметчиков?

Используйте «LLM-судью». Берете более мощную модель (GPT-4, Claude Opus) и просите её оценить: ответ основан на предоставленных документах или выдуман? Это в разы дешевле и быстрее людей, а корреляция с человеческой оценкой — 80-90%. Не идеально, но достаточно для мониторинга трендов. Для критичных случаев всё равно нужна ручная проверка, но их будет немного.

После релиза latency выросла вдвое. Что случилось?

Первым делом — смотрите на промпт. Это классика: разработчик добавил «ещё пару примеров для улучшения качества», и объем входных токенов удвоился. А время генерации пропорционально объему. Второе — проверьте, не отключилось ли кэширование. Третье — возможно, провайдер модели испытывает проблемы (да, у OpenAI тоже бывают плохие дни).

Как соблюсти 152-ФЗ и GDPR?

Главное правило: никогда не сохраняйте персональные данные без маскирования. Реализуйте «право на забвение» технически: по запросу пользователя вы должны найти и удалить все его данные по user_id. Если логи размазаны по разным файлам и базам без единого идентификатора — вы в беде. Поэтому продумайте структуру заранее: один user_id, централизованное хранение, скрипт для полной очистки по ID.

Нужна помощь с настройкой наблюдаемости?

Построить систему мониторинга LLM с нуля — задача не из простых. Мы в CrmAI прошли этот путь несколько раз: набили шишки, потеряли данные, чинили инциденты в три ночи. Теперь помогаем другим командам избежать наших ошибок и сразу построить систему, за которую не стыдно ни перед аудиторами, ни перед пользователями.

Обсудить ваш проект