OpenTelemetry для AI-агентов: трассировка без утечки
Обычный HTTP trace отвечает, какой сервис тормозит. Для AI-агента этого мало: он мог пять раз сходить в модель, зациклиться на инструменте, съесть контекст и выдать ерунду. Нужна трасса решения — но без склада чужих промптов в общей observability.
Коротко. Создайте корневой span на запуск агента, дочерние spans на обращения к модели, retrieval и каждый tool call. Передавайте trace context через сервисы, пишите модель, операцию, задержку, токены, результат и ошибку. Полные входы и ответы не собирайте по умолчанию: для отладки включайте контролируемое семплирование, маскирование и короткое хранение.
Почему логов недостаточно
Строки «model request completed» бесполезны, когда один пользовательский запрос породил двенадцать шагов. Без общего trace id вы не видите причинность: какая версия агента выбрала инструмент, какой запрос ушёл в поиск, где выросло число токенов и после какого ответа возник повтор.
Трассировка не оценивает качество ответа сама. Она создаёт скелет, к которому можно привязать метрики качества, стоимость и обратную связь пользователя.
Модель spans
agent.run
├── retrieval.query
├── gen_ai.chat
├── tool.call inventory.lookup
├── gen_ai.chat
└── tool.call ticket.createНе складывайте всё в один огромный span. Разные операции имеют разный смысл и набор атрибутов. У вызова модели важны provider, model, token usage и finish reason. У инструмента — имя, версия, длительность, код результата и безопасный идентификатор цели. У retrieval — источник, число найденных фрагментов и длительность, но не обязательно сами документы.
Какие атрибуты действительно нужны
service.name, environment и версия приложения;- тип операции и стабильное имя агента;
- провайдер и точная модель;
- input/output tokens и число повторов;
- имя инструмента, статус и класс ошибки;
- идентификатор сессии в хешированном или внутреннем виде;
- версия prompt/config, а не полный текст;
- признак cache hit и выбранный маршрут.
Не делайте user id или полный prompt меткой метрики: получите взрыв cardinality и дорогую систему. Детальные значения живут в spans или защищённом журнале, агрегаты — в metrics.
Промпт — это потенциальный секрет
В пользовательском сообщении могут оказаться паспорт, токен API, кусок договора или исходный код. Если автоматически отправлять всё в tracing backend, observability становится второй базой персональных данных, только с более широким доступом.
Безопасная политика: содержимое выключено по умолчанию; разрешённые поля собраны отдельно; секреты и персональные данные маскируются до экспортера; debug-семплирование ограничено средой, временем и ролью; срок хранения минимален; выгрузка аудируется. Для поиска конкретного инцидента используйте внутренний request id, а не открытый email.
Метрики поверх traces
- успешность agent run и tool calls;
- p50/p95/p99 полной задержки и time to first token;
- токены и стоимость на успешный результат;
- число шагов, повторов и зацикливаний;
- доля fallback и ручной передачи человеку;
- ошибки по модели, версии агента и инструменту.
Сигнал «ответ получен» не равен «задача решена». Добавьте бизнес-исход: создан ли корректный тикет, подтвердил ли пользователь решение, не отменил ли действие через минуту.
Семплирование
Head sampling дёшев, но может выбросить редкую ошибку до того, как она проявилась. Tail sampling принимает решение после завершения: сохраняйте все ошибки, очень медленные трассы и аномально дорогие запросы, а обычные успешные — небольшой долей. Следите, чтобы решение не ломало связность распределённого trace.
Роль Collector
Приложение отправляет OTLP в локальный или кластерный Collector. Там удобно делать batch, retry, фильтрацию атрибутов, маскирование и маршрутизацию в разные backend. Не вшивайте адрес конкретной SaaS-системы в каждый сервис. Collector — не оправдание слать секреты: лучше не создавать чувствительный атрибут вообще, чем надеяться удалить его позже.
Алерты, которые не бесят
Не алертите на каждый неуспешный tool call: агент может штатно повторить попытку. Алерт нужен на влияние — рост доли проваленных запусков, нарушение latency SLO, резкий рост токенов, устойчивый loop или недоступность критичного инструмента. Дашборд должен позволять из агрегата перейти в обезличенный trace.
Проект для портфолио
Соберите агента из двух model calls и одного тестового инструмента. Поднимите Collector, экспортируйте traces и metrics, добавьте correlation id в логи. Затем вызовите таймаут, ошибку инструмента, повтор и утечку фальшивого токена. Покажите, что ошибка находится по trace, а секрет не попадает в backend. Это гораздо сильнее очередного скриншота Grafana без сценария.
Базовый стек логов и метрик есть в гайде по наблюдаемости. Развёртывание model server и системные метрики — в материале про AI inference в Kubernetes.
Частые вопросы
Нужно хранить промпты для отладки?
Иногда это полезно, но не по умолчанию. Нужны согласованная политика, маскирование, доступ, семплирование и срок хранения.
Логи тогда не нужны?
Нужны. Trace показывает причинность, metrics — масштаб проблемы, logs — детали события. Их связывает trace id.
С чего начать?
С одной трассы agent run, spans модели и инструмента, четырёх метрик и проверки, что чувствительное содержимое не экспортируется.
Сначала видимость, потом магия
Один связный trace полезнее сотни строк «AI request done».
Собрать базовую наблюдаемость