Архитектура «оркестратор + сабагенты» на одном экране: оркестратор держит план и раздаёт подзадачи сабагентам.
Один AI-агент в чате – это удобно, пока задача помещается в контекст. Как только она начинает разъезжаться по 30 файлам, четырём ролям и циклу «исследуй – реализуй – отревьюй – поправь», единый чат превращается в свалку: модель путает, какой шаг где, тащит решения из первой задачи в третью и стабильно проседает по качеству начиная с заполнения окна примерно наполовину. Схема «оркестратор + сабагенты» – это инженерный ответ на проблему: оркестратор держит план и раздаёт подзадачи изолированным сабагентам.
Готовы поделиться нашим опытом: как это устроено
Дисклеймер. Сравнений с Claude Code, Junie, Cursor, JetBrains AI Assistant, OpenAI Swarm, LangGraph и другими реализациями оркестратора с сабагентами в этой статье нет – это отдельный жанр, требующий одинакового бенча. Цель статьи – показать архитектурные решения и причины, по которым мы к ним пришли. Материал – конспект внутреннего доклада и практики на нашем плагине.
TL;DR
-
Качество ответа LLM падает по мере заполнения контекста. На наших внутренних замерах в JetBrains-плагине просадка становится заметной после ~50% заполненности и резко обваливается после ~85%. Похожая картина описана в Lost in the Middle (Liu et al., 2023) и в Anthropic Engineering: Effective context engineering.
-
Сабагент – это не «агент, который зовёт агента». Это изолированный подпроцесс со своими тулами и единственным каналом возврата –
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» пишут о 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: информация в середине длинного контекста используется хуже, чем на краях.
Проблемы:
– 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 раз. После – принудительная остановка и возврат с ошибкой в оркестратор. На практике даже на слабых моделях этой эвристики в 10 итераций хватает для завершения задачи.
Когда оркестратор с сабагентами реально выигрывает у одиночного агента
Это место, где много маркетинга. Мы у себя сформулировали честно: оркестратор с сабагентами даёт выигрыш на трёх классах задач, и почти везде вне этих трёх классов проигрывает одиночному агенту.
Project-wide read-only
Задачи, в которых нужно пройти по всему проекту, что-то посмотреть и вернуть структурированный отчёт. Состояние нигде не меняется, шаги независимы.
Что мы у себя гоняем через сабагентов:
– Прогон ревью-чеклистов по всему PR / по всему модулю (пакет → сабагент).
– Триажинг issue из трекера (GitHub / GitLab / YouTrack): воспроизводится / не воспроизводится, severity, дубли (один сабагент на батч issue).
– Инвентаризация фич продукта (один сабагент на функциональную область).
– Сборка полной документации проекта (по модулям).
– Поиск code smells по списку правил (батч связанных правил → один сабагент).
Параллельность тут даёт реальный выигрыш по реальному времени, а изоляция контекста – по precision: сабагент, у которого в контексте связанные правила по организации кода по пакетам, не отвлекается на проверку IDE-специфичных дедлоков.
Сложные пайплайны с явной разбивкой на роли
Когда у задачи действительно есть разные этапы или разные роли, и они работают на разных кусках кода. Не «одна фича + три роли», а именно «разные scope».
Примеры из нашей практики:
– TDD-пайплайн: сабагент-1 пишет тесты по описанию задачи, сабагент-2 пишет реализацию под зелёные тесты, сабагент-3 ревьюит. Каждому в контексте лежит ровно его кусок, не больше.
– SDD + TDD: перед всем этим оркестратор зовёт сабагента-планировщика, который читает issue из трекера или спеку и раскладывает её на task-01.md, task-02.md, … в sharedDir.
– Итеративная разработка через спеку: один сабагент-кодер на каждую итерацию, один общий ревьюер в конце каждой итерации, обновление спеки между итерациями, планирование следующей итерации.
– Автогенерация домашних заданий по шаблону.
Loop-based пайплайны
Внутри одного агента loop работает плохо: к третьей итерации модель уже «знает», что было в первых двух, и не может посмотреть на свой код свежим глазом. С отдельным сабагентом на каждую итерацию это перестаёт быть проблемой, у каждого свой контекст.
Кейсы, где это даёт самый явный выигрыш:
– Поиск багов: сабагенты ищут параллельно, пока оркестратор собирает агрегированный отчёт.
– Поиск code smells: один проход – один сабагент, оркестратор склеивает.
– Параллельный сбор информации о проекте.
Те же задачи можно делать одним чатом с Ralph Wiggum loop (паттерн Geoff Huntley: один и тот же промпт зациклен в while-true, пока не выполнено условие), но тогда нужно вручную следить за размером контекста. На длинной дистанции это всё равно сваливается в захламление.
Где сабагенты строго хуже
Тоже честно. Если задача попадает в этот список, оркестратор с сабагентами дороже и хуже одиночного агента.
Первый случай – задача целиком помещается в контекст. Фикс мелкого бага, мелкое улучшение существующей фичи, рефакторинг до 100 LoC и до 10 файлов. Один чат справится за один шаг, оркестратор будет 4 шага собирать контекст для сабагентов и ещё 2 склеивать ответы.
Второй случай – общий контекст важен и связный. Когда вы решаете несколько связанных задач, и предыдущие решения должны влиять на следующие, оркестратор с сабагентами тут вреден. Каждый сабагент будет переспрашивать и переделывать. Лучше один чат с компрессией.
Третий случай – нужно каждый шаг смотреть глазами. Если задача требует ручной валидации после каждого шага, оркестратор просто добавляет лишний слой между вами и кодом. Все передачи между сабагентами всё равно ложатся на вас.
Эмпирическое правило по объёму, к которому мы пришли:
|
Объём задачи |
LoC |
Файлов |
Что использовать |
|---|---|---|---|
|
Small |
до 100 |
до 10 |
Одиночный агент |
|
Medium |
100–300 |
10–20 |
Одиночный агент |
|
Large |
300 |
20 |
Оркестратор + сабагенты |
|
Сложный пайплайн |
любой |
любой |
Оркестратор + сабагенты |
Граница «medium / large» наша. У вас она может проходить иначе: зависит от того, насколько связан код в проекте.
Как мы декомпозируем и почему по ролям почти всегда плохо
Самая дорогая ошибка при работе с оркестратором и сабагентами: «давайте у нас будет сабагент-планировщик, сабагент-кодер, сабагент-тестировщик и сабагент-ревьюер на каждой задаче». На бумаге логично, на практике эти четверо проводят 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 и файлов). Дорого, но один человек руками это делал бы день.
Что LLM пытается хакнуть
Реальные кейсы, которые мы ловили:
– Claude в роли сабагента просил оркестратора «верни мне содержимое всех изменённых файлов», попытка обойти контракт на компактный summary через social-engineering оркестратора.
– Сабагент-ревьюер периодически решал, что задача не «отревьюить», а «исправить и отревьюить», и начинал писать в файлы.
– Оркестратор иногда не понимал, какую задачу кому делегировать, и запускал двух сабагентов с одинаковыми описаниями. Это вопрос промпта оркестратора и скилла, мы это лечим.
sharedDir накапливается
Папка .tasks (по умолчанию <projectRoot>/.tasks, путь конфигурируется) копит артефакты, которые нужны были на минуту: дифф, который уже применён, отчёт, который уже сведён. У нас она в .gitignore и периодически чистится скриптом.
Известные ограничения
В сабагентах приходится заново собирать контекст для каждого вызова. Это ровно та цена, которую вы платите за изоляцию. Часть контекста (AGENTS.md, правила проекта, общие скиллы) кэшируется автоматически, но «релевантные файлы под эту задачу» сабагенту приходится искать заново.
Координационный оверхэд тоже значимый. На каждом вызове сабагента вы тратите токены на обязательные тулы: report_progress для апдейтов, report_result для возврата. На задачах, где сама работа измеряется минутами, это терпимо. На быстрых задачах это и есть основной расход.
Важно:
– Контекст – главный ограничитель LLM-агента. Не промпт, не модель, не RAG. Если контекст захламлён, деградация модели становится существенной.
– Оркестратор с сабагентами – это инженерное решение проблемы контекста, а не «более умный AI». Поэтому такая схема помогает только там, где проблема контекста реально есть.
– Делите по контекстным границам, не по ролям. Planner / coder / reviewer на одной фиче – это анти-паттерн. Но роль reviewer в любом виде важна: без отдельного ревью-шага (в виде сабагента-ревьюера, отдельной итерации в loop’е или по группам правил) результат не выверить.
– На малых задачах (≤100 LoC, ≤10 файлов) одиночный агент дешевле и часто лучше. Не зовите оркестратор на каждый чих.
– Используйте скиллы (markdown-файлы с алгоритмом), а не свободные промпты. Это единственный способ получить воспроизводимый пайплайн.
– 3–10× по токенам и заметно дольше по реальному времени – нормальная цена за оркестратор с сабагентами. Если выигрыша по качеству нет, вы платите впустую.
А у вас как? Если использовали сабагентов, по каким границам декомпозиция реально окупилась? Любопытно сверить наш «делите по контексту, не по ролям» с вашим опытом, пишите в комментариях.
Workshop / вебинар через 2 недели
Через две недели после публикации соберём вопросы из комментариев под этой статьёй и закроем их вживую: разберём ваши кейсы, покажем настройку оркестратора и сабагентов на реальных проектах, ответим на всё, что не влезло в текст.
Вопросы, на которые ответим вживую
По архитектуре из статьи
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. Ссылку на регистрацию опубликуем там же.
Автор: dirvika


