История, которую я слышал не раз: компания запустила AI-ассистента, отпраздновала успех, а через неделю поддержка прибегает с круглыми глазами — бот начал хамить клиентам. Или, того хуже, рекомендовать продукты конкурентов. CTO открывает логи, а там... ничего. Буквально пустота. Или наоборот — терабайты нечитаемого текста, в котором невозможно найти тот самый злополучный диалог.
Мы в CrmAI через это проходили сами. И теперь, когда к нам приходят клиенты с похожими проблемами, первый вопрос всегда один: «А что у вас с наблюдаемостью?» Обычно следует неловкая пауза.
LLM‑продукт без observability — это классический «черный ящик». Вы не знаете, почему модель ответила именно так, какие данные она увидела, где начала «галлюцинировать» и почему решила, что клиенту обязательно нужно знать про ваших конкурентов. Для технического директора это состояние постоянной фоновой тревоги: всё работает, но непонятно почему, и совершенно неясно, когда сломается.
В этой статье я хочу поделиться тем, что мы узнали за годы работы с LLM-системами. Построим вместе «прожектор» для вашего черного ящика: разберем, что конкретно стоит логировать (и, что не менее важно, чего логировать не надо — чтобы не утонуть в данных), как защитить всё это богатство от утечек, и на какие графики смотреть за утренним кофе, чтобы спать спокойно.
Когда я впервые столкнулся с логированием LLM-систем, думал: ну что тут сложного? Записал вопрос, записал ответ, готово. Как же я ошибался.
Логирование в LLM — это не просто «текст вошел, текст вышел». Это детективная работа. Когда что-то идет не так (а оно обязательно пойдет), вам нужно восстановить полную картину происшествия. Представьте: клиент жалуется, что бот посоветовал ему отменить заказ вместо того, чтобы помочь его оформить. Чтобы понять, что случилось, недостаточно увидеть ответ бота — нужно знать, что он «видел» и как «думал».
За время работы мы выработали правило пяти слоев. Если у вас есть данные по каждому из них — вы сможете разобраться практически в любой ситуации:
Важный момент: не пытайтесь логировать всё и сразу на старте. Начните с базовых вещей — запрос, ответ, время, user_id. Потом добавляйте слои по мере необходимости. Иначе утонете в настройке инфраструктуры вместо того, чтобы улучшать продукт.
Вот о чем редко думают на старте: логи LLM-систем — это минное поле. Пользователи пишут ботам всё подряд. Пароли («забыл пароль, мой текущий — qwerty123, помоги восстановить»), номера карт, адреса, иногда даже интимные подробности. Если вы просто пишете это в файл или обычную базу данных — вы сидите на пороховой бочке. Рано или поздно она взорвется.
Один знакомый стартап узнал об этом на собственном опыте, когда их база с логами утекла в даркнет. Там были переписки пользователей с ботом-психологом. Можете представить масштаб проблемы.
Что делать, чтобы не оказаться на их месте:
Отдельная боль — соответствие 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 и прочие академические метрики. Звучало умно. На практике оказалось бесполезно — эти цифры никак не коррелировали с тем, довольны пользователи или нет.
Бизнесу не нужна наука. Бизнесу нужно знать три вещи: бот помогает или мешает? Сколько это стоит? Пользователи довольны? Всё остальное — для диссертаций.
Вот метрики, которые реально работают:
Ключевой вопрос: модель взяла ответ из вашей базы знаний или придумала из головы? Если бот отвечает «наш офис находится на Марсе», а в базе такого нет — это галлюцинация. Цель — держать показатель выше 0.85. Если падает ниже 0.8 — срочно разбирайтесь с поиском или промптом, ваш бот превращается в фантазера.
Какая доля обращений закрывается ботом без эскалации на оператора. Здоровый диапазон — 30-60%. Меньше 30% — бот практически бесполезен, вы просто платите за лишний слой между клиентом и поддержкой. Больше 80%? Тоже красный флаг. Возможно, вы сделали кнопку «позвать человека» слишком незаметной, и люди просто уходят недовольными.
Простой вопрос после диалога: помог ли бот? Палец вверх или вниз. Это единственная метрика, которая показывает реальность, а не наши фантазии о качестве. Цель — 4.6 из 5 и выше. Всё, что ниже 4.0 — повод для серьезного разговора с командой.
Сколько пользователь ждет ответа. Для текстового чата психологический порог — 3-4 секунды. Дольше — раздражает. Для голосового помощника всё жестче: больше 1.2 секунды паузы — и человек думает, что связь оборвалась. p95 означает, что 95% запросов укладываются в этот лимит. Оставшиеся 5% — это ваши проблемные случаи, которые тоже нужно понимать.
Совет из практики: не пытайтесь отслеживать всё сразу. Начните с CSAT и Latency — это можно настроить за день. Deflection и Groundedness требуют больше инфраструктуры, добавите потом.
Хороший дашборд должен отвечать на вопрос «всё в порядке?» за пять секунд. Серьезно, засеките время. Если вам нужно что-то искать, скроллить, переключать вкладки — дашборд плохой. Утром вы открываете его с чашкой кофе, бросаете взгляд — и либо спокойно идете на стендап, либо срочно пишете в чат команды.
Мы перепробовали много вариантов и пришли к простой структуре из трех блоков: здоровье системы (работает ли вообще?), качество ответов (работает ли хорошо?), бизнес-метрики (работает ли выгодно?). Вот как это выглядит:
Вот вам честная правда: рано или поздно ваш бот «сойдет с ума». Это не вопрос «если», это вопрос «когда». Модель обновится, поиск сломается, кто-то загрузит в базу знаний документ с ошибками — вариантов масса. Важно не избежать инцидентов (это невозможно), а быстро их обнаружить и исправить.
В три часа ночи вы не хотите разбираться в логах. Вы хотите, чтобы система сама сказала: «проблема здесь, вот что случилось». Для этого нужны правильные алерты.
Важно: алерты должны приходить не только на почту (её никто не читает ночью), но и в мессенджер дежурного. И у каждого алерта должен быть runbook — краткая инструкция «что делать», написанная так, чтобы понял человек, которого разбудили в три ночи.
Перед тем как уйти в отпуск (или просто на выходные), пройдитесь по этому списку. Если хотя бы один пункт не выполнен — у вас будет тревожный отдых.
Этот чеклист мы прогоняем перед каждым крупным релизом и перед длинными выходными. Рекомендую делать то же самое.
Эти вопросы нам задают на каждой второй встрече. Собрал ответы в одном месте.
Нужно ли логировать весь диалог целиком?
Да, но с умом. Полный текст диалогов храните 30-90 дней — этого хватит для разбора любых инцидентов и жалоб клиентов. Для долгосрочной аналитики (год и более) оставляйте только обезличенные метаданные: длина сообщений, время ответа, результат (решено/эскалация), эмбеддинги для кластеризации. Так вы и тренды увидите, и под статью не попадете.
Как измерять Groundedness, не нанимая армию разметчиков?
Используйте «LLM-судью». Берете более мощную модель (GPT-4, Claude Opus) и просите её оценить: ответ основан на предоставленных документах или выдуман? Это в разы дешевле и быстрее людей, а корреляция с человеческой оценкой — 80-90%. Не идеально, но достаточно для мониторинга трендов. Для критичных случаев всё равно нужна ручная проверка, но их будет немного.
После релиза latency выросла вдвое. Что случилось?
Первым делом — смотрите на промпт. Это классика: разработчик добавил «ещё пару примеров для улучшения качества», и объем входных токенов удвоился. А время генерации пропорционально объему. Второе — проверьте, не отключилось ли кэширование. Третье — возможно, провайдер модели испытывает проблемы (да, у OpenAI тоже бывают плохие дни).
Как соблюсти 152-ФЗ и GDPR?
Главное правило: никогда не сохраняйте персональные данные без маскирования. Реализуйте «право на забвение» технически: по запросу пользователя вы должны найти и удалить все его данные по user_id. Если логи размазаны по разным файлам и базам без единого идентификатора — вы в беде. Поэтому продумайте структуру заранее: один user_id, централизованное хранение, скрипт для полной очистки по ID.
Построить систему мониторинга LLM с нуля — задача не из простых. Мы в CrmAI прошли этот путь несколько раз: набили шишки, потеряли данные, чинили инциденты в три ночи. Теперь помогаем другим командам избежать наших ошибок и сразу построить систему, за которую не стыдно ни перед аудиторами, ни перед пользователями.
Обсудить ваш проект