Узнайте, как tracelint находит структурные ошибки в трассировках ИИ-агентов без LLM. Детерминированный анализ, примеры кода, внедрение в CI.
Вы запускаете ИИ-агента, он вызывает инструменты, читает результаты, вызывает ещё и отвечает. Чаще всего всё работает. Но однажды пользователь сообщает о проблеме, вы открываете трассировку и находите: инструмент charge_card вернул ошибку 402, а агент просто продолжил работу и сообщил клиенту, что заказ отправлен. Это не галлюцинация в смысле «выдуманного факта» — это структурный дефект выполнения, игнорирование ошибки инструмента. И такие дефекты не требуют привлечения другой LLM: их можно обнаружить детерминированно, анализируя трассировку.
Именно эту задачу решает tracelint — линтер для запусков агентов. Он читает трассировку выполнения (что агент реально делал) и помечает структурные ошибки, используя точные строки трассировки как доказательство и возвращая код выхода для CI. Он работает после запуска, на трассировке, а не на вашем коде. Никакая вторая модель не оценивает результат.
Потому что для этого класса ошибок судья — неправильный инструмент. Опубликованные бенчмарки ошибок трассировок показывают, что LLM-судьи имеют низкую точность локализации: они могут сказать «что-то выглядит не так», но не указать, на каком именно шаге. Они также недетерминированы, требуют денег за каждую трассировку и не могут использоваться в CI (вы бы стали падать сборку из-за подбрасывания монетки?).
Между тем целая категория ошибок агентов является структурно разрешимой:
Ни одна из этих проверок не требует модели. Нужны трассировка и валидатор. Вот что делает tracelint.
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Только структурно доказуемые вещи (нарушение схемы, некорректный JSON) являются жёсткими дефектами, роняющими CI. Эвристические сигналы — зацикливания, избыточные вызовы, подозрительные аргументы — показываются как кандидаты с доказательствами, для просмотра человеком, и никогда не утверждаются как истина и сами по себе не роняют сборку. Цикл с ретраями и застрявший цикл структурно похожи; tracelint показывает доказательства и даёт вам решить, а не притворяется, что знает.
Это самое важное для меня. Если в трассировке отсутствует поле, необходимое для правила (нет схем инструментов, нет полезной нагрузки результатов), это правило не проходит молча. Оно подавляется с указанием причины и выводится в отчёте:
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 минут и сэкономит часы отладки.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →