Перейти к содержанию
Публикация AiManual

Ouroboros: как трассировать код для AI-агентов без написания тестов

Ouroboros автоматически оборачивает функции в логгирование, чтобы агент видел реальные вызовы, аргументы и возвращаемые значения вместо чтения всей кодовой базы

Коротко

Что будет в материале

  1. 01

    Что такое Ouroboros и зачем он нужен AI-агенту

  2. 02

    Как Ouroboros работает под капотом и встраивается в harness

  3. 03

    Установка: два бинаря, uv tool install и brew

  4. 04

    Накладные расходы инструментирования по языкам

Ouroboros - инструмент, опубликованный на GitHub, который автоматически оборачивает функции и строки кода в логгирование: console.log в JavaScript, printf в C и аналоги в остальных языках. В трейс попадают три вещи: сигнатура функции, её аргументы и возвращаемое значение. Читать такой лог может и человек, но адресат здесь AI-агент.

Проблема, которую решает инструмент, знакома каждому, кто гонял кодинг-агента по чужому репозиторию. Чтобы понять, что происходит, агент читает десятки файлов, платит за это токенами и временем, а затем пишет тесты. Тесты он же и подгоняет под то поведение, которое увидел. Независимой проверки не получается.

Подход Ouroboros другой: агент изолированно запускает код, получает фактический список вызовов с данными и по нему рассуждает, где поведение расходится с ожиданием. Это инструмент наблюдения за исполнением, не тестовый фреймворк и не замена тестам. Ниже механика, установка, замеры автора и ограничения. Основной источник - публикация автора на Habr.

Что такое Ouroboros и зачем он нужен AI-агенту

Ouroboros работает на уровне исходного кода: расставляет обёртки вокруг функций и отдельных строк, чтобы при исполнении печатался след вызовов. Агенту не нужно удерживать в голове карту проекта, он получает лог, из которого видно, какие функции реально сработали и с какими данными.

Ценность появляется там, где нет нормальных тестов и документации. Условный legacy-модуль на несколько тысяч строк, где живая логика сидит в трёх функциях. Читать всё - дорого. Запустить с трассировкой и увидеть, что вызов дошёл до apply_discount с пустой корзиной, - дешевле.

Почему генерация тестов агентом - дорогой и ненадёжный путь

Схема, к которой агенты приходят по умолчанию: прочитать код, написать тест, запустить, поправить тест под фактический результат. На последнем шаге конструкция ломается. Проверку писал и подгонял тот же исполнитель, поэтому она перестаёт быть независимым оракулом и подтверждает то, что агент и так думал. Механику такой ловушки мы разбирали в статье про Loop Engineering и reward hacking.

Вторая статья расходов - контекст. Окно модели ограничено, а чтение файлов ради ответа на вопрос «какая функция тут вообще вызывается» сжигает токены без гарантии результата. Трассировка отвечает на тот же вопрос фактом исполнения, а не догадкой по тексту.

Чем Ouroboros отличается от отладчика и логирования вручную

Ручной print и breakpoint решают ту же задачу, но требуют человека в цикле: поставить, посмотреть, переставить, убрать. Автономный harness работает без человека, и такой цикл там не собрать.

Ouroboros автоматизирует расстановку обёрток и приводит трейс к структуре из трёх полей. Структура важна: её проще парсить и передавать модели, чем произвольный текстовый лог. Интерактивный отладчик инструмент не заменяет, у него другая роль: пошаговое исследование под управлением разработчика.

Как Ouroboros работает под капотом и встраивается в harness

Механика предсказуемая. Инструмент вставляет логгирование в код на языке проекта, агент запускает код в изолированном окружении, читает трейс и делает вывод. Промежуточных отчётов и ручных шагов нет: ouroboros вызывается как обычная команда внутри цикла агента.

Встраивание в harness выглядит так: задача, инструментирование нужного участка, запуск, трейс, гипотеза, правка. Цикл повторяется, пока поведение не сойдётся с ожидаемым. Ключевое здесь то, что решение принимает агент по данным исполнения, а не по своим предположениям о коде.

Что попадает в трейс: сигнатура, аргументы, возвращаемое значение

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

Элемент трейсаЧто показываетЗачем агенту
СигнатураКакая функция вызвана и в каком порядкеОтсекает гипотезы о том, какой код исполняется на самом деле
АргументыС какими данными пришёл вызовНаходит пустые, неверные или неожиданные значения
Возвращаемое значениеЧто функция отдала наружуПоказывает, где результат разошёлся с ожиданием

Условный пример чтения трейса, не реальный вывод инструмента:

apply_discount(sum=0, code="SALE10") -> 0
checkout(sum=0) -> "order created"

По двум строкам видно, что скидка применилась к нулевой сумме, а заказ всё равно создан. Дальше агент идёт по цепочке вверх и ищет, где потерялись позиции корзины. Трейс описывает факт исполнения и ничего не говорит о корректности кода: он показывает, что произошло, а не что должно было произойти.

Роль MCP: бинарь ouroboros-mcp

Проект поставляется двумя бинарями: ouroboros и ouroboros-mcp. Второй нужен для интеграции через Model Context Protocol: агент видит трассировку как один из своих инструментов и вызывает её наравне с чтением файлов или запуском команд. Для harness, который уже собран вокруг MCP-серверов, это самый короткий путь подключения.

Выгода в унификации: агенту не нужно осваивать отдельную CLI-схему, он работает с инструментом в привычном интерфейсе. Как устроены агентские каркасы с MCP и субагентами, мы разбирали на примере открытого терминального агента MiniMax Code.

Установка: два бинаря, uv tool install и brew

Инструмент распространяется как два исполняемых файла, ouroboros и ouroboros-mcp. Поставить их можно через uv tool install или через brew. Первый вариант ближе тем, у кого уже стоит Python-тулинг; второй удобен тем, кто держит CLI-утилиты через Homebrew.

uv tool install <пакет>
brew install <формула>

Точные имена пакета и формулы сверяйтесь с README в репозитории: у свежих проектов детали установки меняются быстрее, чем расходятся по перепечаткам. Заодно проверьте, что установленная версия совпадает с той, на которой делались замеры.

Какой бинарь выбрать: ouroboros или ouroboros-mcp

  • ouroboros - базовый вариант, если harness вызывает инструмент напрямую, командой.
  • ouroboros-mcp - если агент общается с внешними инструментами через MCP.

Ставить оба одновременно смысла мало: трассировка одна и та же, различается только способ вызова. Выбирайте по тому, как устроен ваш агентный каркас, а не по количеству доступных вариантов установки.

Накладные расходы инструментирования по языкам

Автор приводит замеры накладных расходов на вызов для восьми языков: Python, JavaScript, C, C++, Go, Java, C#, Elixir. Разброс - от единиц до сотен микросекунд на вызов. Это порядок величин, а не константы: конкретное значение зависит от функции, объёма аргументов и сценария. Точные цифры по каждому языку есть в исходной публикации.

Практическая арифметика простая. На тысячах вызовов микросекунды не заметны, счёт идёт на доли секунды. На миллионах вызовов при сотнях микросекунд накладные расходы складываются в минуты работы. Для отладочного прогона это терпимо, для цикла, который крутится сотни раз за сессию, уже нет.

Почему C и Go получили минимальный режим

Для C и Go предусмотрен отдельный минимальный режим инструментирования. Логика понятна: у компилируемых языков с жёсткими требованиями к скорости обёртка вокруг каждого вызова стоит дороже, поэтому режим срезает часть оверхеда. Что именно он отключает внутри, в описании не детализируется, этот вопрос закрывает README.

Тесты на 600 ответах: где прирост есть, а где почти нет

Вторая часть замеров - проверка на наборе из 600 ответов. Рост точности зафиксирован у qwen3.5:4b, qwen2.5:14b-instruct и qwen3:32b. У субагента на Claude Opus 5 прирост небольшой.

МодельРезультат в тесте
qwen3.5:4bПрирост точности
qwen2.5:14b-instructПрирост точности
qwen3:32bПрирост точности
Субагент на Claude Opus 5Небольшой прирост

Читать эту таблицу стоит как ответ на вопрос «на каких моделях эффект вообще виден», а не как рейтинг. Абсолютные значения прироста имеют смысл только вместе с описанием задач, на которых их считали.

Почему у Claude Opus 5 прирост небольшой

Правдоподобное объяснение: сильная модель и без трассировки неплохо читает чужой код и строит гипотезы о том, где он ломается. Трассировка экономит ей меньше шагов, потому что она и так не тратит их в том же объёме. Это интерпретация опубликованных цифр, а не доказанный механизм.

Для практики вывод такой: если в harness стоит дорогая сильная модель, прирост от инструмента может не окупить времени на интеграцию. Если работают локальные модели поменьше, эффект заметнее. Как сильные модели ведут себя в агентских циклах и сколько это стоит, разбирали в материале про Claude Opus 5.5.

Где подход упирается в ограничения

Три ограничения прямо следуют из описания: растёт время компиляции и интерпретации при разработке, инструментирование не место в production-коде, а все цифры получены автором на его сценариях. Каждое из них стоит проговорить без смягчений.

Почему в production-код это не ставят

Обёртки добавляют работу на каждом вызове и засоряют логи. Трейс нужен агенту в цикле разработки, в бою он превращается в шум и лишние накладные расходы. Инструментирование здесь временное: его ставят на сессию отладки и снимают после.

Второй эффект того же порядка: удлиняется цикл «правка, сборка, запуск». На небольшом проекте разница незаметна, на большом каждый прогон стоит дороже, и агент успевает сделать меньше итераций за тот же бюджет.

Насколько можно доверять цифрам автора

И накладные расходы, и прирост точности измерены автором инструмента на его сценариях и на наборе из 600 ответов. Независимого бенчмарка нет, воспроизводимость на вашем коде не гарантирована. Воспринимайте опубликованные значения как ориентир порядка величин.

Проверка занимает один вечер: возьмите модуль, поведение которого давно непонятно, прогоните его с трассировкой и сравните, сколько шагов агент потратил с инструментом и без. На двух-трёх задачах уже видно, есть ли смысл вносить это в постоянный harness.

Кому Ouroboros реально пригодится, а кому нет

Оправдан подход в нескольких ситуациях: автономный coding-агент работает с незнакомым репозиторием; в harness стоят локальные модели вроде qwen3.5:4b и qwen2.5:14b-instruct, которым не хватает контекста; разбирается legacy-код, где непонятно, что реально вызывается. Как выглядит оркестрация сессий агента на живом проекте, разбирали в кейсе про пет-проект на Java с оркестратором задач.

Не нужен инструмент для продакшена, для сильной модели, которая и так справляется с чтением кода, и для проектов, где каждый прогон сборки стоит минуты. Там накладные расходы перевесят выгоду.

Практический чек-лист: пробовать или нет

  1. Агент регулярно работает с незнакомым кодом и тратит на чтение заметную часть контекста.
  2. Вы готовы терпеть замедление сборки и запуска на этапе разработки.
  3. В harness стоят локальные модели среднего размера, а не самая дорогая доступная.
  4. Нужен MCP-вариант интеграции либо, наоборот, достаточно прямых вызовов ouroboros.

Совпало три пункта из четырёх - ставьте инструмент и прогоняйте на одном проблемном модуле. Совпал один - с высокой вероятностью обойдётесь чтением кода и ручным print. Ouroboros нишевый, но закрывает конкретную боль: дорогое чтение кодовой базы и тесты, которые агент подгоняет сам под себя.

Подписаться на канал