Что это решает
Система ИИ-агентов появляется, когда одному агенту становится тесно: инструментов десятки, системная инструкция разрослась на страницы, контекст забит чужими данными, а сбой в одном месте портит всю задачу. Разделение снимает четыре конкретные боли — конфликт инструментов при выборе, переполнение окна, смешение прав на запись и невозможность понять, на каком шаге всё пошло не туда. Взамен появляются швы: каждый стык между агентами нужно описать контрактом, иначе система превращается в испорченный телефон с умножившимся счётом за токены.
Как устроено
Топологии
Супервизор и исполнители. Главный агент разбирает задачу и вызывает подчинённых как обычные инструменты: имя, аргументы, результат. Подчинённый не знает о существовании соседей и получает только вырезку контекста. Гибко, дороже всех остальных вариантов, труднее предсказать траекторию.
Конвейер. Фиксированный порядок ролей, каждая получает от предыдущей результат в оговорённой схеме: извлечь → проверить → записать. Дёшево, предсказуемо, легко отлаживать. Стартовать разумно отсюда.
Событийная шина. Агенты подписаны на события и пишут результаты обратно в очередь. Подходит для длинных асинхронных процессов, где шаги растянуты во времени и участники меняются.
Генератор и критик. Один делает работу, второй проверяет её на чистом контексте, не видя рассуждений первого. Изоляция контекста здесь и есть весь смысл: критик, которому показали ход мыслей автора, соглашается с ним.
По каким осям делить роли
Три признака, каждый из которых оправдывает выделение отдельного агента:
- Инструменты. Наборы мешают друг другу — модель путает похожие функции из разных доменов.
- Данные. Одному нужны сырые выгрузки, второму — сжатые выводы. Держать и то и другое в одном окне расточительно.
- Права. Один читает откуда угодно, второй пишет в боевую систему. Разделение по правам превращается в разделение по агентам автоматически.
Остальные поводы (красиво выглядит на схеме, «пусть будет команда специалистов») стоят денег и не дают ничего.
Границы
- Контракт входа и выхода — JSON Schema, а не просьба «перескажи результат». Свободный пересказ теряет поля и добавляет выдуманные.
- Изоляция контекста. Подчинённый получает вырезку, необходимую для его задачи, и ничего сверх.
- Общая память — внешняя. Файл, таблица, база, к которой обращаются оба агента. Передача знаний текстом через промпт деградирует на каждом переходе.
- Бюджет на подзадачу. Свой
max_stepsи лимит токенов на каждом узле, иначе один зациклившийся исполнитель съедает бюджет всей системы. - Дедлайн и поведение при таймауте. Что возвращается наверх, если подчинённый не ответил: частичный результат, ошибка, значение по умолчанию.
- Сквозной
trace_id. Один идентификатор задачи проставляется во все записи журнала на всех узлах. - Антизацикливание. Счётчик повторных вызовов одной роли и запрет на кольцевые обращения.
- Единственный писатель. Право записи в каждую систему держит один узел; остальные формируют для него данные.
Цена
Каждый агент прогоняет собственную историю через модель. Веерный запуск десятков параллельных агентов ради простой однотипной операции — разметки, классификации, извлечения полей — сжигает бюджет там, где справился бы батч из нескольких элементов в одном запросе к модели попроще. Сложность связки оправдана, когда узлы делают разную работу.
Правило: роль выделяется в отдельного агента только тогда, когда два дела в одном конфликтуют по инструментам, правам или контексту.
Как подключить
Шаг 1. Начать с одного агента и довести его до рабочего состояния. Система из двух плохих агентов работает хуже одного плохого.
Шаг 2. Дождаться конфликта. Признаки для выделения роли: модель регулярно берёт не тот инструмент из похожих; окно переполняется сырыми данными; часть операций требует прав, которые не хочется давать всему агенту; куски задачи идут в разном ритме (один шаг мгновенный, другой длится минуты).
Шаг 3. Описать контракт. Для каждой роли — схема входа и схема выхода, обе валидируются кодом на границе. Ответ, не прошедший валидацию, возвращается автору с текстом ошибки, а не идёт дальше по цепочке.
Шаг 4. Выбрать топологию. Конвейер, пока не доказано, что нужен супервизор. Порядок ролей описывается в коде оркестратора, а не в промпте.
Шаг 5. Общий журнал. Одна таблица на все узлы: trace_id, agent, step, tool, аргументы, усечённый результат, токены, длительность. Без общей таблицы разбор сбоя превращается в сопоставление разрозненных логов по времени.
Шаг 6. Ограничители на каждом узле. Шаги, токены, таймаут, allowlist инструментов конкретной роли.
Шаг 7. Агрегатор с правилом разрешения конфликтов. Когда два узла вернули несовместимые ответы, решение принимает код по явному правилу (приоритет источника, свежесть данных, передача человеку), а не третья модель «на подумать».
Шаг 8. Права по возрастанию. Сначала все подчинённые только читают, единственный писатель — головной узел с подтверждением. Расширение прав идёт по одной операции.
Шаг 9. Прогон на наборе. Тот же золотой набор, что и для одиночного агента, чтобы сравнение было честным.
Полезные сценарии
- Обработка входящего потока: классификатор определяет тип, профильный агент готовит ответ, отправитель проверяет адресата и шлёт.
- Работа с кодом: планировщик разбирает задачу, исполнитель правит файлы, ревьюер читает диф на чистом контексте.
- Регулярный отчёт: сборщики по источникам работают параллельно, сводящий агент собирает единый документ.
- Поддержка: диалоговый агент говорит с клиентом, поисковый достаёт факты из базы знаний, эскалатор решает, когда звать человека.
- Дежурство: наблюдатель по расписанию ловит аномалию, диагност собирает контекст, человек получает готовую сводку.
- Миграция данных: экстрактор читает источник, валидатор проверяет по схеме, загрузчик пишет с предварительным прогоном вхолостую.
Ограничения
Задержка и стоимость складываются по всей цепочке, а при веерном запуске умножаются. Система из пяти узлов отвечает заметно дольше одиночного агента на той же задаче.
Надёжность перемножается. Если каждый узел справляется в девяти случаях из десяти, цепочка из четырёх узлов доходит до конца заметно реже — арифметика беспощадна, и лечится она сокращением числа узлов, а не уговорами в промпте.
Отладка сложнее на порядок восприятия: сбой проявляется на последнем узле, а причина сидит в неполной вырезке контекста на первом. Без сквозной трассировки такие случаи не разбираются.
Пересказ теряет данные. Любой переход, где вместо схемы используется свободный текст, накапливает искажения от узла к узлу.
Правила расползаются. Два агента с независимыми инструкциями со временем начинают трактовать одну ситуацию по-разному; общий источник правил обязателен.
Гонки за общий ресурс дают дубли: два узла с правом записи создадут две записи по одному событию. Единственный писатель и ключ идемпотентности закрывают это.
Соблазн делить рано — самая частая ошибка. Разбиение добавляет швы, и каждый шов надо обслуживать.
Как проверить результат
Взять одну задачу и прочитать её сквозную трассировку по trace_id от входа до финала: кто кого вызвал, с какими аргументами, сколько шагов и токенов потратил каждый узел. Если трассировка не читается за пару минут, журнал придётся чинить раньше самой системы.
Дальше — цифры по набору прогонов:
- доля задач, дошедших до конца без вмешательства;
- распределение сбоев по узлам: какой узел роняет цепочку чаще прочих;
- доля ответов подчинённых, не прошедших валидацию схемы, — прямая мера качества контрактов;
- суммарные токены и время на задачу против тех же чисел у одиночного агента на том же наборе;
- число повторных запусков одной роли — признак зацикливания;
- проверка на дубли: сравнить число записей в целевой системе с числом обработанных кейсов.
Отдельный тест — намеренная поломка. Выключить один подчинённый узел и посмотреть, что вернёт система: внятную ошибку с указанием места, частичный результат или зависание до таймаута. Ответ на этот вопрос показывает, готова ли связка к бою лучше любых прогонов по счастливому пути.
