- BrainTools - https://www.braintools.ru -
Архитектура «оркестратор + сабагенты» на одном экране: оркестратор держит план и раздаёт подзадачи сабагентам.
Один AI-агент в чате – это удобно, пока задача помещается в контекст. Как только она начинает разъезжаться по 30 файлам, четырём ролям и циклу «исследуй – реализуй – отревьюй – поправь», единый чат превращается в свалку: модель путает, какой шаг где, тащит решения из первой задачи в третью и стабильно проседает по качеству начиная с заполнения окна примерно наполовину. Схема «оркестратор + сабагенты» – это инженерный ответ на проблему: оркестратор держит план и раздаёт подзадачи изолированным сабагентам.
Готовы поделиться нашим опытом [1]: как это устроено
Дисклеймер. Сравнений с Claude Code, Junie, Cursor, JetBrains AI Assistant, OpenAI Swarm, LangGraph и другими реализациями оркестратора с сабагентами в этой статье нет – это отдельный жанр, требующий одинакового бенча. Цель статьи – показать архитектурные решения и причины, по которым мы к ним пришли. Материал – конспект внутреннего доклада и практики на нашем плагине.
Качество ответа LLM падает по мере заполнения контекста. На наших внутренних замерах в JetBrains-плагине просадка становится заметной после ~50% заполненности и резко обваливается после ~85%. Похожая картина описана в Lost in the Middle (Liu et al., 2023) [2] и в Anthropic Engineering: Effective context engineering [3].
Сабагент – это не «агент, который зовёт агента». Это изолированный подпроцесс со своими тулами и единственным каналом возврата – report_result(summary). Сабагентов вызывает только оркестратор.
Оркестратор с сабагентами даёт выигрыш на трёх классах задач: project-wide read-only (ревью, триажинг, инвентаризация), сложные пайплайны с явной разбивкой ролей по разным scope (TDD, SDD, итеративная фича), loop-based задачи (review-loop, поиск code smells).
На задачах, помещающихся в контекст одного агента, оркестратор с сабагентами почти всегда проигрывает одиночному агенту. Anthropic в посте «How we built our multi-agent research system» [4] пишут о 3–10× расходе токенов на эквивалентный результат – на наших задачах цифра близкая.
Главный инженерный выбор – где провести границу декомпозиции. Делить по ролям (planner / coder / reviewer на одной фиче) почти всегда плохо: координация съедает больше токенов, чем сама работа. Делить по контекстным границам – хорошо.
Промпт «сделай через сабагентов» работает плохо, скилл (markdown-файл с алгоритмом, acceptance criteria и явным списком сабагентов) – хорошо.
В презентации внутри команды у нас есть слайд, который мы потом вынесли наружу: «качество ответа = качество контекста». У контекста есть три неприятных свойства, и все три бьют ровно в крупную задачу.
Первое – предвзятое отношение к прошлым ответам. LLM считает свои собственные предыдущие сообщения частью истины. Если в чате вы зацепили неудачное направление и потом передумали, модель будет к нему возвращаться даже после фразы «забудь». Это особенно видно на ревью-лупах: вторая итерация почти всегда «защищает» решение первой, а не оценивает его заново.
Второе – жёсткое ограничение размера. У нас агент по умолчанию читает не целые файлы, а диапазоны строк, предварительно прочитав структуру файла (благо есть возможность получить эту информацию из IDE); даже так окно 200k токенов уходит за 20–30 tool calls на enterprise-репозитории ~4M LoC. На чтении файлов целиком, как делает большинство grep-агентов, бюджет кончается ещё быстрее.
Третье – деградация при заполнении. На наших внутренних замерах (актуальные на апрель 2026 модели семейств Claude Opus, Claude Sonnet и GPT – у всех похожая форма кривой) качество держится примерно линейным до 40–50% заполненности окна. На участке 50–85% начинается заметная просадка: модель чаще теряет нить, путает, какой шаг где, начинает «склеивать» куски разных задач. На 95–99% она формально отвечает, но содержательно нет. Эти наблюдения совпадают с описанием в Lost in the Middle [2]: информация в середине длинного контекста используется хуже, чем на краях.
Проблемы:
– Loop-based пайплайны (ревью, итеративная разработка, поиск code smells) в одном чате системно искажаются: каждая следующая итерация смотрит на предыдущую как на «уже почти ок».
– Context-heavy задачи целиком в один чат не лезут. Суммаризация частично спасает, но теряет детали.
– Сложные пайплайны нельзя гонять в автоматическом режиме: пользователь вынужден быть оркестратором руками.
– Стратегичность скатывается в тактику. Модель начинает решать «следующую очевидную подпроблему», а не план целиком.
– Параллельности нет.
Оркестратор с сабагентами решает ровно эти пять проблем, но не бесплатно.
Сабагент в нашей реализации – это не «агент, который умеет звать агента». Это отдельный процесс с пустым контекстом на старте, со своим (часто урезанным) набором тулов, запущенный с общей папкой для обмена данными и с единственным тулом штатного завершения – вызовом report_result(summary).
Если в одной строке: сабагент – это изолированный агент-ассистент, к которому оркестратор обращается как к чёрному ящику.
report_result.Контракт вызова из оркестратора (упрощённая сигнатура):
data class SubagentCall(
val shortDescription: String, // одна фраза для UI и логов
val fullDescription: String, // полный промпт задачи для сабагента
val context: String, // выжимка релевантного контекста от оркестратора
val sharedDir: Path, // папка, через которую идёт обмен файлами
)
Несколько решений в этом контракте, которые на первый взгляд выглядят странно, и причины, по которым мы к ним пришли.
Почему сабагент не может звать сабагентов – в ранних прототипах мы это разрешали. На второй неделе обнаружили дерево сабагентов глубиной 6, в котором листья тратили токены на пересказ задачи родителя бабушке-родителю, и обратно. Иерархия сворачивается в координационный ад быстрее, чем вы успеваете её отдебажить. Поэтому в текущей версии сабагенты звать сабагентов не могут, и это дисциплинирует декомпозицию у оркестратора.
Почему сабагент не общается с пользователем – это by design. Если сабагенту нужно что-то спросить, он либо отвечает на основе контекста, либо завершает работу с пометкой «не хватает данных». Спрашивать пользователя – задача оркестратора. Иначе у пользователя одновременно живут пять чатов от пяти сабагентов, и никто, включая сам оркестратор, не понимает, кто что делает.
Почему общая папка, а не передача через аргументы – контекст в аргументе тула дорогой и узкий. Если сабагенту нужно отдать обратно дифф на 800 строк или JSON с разметкой 200 issue, он кладёт это в файл в sharedDir, а в report_result возвращает короткую сводку и путь. Все участники, включая оркестратора, могут читать и писать в эту папку, у нас это решено через directory-bound тулы (read_in_dir, write_in_dir), которые ограничены ровно этой папкой.
sharedDir (<projectRoot>/.tasks по умолчанию, путь конфигурируется); тулы сабагента ограничены ровно этой папкой.Почему report_result(summary), а не «верни всё, что наработал» – сабагент по построению генерирует много промежуточного шума: тысячи строк grep-выдачи, прочитанные файлы, чужие классы. Если всё это вернуть в чат оркестратора, мы возвращаемся к проблеме захламлённого контекста, ради ухода от которой всё и затевалось. Поэтому return – это всегда сжатая сводка, а детали через файлы в sharedDir.
Параллельность – оркестратор может запустить несколько сабагентов одним шагом и блокируется до завершения всех. Это упрощает синхронизацию (никаких очередей и колбэков на стороне оркестратора), но накладывает естественное ограничение: задача делится на параллельные ветви, у которых нет кросс-зависимостей. Если зависимости есть, лучше последовательный вызов.
Автономность через «Продолжай» – сабагент должен сам решить, что закончил, и вызвать report_result. Если он этого не сделал, мы пинаем его сообщением «Продолжай или вызови report_result» до 10 раз. После – принудительная остановка и возврат с ошибкой [5] в оркестратор. На практике даже на слабых моделях этой эвристики в 10 итераций хватает для завершения задачи.
Это место, где много маркетинга. Мы у себя сформулировали честно: оркестратор с сабагентами даёт выигрыш на трёх классах задач, и почти везде вне этих трёх классов проигрывает одиночному агенту.
Задачи, в которых нужно пройти по всему проекту, что-то посмотреть и вернуть структурированный отчёт. Состояние нигде не меняется, шаги независимы.
Что мы у себя гоняем через сабагентов:
– Прогон ревью-чеклистов по всему PR / по всему модулю (пакет → сабагент).
– Триажинг issue из трекера (GitHub / GitLab / YouTrack): воспроизводится / не воспроизводится, severity, дубли (один сабагент на батч issue).
– Инвентаризация фич продукта (один сабагент на функциональную область).
– Сборка полной документации проекта (по модулям).
– Поиск code smells по списку правил (батч связанных правил → один сабагент).
Параллельность тут даёт реальный выигрыш по реальному времени, а изоляция контекста – по precision: сабагент, у которого в контексте связанные правила по организации кода по пакетам, не отвлекается на проверку IDE-специфичных дедлоков.
Когда у задачи действительно есть разные этапы или разные роли, и они работают на разных кусках кода. Не «одна фича + три роли», а именно «разные scope».
Примеры из нашей практики:
– TDD-пайплайн: сабагент-1 пишет тесты по описанию задачи, сабагент-2 пишет реализацию под зелёные тесты, сабагент-3 ревьюит. Каждому в контексте лежит ровно его кусок, не больше.
– SDD + TDD: перед всем этим оркестратор зовёт сабагента-планировщика, который читает issue из трекера или спеку и раскладывает её на task-01.md [6], task-02.md [7], … в sharedDir.
– Итеративная разработка через спеку: один сабагент-кодер на каждую итерацию, один общий ревьюер в конце каждой итерации, обновление спеки между итерациями, планирование следующей итерации.
– Автогенерация домашних заданий по шаблону.
Внутри одного агента loop работает плохо: к третьей итерации модель уже «знает», что было в первых двух, и не может посмотреть на свой код свежим глазом. С отдельным сабагентом на каждую итерацию это перестаёт быть проблемой, у каждого свой контекст.
Кейсы, где это даёт самый явный выигрыш:
– Поиск багов: сабагенты ищут параллельно, пока оркестратор собирает агрегированный отчёт.
– Поиск code smells: один проход – один сабагент, оркестратор склеивает.
– Параллельный сбор информации о проекте.
Те же задачи можно делать одним чатом с Ralph Wiggum loop (паттерн Geoff Huntley [8]: один и тот же промпт зациклен в while-true, пока не выполнено условие), но тогда нужно вручную следить за размером контекста. На длинной дистанции это всё равно сваливается в захламление.
Тоже честно. Если задача попадает в этот список, оркестратор с сабагентами дороже и хуже одиночного агента.
Первый случай – задача целиком помещается в контекст. Фикс мелкого бага, мелкое улучшение существующей фичи, рефакторинг до 100 LoC и до 10 файлов. Один чат справится за один шаг, оркестратор будет 4 шага собирать контекст для сабагентов и ещё 2 склеивать ответы.
Второй случай – общий контекст важен и связный. Когда вы решаете несколько связанных задач, и предыдущие решения должны влиять на следующие, оркестратор с сабагентами тут вреден. Каждый сабагент будет переспрашивать и переделывать. Лучше один чат с компрессией.
Третий случай – нужно каждый шаг смотреть глазами. Если задача требует ручной валидации после каждого шага, оркестратор просто добавляет лишний слой между вами и кодом. Все передачи между сабагентами всё равно ложатся на вас.
Эмпирическое правило по объёму, к которому мы пришли:
|
Объём задачи |
LoC |
Файлов |
Что использовать |
|---|---|---|---|
|
Small |
до 100 |
до 10 |
Одиночный агент |
|
Medium |
100–300 |
10–20 |
Одиночный агент |
|
Large |
300 |
20 |
Оркестратор + сабагенты |
|
Сложный пайплайн |
любой |
любой |
Оркестратор + сабагенты |
Граница «medium / large» наша. У вас она может проходить иначе: зависит от того, насколько связан код в проекте.
Самая дорогая ошибка при работе с оркестратором и сабагентами: «давайте у нас будет сабагент-планировщик, сабагент-кодер, сабагент-тестировщик и сабагент-ревьюер на каждой задаче». На бумаге логично [9], на практике эти четверо проводят 70% токенов на пересказ друг другу того, что предыдущий уже сделал.
То же самое формулирует Anthropic в своих заметках по оркестратору с сабагентами: при разделении работы по ролям внутри одной задачи сабагенты тратят больше токенов на координацию, чем на саму работу. По нашим замерам, на задачах, помещающихся в контекст одного агента, оркестратор с сабагентами съедает в 3–10 раз больше токенов на эквивалентный результат.
Правильный критерий декомпозиции – не «какие роли в команде разработки», а где можно изолировать контекст.

Хорошие границы для разделения:
– Независимые исследовательские области (исследование разных модулей, разных issue, разных правил ревью).
– Слабо связанные модули с чистым интерфейсом (фронт и бэк по контракту).
– Чёрный ящик-проверка: тесты, прогон линтера, прогон бенчмарка, не нужен контекст реализации.
Плохие границы:
– Последовательные фазы одной фичи (план → код → тест), слишком много общего контекста.
– Сильно связанные компоненты, которым нужно много синхронизироваться.
– Задачи, требующие общего разделяемого состояния.
В таблице ниже – что мы у себя пробовали и к чему пришли:
|
Стратегия разбивки |
Подход |
Итог |
|---|---|---|
|
По ролям (planner/coder/reviewer) на одной фиче |
Каноничная схема разбивки по ролям |
Плохо. Дорого, медленно, теряется контекст между ролями |
|
По участкам кода: пакет / класс → сабагент |
На каждый класс свой сабагент |
Плохо. Слишком долго, оверхэд на координацию |
|
По модулям, если модули слабо связаны |
Один сабагент на модуль |
Ок |
|
По мини-подзадачам |
Каждый таск – сабагент |
Плохо. Слишком долго |
|
По группам связанных подзадач |
Несколько связанных тасков рядом |
Ок |
|
По итерациям loop-а |
Каждая итерация – свой сабагент |
Хорошо |
|
По группам правил для ревью |
Группа правил → сабагент |
Хорошо |
Когда мы только запустили оркестратор, типичный пользовательский опыт выглядел так: человек писал в чат «сделай ревью этого PR через сабагентов», оркестратор раскладывал задачу как умел, и каждый раз по-новому. Качество прыгало.
Решение оказалось не в «более умном оркестраторе», а в скиллах – markdown-файлах, которые описывают конкретный пайплайн.
Что мы кладём в скилл оркестратора:
– Какие сабагенты вызывать и в каком порядке.
– Какой возвращаемый результат ожидается от каждого.
– Сколько итераций в loop-е (мы не уходим выше 4 для ревью и 5 для генерации, после этого качество перестаёт расти, а токенов жжёт всё больше).
– Acceptance criteria и checklists для итогового результата.
– Всю необходимую инфу в начале скилла, чтобы оркестратору не пришлось «исследовать» задачу самому.
Чего не кладём:
– Слишком сложной логики. LLM-модели всё ещё тупят, и скилл из 12 ветвлений ломается на пятой задаче.
Ключевой эффект: скилл легко дебажить (это просто файл), переиспользовать (между задачами и проектами) и расшарить (через репозиторий команды). Свободный промпт в чате не даёт ни одного из этих свойств.
Скиллы, которые у нас закрепились в общем доступе:
– Скилл поиска всех фич в проекте.
– Скилл итеративной разработки через спеку.
– Скилл поиска code smells.
– Скилл написания/исправления других скиллов (мета).
На задачах, где оркестратор с сабагентами обоснован, мы видим 1.5–2× больше токенов по сравнению с одиночным агентом – это плата за параллельность и изоляцию. На задачах, где он не обоснован, расход уходит в 3–10×. Цифры – наш замер на 24 задачах внутреннего бенчмарка (старшая модель Claude Opus, апрель 2026; 6 задач на каждый класс: ревью PR, триажинг issue, TDD-пайплайн, поиск code smells), методологию опубликуем отдельно (скоро в отдельной статье).
Параллельный шаг оркестратора с N сабагентами идёт дольше самого медленного из N. На review-loop с 5 сабагентами на PR ~10k LoC у нас выходит около 70 минут реального времени (старшая модель Claude Opus, ~180 tool calls суммарно по всем сабагентам, в основном чтение PSI и файлов). Дорого, но один человек руками это делал бы день.
Реальные кейсы, которые мы ловили:
– Claude в роли сабагента просил оркестратора «верни мне содержимое всех изменённых файлов», попытка обойти контракт на компактный summary через social-engineering оркестратора.
– Сабагент-ревьюер периодически решал, что задача не «отревьюить», а «исправить и отревьюить», и начинал писать в файлы.
– Оркестратор иногда не понимал, какую задачу кому делегировать, и запускал двух сабагентов с одинаковыми описаниями. Это вопрос промпта оркестратора и скилла, мы это лечим.
Папка .tasks (по умолчанию <projectRoot>/.tasks, путь конфигурируется) копит артефакты, которые нужны были на минуту: дифф, который уже применён, отчёт, который уже сведён. У нас она в .gitignore и периодически чистится скриптом.
В сабагентах приходится заново собирать контекст для каждого вызова. Это ровно та цена, которую вы платите за изоляцию. Часть контекста (AGENTS.md [10], правила проекта, общие скиллы) кэшируется автоматически, но «релевантные файлы под эту задачу» сабагенту приходится искать заново.
Координационный оверхэд тоже значимый. На каждом вызове сабагента вы тратите токены на обязательные тулы: report_progress для апдейтов, report_result для возврата. На задачах, где сама работа измеряется минутами, это терпимо. На быстрых задачах это и есть основной расход.
– Контекст – главный ограничитель LLM-агента. Не промпт, не модель, не RAG. Если контекст захламлён, деградация модели становится существенной.
– Оркестратор с сабагентами – это инженерное решение проблемы контекста, а не «более умный AI». Поэтому такая схема помогает только там, где проблема контекста реально есть.
– Делите по контекстным границам, не по ролям. Planner / coder / reviewer на одной фиче – это анти-паттерн. Но роль reviewer в любом виде важна: без отдельного ревью-шага (в виде сабагента-ревьюера, отдельной итерации в loop’е или по группам правил) результат не выверить.
– На малых задачах (≤100 LoC, ≤10 файлов) одиночный агент дешевле и часто лучше. Не зовите оркестратор на каждый чих.
– Используйте скиллы (markdown-файлы с алгоритмом), а не свободные промпты. Это единственный способ получить воспроизводимый пайплайн.
– 3–10× по токенам и заметно дольше по реальному времени – нормальная цена за оркестратор с сабагентами. Если выигрыша по качеству нет, вы платите впустую.
А у вас как? Если использовали сабагентов, по каким границам декомпозиция реально окупилась? Любопытно сверить наш «делите по контексту, не по ролям» с вашим опытом, пишите в комментариях.
Через две недели после публикации соберём вопросы из комментариев под этой статьёй и закроем их вживую: разберём ваши кейсы, покажем настройку оркестратора и сабагентов на реальных проектах, ответим на всё, что не влезло в текст.
По архитектуре из статьи
1. Как понять, что в моём чате контекст уже «захламлён» и пора создавать новый чат?
2. Как быть, если есть одна большая задача, связанная с одним компонентом?
3. Граница Medium/Large — ваш эмпирический порог. Как найти свой?
По сабагентам в продукте Veai
4. Чем сабагент Veai отличается от sub-agents в Claude Code и task-agent в Cursor?
5. Как выглядит UI оркестратора: видно ли, какой сабагент работает, можно ли его остановить
6. Как сабагенты Veai используют PSI-индекс IntelliJ вместо grep, и почему это выигрывает в токенах?
7. Как запустить свой скилл и расшарить его внутри команды?
По продукту Veai — безопасность, модели, enterprise
8. Какие модели поддерживает плагин и можно ли подключить свой LLM-эндпоинт (on-prem / vLLM / российские провайдеры)?
9. Что уходит в провайдера модели при работе сабагента, а что остаётся локально?
10. Как Veai ведёт себя на monorepo 4M+ LoC и можно ли запустить оркестратор из CI?
11. Чем Veai отличается от Claude Code, Junie, JetBrains AI Assistant и Cursor именно на больших задачах?
По цифрам и экономике
12. Какие реальные ценники по токенам на ревью PR ~10k LoC и на поиск code smells по модулю?
13. Как вы считаете 1.5–2× и 3–10× на внутреннем бенчмарке 24 задач? Какая методология?
14. Когда экономически не окупается звать оркестратор, даже если задача Large?
Чтобы понять формат, который будет полезен большинству, проголосуйте в коротком опросе:
Что хотите увидеть на воркшопе в первую очередь?
Живой разбор кейсов из комментариев под статьёй
Пошаговая настройка оркестратора и сабагентов в JetBrains IDE
Сравнение «одиночный агент vs оркестратор с сабагентами» на одной и той же задаче
Скиллы (markdown-алгоритмы) и как их писать под свой проект
Замеры: токены, время, качество — методология и цифры
Q&A с разработчиками плагина без сценария
Свой вопрос для разбора — пишите в комментариях или в наш чат: https://t.me/veai_devs [11]. Ссылку на регистрацию опубликуем там же.
Автор: dirvika
Источник [12]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/30171
URLs in this post:
[1] опытом: http://www.braintools.ru/article/6952
[2] Lost in the Middle (Liu et al., 2023): https://arxiv.org/abs/2307.03172
[3] Anthropic Engineering: Effective context engineering: https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents
[4] «How we built our multi-agent research system»: https://www.anthropic.com/engineering/built-multi-agent-research-system
[5] ошибкой: http://www.braintools.ru/article/4192
[6] task-01.md: http://task-01.md
[7] task-02.md: http://task-02.md
[8] паттерн Geoff Huntley: https://ghuntley.com/ralph/
[9] логично: http://www.braintools.ru/article/7640
[10] AGENTS.md: http://AGENTS.md
[11] https://t.me/veai_devs: https://t.me/veai_devs
[12] Источник: https://habr.com/ru/companies/veai/articles/1034208/?utm_campaign=1034208&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.