Мультиагентные системы на n8n: оркестрация LLM в реальных пайплайнах

Что в n8n называют мультиагентной системой и где проходит граница

Если открыть r/n8n и поискать "multi-agent", найдёшь десятки скриншотов: цепочка из трёх-четырёх AI Agent нод, стрелки между ними, гордая подпись "my multi-agent system". Проблема в том, что большинство из них не агентные системы. Это пайплайны с красивым названием.

Разница принципиальная. Линейный AI-пайплайн берёт входные данные, прогоняет через узлы по порядку и отдаёт результат. Каждый узел не знает, что делают остальные, не может передать задачу обратно или в сторону, не хранит контекст между вызовами. Это автоматизация с языковой моделью внутри. Полезная, но не агентная.

Настоящая мультиагентная система держится на четырёх вещах.

Первая: общая память или общий контекст. Агенты должны видеть, что уже сделали другие. Без shared memory каждый агент работает вслепую, и вся "агентность" разваливается на изолированные вызовы LLM.

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

Третья: делегирование и рефлексия. Worker-агент выполнил задачу, вернул результат, critic-агент оценил его и отправил обратно на доработку. Или оркестратор переформулировал задачу, потому что первый ответ не подошёл. Петля обратной связи обязательна.

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

В n8n на практике всё это реализуется через комбинацию: AI Agent нода с инструментами, где часть инструментов сама является вызовом другого агента (tool-agent pattern), плюс хранилище состояния через memory-ноды или внешний стор. Без memory-ноды между агентами получаешь именно то, о чём пишут на r/n8n: "я подключил пять агентов, но они не понимают друг друга".

Терминология в 2026 году уже устоялась. Orchestrator принимает задачу верхнего уровня и решает, кому её отдать. Worker выполняет конкретную, ограниченную задачу: парсит данные, пишет код, ищет по базе знаний. Router анализирует результат и выбирает следующий шаг, часто это отдельный промпт без тяжёлого контекста. Critic валидирует выход worker-а по заданным критериям и возвращает feedback. Tool-agent это агент, который оркестратор вызывает как инструмент через функциональный вызов.

Когда один AI Agent с несколькими инструментами полностью закрывает задачу? Когда задача однородная: суммаризация документа, ответ на вопрос по базе знаний, генерация текста по шаблону. Один агент с RAG-инструментом и парой API-вызовов справляется лучше, чем переусложнённая оркестрация. Я видел системы, где три агента делали то, что один делал чище и дешевле, просто потому что автор хотел "мультиагентность".

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

Диаграмма: pipeline и multi-agent архитектуры с общей памятью между агентами

Pipeline гонит данные последовательно через каждый узел, а multi-agent позволяет агентам обращаться к общей памяти в любом порядке.

Архитектурные паттерны: orchestrator-workers, router, reflexion

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

Orchestrator-workers. Один агент-оркестратор получает задачу целиком, декомпозирует её на подзадачи и раздаёт воркерам. Воркеры специализированы: один умеет работать с базой, другой пишет код, третий читает PDF. Оркестратор не знает деталей реализации каждого; он знает только, кому что отдать и как собрать результаты обратно. В n8n это выглядит как главный AI Agent, который через Sub-workflow ноду вызывает дочерние workflow. Каждый воркер живёт в своём workflow и получает на вход только то, что ему нужно.

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

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

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

Reflexion и self-healing. Исполнитель генерирует ответ. Критик проверяет его по заранее заданным критериям: корректность, полнота, соответствие формату. Если критик недоволен, он возвращает ревью исполнителю с конкретными замечаниями, и цикл повторяется. В n8n это петля: AI Agent (исполнитель) → AI Agent (критик) → условный узел → обратно к исполнителю или выход.

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

Self-healing немного другое. Там агент сам ловит ошибку выполнения инструмента (HTTP 500, невалидный JSON, отказ API) и переформулирует запрос к инструменту. Это не рефлексия над качеством, это устойчивость к сбоям. В n8n реализуется через Error Trigger или retry-логику внутри Custom Code ноды.

Hierarchical agents. Это обобщение orchestrator-workers на несколько уровней. Агент верхнего уровня вызывает агентов второго уровня, те вызывают агентов третьего. Sub-workflow нода в n8n делает это нативно: вызов дочернего workflow выглядит с точки зрения родителя как обычный инструмент. Иерархия нужна, когда задача слишком большая, чтобы её декомпозировал один оркестратор, или когда домены пересекаются и нужна промежуточная координация.

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

Какой паттерн брать:

Задача Паттерн
Параллельная обработка независимых кусков Orchestrator-workers
Несколько доменов, разные промпты/модели Router
Высокие требования к качеству вывода Reflexion
Глубокая декомпозиция сложных задач Hierarchical agents
Устойчивость к сбоям инструментов Self-healing (retry loop)

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

Схема паттернов оркестратор-воркеры, роутер и рефлексия для мульти-агентных систем

Три базовых паттерна мульти-агентных систем: оркестратор раздаёт задачи воркерам, роутер выбирает нужного агента, рефлексия запускает самопроверку результата.

Сборка orchestrator-workers воркфлоу в n8n: пошагово

Начинаю с точки входа. Chat Trigger ловит сообщение пользователя и пробрасывает его в AI Agent, который у меня выполняет роль диспетчера. В системном промпте оркестратора я прямо описываю доступных воркеров и условия их вызова. Не "ты умный помощник", а конкретика: какие задачи бывают, какие инструменты есть, в каком формате звать.

Кусок промпта оркестратора, который реально работает у меня в проде:

Ты диспетчер. Доступные воркеры:
- invoice_extractor: извлечение данных из счетов (PDF, JPG)
- contract_classifier: классификация типа договора
- entity_resolver: матчинг контрагентов с базой

Для каждой подзадачи вызови соответствующий tool с JSON по схеме task_envelope.
Если задач несколько, вызывай параллельно.
Никогда не придумывай данные сами, только через воркеры.

Воркеры. Каждый сидит в отдельном workflow со своим триггером Execute Workflow Trigger. Подключаю их к оркестратору через ноду Call n8n Workflow Tool: один tool = один воркер. Это даёт мне три вещи. Версионирование по отдельности, изолированный лог выполнения и возможность гонять воркер руками без оркестратора.

Контракт между оркестратором и воркером строгий, JSON конверт:

{
  "task": "extract_invoice_data",
  "context": {
    "file_id": "{{$json.file_id}}",
    "language": "ru"
  },
  "expected_output": {
    "schema": "invoice_v2",
    "required": ["number", "date", "total", "vat"]
  },
  "timeout_ms": 45000
}

Поле task использую внутри воркера для роутинга, если воркер обслуживает несколько связанных операций. expected_output.schema подставляю в системный промпт LLM-ноды воркера через выражение, чтобы агент знал, какие поля он обязан вернуть. timeout_ms читаю в первой ноде воркера и прокидываю в HTTP Request и в Wait, чтобы оркестратор не висел вечно.

Сбор результатов. Если воркеры вызывались параллельно через несколько tool calls подряд, AI Agent сам соберёт ответы в финальное сообщение, тут ничего делать не надо. Но когда мне нужен детерминированный merge (например, склеить инвойс с резолвом контрагента в одну запись), я вешаю после оркестратора ноду Merge в режиме Combine by Position или Combine by Matching Fields по file_id. Для семантической агрегации, где надо взвесить противоречивые ответы воркеров, ставлю второго агента с reduce-промптом:

На вход придут N результатов от воркеров в массиве items.
Сверь поля. При расхождении выбери значение с большим confidence.
Верни единый JSON по схеме invoice_v2.
Если данные несовместимы, верни {"error": "conflict", "fields": [...]}.

Сбои. Воркер падает редко, но больно: либо LLM провайдер вернул 429, либо PDF-парсер подавился сканом. В каждом воркере держу Error Trigger в отдельном workflow, который пишет инцидент в таблицу и шлёт алерт. А retry делаю на уровне ноды: в настройках Call n8n Workflow Tool включаю Retry On Fail, ставлю 4 попытки с Wait Between Tries и формулой экспоненты {{ 1000 * Math.pow(2, $runIndex) }} мс. Получается 1с, 2с, 4с, 8с. Для 429 от OpenAI этого хватает почти всегда.

Один нюанс, на котором я сжёг пару вечеров. Если воркер вернул ошибку, но оркестратор-агент должен это пережить и продолжить с остальными задачами, в Call n8n Workflow Tool обязательно включи "Continue On Fail" и в выходе оборачивай результат в {"status": "error", "reason": ...}. Иначе агент получит исключение, потеряет контекст параллельных вызовов и начнёт галлюцинировать ответ за упавшего воркера. Проверено.

Общая память агентов: Postgres Memory, Redis и векторные хранилища

Когда я первый раз собрал мультиагентную схему в n8n (Supervisor + три воркера: billing, shipping, support), я наступил на классические грабли. У каждого AI Agent нода своя Window Buffer Memory. Это значит, что billing-агент не знает, что support-агент уже спросил у клиента номер заказа. Клиент пишет "ну я же только что сказал", а система переспрашивает. Изоляция памяти ломает иллюзию единого ассистента быстрее, чем кривой prompt.

Минимально рабочее решение, с которого я советую начинать: Postgres Chat Memory нода с одним общим session_id на всех агентов в воркфлоу. Не на агента, а на разговор. В n8n это делается тривиально, надо подставить в поле Session ID одно и то же выражение, например ={{ $json.chatId }} во всех Memory нодах. Все агенты пишут и читают из одной таблицы n8n_chat_histories, и Supervisor видит реплики воркеров как часть истории. Этого хватает примерно для 80% сценариев поддержки, где диалог короткий и линейный.

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

Я делаю двухуровневую схему:

Short-term, Redis. Хеш с оперативным состоянием сессии: какой агент сейчас активен, какой intent распознан последним, ID клиента, флаги. Это не история сообщений, это рабочая память маршрутизатора. Читается за доли миллисекунды, переживает рестарт n8n, легко чистится по TTL.

// Структура записи в Redis для shared memory
HSET agent:session:{sessionId} 
  last_intent "refund_request" 
  active_agent "billing_worker" 
  customer_id "c_8821" 
  updated_at "2026-05-01T10:22:14Z"
EXPIRE agent:session:{sessionId} 3600

TTL в час я ставлю по умолчанию, для саппорта норм. Для B2B-сценариев с длинными кейсами поднимаю до суток и обновляю expiry при каждом сообщении (EXPIRE после HSET). В n8n это нода Redis с операциями Hash Set и Expire, либо одна Execute Command нода с pipeline.

Long-term, векторка. Сюда уходит всё, что должно искаться семантически: фрагменты диалогов, извлечённые факты о клиенте, решения по тикетам. Я гоняю и Qdrant, и pgvector, выбор по инфре. Если Postgres уже стоит для n8n, проще не плодить сервисы и взять pgvector. Если нагрузка серьёзная и нужны фильтры по метаданным с приличной скоростью, Qdrant выигрывает.

Поверх векторки вешается Vector Store Question Answer Tool, и каждый агент получает его в tools. Агент сам решает, нужно ли лезть в долговременную память. Это и есть RAG поверх собственной истории диалога. Порог косинусной близости и число возвращаемых фрагментов подбираются под конкретный корпус: слишком низкий порог даёт шум, слишком высокий режет релевантные куски.

Стратегия вытеснения и сжатия. Без неё векторка за месяц превращается в свалку. Я делаю отдельный summarization-воркфлоу, который запускается каждые N сообщений или по крону раз в сутки. Он берёт сырые сообщения из Postgres, прогоняет через дешёвую модель (gpt-4o-mini или Llama 3.3 локально) с промптом "выдели факты о клиенте, решения и нерешённые вопросы", складывает результат в векторку с метаданными type=summary, а сырой кусок помечает как обработанный. Так в long-term живут только сжатые знания, а не транскрипт.

Один нюанс, на котором я сжёг пару дней. Если агентов несколько и они пишут в одну Postgres Memory параллельно (например, Supervisor вызывает billing и shipping одновременно через Parallel ноду), порядок сообщений в истории может нарушаться. Решение: либо последовательный вызов через Supervisor, либо писать в Redis Stream с временными метками и периодически сливать в Postgres отсортированно. Я остановился на последовательном, параллелизм в диалогах редко даёт выигрыш, который окупает геморрой с консистентностью.

Двухуровневая память агента: Redis для краткосрочного контекста, Qdrant для долгосрочных векторных записей

Redis хранит текущий диалог и горячие переменные, Qdrant берёт на себя долгосрочную семантическую память с поиском по близости.

Выбор моделей под роли: GPT-5.2, Claude 4, Gemini Flash, локальные через Ollama

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

Orchestrator: GPT-5.2 или Claude 4 Opus. Это мозг, который читает запрос пользователя, разбирает его на подзадачи и решает, кому что отдать. Здесь нельзя экономить. Мне нужен длинный контекст (минимум 200k токенов, потому что в оркестратор летит вся история диалога плюс описания инструментов), точная декомпозиция и стабильное следование схеме JSON для плана. GPT-5.2 у меня выигрывает на сложных мультишаговых планах с ветвлениями, Claude 4 Opus лучше держит длинные технические ТЗ без галлюцинаций промежуточных шагов. Я обычно ставлю Opus, если в проекте много кода и документации, и GPT-5.2, если задачи разнородные.

Router/классификатор: Gemini 2.5 Flash или GPT-5 mini. Это быстрая модель на входе, которая решает "это вопрос про биллинг, юридический, технический или smalltalk". Один промпт, один JSON на выходе, латентность критична. На нагрузке от 50k запросов в день экономия по сравнению с использованием большой модели колоссальная. Что быстрее и точнее на пограничных случаях именно для вашей задачи, стоит замерить самостоятельно.

Воркеры по доменам. Тут уже без универсалов:

  • Текст, копирайт, длинные ответы клиенту, ревью кода: Claude 4 Sonnet. Тон живее, меньше воды, лучше работает с инструкциями стиля.
  • Логика, расчёты, цепочки tool calling с 5+ инструментами подряд: GPT-5 (не mini). Function calling у OpenAI всё ещё надёжнее, особенно когда нужно дёргать API в строгом порядке с обработкой ошибок.
  • PII-чувствительные данные (медкарты, паспорта, внутренние HR-документы): Llama 3.3 70B локально через Ollama на своём железе. Никакие персональные данные не уходят к провайдерам. Качество ниже, чем у Sonnet, но для извлечения сущностей и суммаризации хватает с запасом. Держу на двух A100, кванты Q5_K_M, throughput около 35 токенов/сек на одного клиента.

Critic-агент: всегда другая модель, не та, что исполняла. Это правило, которое я выстрадал. Модель, склонная к определённым ошибкам, при самопроверке подтверждает их значительно чаще, чем ловит. Ставлю Claude 4 Sonnet критиком к GPT-исполнителю и наоборот. На сложных проверках (фактологическая верификация, поиск противоречий в плане) критиком идёт Opus, даже если воркер был дешёвой моделью.

Цены и расчёт

Актуальные тарифы на модели меняются, поэтому сверяйтесь напрямую с pricing-страницами OpenAI, Anthropic и Google. Ценообразование часто обновляется, и любые конкретные цифры в тексте устаревают быстрее, чем статья доходит до читателя.

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

Fallback-цепочка

Провайдеры падают. OpenAI, Anthropic, Google периодически сталкиваются с инцидентами и деградацией. Без резерва агент молчит, клиенты пишут злые сообщения.

В n8n я делаю это через Switch ноду после AI Agent: проверяется код ошибки и доступность. Цепочка для оркестратора: GPT-5.2 → Claude 4 Opus → GPT-5 (деградация по качеству, но работает). Для воркера-текстовика: Sonnet → GPT-5 → Llama 3.3 локально. Для роутера: Gemini Flash → GPT-5 mini.

Переключение делаю не по длинному таймауту, а по нескольким подряд 5xx или быстрому таймауту. Состояние "провайдер деградирует" держу в Redis с TTL, чтобы не долбиться в мёртвый эндпоинт каждым новым запросом. После TTL пробую снова. Простая схема, но именно она стабилизирует SLA при инцидентах у провайдеров.

Tool calling и интеграция с внешними системами

Агент без инструментов это просто чат-бот с лишним промптом. Реальная работа начинается там, где LLM получает доступ к API, базам и внутренним сервисам. В n8n у меня обычно три слоя инструментов, и я держу их отдельно по уровню доверия.

HTTP Request Tool это универсальный мост ко всему, что говорит по REST. Описание инструмента (поле description) LLM читает как часть промпта, поэтому я пишу его жёстко: какой эндпоинт, какие параметры обязательны, что вернётся, и главное чего делать НЕ надо. Например, для CRM прописываю "только чтение карточек по customer_id, никаких mutations". Это не защита, это подсказка модели. Реальная защита ниже.

Code Tool на JavaScript беру там, где LLM нельзя доверять арифметику, форматирование сумм, проверку лимитов, работу с деньгами. Модель отлично роняет копейку в дробях и охотно округляет 49999 до 50000 если её попросить "проверь лимит". Поэтому любая операция с финансовыми последствиями идёт через детерминированный код, а LLM только собирает аргументы.

// Code Tool: безопасная обёртка над платёжным API
const { amount, currency, customer_id, idempotency_key } = $input.item.json;

if (amount > 50000) {
  return { error: 'amount_exceeds_agent_limit', requires_human: true };
}

const res = await this.helpers.httpRequest({
  method: 'POST',
  url: 'https://api.billing.internal/refunds',
  headers: { 'Idempotency-Key': idempotency_key },
  body: { amount, currency, customer_id },
  json: true
});

return { status: res.status, refund_id: res.id };

Здесь есть три вещи, на которые я обращаю внимание у себя в команде. Первое: лимит 50000 живёт в коде, а не в промпте. Если завтра LLM решит "ну тут особый случай, можно и больше", она упрётся в return с requires_human. Второе: Idempotency-Key прокидывается в headers и генерируется выше по графу (обычно как hash от ticket_id + action_type). Если агент дёрнул refund, упал на таймауте и ретраит, биллинг вернёт тот же refund_id, а