Аудиторский след агента: что логировать по умолчанию
Автономный агент вызывает API, тратит токены и трогает файлы без вашего участия. Разбираем, какие события нужно писать в лог с первого дня — до того, как что-то пойдёт не так.

Почему лог агента — это не то же самое, что лог обычного сервиса
Обычный веб-сервис делает то, что вы ему прописали: пришёл запрос — вернулся ответ. Агент на основе языковой модели действует иначе. Он сам решает, какой инструмент вызвать, сколько раз повторить попытку, стоит ли залезть в базу или отправить письмо. Между вашим промптом и результатом — цепочка решений, которую вы не писали руками. Когда агент удалит не тот файл, спишет лишние деньги на вызовах модели или вернёт клиенту чужие данные, у вас будет ровно один способ понять, что произошло: аудиторский след.
Проблема в том, что дефолтные фреймворки для агентов (LangChain, LlamaIndex, OpenAI Agents SDK и подобные) логируют по-минимуму — обычно только финальный ответ и, если повезёт, трассировку вызовов. Этого достаточно, чтобы отладить демо, и совершенно недостаточно, чтобы разобрать инцидент через две недели или ответить на вопрос службы безопасности «а что именно агент отправил наружу».
Если вы не можете по логам восстановить, какое решение агент принял, на основании какого контекста и какой инструмент вызвал с какими аргументами — значит, у вас нет аудиторского следа, у вас есть отладочный вывод.
Что писать по умолчанию: минимальный набор событий
Разделите лог на события, а не на «строчки текста». Каждое событие агента — это отдельная запись со своим типом. Минимум, который стоит включать с первого дня в прод:
- Входящий запрос и его источник. Кто или что запустило агента, с каким исходным заданием, в какой сессии.
- Собранный контекст. Не сам сырой текст (о персональных данных ниже), а хотя бы: сколько токенов ушло в контекстное окно*, из каких источников подтянуты документы (при RAG** — идентификаторы найденных фрагментов, а не их содержимое).
- Каждое решение о вызове инструмента. Название инструмента, аргументы, обоснование модели, если оно доступно.
- Результат вызова инструмента. Код возврата, длительность, размер ответа, факт ошибки.
- Повторы и откаты. Сколько раз агент переспрашивал модель, зациклился ли, сработал ли лимит итераций.
- Расход. Токены на входе и выходе, модель и её версия, оценочная стоимость вызова.
- Финальное действие. Что агент отдал наружу — отправил письмо, записал в базу, вернул пользователю.
Ключевой принцип: логируйте намерение и результат каждого шага, а не только итог всей цепочки. Инцидент почти всегда происходит на третьем вызове из семи, и без промежуточных записей вы этот шаг не найдёте.
Идентификаторы, которые связывают всё воедино
Одна пользовательская задача порождает десятки внутренних событий. Чтобы потом собрать их в единую картину, каждой записи нужны сквозные идентификаторы:
- trace_id — на всю задачу целиком, от запроса до финального действия;
- span_id — на отдельный шаг (один вызов модели, один вызов инструмента);
- parent_span_id — чтобы восстановить дерево вложенных вызовов, когда агент запускает суб-агента.
Это ровно та модель, которую задаёт стандарт OpenTelemetry, и в 2024 году в нём появились семантические соглашения для генеративного ИИ (GenAI semantic conventions). Если вы строите логирование с нуля, привязываться к готовому стандарту дешевле, чем изобретать свою схему: под OpenTelemetry уже есть экспортёры и визуализаторы трейсов.
Персональные данные: что нельзя писать в лог как есть
Соблазн залогировать весь промпт и весь ответ целиком велик — так проще отлаживать. Но если через агента проходят данные клиентов, вы этим действием создаёте вторую копию персональных данных в системе логирования, которая обычно защищена хуже основной базы и хранится дольше.
Практичный компромисс:
- Логируйте метаданные (сколько токенов, какие поля, какой источник), а не сырое содержимое.
- Если содержимое нужно для разбора — маскируйте или хешируйте чувствительные поля перед записью.
- Разделяйте потоки: технический трейс без ПДн — с длинным сроком хранения, полный контент — с коротким и жёстким доступом.
- Задайте срок хранения явно. «Храним всё вечно на всякий случай» — это не политика, а риск.
Как это выглядит в разных подходах
Логирование агента можно строить тремя способами, и они не взаимоисключающие.
| Подход | Что даёт | Ограничения |
|---|---|---|
| Ручной лог во фреймворке (callbacks/handlers) | Полный контроль над форматом, ноль внешних зависимостей | Легко забыть залогировать новый инструмент; свой велосипед для трейсинга |
| OpenTelemetry + GenAI conventions | Стандартная схема, готовые визуализаторы, связка с остальной инфраструктурой | Порог входа выше; часть SDK ещё дозревает |
| Специализированные платформы (LangSmith, Langfuse, Arize Phoenix и аналоги) | Трейсы из коробки, дашборды, оценка качества ответов | Зависимость от вендора; при облачном варианте — вопрос, куда уходят данные |
Langfuse и Phoenix можно поднять self-hosted, что снимает вопрос с утечкой данных наружу; LangSmith исторически ориентирован на облако. Точную модель развёртывания и актуальные тарифы сверяйте на сайтах проектов — они меняются.
Кому это пригодится и кому нет
Пригодится обязательно:
- Агент, который выполняет записывающие действия — платит, отправляет письма, меняет данные в базе. Здесь аудиторский след — это ваша единственная защита при разборе инцидента.
- Продукты с ПДн клиентов: нужно уметь доказать, что и куда уходило.
- Команды, где агент крутится в проде дольше пары недель: без учёта токенов расходы незаметно съедают бюджет.
Можно отложить:
- Одноразовый скрипт или личный прототип, который читает и никуда не пишет.
- Демо на выброс, где стоимость и приватность не в игре.
Но даже в прототипе минимальный лог вызовов инструментов окупается на первой же непонятной галлюцинации — вы увидите, что модель придумала аргумент, которого не было в задаче.
Практический старт
Если начинаете сегодня, порядок такой:
- Определите список типов событий (из раздела выше) и заведите под них структурированный формат — JSON-строки, а не свободный текст.
- Добавьте trace_id на входе и протащите его через все шаги.
- Отдельно решите вопрос с ПДн до первого прод-запуска, а не после.
- Подключите визуализатор трейсов — глазами в plain-логи цепочку из двадцати шагов не разберёшь.
- Настройте алерты на аномалии: превышение лимита итераций, всплеск токенов, повторяющиеся ошибки инструмента.
* Контекстное окно — максимальный объём текста (в токенах), который модель обрабатывает за один вызов: и ваш промпт, и подтянутые документы, и ответ. Когда данных больше, чем помещается, часть контекста отбрасывается — и это стоит логировать.
** RAG (retrieval-augmented generation) — подход, при котором перед ответом система ищет релевантные документы во внешнем хранилище и подкладывает их в контекст модели. В логе полезно фиксировать, какие именно фрагменты были найдены.
Prompt-инженер: Идеальные запросы для Midjourney, ChatGPT и других моделей.
Спросить за 15 ₽Источники: OpenTelemetry — Semantic conventions for generative AI, Langfuse — Open source LLM engineering platform (docs)
Частые вопросы
Разве трассировки из коробки в LangChain недостаточно?
Нужно ли логировать весь промпт и весь ответ модели целиком?
Что важнее логировать в первую очередь при нехватке времени?
Стоит ли брать готовую платформу или писать логирование самому?
Как долго хранить логи агента?
Поможет ли аудиторский след контролировать расходы?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.