Главная / Статьи

Почему агентам с долгосрочными целями нужен Harness: как глубокие агенты управляют состоянием и контекстом.

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

Издатель: REACTAPP.TOP12 мин чтения2727 слов

Источники: The Deep Agents Architecture, Part 1: Understanding the Agent Harness

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

Лучшим доказательством того, что потолок производительности обусловлен структурными ограничениями, являются работы трех команд, которые никогда не координировались между собой. Anthropic достиг этого при разработке Claude Code, OpenAI — с помощью Deep Research, а проект Butterfly Effect столкнулся с такими проблемами, что Manus пришлось переписывать четыре раза. Во всех случаях речь шла о четырех одинаковых компонентах: инструменте планирования, делегировании задач подагентам, доступе к файловой системе и подробном запросе. Независимые усилия разных компаний, приведшие к одинаковой архитектуре, указывают на то, что проблема была обусловлена самой структурой, а не личными предпочтениями разработчиков.

Настоящей причиной является порча контекста

Хочется сказать, что длительная работа агентов проваливается из-за заполнения окна контекста. Но это не является истинной причиной.

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

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

Пробел, который не предусматривалось преодолеть ни LangChain, ни LangGraph

LangGraph сосредотачивается на надежной работе: контрольные точки, потоковая обработка, проверка человеком и сохранение данных между потоками. Его реальным аналогом является Temporal, а не другие фреймворки агентов. Он обеспечивает, что агент будет продолжать работать после сбоя, но ничего не говорит о том, способен ли агент ясно мыслить спустя четыре часа. LangChain находится на более высоком уровне и предоставляет абстракции: цикл вызова инструментов, структурированный контент и промежуточные компоненты для настройки. Тем не менее стандартный цикл, созданный на основе этих абстракций, остается тем же поверхностным циклом, о котором только что говорилось. Надежность и абстракции действительно важны и необходимы, но ни одна из них не указывает на то, остается ли рабочий контекст модели чистым.

Это можно проверить по способу подключения компонентов. В объявленных зависимостях Deep Agents указаны langchain, langchain-core, langchain-anthropic, langchain-google-genai и langsmith. LangGraph в этом списке отсутствует; он присутствует лишь потому, что LangChain от него зависит. Структура компонентов строго иерархична: Deep Agents находятся поверх LangChain, а тот — поверх LangGraph; речь не идет о трех независимых компонентах, объединенных вместе. Ни на уровне выполнения, ни на уровне фреймворка никогда не существовало механизма для обеспечения чистоты контекста, поскольку слой, предназначенный для этого, расположен выше обоих остальных.

Тезис: проблема состояния, а не проблема рассуждения

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

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

Каждый механизм, добавляемый брелоком — будь то файловая система для перегрузки, подагенты для изоляции или инструмент планирования для отслеживания прогресса — рассматривает случай амнезии. Ни один из них не делает отдельный шаг рассуждения более умным. Следовательно, управление состоянием не является конкурирующим объяснением процесса рассуждения. Это основа, позволяющая рассуждениям развиваться на протяжении множества шагов и не сбрасываться после каждого из них. Модель, которая правильно рассуждает на каждом шаге, всё равно может потерпеть неудачу при выполнении задачи из двухсот шагов, если на 150-м шаге невозможно узнать, что было решено на 12-м шаге. Рассуждения были неверными не по своей природе; у них просто не было непрерывности для работы.

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

Четыре столпа с множеством компонентов

Что такое Deep Agents

Deep Agents поставляется как пакет на Python с открытым исходным кодом под лицензией MIT, устанавливается с помощью pip и в настоящее время находится на версии 0.7.5. Вокруг него существует порт на TypeScript, терминальная CLI под названием deepagents-code, а также хостинговая, управляемая версия, которая всё ещё находится в приватном бета-тестировании. Он не является конкурентом LangChain и LangGraph. Как уже упоминалось, он напрямую зависит от LangChain и получает доступ к LangGraph только через него. Вызов функции create_deep_agent() приводит к вызову функции create_agent() из LangChain, которая создаёт граф LangGraph; следовательно, любая стабильность агента определяется тем, что передаёт LangChain.

Четыре основных компонента и стек технологий под ними

По мнению LangChain, для того чтобы агент был «глубоким», необходимы четыре компонента: инструмент планирования, возможность делегирования задач субагентам, доступ к файловой системе и подробный промпт. Харрисон Чейз предложил эту концепцию, заметив схожую структуру в Claude Code, Deep Research и Manus. В качестве ментальной модели она хорошо себя проявляет, поскольку именно эти четыре категории действительно определяют разницу между поверхностным циклом действий и агентом, способным выполнить сложную задачу до конца.

Четыре пункта были лишь первоначальным описанием, а не окончательным планом. Функция create_deep_agent() собирает каждую из этих способностей из более обширного и постоянно расширяющегося набора промежуточных компонентов, которые можно свободно комбинировать. В этот набор входят файлы, подагенты, функции обобщения информации, корректировка вызовов инструментов, различные варианты кэширования запросов, связанные с конкретными поставщиками, механизмы работы с памятью, навыки и проверка результатов человеком, а также любые пользовательские слои, написанные разработчиком. Указанные пункты определяют, что может делать агент. Стек промежуточных компонентов — это способ реализации этих возможностей, и он постоянно меняется.

Структурно требуются лишь две части стека, и это важнее любого количества. FilesystemMiddleware необходим, поскольку он обеспечивает соблюдение правил доступа, которые контролируют доступ к файлам, что в комментарии к исходному коду называется гарантией безопасности. SubAgentMiddleware требуется, потому что именно его использует инструмент task. Игнорирование любой из этих частей приводит к ошибке и не приводит к тихому снижению производительности. Все остальное является необязательным и собирается только по запросу.

Все, кто сейчас разрабатывает на этой основе, должны знать, что две из первоначальных четырех категорий стали факультативными. Начиная с версии v0.7.0, инструмент планирования (write_todos) больше не входит в стандартный набор компонентов, а базовый системный запрос поступает пустым в соответствии с уведомлением о устаревании. Для восстановления каждого из этих элементов требуется одна строка конфигурации. Простой вызов create_deep_agent() предоставляет доступ к файлам и возможность делегирования задач подагентам из коробки, а планирование и детальный запрос — только по запросу.

Профили использования, слой настройки, отсутствующий у более новых моделей

Под средой промежуточной обработки находится отдельный механизм настройки, называемый профилем harness. Профиль добавляет дополнительный текст системных подсказок и удаляет определённые инструменты в зависимости от конкретной строки модели, передаваемой агенту. Не следует путать его с ProviderProfile, который определяет способ создания объекта модели. HarnessProfile влияет на поведение после его создания.

Для поиска требуется точный зарегистрированный ключ provider:model; в случае его отсутствия в качестве альтернативы используется запись для всего провайдера. По умолчанию существуют профили для семейства Codex от OpenAI и для трех поколений Claude: Haiku 4.5, Sonnet 4.6 и Opus 4.7. Профиль Sonnet 4.6 — это не просто общие рекомендации по формулировке запросов; он настолько тесно следует официальным руководствам Anthropic, что об этом прямо говорят комментарии в коде. Кроме того, в нем намеренно опущены предупреждения, связанные с использованием модели Opus, касающиеся чрезмерной активности и большого количества вспомогательных агентов, поскольку они были признаны нерелевантными для Sonnet.

Модель, выпущенная на одно поколение позже зарегистрированных, не получает ничего. При проверке с помощью резолвера claude-sonnet-5, anthropic:claude-sonnet-5 и просто anthropic не возвращают никаких профилей. Поскольку точного совпадения нет, а также нет общего для всех поставщиков записи Anthropic, на которую можно было бы опереться (существуют только профили, привязанные к конкретным версиям), ничего не совпадает. Отсутствие результата происходит совершенно бесшумно. Согласно собственной документации резолвера, единственной строкой в логе является запись для отладки, генерируемая при использовании резервного варианта на уровне поставщика. Если оба поиска проваливаются, лог вообще не записывается.

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

Как это работает

Одна абстракция над всем

Весь этот промежуточный слой основан на едином механизме, принадлежащем LangChain, а не Deep Agents. В версии LangChain 1.0 были добавлены точки, в которых код может выполняться при начале или окончании выполнения, до и после каждого вызова модели, а также при каждом вызове инструмента, что позволяет одному агенту с циклом поддерживать совершенно разные конфигурации. Функции before-hooks выполняются в порядке их регистрации, а функции after-hooks — в обратном порядке, что соответствует способу, которым веб-фреймворки структурируют свой промежуточный слой. Функция-обертка может попытаться выполнить вызов заново, загрузить его из кэша или полностью перехватить его. Настройки supervisor, стаи агентов, циклы рефлексии и deep agents на самом деле представляют собой один цикл с разными привязанными функциями, причем create_deep_agent() — это просто один из возможных способов их выбора.

Файлы: два бэкенда, две гарантии

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

  • StateBackend, являющийся стандартным вариантом, хранит файлы в канале состояния LangGraph: данные графа с собственными правилами объединения, а не на диске. Он работает только во время выполнения графа в реальном времени. То, переживут ли данные один вызов, зависит от наличия как контрольного указателя, так и стабильного идентификатора потока. Без них каждый вызов начинается с пустого состояния, что объясняет, почему простой вызов create_deep_agent() всегда показывает пустую рабочую директорию.
  • FilesystemBackend осуществляет реальные операции чтения и записи на диске, что приносит как преимущества в виде надежного хранения, так и реальные риски. В описании ясно указано, что он подходит для локальной разработки и процессов CI/CD, но не подходит для систем, доступ к которым имеют пользователи, поскольку агент может читать всё, до чего может добраться, включая конфиденциальные данные, а его изменения невозможно отменить. При использовании стандартного параметра virtual_mode=True доступ ограничивается корневым каталогом, просмотр путей запрещается как в исходном, так и в разрешенном виде, а настоящие абсолютные пути скрываются в выводе агента, чтобы местоположение корневого каталога не становилось известным.

Одна система разрешений охватывает оба случая. Правило связывает операцию с шаблоном пути и одним из трех режимов: разрешить, отклонить или прервать. Действие по удалению тщательно оценивается с учётом правил записи. Рекурсивное удаление отклоняется, если какое-либо правило отклонения перекрывает элементы, находящиеся ниже целевого объекта, а не только первое совпадающее правило; поэтому раннее широкое разрешение не может авторизовать удаление того, что защищено более поздним, более узким правилом.

Подагенты, специально изолированные

До подагентов можно добраться так же, как и до любого инструмента. Когда модель вызывает task, запускается совершенно отдельный агент, оснащённый собственной моделью, инструментами и промежуточным программным обеспечением. Настройки его модели принимают либо строку вида provider:model, либо уже созданный объект модели; поэтому размещение подагента на другом провайдере, чем у родительского агента, требует всего одной строки конфигурации, а не сложных инженерных усилий.

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

Память подлежит изменению, она не является авторитетным источником

Файл памяти, после загрузки, не попадает сразу в системный промпт. Он поступает в виде чётко обозначенного блока с инструкциями, добавленными фреймворком, которые сообщают модели, что содержимое является справочным материалом, который может быть устаревшим или созданным кем-то другим, а не командой, которую следует выполнять без вопросов. Это соответствует более низкому уровню доверия по сравнению с системным промптом и соответствует предназначению: это то, что агент читает и корректирует в процессе работы, а не свод правил, который разработчик пишет один раз и ожидает, что он будет обладать полной авторитетностью.

Детали масштабирования

Состояние разговора определяется собственным редьюсером под названием DeltaChannel, разработанным таким образом, чтобы объем хранилища чекпоинтов рос линейно, O(N), по мере увеличения длины разговора, а не квадратично, O(N²).

Поведение на границах

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

Одна ошибка — множество потерь (проблема №694). Если несколько подагентов работают одновременно и один из них выдает исключение, все остальные также прерываются вместе с ним. Пакетная обработка успешна или неудачна в целом, без возможности изоляции отдельных элементов. Отчет датируется январем 2026 года и относится к ранней версии продукта; проблема впоследствии была закрыта, однако изменения в коде, которые её устранили, не могут быть найдены ни в коде подагентов, ни в слое выполнения инструментов LangChain. Тем не менее следует учитывать этот факт: считайте, что любое распределение независимых подзадач может привести к частичной неудаче, пока не будет подтверждено иное на фактически развернутой версии.

Ошибки попадают к неправильному пользователю (#947). Обычно после того, как инструмент сообщает об ошибке, модель должна попытаться выполнить действие заново или внести коррективы. Однако в некоторых зафиксированных случаях она обращалась непосредственно к конечному пользователю с текстом, предназначенным для внутренней коррекции, в результате чего человек видел сообщение об ошибке, которое вовсе не предназначалось ему. На момент проверки проблема оставалась нерешенной. В отдельном отчете отмечается, что после последнего обновления фреймворка некоторые исключения инструментов полностью останавливают работу агента, вместо того чтобы передать сообщение модели для повторной обработки, в то время как более ранние версии продолжали работу, игнорируя такие исключения.

Два более старых отчета по той же теме закрыты: субагенты, игнорирующие лимит рекурсии родительского агента (#1698), и сбои в возобновлении работы при принятии решений об изменении или отклонении (#554). Исправление проблемы с лимитом рекурсии также было проверено на установленном исходном коде. Эти отчеты показывают, насколько быстро обычно удается решать проблемы в этой области, поэтому они не являются основанием для изменения дизайна.

Практические альтернативы

В настоящее время существует три практических варианта для создания агентов с долгосрочными целями: Deep Agents, Claude Agent SDK и OpenAI Agents SDK. Каждый из них отражает разный подход к определению того, что находится в ведении команды и что она предоставляет другим, причем ни один из них не является неполной версией остальных.

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

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

Что взять с собой

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

Связанные материалы

  • Beta-версия Managed Deep Agents: способ развертывания агентов LangChain на основе каталогов — функция Managed Deep Agents от LangChain превращает папку проекта в хостингового агента. Что делает каждый файл, как работает процесс развертывания mda, и какие недостатки бета-версии стоит знать.
  • Создание эффективных ИИ-агентов: архитектурные шаблоны и фреймворки — обзор архитектуры агентов, от циклов использования инструментов, моделей ReAct и маршрутизаторов до механизмов хранения данных, ограничений, проверки человеком и возможностей мониторинга, а также пошаговая инструкция по созданию агента.