Модель отвечает, обвязка работает
Языковая модель умеет ровно одно: получить текст и вернуть текст. У неё нет памяти между вызовами, нет рук, нет часов и нет доступа к вашему компьютеру. Вызов модели — это чистая функция: положили строку, получили строку. Всё.
И тем не менее агент открывает файлы, запускает тесты, видит, что три из них упали, исправляет код и запускает снова. Кто это сделал? Не модель. Это сделала программа вокруг неё: она приняла текст «хочу прочитать файл cart.js», распознала в нём просьбу, сама открыла файл, сама положила содержимое в следующий вызов модели — и так по кругу, пока не решила, что пора остановиться.
Вот эта программа и называется обвязкой. Английское слово — harness, «упряжь»: то, чем силу приделывают к работе. Лошадь без упряжи сильная, но телегу не везёт.
Разница между «модель ответила» и «агент сделал» целиком лежит в обвязке, и это не фигура речи. Возьмите самую сильную модель, какая есть, и вызовите её один раз с вопросом «почини корзину в моём проекте». Она вернёт текст. Текст будет разумный: скорее всего, список предположений о том, что могло сломаться, и наброски кода. Она не узнает, какой у вас язык, как называются ваши файлы, есть ли у вас тесты и прошли ли они. Не потому, что она слабая, — а потому, что ей этого не дали.
Отсюда первый и самый практичный вывод курса. Когда агент работает плохо, первая мысль почти у всех одна: модель недостаточно умная, возьмём получше. Мысль понятная и в подавляющем большинстве случаев неверная. В типичном отказе модель сделала ровно то, о чём её попросили, ровно с тем, что ей дали. А о чём попросили и что дали — это работа обвязки, то есть ваша.
Второе следствие важнее первого. Модель — это единственная часть системы, которая у всех одинаковая. Её делает не ваша команда, вы её не правите, и ваш конкурент берёт ту же самую. Всё, чем одна агентная система отличается от другой, находится вокруг модели. Именно поэтому обвязку стоит уметь строить: это та часть, где вообще возможна разница.
И третье, менее очевидное. Обвязка — это обычный код. Не магия, не подбор заклинаний, не «промпт-инжиниринг» в смысле угадывания удачной формулировки. Цикл, ветвления, вызовы функций, обработка ошибок, таймауты, логи. Всё то, что вы и так умеете писать. Необычно в нём ровно одно место: в середине цикла сидит нечто, что иногда отвечает не так, как вчера. Вся инженерия дальше — про то, как строить надёжное поверх ненадёжного, и это давно знакомая инженерам задача: так строят системы поверх сети, которая теряет пакеты, и поверх дисков, которые ломаются.
Полезно представить, как просьба о действии выглядит на самом деле. Модель не нажимает кнопку — она возвращает текст в оговорённом формате: имя инструмента и его параметры. Обвязка этот текст разбирает, проверяет, что такой инструмент есть и что параметры годные, зовёт настоящую функцию, а результат кладёт в следующий вызов обычным сообщением. То есть для модели вызов инструмента неотличим от «мне сказали, что получилось вот это».
Из этого следует неприятное, но важное: модель не может отличить настоящий результат от выдуманного. Если обвязка положит ей в окно строку «тесты прошли», она поверит — проверить ей нечем. Вся достоверность в агентной системе создаётся снаружи модели, кодом, который решает, что именно положить в окно. Это одна из причин, почему проверка — отдельный слой, а не пожелание к формулировке.
Шесть слоёв
Обвязку удобно разбирать по слоям. Их шесть, и дальше весь курс идёт по ним же — примерно по два-три урока на слой.
1. Задача. Что просят и, главное, что считается сделанным. Формулировка «улучши производительность» не содержит условия остановки: агент не может понять, когда закончить, и будет либо останавливаться слишком рано, либо чинить всё подряд. Формулировка «время ответа на списке заказов должно стать меньше 300 мс, мерить скриптом bench/orders.js» — содержит.
2. Контекст. Что модель видит в момент решения. Это не «весь проект»: в окно помещается ограниченный кусок, и что именно туда попадёт — решает обвязка. Половина странных ответов объясняется тем, что нужного файла в окне не было, а лишних было на сорок тысяч знаков.
3. Инструменты. Чем агент может действовать: прочитать файл, записать файл, запустить команду, сходить в базу, дёрнуть сервис. У каждого инструмента есть описание, и это описание — единственное, по чему модель понимает, когда его звать. Плохо названный инструмент не зовётся вовсе или зовётся не к месту.
4. Круг. Кто решает, что нужен ещё один заход, и кто решает, что хватит. Обычно это правило в коде: «пока модель просит инструменты — зови, как перестала — отдай ответ», плюс потолок по числу шагов. Без потолка первый же кривой случай даёт бесконечный круг.
5. Проверка. Кто говорит «получилось». Слова агента к этому отношения не имеют: «должно работать» означает ровно то, что означает. Проверка — это тесты, линтер, сборка, сравнение с эталоном, повторное чтение результата другим заходом.
6. Границы. Что агенту нельзя и где его останавливают: права на файлы, доступ в сеть, подтверждение перед необратимым, потолок расхода и времени.
Полезно понимать, что слои не независимы: они подпирают друг друга. Слабая проверка компенсируется человеком в контуре — но дороже. Слабый контекст компенсируется тем, что агент сам ищет, — но медленнее и с большим расходом. Идеальных систем не бывает, бывает сознательный выбор, где именно вы платите.
Стоит сразу сказать, чего этот список не значит. Шесть слоёв — не стандарт и не архитектура: в готовых библиотеках их называют иначе, режут по-другому и часть прячут внутри. Это язык для разбора, а не схема сборки. Ценность у него ровно одна и практическая: он превращает бесполезное «агент плохо работает» в вопрос с адресом — «в каком слое?». После такого вопроса становится понятно, что делать; после первой формулировки — нет.
И ещё одно наблюдение, которое пригодится дальше. Слои перечислены в порядке, в котором они влияют на результат, и он же — порядок разбора. Чем выше слой, тем дешевле его починить и тем больше он даёт: переписать поручение стоит минуту, а переделать контур проверки — неделю. Поэтому идти снизу вверх (начать с «давайте добавим ещё инструмент») почти всегда означает потратить неделю там, где хватило бы минуты.
Отказ чинится в слое
Теперь главное практическое умение курса: увидеть отказ и назвать слой. Это звучит просто, но именно его отсутствие превращает работу над агентом в бесконечную возню с формулировками.
Разберём шесть типовых жалоб.
«Сделал не то, о чём просили». Слой — задача. В девяти случаях из десяти в поручении не было признака готовности, и агент понял его по-своему; в оставшемся — было два требования, и второе противоречило первому. Починка: дописать, что считается сделанным, и что трогать нельзя.
«Сослался на функцию, которой нет». Слой — контекст. Модель не видела файла и достроила его содержимое по названию. Починка: класть в окно то, чего касается задача, и давать инструмент поиска, а не надеяться на память.
«Сказал, что всё работает, а ничего не работает». Слой — проверка. Он не запускал: у него либо не было инструмента запуска, либо была свобода не запускать. Починка: сделать проверку частью круга, а не пожеланием.
«Крутится и не останавливается». Слой — круг. Нет потолка шагов или нет условия остановки: модель каждый раз находит, что ещё улучшить. Починка: явный потолок и явный признак завершения.
«Потратил месячный бюджет за вечер». Слой — границы. Потолка расхода не было вовсе. Починка: потолок на задачу и на день, с остановкой, а не с предупреждением.
«Каждый раз отвечает по-разному». А вот это не отказ, а свойство. Модель вероятностная, и одинакового ответа на один вход от неё требовать нельзя. Чинится это не в модели: система строится так, чтобы разброс не приводил к разному результату, — то есть через проверку и границы, а не через надежду на стабильность.
Полезно завести привычку: перед тем как что-то править, вслух назвать слой. Это занимает секунду и отсекает самое дорогое — правку наугад. Правка наугад особенно коварна тем, что иногда помогает: следующий заход прошёл удачно, вывод «помогло» сделан, а на деле просто выпал другой бросок кубика.
И отдельно про соблазн, с которого мы начали. Замена модели на более сильную действительно иногда помогает — но помогает она по той же причине, по которой помогает удачный бросок: более сильная модель лучше догадывается о том, чего ей не сказали. Это не починка, а покупка запаса прочности поверх непочиненного места. Запас кончается ровно тогда, когда задача становится чуть сложнее.
Есть и вторая привычная подмена, менее заметная: дописать правило в инструкцию. Агент выдумал имя функции — в инструкцию добавляется «не выдумывай имена, проверяй их существование». Формально слой назван (задача), по существу — нет: причина была в контексте, а инструкция просто просит модель компенсировать то, чего ей не дали. Иногда просьба срабатывает. Но инструкция растёт от каждой такой правки, и через полгода это документ на три страницы, где половина строк — заклинания против давно починенных бед. Читает его модель при каждом вызове, и каждая строка отнимает место у полезного.
Различить два случая просто. Правка в инструкцию уместна, когда речь о том, чего модель не может узнать сама: соглашение команды, принятый стиль, запрет трогать определённую папку. И неуместна, когда она просит модель заменить собой недостающий инструмент или недостающий кусок контекста.
Что меняется, когда обвязка есть
Стоит понимать, ради чего вся эта работа, — иначе легко построить сложную обвязку там, где хватило бы одного вызова.
Обвязка превращает «помог» в «сделал». Разница между ними не в качестве ответа, а в том, сколько работы остаётся человеку после.
| Один вызов модели | Агент с обвязкой | |
|---|---|---|
| что на входе | ваш текст | задача и доступ к проекту |
| что делает | отвечает | читает, правит, запускает, повторяет |
| что на выходе | текст | изменённые файлы и вывод проверки |
| что остаётся вам | перенести и проверить | проверить |
| сколько это стоит | один вызов | десятки вызовов |
Последняя строка — не мелочь. Агент, который сходил в проект двадцать раз, стоил в двадцать раз дороже одного вопроса. Поэтому обвязка оправдана не всегда, и решение «нужен ли здесь агент» принимается по простому правилу: выигрыш появляется там, где между постановкой и приёмкой лежит много механической работы. Если её мало, вы заплатите за круг, а сэкономите минуту.
Есть и вторая причина строить обвязку, менее очевидная и в длинную сторону более важная: повторяемость. Один вызов модели — это разговор, который прошёл так, как прошёл, и воспроизвести его нельзя. Агент с обвязкой — это процесс: у него есть вход, шаги, проверки и записанная трасса. Процесс можно измерить, сравнить с прошлой неделей, показать другому человеку и починить адресно. Разговор — нельзя.
Отсюда, кстати, растёт весь дальнейший курс. Уроки про наблюдаемость, оценку и бюджеты существуют не потому, что это модно, а потому что без них у вас нет процесса — у вас есть удачные и неудачные разговоры, и вы не можете сказать, стало ли лучше.
И последнее на этот урок. Обвязка не делает модель умнее. Она делает её применимой: даёт ей глаза, руки, условие остановки и того, кто скажет «получилось». Вся работа дальше — про эти четыре вещи.
Напоследок — про обратную сторону, о которой в разговорах про агентов вспоминают редко. Обвязка стоит не только денег за вызовы: её надо написать, проверить, сопровождать и чинить. У неё есть настройки, которые разъезжаются, потолки, которые кто-то поднял и забыл, и трассы, которые никто не читает, пока не случится беда. Это обычная система, и обходится она как обычная система.
Поэтому честный ответ на вопрос «строить ли агента» звучит так: строить там, где одна и та же работа повторяется достаточно часто, чтобы окупить сопровождение. Разовую задачу дешевле сделать руками или одним вопросом к модели, даже если агент справился бы. Это не пессимизм, а то же правило, по которому решают, писать ли скрипт: тот, который запустят один раз, писать не стоит.
И про то, куда всё это ведёт. Обвязку не обязательно писать с нуля: её уже написали за вас — это и есть готовые агентные инструменты, Codex, Cursor, Claude Code и другие. Внутри у каждого ровно тот цикл, который мы разобрали, и те же шесть слоёв; различаются они тем, где живут (терминал, редактор, облако), что дают настроить и насколько крепко держат границы.
Отсюда и устройство курса. Сначала мы разбираем слои — на этом держится всё остальное, и без этого настройки готового инструмента выглядят набором переключателей с непонятными последствиями. Потом смотрим на сами инструменты и на то, как распределить между ними работу. И заканчиваем тем, ради чего это затевалось: как этими средствами ведут крупный проект — учётную систему, производственную, сайт, сервис, — где работы на месяцы и одной удачной формулировкой не обойтись.