ГлавнаяБлогЛинтер для трассировок ИИ-агентов: ловим структурные баги
AI / Нейросети

Линтер для трассировок ИИ-агентов: ловим структурные баги

Узнайте, как tracelint находит структурные ошибки в трассировках ИИ-агентов без LLM. Детерминированный анализ, примеры кода, внедрение в CI.

Al
Редакция Algolitalgolit.ru
8 мин чтения18 августа 2026 г.

Зачем нужен линтер для трассировок ИИ-агентов

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

Именно эту задачу решает tracelint — линтер для запусков агентов. Он читает трассировку выполнения (что агент реально делал) и помечает структурные ошибки, используя точные строки трассировки как доказательство и возвращая код выхода для CI. Он работает после запуска, на трассировке, а не на вашем коде. Никакая вторая модель не оценивает результат.

Почему не использовать LLM-судью?

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

Между тем целая категория ошибок агентов является структурно разрешимой:

  • Вызов инструмента, аргументы которого нарушают JSON-схему инструмента. Это не мнение — вы запускаете валидатор схемы.
  • Инструмент вернул ошибку, а агент продолжил работу, как будто её не было.
  • Один и тот же инструмент вызван 5 раз с одинаковыми аргументами и одинаковыми результатами (зацикливание).
  • Аргументы, которые нигде не встречаются в том, что агент наблюдал (возможное галлюцинированное значение).

Ни одна из этих проверок не требует модели. Нужны трассировка и валидатор. Вот что делает tracelint.

Быстрый старт за 60 секунд

pip install tracelint
tracelint demo --html demo.html

Команда demo запускает набор проверок без ключей — по одному экземпляру каждого дефекта, плюс чистые контрольные примеры — и создаёт HTML-отчёт. Никаких API-ключей и загрузки моделей.

Для проверки реальной трассировки в CI:

tracelint check ./trace.json --tools ./tools.json
# код выхода 2 при структурном дефекте

Коды выхода: 0 — чисто, 2 — структурно доказуемый дефект, 3 — ошибка входных данных. Эвристические находки никогда не роняют CI сами по себе.

Интеграция с уже собираемыми трассировками

Ключевая идея: вы, скорее всего, уже инструментируете своего агента — через OpenInference (семантический стандарт OpenTelemetry для ИИ), отправляя данные в Arize Phoenix, Langfuse или OTel-коллектор. tracelint читает эту телеметрию напрямую. Вам не нужно изучать новый формат трассировки — просто укажите на имеющиеся спаны.

tracelint check spans.json --format openinference
# Phoenix, OTLP, TRAIL
tracelint check trace.json --format langfuse
tracelint check messages.json --format openai

Или напрямую из запущенного экземпляра Phoenix на Python:

import phoenix as px
from tracelint import lint_otel_trace

spans = px.Client().get_spans_dataframe().to_dict("records")
report = lint_otel_trace(spans)
print(report.exit_code)  # 0 или 2
for f in report.active_findings:
    print(f.rule, f.tier.value, f.summary)

Я проверил работу на реальных экспортах OpenInference, а не только на ручных фикстурах: реальная трассировка Phoenix, экспорт спанов OTel-SDK, формат датафрейма Phoenix. На одной реальной трассировке Phoenix tracelint детерминированно локализовал настоящую ошибку инструмента:

[hard_event] R2a tool_error_event  (step 9)
  'add_spans_to_dataset' returned an error (GraphQL query 'exampleMutation' ... 'an unexpected error occurred')

Никакой модели в цикле. Просто: этот TOOL-спан имеет статус ERROR, и вот точное сообщение.

Что умеет находить

ПравилоОписание
R1нарушение схемы — аргументы не проходят JSON-схему инструмента
R2инструмент вернул ошибку / ошибочное значение использовано в последующем вызове с побочным эффектом
R3галлюцинированный аргумент — значение, не выводимое из наблюдаемого
R4зацикливание — N одинаковых вызовов без прогресса
R5избыточный вызов — одинаковый вызов и результат, без мутаций между ними
R6некорректные аргументы — аргументы вызова не являются валидным JSON
R7неизвестный инструмент — вызов инструмента, отсутствующего в объявленном наборе

Пример зацикливания через адаптер OpenInference:

[candidate] R4 loop  (step 2,4,6)
  'search' called 3 times in a row with identical arguments and no change in result state (ok)
[candidate] R5 redundant_call  (step 2,6)
  'search' repeats an earlier identical call with no mutating call in between

Два дизайн-решения, которые я защищаю

1. Кандидат, а не вердикт

Только структурно доказуемые вещи (нарушение схемы, некорректный JSON) являются жёсткими дефектами, роняющими CI. Эвристические сигналы — зацикливания, избыточные вызовы, подозрительные аргументы — показываются как кандидаты с доказательствами, для просмотра человеком, и никогда не утверждаются как истина и сами по себе не роняют сборку. Цикл с ретраями и застрявший цикл структурно похожи; tracelint показывает доказательства и даёт вам решить, а не притворяется, что знает.

2. Сообщает, что не смог проверить

Это самое важное для меня. Если в трассировке отсутствует поле, необходимое для правила (нет схем инструментов, нет полезной нагрузки результатов), это правило не проходит молча. Оно подавляется с указанием причины и выводится в отчёте:

suppressed (2) — not checked, not a clean pass:
  R1 schema_violation: no tool schema available for any called tool
  R7 unknown_tool: no tool registry supplied — cannot know which tools were declared

Чистый отчёт со скрытыми пробелами хуже, чем отсутствие отчёта — это ложная уверенность. tracelint отказывается давать вам такую уверенность.

Честные ограничения

Инструмент ловит структурные дефекты, а не то, был ли правильным конечный ответ. Он не скажет, что агент дал плохой совет; он скажет, что агент проигнорировал неудачный вызов инструмента на пути к этому совету.

Находки «галлюцинированный аргумент», «зацикливание» и «избыточный вызов» являются кандидатами, если не доказаны структурно. Легитимные преобразования значений и намеренные ретраи могут вызывать ложные срабатывания — поэтому они показываются с доказательствами, а не утверждаются.

Трассировка настолько хороша, насколько хороша инструментация. Отсутствующие поля означают подавленные правила, а не выдуманные.

Попробуйте прямо сейчас

pip install tracelint
tracelint demo --html demo.html

Проект с открытым исходным кодом (MIT), минимальные зависимости (jsonschema + стандартная библиотека), Python 3.10–3.12, весь набор тестов офлайн и детерминирован.

Репозиторий: https://github.com/AshwinUgale/tracelint

Если вы собираете трассировки агентов и хотите детерминированных проверок, я искренне хочу узнать, что ломается на ваших реальных экспортах — именно так появились последние три исправления формы. Присылайте issues и трассировки.

Практический вывод

Установите tracelint, запустите демо и проверьте одну свою реальную трассировку. Интегрируйте проверку в CI, чтобы структурные баги не попадали в прод. Начните с малого: добавьте проверку на ошибки инструментов и нарушения схем — это займёт 10 минут и сэкономит часы отладки.

#ИИ-агенты#трассировка#линтер#структурные ошибки#CI
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →