Архив рубрики ~Лента новостей~

Агентный харнес: почему агент разваливается из-за обвязки, а не из-за модели

Агентный харнес: почему агент разваливается из-за обвязки, а не из-за модели
Агентный харнес: почему агент разваливается из-за обвязки, а не из-за модели

Разработчик на r/LangChain описал знакомую многим ситуацию: агент упал на середине задачи, перезапустился и отправил клиенту второе письмо. То же самое, слово в слово, второй раз. Модель тут ни при чём. Она отработала правильно — оба раза. Развалилось то, что вокруг неё: перезапуск не знал, что первое письмо уже ушло.

Когда агент в продакшене ведёт себя непредсказуемо, первый инстинкт — взять модель поумнее. Почти всегда сломано не там. Ломается обвязка: цикл выполнения, управление состоянием, обработка ошибок инструментов, восстановление после сбоя. По-английски это называют harness — сбруя вокруг модели, всё, что превращает вероятностный вывод в воспроизводимый процесс.

Статья для тех, кто уже вытаскивал агента из демо в прод и знает, что там начинается. Разберу на своём коде три места, где рвётся обвязка, и честно отделю то, что проверил руками, от того, что индустрия наработала помимо меня.

Главное

  • Надёжность агента — свойство связки «модель плюс обвязка», а не самой нейросети. Бенчмарк Harness-Bench 2026 года показал: смена конфигурации обвязки двигает результат так же сильно, как смена модели.
  • Длинная цепочка шагов разваливается по арифметике, а не по глупости модели: при 5% отказов на шаг двадцатишаговый агент доходит до конца примерно в трети случаев.
  • Три места, где рвётся обвязка: отказ провайдера, потеря состояния при перезапуске, необработанная ошибка инструмента. Все три чинятся архитектурой, а не промптом.
  • Свой цикл на полсотни строк оправдан на узкой задаче. Как только нужны паузы на человека и аудит, вы начинаете переизобретать LangGraph без его тестов — честнее взять готовый.
  • Индустрия развернулась к этому в 2026-м: год назад спорили, какая модель умнее, теперь — как сделать систему, которая переживёт плохую ночь в проде.

Арифметика, которую не победить умом модели

Начну с цифры, потому что она объясняет всё остальное.

Пусть каждый шаг агента — вызов инструмента, запрос к API, парсинг ответа — срабатывает с надёжностью 95%. Звучит прилично. Но шаги перемножаются: двадцать последовательных шагов дают 0.95²⁰ ≈ 0.36. Агент доходит до конца в 36% случаев. При более грубых 85% на шаг и десяти шагах остаётся около 20%.

Длинный агент падает из-за арифметики: маленькие вероятности отказа перемножаются, и цепочка из десяти шагов сегодня уже считается длинной.

Кривая надёжности цепочкиКривая надёжности цепочки

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

Место первое: провайдер отвечает не то

Самая частая точка отказа у любого продукта с LLM внутри — сам провайдер. Он отвечает 429 (лимит), 5xx (лёг), 401 (ключ забанен). На бесплатных тирах это происходит постоянно.

Я вынес это в отдельную библиотеку — llm-rotator. Задача у неё одна: чтобы запрос всё равно дошёл до ответа, перебирая ключи, модели и провайдеров. Внутри оказалось несколько решений, которые я бы не придумал заранее, а нащупал в бою.

Первое: отказы нельзя обрабатывать одинаково. У меня стоит классификатор ошибок, который разводит их по типу и блокирует гранулярно. 429 блокирует пару «ключ плюс модель» по TTL из заголовка Retry-After; для других моделей этот ключ ещё живой. 401 и 402 убивают ключ глобально: если баланс кончился, он мёртв везде. 5xx даёт один быстрый retry и переключается. Заблокированная комбинация дальше пропускается вообще без HTTP-запроса, пока не истечёт срок.

Второе оказалось контринтуитивным. Я честно попробовал классический экспоненциальный backoff — retry с нарастающей задержкой 1, 2, 4 секунды. И убрал его. Задача ротатора не «дождаться», а быстро найти живую комбинацию. Переключиться на другого провайдера за 50 миллисекунд полезнее, чем висеть на упавшем. Остался один быстрый retry, дальше — следующий кандидат.

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

Что здесь важно для темы статьи: ни одно из этих решений не про модель. Это чистая обвязка — маршрутизация, учёт лимитов, классификация отказов. Библиотека собрана по TDD, 2578 строк кода на 6459 строк тестов, и почти весь этот объём тестов проверяет именно поведение обвязки при сбоях, а не «умность» ответов.

Место второе: состояние теряется при перезапуске

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

Модель сказала «письмо отправлено». Отправилось ли оно на самом деле — отдельный факт, и лог диалога его не знает. Знает его только сохранённое, зафиксированное состояние. Транскрипт — не знает.

У меня контент-конвейер для Дзена собран как цепочка из восьми шагов на разных моделях. Ранняя версия падала на середине и запускалась заново с нуля — теряла сделанную работу и деньги за уже потраченные вызовы. Чинилось это не умной моделью, а файловым состоянием: каждый шаг пишет свой результат в отдельную папку прогона. При перезапуске срабатывает то, что я называю Smart Resume: если выходной файл шага уже есть, шаг пропускается, а не переделывается. Конвейер ищет незавершённый прогон за сегодня и продолжает с точки обрыва.

Это защищает от повторной работы. Но у решения есть граница: оно спасает от повторной генерации, не от повторного действия во внешнем мире. Мне тут повезло — финальный шаг Дзен-бота создаёт черновик, а не публикует сразу, так что дубль стоит копеек. Опасность появляется там, где последний шаг необратим: отправить письмо, списать оплату. Вот там идемпотентность из удобства превращается в обязанность.

В той же ветке r/LangChain на это ответили точнее всего: retry неизбежен, дубль побочного эффекта — нет. Крах и перезапуск предотвратить нельзя. Можно сделать действие безопасным для повторного запуска. Это разные задачи, и вторая — не про модель совсем.

Карта трёх слоёв обвязки вокруг моделиКарта трёх слоёв обвязки вокруг модели

Место третье: инструмент упал, и агент упал следом

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

У меня есть браузерные боты на Playwright — постинг в Дзен, генерация обложек. Живой браузер ломается непредсказуемо: селектор уехал, страница не догрузилась, всплыла капча. Обвязка тут вот в чём. Сессия персистентна: состояние авторизации сохраняется между запусками, не логинимся каждый раз заново. При падении сохраняется error-state: скриншот плюс HTML страницы на момент сбоя, иначе воспроизводить нечего. Исключения типизированы, чтобы «не залогинились» и «не нашли кнопку» лечились по-разному.

Отдельная история: как вставлять текст в поле. Я перебрал три режима: посимвольный ввод, fill и вставку через буфер. fill триггерил капчу, посимвольный был медленным, вставка через буфер оказалась рабочим дефолтом. А ещё осознанно убрал «слепой» цикл переотправки — тот самый, что в истории с письмом шлёт дубли. Лучше честно упасть с сохранённым состоянием, чем повторять вслепую.

Что индустрия называет тем же словом

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

В основе любого агента с инструментами лежит один и тот же цикл while: отправить модели запрос со схемами инструментов, выполнить то, что она попросила вызвать, вернуть результат обратно, повторить. На любом языке это полсотни строк без всякого фреймворка, будь то Python, Node или Rust; разница только в синтаксисе. У цикла два обязательных предохранителя. max_iterations принудительно обрывает цикл после 10–15 шагов: без него модель, галлюцинируя, бесконечно вызывает инструмент с неверными аргументами и жжёт бюджет до упора. Второй предохранитель тоньше: текст ошибки парсинга уходит обратно модели как результат вызова инструмента, и она исправляет аргументы на следующей итерации. Сообщество назвало это «exceptions as observations»: ошибка становится не крахом, а сигналом.

Дальше идёт durable execution — надёжное выполнение, которое переживает падение процесса и возобновляется ровно с места сбоя, не повторяя уже сделанные вызовы. Это старая идея из распределённых систем, и вокруг неё сейчас крутятся деньги: Temporal подняла раунд при оценке 5 млрд долларов, а их формулировка проблемы звучит буднично — команды выкатили первое поколение агентов в прод, «не позаботились об обвязке», посмотрели, как оно горит, и вернулись строить на надёжном фундаменте.

Есть и слой фреймворков — LangGraph для долгих процессов с аудитом, Pydantic AI для строгой типизации, Smolagents для генерации кода. Про них важно знать одну вещь из community: канонический тред «Why we no longer use LangChain» от команды Octomind. Претензия не в том, что фреймворк не тянет простой случай. В том, что за пределами простого случая продираешься через слои абстракции ради одной детали и теряешь из виду, что система вообще делает.

Всё это подытожил бенчмарк Harness-Bench: 106 реалистичных задач в песочницах, при фиксированной модели меняется только конфигурация обвязки. Вывод, который он зафиксировал в цифрах: надёжность — характеристика связки «модель плюс харнес», а не одной нейросети.

Свой цикл или фреймворк

Раз цикл умещается в полсотни строк, соблазн написать своё велик. Отвечу, как решаю это сам.

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

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

Где обвязка не спасает

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

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

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

И само состояние — недоверенный ввод. В конце 2025-го в чекпоинтерах LangGraph нашли уязвимость небезопасной десериализации: тот, кто может записать данные в хранилище состояний, получает выполнение произвольного кода при загрузке чекпоинта. Восстановление состояния требует проверки подписи и валидации схемы до десериализации, независимо от того, кто, по-вашему, имеет доступ к базе.

Наконец, надёжность через избыточность стоит денег. Обернуть модель с точностью 80% в проверку «лучшее из трёх» математически снижает частоту ошибок, но вы платите тройной задержкой и тройными токенами. На расчёте налога это оправдано, на генерации приветственного письма — сожжённые деньги.

Выводы

Первое. Обвязка — не то, что достраивают после того, как «агент заработал». Агент работает ровно настолько, насколько надёжна обвязка вокруг него; в проде это одна система, а не модель с довесками.

Второе. Самые дорогие отказы — с побочным эффектом во внешнем мире. Дубль генерации стоит токенов, дубль отправки или платежа стоит денег и репутации. Проектируйте идемпотентность там, где действие необратимо, — это ровно тот же принцип, что «последний шаг оставь человеку».

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

FAQ

Разве более умная модель не решает большинство этих проблем?
Нет, потому что проблемы не про интеллект. Классификация 429, возобновление с точки обрыва, идемпотентность отправки — это инженерия обвязки. Более умная модель точнее рассуждает, но так же не знает, ушло письмо или нет: это знает состояние, а не она.

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

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

Что такое durable execution простыми словами?
Способность процесса пережить падение и продолжить ровно с места сбоя, не повторяя уже сделанные вызовы. Если агент упал, обработав 9 999 из 10 000 записей, он не начинает заново, а поднимает состояние и идёт дальше.

Собираете агентов для прода? Расскажите в комментариях, на каком именно месте обвязки вас ловило чаще всего — на состоянии, на ошибках инструментов или на отказах провайдера. Такие разборы я собираю в своём канале @dmitra_ai.

Источник: vc.ru

Оцените материал:

Поделиться
Понравилась статья? Расскажите другим
ВКонтакте
Читайте также
Новости робототехники Weave Robotics запускает Айзека, своего первого представителя робота-гуманоида Новости робототехники Страх перед человекоподобными роботами подтолкнул рабочих к забастовке на автомобильном заводе Hyundai. Новости робототехники Основатель Максимо рассказывает, как робототехника строит строительство солнечной энергетики. Архив рубрики ~Обо всем~ Астрономы нашли кандидата в самый далекий галактический бар. Он существовал спустя почти 1,2 миллиарда лет после Большого Взрыва Новости робототехники По заключению Национального совета по безопасности на транспорте (NTSB), водитель Tesla, который объяснил аварию тем, что автопилот нажал на педаль газа на 100%. Новости робототехники Mondo Robotics представляет собой Beni, вездеходного робота с электрической розеткой и искусственным интеллектом для потребителей. Архив рубрики ~Обо всем~ «Парачастицы» могут стать представителями третьего царства квантовых частиц Архив рубрики ~Коротко из Telegram~ Нейросеть обучили подсчету и оценке качества семян Архив рубрики ~Коротко из Telegram~ «Комендантский час» на соцсети для подростков 16-17 лет хотят ввести… Архив рубрики ~Коротко из Telegram~ В Южной Корее создадут бесплатного ИИ-бота для всех граждан. Архив рубрики ~Коротко из Telegram~ В США 73% технических вакансий требуют навыков работы с ИИ,… Архив рубрики ~Обо всем~ Компания SpaceX внезапно прервала второй запуск Starship V3 после запуска двигателя. Архив рубрики ~Коротко из Telegram~ Samsung хочет обучать ИИ на данных здоровья Архив рубрики ~Коротко из Telegram~ Бывший глава «Яндекс Лавки» вышел в Nebius Илья Красильщик, медиаменеджер… Новости робототехники Weave Robotics запускает Айзека, своего первого представителя робота-гуманоида Новости робототехники Страх перед человекоподобными роботами подтолкнул рабочих к забастовке на автомобильном заводе Hyundai. Новости робототехники Основатель Максимо рассказывает, как робототехника строит строительство солнечной энергетики. Архив рубрики ~Обо всем~ Астрономы нашли кандидата в самый далекий галактический бар. Он существовал спустя почти 1,2 миллиарда лет после Большого Взрыва Новости робототехники По заключению Национального совета по безопасности на транспорте (NTSB), водитель Tesla, который объяснил аварию тем, что автопилот нажал на педаль газа на 100%. Новости робототехники Mondo Robotics представляет собой Beni, вездеходного робота с электрической розеткой и искусственным интеллектом для потребителей. Архив рубрики ~Обо всем~ «Парачастицы» могут стать представителями третьего царства квантовых частиц Архив рубрики ~Коротко из Telegram~ Нейросеть обучили подсчету и оценке качества семян Архив рубрики ~Коротко из Telegram~ «Комендантский час» на соцсети для подростков 16-17 лет хотят ввести… Архив рубрики ~Коротко из Telegram~ В Южной Корее создадут бесплатного ИИ-бота для всех граждан. Архив рубрики ~Коротко из Telegram~ В США 73% технических вакансий требуют навыков работы с ИИ,… Архив рубрики ~Обо всем~ Компания SpaceX внезапно прервала второй запуск Starship V3 после запуска двигателя. Архив рубрики ~Коротко из Telegram~ Samsung хочет обучать ИИ на данных здоровья Архив рубрики ~Коротко из Telegram~ Бывший глава «Яндекс Лавки» вышел в Nebius Илья Красильщик, медиаменеджер…

Оставить комментарий