Всем привет! ИИ-агенты и их производные стремительно ворвались в повседневную практику разработки, вызывая восторг у менеджеров и головную боль у архитекторов. Если с одиночным агентом обычно не возникает проблем, то когда их становится много, появляется вопрос: как ими управлять? В этой статье рассмотрим основные подходы к созданию управляющего слоя в такой системе. На примере выясним, почему не все очевидные подходы работают и какие классические архитектурные паттерны актуальны в новой реальности. И, конечно же, я расскажу, как это работает в Домклик. Обещаю, будет интересно!
Проблемы оркестрации
Давайте разберёмся, в чём заключается сложность взаимодействия агентов. Казалось бы, всё работает и хорошо, дай им базу, навешай API сверху — и этот кубик можно встраивать в бизнес-процессы. Один агент (или просто LLM) легко встраивается в любую архитектуру, но когда бизнес требует множества агентов, особенно с разными ролями, возникает интересный вопрос: как обеспечить совместимость агентов и повторяемость результатов? Основные препятствия включают разроз��енную автоматизацию, недоверие к ИИ и негибкость систем. Добавьте к этому сложность реагирования на изменения: по статистике, более 72% компаний с ИИ-агентами не успевают их актуализировать.
Для наглядности рассмотрим пример. Представим, что нужно разработать систему для определения ингредиентов блюда. Первый слой — ИИ-агент на основе омниканальной LLM (рецепт можно прислать в виде фотографии, текста или голосовым сообщением). Второй слой — отдельная LLM, классифицирующая и нормализующая результат с помощью RAG. Отдельным компонентом над всем этим является API, через который внешние потребители ставят задачи и получают результаты.

На схеме сервис не выглядит сложным. Однако первый слой испытывает наибольшую логическую нагрузку: он должен распознать входящие данные, выбрать оптимальный путь для обработки, собрать и интерпретировать результаты. То есть ему необходимо вначале выделить последовательность шагов. Существует несколько способов решения этой задачи.
Динамическая оркестрация через LLM
Самый простой подход заключается в том, что у нас есть умный ИИ, который самостоятельно определяет, что и как нужно делать. Это отличный вариант, но он скрывает множество подводных камней. Ключевая проблема в том, что всё управление качеством плана сосредоточено на промпте. Любое изменение приводит к появлению нового плана по формату. Даже если мы приведём вывод к единому стандарту, то можем столкнуться с километровым промптом. Кроме того, в таком подходе полностью отсутствует аудит: почему был составлен именно такой план и выбрана такая последовательность. Не стоит забывать и о галлюцинациях: иногда модель может выдать нечто невообразимое, что полностью сломает всю обработку.

Детерминированная логика
Старые надёжные гвозди логики: вся последовательность жёстко фиксируется условиями, управляющими вызовами. Получаем высокую стабильность (при должном уровне тестирования), но минимальную гибкость. Любое изменение превращается в настоящий квест, требующий пересмотра тестов.
Гибридный подход
Сочетание первого и второго вариантов. Здесь использование BPMN значительно упрощает задачу, позволяя внедрить проверку решений LLM и предоставить возможность гибко управлять логикой. Архитектура нашего сервиса может выглядеть следующим образом:

Изоляция агентов и возможность контроля
Переход от схемы к реализации ставит перед нами интересную задачу: как изолировать агентов? На первый взгляд, этот сервис должен быть единым: один контекст, отсутствие сетевых издержек, простота добавления хранилищ или кешей результатов. Однако это сопряжено с большими рисками: чем больше мы встраиваем в один сервис, тем меньше контроля за происходящим внутри. И если API пропустит новомодную атаку prompt injection, то на выходе можем получить ощутимое воздействие на другие системы, вплоть до повреждения данных. Поэтому каждый агент запускается в собственной, полностью изолированной «песочнице», например, на уровне контейнера. Такой подход также обеспечивает гибкое управление ресурсами, сбор метрик и логов.
Пример Docker для нескольких агентов с реестром функций
services:
# Агенты
orchestrator-agent:
build:
context: .
dockerfile: agents/orchestrator_agent/Dockerfile
environment:
AGENT_ID: orchestrator_agent
TASK_QUEUE_URL: ${MQ_ORCHESTRATOR_TASK_QUEUE_URL}
RESULT_QUEUE_URL: ${MQ_RESULT_QUEUE_URL}
ORCHESTRATOR_VISION_TASK_QUEUE_URL: ${MQ_VISION_TASK_QUEUE_URL}
depends_on:
- function-registry
networks:
- agents-net
vision-agent:
build:
context: .
dockerfile: agents/vision_agent/Dockerfile
environment:
AGENT_ID: vision_agent
TASK_QUEUE_URL: ${MQ_VISION_TASK_QUEUE_URL}
RESULT_QUEUE_URL: ${MQ_RESULT_QUEUE_URL}
depends_on:
- function-registry
networks:
- agents-net
video-agent:
build:
context: .
dockerfile: agents/vision_agent/Dockerfile
environment:
AGENT_ID: vision_agent
TASK_QUEUE_URL: ${MQ_VISION_TASK_QUEUE_URL}
RESULT_QUEUE_URL: ${MQ_RESULT_QUEUE_URL}
depends_on:
- function-registry
networks:
- agents-net
# Реестр функций
function-registry:
build: ./function_registry
ports:
- "8001:8000"
networks:
- agents-net
# Роутер тасок
task-router:
build: ./task_router
ports:
- "8002:8000"
environment:
TASK_QUEUE_URL: ${MQ_ORCHESTRATOR_TASK_QUEUE_URL}
RESULT_QUEUE_URL: ${MQ_RESULT_QUEUE_URL}
restart: unless-stopped
networks:
- agents-net
networks:
agents-net:
driver: bridge
Протоколы взаимодействия между агентами
Исходя из нашей схемы, сразу просится event-based паттерн. Однако современные тенденции также диктуют применение различных протоколов: A2A, ACP, MCP и т.п. В случае с MCP ситуация относительно проста, но при работе с агентами возникают сложности. Каждый агент должен выполнять свою роль и иметь чётко определённые каналы взаимодействия с другими агентами. Как мы изначально верно предположили, проще создать собственный протокол на основе любой шины. Это позволит полностью настроить взаимодействие и маршрутизацию, эффективно управлять полезной нагрузкой и реализовать сквозной мониторинг. Этот подход особенно актуален для существующих микросервисных архитектур, где уже используются собственные протоколы. В таком случае агенты могут обрести некую степень самостоятельности, интегрируясь с другими сервисами вне основного маршрутизатора.
Пример сообщения для общения между агентами
{
"message_id": "msg_12345",
"correlation_id": "corr_67890",
"timestamp": "2024-07-15T12:00:00Z",
"protocol_version": "1.0",
"message_type": "task",
"sender": "http_gateway",
"recipients": ["broadcast", "vision_agent", "socials_agent", "text_recognize_agent", "uploader_agent"],
"content": {
"task_id": "task_abc123",
"task_type": "multimodal_analysis",
"priority": 5,
"deadline": "2024-07-15T12:30:00Z",
"payload": {
"text": "Проанализируй изображение и опиши что на нем происходит",
"image_url": "https://storage.example.com/image.jpg",
"audio_url": "https://storage.example.com/audio.mp3"
},
"requirements": {
"response_format": "json",
"quality_level": "high",
"context_ttl": 3600
},
"context": {
"session_id": "sess_xyz",
"user_id": "user_123",
"previous_tasks": ["task_prev1", "task_prev2"]
}
},
"metadata": {
"idempotency_key": "idemp_key_123",
"source": ["http_api", "direct_queue", "vlm_layer"],
"retry_count": 0
}
}A2A можно использовать в качестве промежуточного слоя для решения задач идентификации агентов.
А если добавить BPMN

BPMN в сочетании с любым движком интерпретации схем может значительно облегчить жизнь, если количество агентов сильно возрастает. Несмотря на дополнительные накладные расходы, такой движок может стать центральным узлом оркестрации, обеспечивая гибкое управление логикой. Логика может быть описана как на границах взаимодействия с агентом, так и внутри него. Приведу пример схемы с сайта Camunda, которая иллюстрирует сразу несколько паттернов, встречающихся в BPMN. Их также можно использовать по отдельности, включая по мере необходимости в вашем бизнес-процессе.

Мультиагентный паттерн
Наш базовый сценарий, повторённый в BPMN. Мы просто копируем и описываем логику на основе сообщений (message flow) между пулами.

Human-in-the-loop
Когда бизнес-процесс прерывается и требуется вмешательство человека, схема BPMN обычно переходит в режим ожидания. В зависимости от процесса отправляются уведомления, и схема требует работы вручную. Агент также может запросить помощь человека, если сомневается в решении или этого необходимо бизнес-процессу. Для этого достаточно функциональности событий BPMN-нотации.
Long-running processes
Если процесс работает слишком долго, его можно прервать по истечении заданного времени (таймауту). Это может произойти автоматически через события или по решению агентов.
Prompt chaining
Управление процессом путём корректировки промптов: по результатам работы одного агента корректируется или заново составляется промпт для следующего.
Orchestrator-workers
Для улучшения оркестрации решения о маршрутизации задач принимают сразу несколько LLM или задач с логикой. В этом случае необходимо реализовать подходящий по сценарию алгоритм консенсуса.
Evaluator-optimizer
Это отдельная роль LLM, предназначенная для оценки полученных результатов и их последовательного улучшения. Компонент можно использовать как в связке с несколькими оркестраторами, так и для улучшенной обработки пограничных событий.
А как же Dify, n8n, Langflow
Рассмотрим инструменты для графической визуализации таких сценариев. По нашему опыту, они значительно упрощают разработку. Вместо развёртывания нескольких микросервисов достаточно создать схему в визуальном редакторе и запустить его. Однако, как всегда, есть нюансы при внедрении. Так, потребуется держать дополнительные ресурсы для поддержания работоспособности самой системы. Ожидается снижение производительности, так как всю обработку необходимо будет проводить внутри этих инструментов. Мониторинг и метрики также будут привязаны внутри них, что затруднит их вывод в существующие системы мониторинга. Кроме того, всегда придётся тащить за собой всю неиспользуемую функциональность в лице плагинов, коннекторов и прочего. Но зато они очень удобны, когда нужно в целом реализовать прототип и проверить, как всё это стыкуется между собой.
А как в Домклик
Мы реализовали несколько агентов и создали собственную платформу для их управления. Для модерации и OCR у нас существуют отдельные пайплайны, частично использующие BPMN. В настоящее время мы оптимизируем пайплайны OCR, добавляя маршрутизаторы на основе BPMN-схем. Придерживаться единого паттерна по организации оркестрации между агентами сложно, так как их количество пока невелико и они только осваиваются бизнесом на собственных задачах. Кроме того, прежде чем решать задачи оркестрации, необходимо настроить guardrails — набор правил и ограничений, которые не позволят агентам «разгуляться».
Подробнее про ИИ-агентов в Домклик вы можете узнать из статьи моей коллеги @Quvele.