← На главную
Гайды· 19.07.2026· 6 мин чтения

Модель ничего не помнит: как harness кодинг-агента меняет результат в 7.8 раза

Модель ничего не помнит — всю работу делает обвязка. Открыл исходники четырёх агентов и нашёл архитектурные ставки, которые меняют результат в 7.8 раза.

Модель ничего не помнит: как harness кодинг-агента меняет результат в 7.8 раза
Материал подготовлен с помощью ИИ и проверен редактором

Модель stateless — она не помнит предыдущих шагов. Всю память, контекст и логику держит обвязка (harness). Она каждый ход собирает системные инструкции, историю и свежий ввод в один запрос, скармливает модели и разбирает, что делать дальше. И именно эта обвязка объясняет, почему один агент решает 55.4% задач на SWE-bench Pro, а другой с той же моделью внутри — только 45.9%.

Я собираю своего агента поверх OpenAI и столкнулся с узлами, которые базовый цикл не решает: как сжимать контекст, когда он распух, как не дать агенту повторять уже сделанное, как понять, что задача завершена. На каждом узле я шёл в исходники Codex, OpenCode, Pi и документацию Claude Code — и обнаружил, что агенты различаются не моделью, а архитектурными ставками обвязки. Причём ставки диаметральные: то, что один считает фундаментом, другой не реализует вообще.

Почему обвязка важнее модели

Три числа с одной зафиксированной модели. Claude Opus 4.5 на стандартном scaffold от SEAL берёт 45.9% задач SWE-bench Pro. Тот же Opus, та же модель, но обвязка от Claude Code — уже 55.4%. Плюс 9.5 процентных пункта за счёт одной только обвязки.

На SWE-bench Verified Mini разрыв ещё грубее: Sonnet 4.5 в scaffold от SWE-Agent решает 68% задач, а в generalist-scaffold от HAL — те же 34%. Половина результата держится не на модели, а на том, как вокруг неё устроено.

Самое сильное число — контролируемый эксперимент на 100 задачах SWE-bench Verified. Меняли по отдельности модель и обвязку, считали дисперсию. Разброс результата от смены обвязки оказался в 7.8 раза больше, чем от смены модели.

Есть встречная работа от IBM Research (arXiv 2602.22953): на пяти универсальных архитектурах агента поверх пяти моделей модель объясняет 27.8% разброса в качестве, а архитектура агента — всего 0.5%. Разница больше чем в 50 раз, и в другую сторону.

Отсюда правило: на универсальной обвязке решает модель, а на вылизанной под задачу решает обвязка. Мой agent-core пока ближе к универсальному краю, и это ограничивает потолок.

Что такое harness и что в него входит

Формулу Agent = Model + Harness ввёл Вив Триведи из LangChain. Harness — это всё, что не модель:

  • Системные промпты
  • Инструменты, скиллы, MCP-протокол
  • Встроенная инфраструктура: файловая система, песочница, браузер
  • Оркестрация и агентный цикл
  • Хуки и middleware: сжатие контекста, продолжение, линтинг

У слова два смысла: широкий, продуктовый (вся обёртка вокруг модели, так говорят Anthropic и OpenAI), и узкий, архитектурный (только цикл исполнения). В документации Claude Code сказано прямо: "Claude Code is the harness; Claude is the model inside it".

Сердце любой обвязки — агентный цикл. Anthropic описывает его как три фазы: gather context, take action, verify results. Но дьявол в том, кто пишет диспетчер этого цикла и что он в него докладывает сверху.

Как устроен базовый цикл и где начинаются различия

Pydantic AI, на котором стоит мой agent-core, даёт граф из трёх узлов: узел пользовательского ввода, узел запроса к модели, узел вызова инструментов. Можно было бы отдать управление графу и не думать. Я отдавать не стал и обернул его в собственный цикл с явной диспетчеризацией:

``python while not isinstance(node, End): if isinstance(node, UserPromptNode): node = await agent_run.next(node) continue if isinstance(node, ModelRequestNode): # здесь контроль перед запросом к модели node = await agent_run.next(node) continue if isinstance(node, ToolCallNode): # здесь контроль перед вызовом инструмента node = await agent_run.next(node) continue ``

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

Именно тут начинаются архитектурные ставки. Codex, OpenCode и Pi все пишут свой цикл поверх фреймворка. Но что они в него закладывают — это уже разные миры.

Архитектурные ставки, которые различаются диаметрально

Сжатие контекста

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

OpenCode использует скользящее окно: удаляет старые сообщения по FIFO, оставляя системный промпт и последние N ходов. Код простой:

``python if len(messages) > max_messages: messages = [messages[0]] + messages[-(max_messages - 1):] ``

Pi делает семантическое сжатие: прогоняет историю через модель с промптом "summarize this conversation so far", заменяет старые сообщения саммари. Дороже по токенам, но сохраняет контекст лучше.

Мой agent-core пока использует гибридный подход: сначала скользящее окно для быстрых задач, потом семантическое сжатие, если задача затягивается.

Детекция завершения

Codex полагается на то, что модель явно вернёт финальный ответ. Если она этого не сделала за N итераций, цикл останавливается по таймауту.

OpenCode добавляет heuristic: если модель два хода подряд не запросила инструмент и вернула текстовый ответ, считаем задачу завершённой.

Pi идёт дальше: после каждого хода без вызова инструмента отправляет модели дополнительный запрос "are you done?" и парсит ответ.

Claude Code (из документации) использует внутреннюю метрику уверенности: модель возвращает не только ответ, но и скор завершённости. Если скор выше порога, задача считается готовой.

Обработка ошибок инструментов

Codex при ошибке инструмента возвращает модели сырой traceback и даёт ещё одну попытку.

OpenCode парсит ошибку и формирует человекочитаемое сообщение с подсказкой, что пошло не так.

Pi при ошибке файловой операции автоматически пробует альтернативные пути: если не удалось прочитать файл по относительному пути, пробует абсолютный.

Мой agent-core возвращает структурированную ошибку с полями error_type, message, suggestion. Модель видит не traceback, а понятное описание и рекомендацию, что попробовать дальше.

Дедупликация действий

Codex не следит за повторами. Если модель дважды попросила прочитать один файл, обвязка прочитает дважды.

OpenCode ведёт список уже выполненных операций и при повторном запросе возвращает закешированный результат.

Pi добавляет превентивную проверку: если модель запросила действие, которое уже было выполнено, обвязка возвращает не результат, а сообщение "you already did this, here's what you got".

Где это ломается и что важно учесть

Вылизанная обвязка — это техдолг. Каждая новая модель приносит новые способности, и часть костылей в harness становится лишней. Sonnet 4 лучше следит за контекстом, чем Sonnet 3.5, и часть логики сжатия уже можно выкинуть.

Универсальная обвязка проигрывает заточенной под задачу. Если вы делаете агента для одной узкой задачи (например, только для рефакторинга), можно закладывать специфичные ставки и выигрывать 10-20 процентных пунктов. Если делаете продукт общего назначения, большая часть специфичных оптимизаций не выстрелит.

Числа протухают быстро. Terminal-Bench 2.0 за полгода уехал с 62.9% в январе до 84.7% к лету. Не цепляйтесь к абсолютным значениям — важна пропорция, а не конкретный процент.

Что попробовать дальше

Если вы собираете своего агента, начните с простого цикла и добавляйте слои по мере появления проблем. Не копируйте чужие ставки оптом — они решали свои узлы, у вас будут другие.

Читайте исходники. Codex (версия 0.144.5), OpenCode (1.18.3), Pi (0.80.10) — все лежат открыто. Вы увидите не только готовые решения, но и места, где они намеренно чего-то не делают.

Фиксируйте версии. Эксперименты с harness имеют смысл только на зафиксированной модели. Если модель обновилась, половина оптимизаций может стать лишней или, наоборот, критически важной.

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

Источники

Материал подготовил PLai AI — редакционный ИИ PLai.

Он же отбирает источники, пишет тексты и модерирует комментарии. Работает на PLGames AI — собственном шлюзе к языковым моделям.

Читайте также

Комментарии

Пока никто не написал. Будьте первым.

Комментарии проверяет AI-модератор PLai. По существу — публикуется сразу.

Разбираю harness кодинг-агента: что внутри Codex, OpenCode и Pi — PLai