Multi Agent Patterns

Два обязательных класса паттернов MAS: параллелизм (fan-out / map-reduce / pipeline) и критик/ревьюер. Они закрывают две системные слабости, растущие со сложностью: без разбиения задач не получишь выигрыша от мультиагента (платишь только цену оркестрации), а без критика система «не доводит» задачу из-за накопления ошибок.

Суть

MAS даёт выигрыш не от «много агентов», а от правильного разделения работы (параллелизм) и контроля качества (критик). Иначе агенты ходят последовательно, множат токены и latency — и проигрывают одному LLM.

Паттерны параллелизма

  • Fan-out / Fan-in — планировщик разбивает задачу на N разных подзадач, N исполнителей берут их одновременно, агрегатор склеивает. Классика research: «проанализируй 10 конкурентов» → 10 агентов по сайту → один собирает таблицу. Время ≈1× самого медленного, не N×.
  • Map-Reduce — всем агентам одинаковый промпт, но разные куски данных (reducer объединяет). Для однородной большой задачи: «прочитай 200 PDF-страниц, собери цитаты». Разновидность fan-out без планировщика — структура задана заранее.
  • Pipeline parallel — конвейер: Stage A берёт batch 2, пока Stage B обрабатывает то, что отдал A. Это про throughput, не latency (одна задача быстрее не станет, но за час прогонишь больше) — модерация, классификация, ETL.

Выбор по природе задачи: подзадачи разные → fan-out; одинаковые → map-reduce; поток → pipeline.

Критик / ревьюер (must-have)

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

  • Проблема каскадных ошибок (compounding errors): если точность исполнителя 90%, то к 4-му звену без промежуточного контроля она падает до ~65% — ошибки перемножаются. Критик «разрывает цепь»: ошибка ловится до того, как пойдёт дальше (ссылка на CTO Replit).
  • Виды критика: critic-after-executor (линейная проверка), multi-critic ensemble (ансамбль специалистов), self-critique (самопроверка — слабее, см. выше).
  • Защита от зацикливания: жёсткий лимит итераций критика (1–3); если после третьей правки не принято — эскалация на человека (Human in the Loop). Это и есть автокоррекция без постоянного HITL.

Каталог паттернов: у каждого своя уязвимость

Факультатив про архитектуру MAS в продакшене раскладывает пространство решений на девять шаблонов и к каждому даёт «паспорт»: суть, домен, уязвимость, приём против неё. Ценность именно в третьем пункте — паттерн выбирают не по красоте схемы, а по тому, готовы ли вы платить за его слабое место.

Одноагентный подход с инструментами. Домен — простые ассистенты. Уязвимость — эффект свалки: точность падает по гиперболе с ростом числа инструментов, и перелом наступает примерно после семи. Дальше не «чуть хуже», а заметно хуже; лечится дроблением на специализированных агентов (см. Tool Calling).

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

Координатор с динамической маршрутизацией. Диспетчер раскидывает запросы по изолированным исполнителям, у каждого чистый и короткий системный промпт (ориентир — до 500 токенов). Уязвимость — координатор становится единой точкой отказа: ошибка классификации отправляет пользователя в тупиковую ветку. Приёмы: не тратить на роутинг тяжёлую генерацию, брать лёгкую модель со строгим JSON или вовсе семантический поиск по эмбеддингам, и обязательно ставить температуру в ноль — маршрутизатор не должен «творить» (см. Agent Routing).

Ориентир «до 500 токенов» стоит на качестве работы исполнителя, и у него есть побочный эффект по деньгам: такой промпт короче минимального кэшируемого префикса у любой актуальной модели Anthropic (512–4096 токенов, см. Prompt Caching), то есть каждый вызов субагента оплачивается по полной ставке. На редких вызовах это неважно, на веерном запуске десятков исполнителей — заметная статья. Выбор между «короткий промпт ради точности» и «промпт длиннее порога ради кэша» решается замером, а не по умолчанию.

Рефлексия с обратной связью от среды. Отличается от критика тем, что оценку даёт не другая модель, а среда: компилятор, линтер, тесты. Накопленный лог ошибок и удачных исправлений подаётся в контекст следующей попытки. Домен — ETL, генерация SQL под меняющуюся схему. Критическая оговорка: без изолированной песочницы паттерн означает выполнение произвольного сгенерированного кода на хосте (см. Agent Sandboxing).

Три оставшихся шаблона вынесены в отдельные заметки: Hierarchical Decomposition (планировщик и воркеры, правило D_max ≤ 3), Hybrid Orchestration (вероятностный слой над детерминированным) и Event Driven Agents (шина событий вместо оркестратора).

Общий вывод каталога, который стоит держать отдельно от самих паттернов: начинать надо с малого. Один агент с инструментами стабильнее роя, и переход к мультиагентности оправдан только когда задачу нельзя надёжно решить за один проход, нужен динамический вызов инструментов или ветвление, которое не описать через if-else.

Матрица по движению информации

Пять названий Anthropic полезны не как ещё один каталог, а как короткая диагностика того, кто хранит контекст и как распространяются находки:

Структурный вопрос Паттерн Цена
результат можно проверить по явным критериям? generator–verifier цикл может не сойтись
подзадачи короткие, ограниченные и сводятся одним владельцем? orchestrator–subagent оркестратор становится информационным bottleneck
независимым разделам нужен долгоживущий локальный контекст? persistent agent team конфликты общих ресурсов и сложное завершение
работа возникает из событий, а состав обработчиков растёт? message bus причинность и потерянные события сложнее трассировать
агенты должны немедленно строить работу на находках друг друга? shared state дубли, гонки и реактивные петли

Различие subagent и teammate проходит по времени жизни контекста: первый возвращает один bounded result и завершается, второй сохраняет специализацию через несколько заданий. Различие message bus и shared state — по семантике записи: событие запускает действие, состояние накапливает знание. Если события используются только для публикации находок, это уже сигнал в пользу shared state.

Эти варианты не отменяют правило минимальной системы. После того как необходимость MAS уже доказана, начинать разумно с orchestrator–subagent и переходить к другой топологии после наблюдаемого отказа; Dynamic Agent Workflows может собрать такой гибрид под задачу, но не делает его бесплатным.

Роли по правам и модели, а не по предметной области

Обычное деление подагентов — по теме: «агент по базе данных», «агент по фронтенду». Есть другое, и оно решает конкретные отказы: делить по правам и по цене модели.

Роль Инструменты Модель Что не может
родитель планирование, вопросы пользователю сильная не исследует и не правит сам
исследователь только чтение и поиск дешёвая, бюджет шагов мал ничего не меняет и никого не спрашивает
исполнитель полный набор, включая запись и команды сильная не задаёт вопросов пользователю

Три отказа одиночного агента, которые это лечит, и ни один из них не чинится уплотнением контекста:

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

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

Право задавать вопросы принадлежит только родителю — иначе вопрос приходит из середины делегированной задачи, вне контекста разговора, и пользователю нечем на него ответить осмысленно.

Инструмент делегирования при этом — слой маршрутизации: родитель говорит, что нужно, инструмент выбирает роль, проверяет право её породить и возвращает результат. Добавление роли должно быть добавлением ветки, а не переделкой. Модель и бюджет шагов задаются на роль, и это же связывает делегирование с Agent Routing: выбор модели тут не по сложности запроса, а по тому, что роли позволено делать.

Сколько кругов критики и сколько критиков

Лимит кругов выводится так же, как лимит итераций агентного цикла: от глубины задачи и потолка стоимости, в паре с детектором отсутствия прогресса (ReAct). Специфика пары критик↔исполнитель в том, что признак застревания здесь нагляднее: если замечания критика от круга к кругу перестали меняться, следующий круг ничего не добавит — эскалировать надо на этом месте, а не по исчерпании счётчика.

Несколько критиков окупаются не количеством, а разнородностью. Два критика с одинаковым промптом дают почти одинаковый вердикт и удваивают цену; смысл появляется, когда каждый смотрит своей оптикой — корректность, безопасность, соответствие требованиям. Тот же принцип лежит за коллегией судей в LLM as Judge. И то же ограничение: всё, что проверяется кодом, критику не отдают вовсе — детерминированный гейт дешевле и надёжнее любого числа критиков.

Протокол координации — это общее состояние

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

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

Что это даёт:

  • Агента можно заменить или убрать, не трогая соседей: связь идёт через поля состояния, а не через имена функций. Добавить редактора между ресерчером и райтером — это правка маршрута, а не правка агентов.
  • Порядок виден в одном месте. Когда агенты зовут друг друга напрямую, схема системы существует только в головах: чтобы её восстановить, надо прочитать все вызовы во всех агентах.
  • Состояние само становится протоколом. Набор полей и есть контракт между участниками, и его можно типизировать — в отличие от неявной договорённости «ресерчер вернёт строку, а райтер как-нибудь разберёт».

Цена — дисциплина полей: общее состояние легко превращается в свалку, куда каждый агент дописывает своё. Помогает то же, что и в обычном коде: объявленный тип состояния и явный контракт узла на вход и выход (см. LangGraph Reliability).

Отдельно стоит держать в голове, что это тот же приём, который делает возможной Pregel Model в LangGraph: раз агенты общаются только через состояние, их можно исполнять параллельно и сливать результаты по явным правилам.

Изоляция режет историю, а не рабочую область

«Изоляция контекста подагента» звучит так, будто подагент стартует с чистого листа. В работающих реализациях это не так, и различие существенное: подагенту передаётся всё состояние родителя, у которого заменено одно поле — история сообщений, вместо которой кладётся единственная формулировка задачи. Общая рабочая область при этом остаётся общей и после возврата вливается обратно правилом слияния.

Разделение проходит по линии «рассуждения против артефактов»:

  • история изолируется, потому что чужие рассуждения — главный источник порчи: подагент, видящий, как родитель обсуждал соседнюю задачу, начинает решать её;
  • рабочая область разделяется, потому что иначе результат придётся передавать через текст ответа, а это ровно тот канал, который мы бережём.

Из той же конструкции следует, что подагент отдаёт родителю последнее сообщение, а не траекторию: сорок шагов промежуточных чтений остаются в его изолированной истории и умирают вместе с ней, а наверх идёт ответ плюс изменения в общей области.

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

Связано с

  • Multi Agent Systems — паттерны как причина, по которой MAS вообще окупается
  • Hierarchical Decomposition — планировщик, воркеры, синтезатор и предел глубины
  • Hybrid Orchestration — разделение вероятностного и детерминированного слоёв
  • Event Driven Agents — реактивная модель без оркестратора
  • Agent Routing — механика координатора и почему для него нужна температура 0
  • Agent Sandboxing — обязательное условие для паттерна рефлексии
  • Cohort Diversity — параллельные ветки, сошедшиеся к одному замыслу: дефект, который топология не ловит
  • Batch Close Protocol — вторая половина веера: как пачку сводят и чем фиксируют её закрытие
  • Generator Evaluator — критик = внешний верификатор (асимметрия проверки)
  • CrewAI — где роли исполнитель/критик собираются в crew
  • Agent CostControl — параллелизм/критик влияют на токены и latency
  • LangGraph Nodes and Edges — маршрут как рёбра: единственное место, где живёт топология
  • Pregel Model — что становится возможным, когда агенты общаются только через состояние