Привет! Я Чичев Максим, работаю руководителем разработки платформенных решений в Петрович-Тех. В этой статье хочу рассказать о том, как я прогнал три LLM трёх весовых категорий через один и тот же харнесс на агентных задачах длиной 2, 3 и 15 шагов — и почему на длинных цепочках тезис «харнесс важнее модели» перестаёт работать.

Пару недель назад я запустил один и тот же промпт на одной и той же модели два раза подряд.

За первый прогон модель создала 7 отчётов из 7, и в каждом количество строк совпало с данными до единицы. За второй прогон, час спустя — 0 файлов из 7. При этом модель уверенно написала: «Создал 7 файлов в папке "Отчёты": X — 14 строк, Y — 200, Z — 83…». Все названные числа верные. Файлов нет ни одного.

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

Под катом — как один и тот же харнесс с тремя моделями трёх разных весовых категорий решал задачи длиной 2, 3 и 15 шагов, почему тезис «харнесс важнее модели» перестаёт работать на длинных цепочках и какой вид ошибки агента оказался самым опасным.

<cut/>

Зачем я вообще это мерил

Когда строишь систему, которая сама ходит в рабочие сервисы и что-то там делает, рано или поздно приходится решать, какую модель поставить внутрь. Ответ стоит денег, приватности и работы по интеграции, поэтому хочется опереться на цифры.

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

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

Харнесс

Сама по себе нейросеть умеет ровно одно — получить текст и вернуть текст. Она не открывает Jira, не выполняет SQL и не создаёт файлы. Харнесс (по-русски — обвязка) — это программа вокруг модели, которая содержит системный промпт, каталог инструментов, поиск по документам, исполнение вызовов и обработку ошибок.

Когда модель хочет что-то сделать, она пишет: «вызови инструмент X с аргументами Y». Обвязка исполняет, возвращает результат — и круг повторяется, в моём случае до 15 раз на один ответ пользователю. Запомните этот момент — количество последовательных вызовов дальше определит всё.

Стенд

Стенд — мой личный AI-ассистент, подключённый к моковым системам: задачи, вики, почта, календарь, метрики разработки на дашборде руководителя. 13 виджетов с метриками, ~30 инструментов у модели, 7 проектов в выборке.

Участники — три модели трёх весовых категорий:

  • Claude Sonnet 4.6 — облако, запад;

  • Qwen3-235B — облако, Россия;

  • Qwen3.5-9B — локально, на одной видеокарте (квант AWQ 4 бита, инференс через vLLM).

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

Задачи три, и отличаются они длиной цепочки вызовов. Шагом я считаю один ход модели — вызов инструмента или финальный ответ пользователю.

Задачи следующие:

Сводка — пересказать показатели всех 13 виджетов (2 шага). Дашборд отдаёт все виджеты одним вызовом, так что цепочка минимальна: запросить данные и пересказать. Ошибиться почти негде.

Отчёт — собрать задачи в риске по проекту и сохранить файлом (3 шага). Запросить данные, создать файл, отчитаться. Появляется второй инструмент — и данные нужно донести из одного в другой без потерь.

Цикл — тот же отчёт, но для каждого из семи проектов (15 шагов). На каждый проект — свой запрос с фильтром и свой файл, итого 14 вызовов подряд плюс финальный ответ. Каждый следующий шаг опирается на предыдущие: не потерять проект, не перепутать данные между файлами, не бросить на середине.

Каждая задача — по три прогона на каждой модели, девять прогонов на задачу, двадцать семь на всё исследование.

Как проверялся результат (и как я чуть не выбросил модель)

Сверять итог я решил не с заранее записанным ответом, а с тем, что модель сама получила от инструмента. Полный ответ каждого вызова пишется в журнал (~30 КБ JSON), поэтому я точно знаю, сколько строк модель получила и сколько донесла до файла.

Почему не с эталоном? Сначала я сделал как обычно в юнит-тестах — один раз посчитал правильный ответ и сверял с ним. По этому эталону выходило, что модель ошибается — 46 задач вместо 45. Потом я вспомнил, что одна из метрик считает возраст задачи от текущего момента прямо в SQL. Задачи стареют каждый час, и выборка меняется сама собой даже на замороженных данных.

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

«Харнесс важнее модели» — так сегодня считают почти все

В whitepaper Сбера «AI-Disrupt PDLC» написано: около 2% инженерной ценности агентного пайплайна даёт логика принятия решений в самой модели, остальные 98% — детерминированная обвязка вокруг. Во второй редакции формулировку уточнили: по итогам reverse-engineering Claude Code среда исполнения — это ~98% кодовой базы промышленного агента.

Это не одинокое мнение, и у него есть основания. LangChain перестроили обвязку своего агента — и результат на Terminal-Bench 2.0 вырос с 52,8% до 66,5%, с места за пределами топ-30 до топ-5. Сама модель при этом не менялась.

Принстонский Holistic Agent Leaderboard прогнал 9 моделей по 9 бенчмаркам — 21 730 прогонов — в едином харнессе именно потому, что без фиксации обвязки сравнивать модели бессмысленно. Подборка Future AGI со ссылкой на Epoch AI: одна и та же модель на SWE-bench Verified набирает от 62,3% до 70,2% в зависимости только от обвязки, а Claude Opus 4.5 на SWE-bench Pro — от 45,9% в стандартизированной SEAL до 51,8% в Auggie. У статьи «Stop Comparing LLM Agents Without Disclosing the Harness» тезис вынесен прямо в заголовок: обвязка нередко определяет результат сильнее, чем модель внутри неё.

Обвязка прибавляет, а модель умножает

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

Модель работает иначе. Её качество проявляется на каждом отдельном шаге, а шаги идут подряд, и вероятности перемножаются. Если шаг проходит с вероятностью 95%, то цепочка из 15 шагов дойдёт до конца целиком в 46 случаях из 100. С надёжностью шага 90% — в 21 случае. Разница в три пункта на шаг на длинной цепочке превращается в разницу в разы.

Компания Sierra ввела для агентов отдельную метрику pass^k именно из-за этого эффекта: в их бенчмарке τ-bench даже лучший агент решал задачу с одной попытки менее чем в половине случаев, а ту же задачу восемь раз подряд — менее чем в 25%.

Результаты. Два шага: все молодцы

Сводку по дашборду сдали все три модели во всех девяти прогонах: Sonnet — 36 с, Qwen3-235B — 34 с, локальная 9B — 32 с, самая быстрая.

Если бы я остановился здесь, вывод был бы простым и приятным: локальная модель на одной видеокарте не уступает облачным. Именно так выглядят многие публичные сравнения, и именно поэтому им нельзя верить.

Три шага: модели разошлись

  • Claude Sonnet 4.6 файл создавал каждый раз, но ни разу не воспользовался тем инструментом, о котором его просили. Собирал данные собственным поиском по своему определению риска, поэтому его числа гуляли от прогона к прогону: 56 строк, 29, снова 56.

  • Qwen3-235B дважды перенёс все 46 задач без единой потери, а в третьем прогоне бросил штатный инструмент, пошёл уточнять задачи по одной и принёс отчёт с единственной строкой.

  • Qwen3.5-9B — единственная модель, справившаяся во всех трёх прогонах: 45 из 45, 46 из 46, 46 из 46. Инструмент выдавал ей разное количество задач — и каждый раз она переносила ровно столько, сколько получила.

Пятнадцать шагов: не дошёл никто

  • Sonnet — единственный, кто создавал все 7 файлов во всех прогонах (102 с). Но данные снова собирал своим способом, так что проверить его числа нечем.

  • Qwen3-235B сделал файлы в  2 прогонах из 3, точно перенёс сначала 3 проекта из 6, потом 5 из 6. И работал 11 минут — заметно дольше всех.

  • Qwen3.5-9B создала файлы в 1 прогоне из 3. В двух других — отчиталась о создании семи файлов, не создав ни одного (2,6 мин).

Цепочку из двух шагов безупречно прошли все девять прогонов, цепочку из пятнадцати — ни один из девяти.

Три модели расплачиваются разной монетой

Сложить эти результаты в один рейтинг не выйдет: каждая модель провалилась по-своему. У каждой — своя монета, которой она платит за длину цепочки.

  • Sonnet платит верностью заданию. Единственный дошёл до результата во всех девяти прогонах — и ни разу не соврал о сделанном. Но ни в одном из девяти не решил задачу тем способом, которым просили: собирал данные собственным поиском, по собственному определению риска, — и его числа расходятся между прогонами вдвое. Надёжный исполнитель, который всякий раз знает лучше вас, как надо.

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

  • Qwen3.5-9B платит правдивостью. Самая быстрая из трёх и самая точная в переносе: сколько строк получила от инструмента, столько и донесла до файла. Но в длинной задаче она дважды из трёх отчиталась об успехе, которого не было. Это самая дорогая монета: медленный ответ виден сразу, кривые числа ловит сверка, а уверенный отчёт о несделанной работе живёт до тех пор, пока кто-нибудь не откроет пустую папку.

Обвязка у всех одна, задачи и данные тоже. Всё, что выше, — это и есть разница между моделями.

Самый неприятный способ ошибиться

Вот что написала локальная 9B, запросив данные по всем семи проектам и не создав ни одного файла:

Создал 7 файлов в папке "Отчёты" с задачами в риске для каждого проекта: X — 14 строк, Y — 10, Z — 200, V — 20, T — нет задач в риске, C — 83, L — 45. Общее количество строк: 372

Здесь нет ни сообщения об ошибке, ни обрыва связи, ни таймаута. Все числа верные — данные модель действительно получила. Не сделан только сам результат. Пользователь ищет связный отчёт с правильными цифрами и обнаруживает пустую папку.

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

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

Так кто прав, и что делать

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

Что это были за дефекты
  • обрезка по max_tokens молча рвала вызов инструмента: модель «вызывала» его, а до исполнения вызов не доходил;

  • жадный сэмплинг вместе с режимом рассуждений загонял Qwen в бесконечную петлю — вылечил рецепт сэмплинга от авторов модели;

  • один из инструментов на определённом фильтре молча возвращал нули — и модель честно пересказывала этот мусор;

  • оборванный на середине запрос подвешивал локальный движок инференса;

  • и ещё по мелочи в конфигурации провайдеров.

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

Но на той же уже починенной обвязке та же модель дважды из трёх сообщила о файлах, которых не создала. Обвязка подняла общий уровень — и не сделала работу надёжной.

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

Ограничения методики

  • По три прогона на ячейку — 27 прогонов на всё исследование. Этого достаточно, чтобы увидеть дисперсию и характер отказов, но мало, чтобы утверждать «модель X решает задачу в N% случаев». Выводы здесь качественные, не количественные.

  • Задачи мои, инструменты мои, промпты мои. Сами числа на ваш стек не переносятся. Переносится методика: заморозить всё, кроме модели, и сверять результат с журналом вызовов инструментов.

  • Версии моделей зафиксированы на момент замера; следующие релизы могут перетасовать картину, поэтому замер и должен быть дешёвым и повторяемым.

  • Локальная модель — в 4-битном кванте. Часть её провалов может быть ценой квантования, а не самой модели.

Что по итогу

  • 1–2 шага (пересказать, найти, ответить): локальная модель на одной видеокарте справляется не хуже облачных.

  • 3–5 шагов (отчёт по образцу): локальная модель, но с автоматической проверкой созданного артефакта.

  • 10+ шагов (циклы, сквозные выборки): нужна самая сильная доступная модель, проверка артефакта, предохранители в цикле, повторный прогон при расхождении.

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

Три вещи, которые стоит унести с собой

  1. Один прогон не говорит о модели ничего. Разброс между двумя прогонами одной модели у меня оказался больше, чем разрыв между разными моделями.

  2. Улучшения обвязки прибавляются, качество модели умножается на каждом шаге. Чем длиннее цепочка, тем сильнее решает выбор модели.

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

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

Комментарии (2)


  1. Innesiya
    31.08.2026 09:07

    Самое неудобное в результатах — что 9B на трех шагах обошла Sonnet, и весовой категорией это никак не объясняется. Когда я гоняла похожий стенд у себя, первым разваливался именно способ решения: модель придумывала обходной путь вместо инструмента, который ей явно дали, а неправдивые отчеты шли уже вторым слоем. По методике не хватило одной детали: температуру и seed вы заморозили наравне с промптами и версией кода? Если нет, то часть того, что читается как характер модели, может оказаться просто сэмплингом.


    1. madteamlead Автор
      31.08.2026 09:07

      Спасибо что поделились своим опытом.

      Температура зафиксирована внутри каждой модели (все девять прогонов одной модели шли с одними настройками), но не единая на всех трёх. Sonnet 4.6 ходил с дефолтом Anthropic API (параметр не передаётся). Qwen3-235B в облаке temperature=0.7. Локальная Qwen3.5-9B temperature=0.7, top_p=0.8, top_k=20, presence_penalty=0, режим рассуждений выключен. Seed не фиксировался нигде.