Логирование LLM: где ломается сбор запросов и ответов
Типовой сбой выглядит одинаково: в журнале есть время, код ответа и длительность вызова, а тел запроса и ответа — нет. Логирование обычно включают на уровне обратного прокси, тогда как промпт собирается в сервисе и до него не доходит. В итоге журнал обращений к модели состоит из метаданных, по которым разбор инцидента невозможен.
Второе узкое место — потоковая отдача ответа. Модель возвращает текст фрагментами, и сборщик либо сохраняет только первый, либо склеивает их без границ сообщений. При таймаутах и повторных попытках в журнал попадает одна запись вместо нескольких — причина отказа не видна. Сквозной идентификатор между сервисами теряется, поэтому связать запрос, ответ и последующее действие пользователя нечем.
Ещё одна причина — персональные данные и ключи внутри промптов: из-за них логирование LLM часто выключают целиком либо маскируют так, что от текста остаётся непригодный для отладки набор символов. Из-за этого страдает отладка AI-интеграции. Работающее решение — правила редактирования на стороне приложения до записи: чувствительные поля заменяются, остальное сохраняется полностью. Выгрузку удобно строить на открытом стандарте OpenTelemetry — единый формат снимает привязку журнала к одному поставщику модели.
Для поддержки и продукта это оборачивается слепой зоной: воспроизвести жалобу нельзя, качество ответов не измерить, доля неудачных вызовов неизвестна. Разбираем, как сбор запросов и ответов закрывается на каждом из этих участков.
Что меняется после настройки: время разбора и классы отказов
До настройки сбора данных разбор обращения к AI-сервису напоминает археологию: пользователь описывает симптом словами, поддержка восстанавливает цепочку по скриншотам и логам приложения, а сам запрос к модели уже нигде не сохранён. На воспроизведение уходит два-три часа, и в половине случаев причина остаётся недоказанной — правку в промпт или в обработку ответа вносят «на всякий случай».
Трассировка запросов закрывает это напрямую. Каждому обращению присваивается идентификатор, который связывает запрос пользователя, итоговый промпт, ответ модели, вызванные инструменты и время каждого шага. Инженер открывает одну карточку и видит последовательность целиком — без догадок. На практике время разбора инцидента падает с часов до 10–15 минут, а спорные случаи разбираются по фактическим данным, а не по описанию.
Наблюдаемость AI-сервиса даёт второе следствие — управление классами отказов модели. Вместо одного «сервис не ответил» в статистике появляются разделимые категории: превышение времени ожидания у провайдера, отказ разбора структуры ответа, расхождение с обязательным форматом, отказ собственной проверки. Для каждого класса настраивается своё поведение: повтор, откат на резервную модель или корректный отказ с понятным сообщением. Часть сбоев перестаёт доходить до пользователя просто потому, что теперь она обнаруживается на нашей стороне.
Контроль качества ответов меняется не меньше. Когда каждая пара «запрос — ответ» сохранена и размечена, сплошная ручная вычитка не нужна: достаточно выборочной проверки по выборке и автоматических правил на формат и запрещённые формулировки. Доля обращений, требующих участия человека, снижается до нескольких процентов. Собираем это на базе стандарта распределённой трассировки OpenTelemetry — совместимые выгрузки остаются у вас, а не растворяются в чужой панели.
Способы сбора: промежуточный слой, обёртка вызова, поток событий
Способ сбора определяет, где именно перехватывается обращение к модели и кто отвечает за схему записи. Промежуточный слой стоит на границе между сервисом и моделью и видит весь трафик, включая вызовы из унаследованных сервисов, которые никто не хочет править. Обёртка вызова живёт внутри приложения, поэтому знает пользователя, сценарий и идентификатор сессии, но требует правки в каждой точке обращения.
Поток событий развязывает приложение и хранилище: сервис только публикует событие, а запись, обогащение и срок хранения живут в отдельном конвейере. По нагрузке варианты различаются: промежуточный слой добавляет сетевой переход, обёртка — задержку в самом ответе модели, поток событий — риск потери при переполнении буфера, если не настроен сброс на диск. Разное и сопровождение: при смене формата запроса схему правят в одном месте шлюза, в нескольких точках кода или в контракте события.
| Вариант | Когда подходит | Ограничения |
|---|---|---|
| Промежуточный слой | Разнородный стек, есть вызовы из чужого кода, нужен единый формат записи | Не видит бизнес-контекст без меток в заголовках; становится точкой отказа на пути запроса |
| Обёртка вызова модели | Один сервис, важен полный контекст сессии и пользователя | Правки в каждой точке вызова; обращения в обход обёртки не фиксируются |
| Поток событий | Высокая частота обращений, аналитика и хранение отдельно от продукта | Задержка до попадания в хранилище; нужен контроль переполнения и дублей |
На практике способы комбинируют: обёртка даёт контекст, промежуточный слой — полноту охвата, поток событий — устойчивость под нагрузкой.
Этапы внедрения: от разведки до передачи регламентов
Порядок шагов здесь важнее скорости: если начать с перехвата, получится поток разрозненных записей без владельца, срока хранения и привязки к пользователю. Поэтому идём от карты потоков к схеме хранения, и только затем включаем сбор. Каждый этап заканчивается артефактом, который можно проверить до перехода к следующему.
- Разведка потоков. Инвентаризация: какие сервисы обращаются к модели, где вызовы синхронные, а где пакетные, какие пиковые объёмы и в каких полях запроса встречаются персональные данные.
- Схема потоков данных. Фиксируем состав записи (запрос, ответ, длительность, признак ошибки), место и срок хранения, разграничение доступа и правила маскирования чувствительных полей до записи.
- Настройка перехвата. Сбор ставим на отдельный слой перед моделью, чтобы приложение не обрастало обвязкой. Записи приводим к единому формату, связываем идентификатором запроса, версией шаблона и учётной записью инициатора.
- Проверка на живом трафике. Включаем постепенно: сначала малая доля запросов, затем полный поток. Замеряем задержку, долю потерь записей и полноту полей, сверяя лог с фактическими вызовами.
- Обучение команды. Показываем, как найти конкретный диалог, воспроизвести сбой и разобрать спорный ответ модели по сохранённым данным, без выгрузок из продуктивной среды.
- Передача документации. Отдаём схему потоков, описание полей, политики хранения и доступа, порядок обновления при появлении новых сценариев.
На выходе — не разовая настройка, а регламент: понятно, кто владеет логом, что в нём лежит и как это использовать при разборе инцидентов.
Артефакты: схемы, правила доступа, регламенты и разметка
На руки заказчику уходит не набор настроек, а рабочая документация, по которой его команда сама сможет менять фильтры, добавлять поля и разбирать обращения без нашего участия. Всё привязано к конфигурациям в репозитории: правка описана так, что её можно внести и проверить на тестовом контуре.
- Схема потоков записей — от точки входа запроса до хранилища: где происходит обезличивание, на каком шаге запись становится необратимой, какие сервисы пишут в один поток.
- Конфигурации сбора — какие поля запроса и ответа фиксируются, уровни детализации, доля сэмплирования, теги сервиса, окружения и версии модели.
- Политики доступа — роли и области видимости: кому доступно тело ответа, кому только метаданные, как выдаются и отзываются ключи.
- Правила хранения и удаления — сроки на горячем и архивном контуре, правила жизненного цикла, порядок удаления записей по обращению пользователя.
- Регламент разбора обращений — как по идентификатору найти полную цепочку обработки, кто отвечает и в какие сроки.
- Документация по сборам — перечень полей с назначением каждого, список маскируемых данных и способ проверить, что маскирование сработало.
- Чек-лист приёмки — тестовые сценарии: запись появляется, доступ ограничен ролью, удаление отрабатывает, при смене модели схема не ломается.
Комплект лежит в репозитории заказчика и обновляется вместе с изменениями сбора — так документация не расходится с реальной конфигурацией.
Кейс: как сократили время разбора обращений в поддержку
До внедрения сквозного логирования разбор обращения в поддержку выглядел так: в тикете есть вопрос пользователя и странный ответ модели, а какая версия промпта была в момент вызова, с какими параметрами генерации и что сработало до и после — неизвестно. Причину искали перебором гипотез, часть обращений закрывалась формулировкой «воспроизвести не удалось». Найденный один раз дефект мог вернуться после следующей правки промпта и снова проходил тот же путь.
Что изменили
Каждое обращение получило сквозной идентификатор, который связывает тикет в Jira с записью вызова модели. В записи остаются полный текст промпта с меткой версии, параметры генерации, ответ целиком, причина остановки, сработавшие фильтры и итог повторных вызовов при сбое. Персональные данные маскируются до записи, доступ к архиву разграничен ролями, срок хранения задан политикой и не требует ручной чистки.
| Метрика | До | После |
|---|---|---|
| Доля обращений без объяснимой причины ответа | 31% | 4% |
| Время поиска причины по обращению (медиана) | 95 минут | 12 минут |
| Доля дефектов, воспроизводимых по логу | 18% | 94% |
| Возврат закрытого дефекта после правки промпта | замечали постфактум | ловится на прогоне перед выкатом |
Повторяемость дефектов перестала быть лотереей: однотипные сбои группируются по версии промпта и классу ошибки, а правка проверяется тем же набором обращений из архива. Воспроизводимость ответа стала свойством системы, а не удачей конкретного инженера.
Чем отличается логирование LLM от обычного журнала приложения?
Обычный журнал приложения пишется вокруг события: фиксированный набор полей, уровень важности, идентификатор запроса, время. Логирование LLM строится вокруг диалога — единица записи здесь не «сервис вернул ошибку», а полный обмен с моделью, у которого нет стабильной структуры и предсказуемого размера.
Контекст запроса — главная причина, по которой схему записи нельзя взять из журнала приложения. В один вызов уходят системная инструкция, история переписки, подставленные фрагменты из базы знаний и текст пользователя; длина колеблется от пары строк до десятков тысяч знаков. Поэтому запись раскладывают на поля с ролями и отдельно помечают, какие части контекста реально повлияли на ответ, — без этого разбор инцидента превращается в чтение одной гигантской строки.
Потоковый ответ ломает привычную модель «одна запись — один факт». Фрагменты приходят по частям, и журнал должен собрать их в целое, сохранив время до первого фрагмента и признак того, что генерация завершилась, а не оборвалась на середине.
Обязательный слой — фильтрация чувствительных данных: персональные данные, ключи доступа и внутренние документы попадают в запрос вместе с вопросом пользователя. Маскирование выполняют до сохранения, а не при чтении, иначе в хранилище уже лежит то, что утекло.
Объём хранения растёт не по числу обращений, а по длине контекста: сутки работы диалогового помощника с историей переписки перевешивают месяцы обычного журнала. Рабочая схема — разделять горячий слой с полными телами запросов и холодный с метаданными и метриками, хранить ошибочные обращения целиком, а успешные — выборочно.
Частые технические сомнения перед стартом работ
Сомнения перед стартом обычно не про «нужно ли логирование запросов к LLM», а про то, как оно уживается с продом: чувствительные данные в текстах, объём хранилища, влияние на время ответа. Разбираем пять возражений, которые всплывают чаще всего.
В запросах есть персональные данные — что с ними?
Маскируем на входе в хранилище: почта, телефоны, номера документов заменяются плейсхолдерами, оригинал не сохраняется. Сырые записи доступны только отдельной роли и живут ограниченный срок — логирование не превращается во вторую копию базы с клиентскими данными.
Логи быстро займут всё хранилище?
Пишем не полный запрос, а нормализованную структуру: идентификатор сессии, отпечаток промпта, длину, статус. Горячее окно короткое — его хватает на разбор инцидентов, дальше остаются агрегаты. Объём растёт от числа сценариев, а не линейно трафику.
Выдержит ли это рабочая нагрузка?
Запись асинхронная: ответ уходит пользователю, не дожидаясь хранилища. Если приёмник недоступен, записи буферизуются, а основной путь не блокируется. На массовых сценариях работает выборочная запись, на критичных — полная.
Как найти все шаги одного диалога?
Сквозной идентификатор сессии создаётся на входе в цепочку и прокидывается через все вызовы, включая повторы и обращения к внешним сервисам. По нему диалог собирается целиком, а не как набор несвязанных строк.
Как понять, что именно отказало?
В записи фиксируется класс сбоя: отказ самой модели, ошибка интеграции — транспорт, доступы, разбор ответа — или ошибка нашего кода. Метрики и оповещения по ним раздельные, поэтому дежурный сразу видит зону поиска.
Обсудим вашу задачу: что нужно для оценки и плана
Чтобы вернуться с оценкой и планом работ, а не с общими соображениями, нужны вводные по вашей системе. Полный перечень не обязателен — начнём с того, что уже описано, остальное уточним по ходу разбора. Чем точнее задан контур, тем меньше допущений попадёт в план внедрения.
- Схема вызовов: какие сервисы обращаются к модели, синхронно или через очередь, есть ли промежуточный шлюз между приложением и моделью.
- Профиль нагрузки: сколько запросов в сутки, пиковые окна, доля потоковых ответов и длинных сессий.
- Требования к хранению: срок жизни журнала, нужны ли полные тексты запросов и ответов или достаточно метаданных, где физически лежат данные.
- Роли и доступы: кто читает журнал, как разграничиваются права, что нужно маскировать перед записью.
- Порядок разбора обращений: как сейчас разбираются жалобы на качество ответов, кто принимает решение и в какой срок нужен результат.
- Инфраструктура: где размещены компоненты, какие хранилища и очереди уже используются, есть ли сетевые ограничения.
- Текущие инструменты: что уже собирает метрики и связывает записи между сервисами, чтобы не дублировать сбор.
По этим вводным мы описываем схему логирования: точки перехвата, формат записи, разграничение доступа, правила хранения и очистки. После этого возвращаемся с оценкой и планом работ — этапами, зонами ответственности и регламентом разбора обращений.







