Мульти-агентные AI-системы: архитектура, фреймворки и практическая реализация на Python

Практическое руководство по мульти-агентным AI-системам: архитектурные паттерны, сравнение фреймворков LangGraph и CrewAI, протоколы MCP и A2A, примеры кода на Python и советы для production.

Введение: от одного агента к команде

В первой статье этой серии мы разобрали, как работает Function Calling и Tool Use — механизмы, позволяющие LLM-агенту взаимодействовать с внешним миром: вызывать функции, обращаться к API, выполнять действия. Во второй статье мы построили полноценный RAG-пайплайн — от индексации документов до генерации ответов с опорой на контекст. Те статьи были про то, как сделать одного агента умным и полезным. А сегодня поговорим о том, как заставить нескольких агентов работать вместе.

Почему это важно? Потому что реальные задачи редко укладываются в возможности одного агента.

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

Цифры подтверждают тренд. По данным McKinsey, 23% организаций уже масштабируют агентные AI-системы, а ещё 39% активно экспериментируют. Прогнозы на 2026 год говорят о том, что до 80% корпоративных рабочих нагрузок будут опираться на AI-управляемые системы. И вот что особенно интересно — мульти-агентная перекрёстная валидация повышает точность результатов до 40%, просто за счёт того, что один агент проверяет работу другого.

В этой статье мы разберём архитектурные паттерны мульти-агентных систем, сравним ключевые фреймворки 2026 года, напишем рабочий код на LangGraph и CrewAI, разберёмся в протоколах MCP и A2A, и честно обсудим, когда мульти-агентные системы — это оверинжиниринг. Итак, поехали.

Архитектурные паттерны мульти-агентных систем

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

Supervisor (центральный координатор)

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

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

Hierarchical (иерархический)

Расширение паттерна Supervisor на несколько уровней. Главный супервайзер управляет несколькими подсупервайзерами, каждый из которых координирует свою группу агентов. Напоминает организационную структуру крупной компании: CEO → директора направлений → руководители отделов → исполнители.

Этот паттерн хорош для задач, которые естественным образом распадаются на независимые подзадачи. Например, система автоматизации маркетинга: один подсупервайзер отвечает за контент (копирайтер, дизайнер, SEO-оптимизатор), другой — за аналитику (сборщик данных, аналитик, визуализатор), третий — за дистрибуцию (email-агент, SMM-агент, рекламный агент). Красиво ложится на бизнес-структуру, правда?

Fully Connected (полносвязная сеть)

Каждый агент может общаться с каждым напрямую, без центрального координатора. Звучит демократично, но на практике — это хаос, если не ввести строгие протоколы взаимодействия. Количество возможных связей растёт квадратично: для 5 агентов — 10 связей, для 10 — уже 45.

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

Dispatcher (интеллектуальная маршрутизация)

Вариация паттерна Supervisor, где координатор не просто делегирует задачи, а выполняет интеллектуальную маршрутизацию на основе анализа запроса. Диспетчер классифицирует входящий запрос и направляет его к наиболее подходящему агенту (или цепочке агентов). В отличие от супервайзера, диспетчер обычно не собирает результаты — направил запрос и забыл.

Типичный пример: входящий запрос в техподдержку. Диспетчер определяет, что это проблема с биллингом, и направляет к биллинг-агенту. Или видит, что это технический баг, и перенаправляет к агенту технической поддержки. Простой, эффективный, хорошо масштабируемый паттерн.

Sequential Chain (последовательная цепочка)

Агенты выстроены в конвейер: выход первого является входом для второго, выход второго — входом для третьего, и так далее. Самый простой паттерн, и он идеально подходит для задач с чёткой последовательностью шагов: извлечение данных → анализ → генерация отчёта → проверка качества.

Ограничение здесь довольно очевидное: если одному из агентов в середине цепочки вдруг нужна информация от агента, стоящего позади, система ломается. Для таких случаев придётся переходить к циклическим графам или возвращаться к паттерну с супервайзером.

Обзор фреймворков 2026 года

Рынок фреймворков для мульти-агентных систем за последний год стал заметно зрелее. Если в 2024 году это были экспериментальные библиотеки для энтузиастов, то к 2026-му несколько решений уверенно вышли на уровень production-ready. Давайте разберём ключевых игроков.

LangGraph

Мой текущий фаворит для production-систем (и я говорю это, попробовав все остальные). LangGraph — фреймворк от создателей LangChain, построенный на концепции направленных графов. Каждый агент — это узел графа, рёбра определяют потоки данных между ними. Это даёт исключительную гибкость: можно строить любые паттерны — от простой последовательной цепочки до сложных циклических графов с условными переходами.

Ключевые преимущества: работа с состоянием (state management) из коробки, поддержка стриминга, встроенное persistence для возобновления прерванных воркфлоу, и — что немаловажно — бенчмарки показывают, что он в 2.2 раза быстрее CrewAI. LangChain сейчас активно рекомендует паттерн supervisor через функцию create_supervisor, где супервайзер использует подчинённых агентов как инструменты (tools).

CrewAI

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

Версия 0.152.0 поддерживает два основных процесса: Sequential (агенты работают друг за другом) и Hierarchical (агент-менеджер распределяет задачи). Параметр allow_delegation=True позволяет агентам делегировать подзадачи друг другу. CrewAI отлично подходит для быстрого прототипирования и систем, где бизнес-логика хорошо ложится на ролевую модель. Но для сложных графов с условными переходами и циклами LangGraph будет удобнее.

OpenAI Agents SDK

Эволюция экспериментального проекта Swarm, теперь — production-ready SDK от OpenAI. Ключевые фичи: Handoffs (передача управления между агентами), Guardrails (встроенные ограничители), Sessions (управление состоянием диалога), Human-in-the-loop (подключение человека в критических точках), Tracing (полная трассировка выполнения) и поддержка Realtime Agents.

Если ваш стек уже построен на OpenAI и менять провайдера вы не планируете, Agents SDK — логичный выбор. Он хорошо интегрируется с остальной экосистемой OpenAI и предоставляет удобный механизм хэндоффов, когда один агент передаёт управление другому вместе с контекстом беседы. Из минусов — привязка к экосистеме OpenAI (впрочем, для кого-то это и плюс).

Google ADK (Agent Development Kit)

Открытый фреймворк от Google, представленный на Cloud NEXT 2025. ADK предлагает три типа workflow-агентов: Sequential (последовательное выполнение), Parallel (параллельное выполнение) и Loop (циклическое выполнение). В феврале 2026 добавлена поддержка TypeScript.

Главное отличие ADK — нативная поддержка протокола A2A (Agent-to-Agent), о котором мы поговорим ниже. Если вы строите систему, где агенты от разных провайдеров должны взаимодействовать друг с другом, ADK с A2A — пока единственное по-настоящему зрелое решение для этого сценария.

AutoGen (Microsoft)

AutoGen делает ставку на разговорную архитектуру: агенты общаются между собой в формате диалога, динамически распределяя роли. Фреймворк отлично поддерживает human-in-the-loop — включение человека в диалог агентов на любом этапе.

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

Практика: мульти-агентная система на LangGraph

Ладно, хватит теории — переходим к коду. Построим мульти-агентную систему для анализа новостей с использованием паттерна Supervisor в LangGraph. Система будет состоять из трёх агентов: исследователь (ищет информацию), аналитик (анализирует найденное) и редактор (формирует финальный текст).

Сначала установим необходимые пакеты:

pip install langgraph langchain-openai langchain-core

Теперь определим агентов и построим граф:

from typing import Annotated, Any
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.tools import tool
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.prebuilt import create_react_agent

# Инициализируем LLM
llm = ChatOpenAI(model="gpt-4o", temperature=0.1)


# --- Определяем инструменты для агентов ---

@tool
def search_news(query: str) -> str:
    """Поиск свежих новостей по заданной теме."""
    # В реальной системе здесь был бы вызов News API или веб-поиска
    return (
        f"Результаты поиска по запросу '{query}':\n"
        "1. AI-стартапы привлекли $12 млрд инвестиций в Q1 2026\n"
        "2. Новый стандарт A2A получил поддержку 150+ организаций\n"
        "3. 80% предприятий планируют внедрение агентных систем к концу 2026"
    )


@tool
def analyze_sentiment(text: str) -> str:
    """Анализ тональности и ключевых трендов в тексте."""
    return (
        f"Анализ текста:\n"
        "- Общая тональность: позитивная\n"
        "- Ключевые тренды: рост инвестиций, стандартизация, "
        "массовое внедрение\n"
        "- Уровень достоверности: высокий (множественные источники)"
    )


@tool
def format_report(content: str, style: str = "brief") -> str:
    """Форматирование контента в структурированный отчёт."""
    return f"[Отчёт в стиле '{style}']\n{content}"


# --- Создаём специализированных агентов ---

researcher = create_react_agent(
    llm,
    tools=[search_news],
    prompt=(
        "Ты — исследователь. Твоя задача — находить актуальную "
        "информацию по заданной теме. Используй инструмент поиска "
        "новостей. Возвращай только факты, без интерпретаций."
    ),
)

analyst = create_react_agent(
    llm,
    tools=[analyze_sentiment],
    prompt=(
        "Ты — аналитик. Твоя задача — анализировать предоставленную "
        "информацию, выявлять тренды, оценивать достоверность "
        "и делать выводы. Будь объективен и критичен."
    ),
)

editor = create_react_agent(
    llm,
    tools=[format_report],
    prompt=(
        "Ты — редактор. Твоя задача — взять результаты исследования "
        "и анализа, и сформировать из них краткий, понятный отчёт "
        "для бизнес-аудитории. Структурируй информацию."
    ),
)


# --- Строим граф с паттерном Supervisor ---

from langgraph.prebuilt import create_supervisor

# Супервайзер автоматически управляет маршрутизацией
# между агентами на основе текущего состояния задачи
supervisor = create_supervisor(
    llm,
    agents={
        "researcher": researcher,
        "analyst": analyst,
        "editor": editor,
    },
    prompt=(
        "Ты — координатор аналитической команды. "
        "Управляй процессом анализа: сначала поручи "
        "исследователю собрать информацию, затем аналитику — "
        "проанализировать её, и наконец редактору — "
        "оформить финальный отчёт. "
        "Убедись, что каждый этап завершён перед переходом "
        "к следующему."
    ),
)

# Компилируем граф
app = supervisor.compile()

# --- Запускаем систему ---

result = app.invoke({
    "messages": [
        HumanMessage(
            content="Подготовь краткий аналитический обзор "
                    "о текущем состоянии рынка AI-агентов"
        )
    ]
})

# Выводим финальный результат
for message in result["messages"]:
    if hasattr(message, "content") and message.content:
        print(f"[{message.type}]: {message.content[:200]}...")
        print("---")

Что тут происходит? Функция create_supervisor создаёт агента-координатора, который видит подчинённых агентов как инструменты. Когда поступает запрос, супервайзер сам решает, в каком порядке вызывать агентов и когда считать задачу выполненной. При этом каждый агент — полноценный ReAct-агент со своими инструментами и системным промптом.

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

Практика: команда агентов в CrewAI

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

pip install crewai crewai-tools
from crewai import Agent, Task, Crew, Process

# --- Определяем агентов как «членов экипажа» ---

researcher = Agent(
    role="Исследователь рынка AI",
    goal=(
        "Находить актуальную и достоверную информацию "
        "о рынке AI-агентов, технологических трендах "
        "и ключевых игроках"
    ),
    backstory=(
        "Ты — опытный технологический аналитик с 10-летним "
        "стажем. Специализируешься на рынке искусственного "
        "интеллекта. Известен своей тщательностью в проверке "
        "фактов и умением находить неочевидные связи между "
        "трендами."
    ),
    verbose=True,
    allow_delegation=True,  # Может делегировать подзадачи
)

analyst = Agent(
    role="Стратегический аналитик",
    goal=(
        "Глубоко анализировать собранные данные, выявлять "
        "закономерности и формулировать стратегические выводы"
    ),
    backstory=(
        "Ты — аналитик из топ-консалтинговой компании. "
        "Умеешь переводить технические данные в бизнес-инсайты. "
        "Всегда подкрепляешь выводы цифрами и критически "
        "оцениваешь источники."
    ),
    verbose=True,
    allow_delegation=False,
)

editor = Agent(
    role="Главный редактор",
    goal=(
        "Создавать чёткие, структурированные отчёты, "
        "понятные бизнес-аудитории без технического бэкграунда"
    ),
    backstory=(
        "Ты — редактор технологического издания с опытом "
        "работы в деловых СМИ. Превращаешь сложные "
        "технические материалы в увлекательные и понятные "
        "тексты. Ценишь краткость и ясность."
    ),
    verbose=True,
    allow_delegation=False,
)

# --- Определяем задачи ---

research_task = Task(
    description=(
        "Исследуй текущее состояние рынка мульти-агентных "
        "AI-систем. Найди ключевые фреймворки, статистику "
        "внедрения, основных игроков и свежие тренды 2026 года. "
        "Обрати особое внимание на протоколы MCP и A2A."
    ),
    expected_output=(
        "Структурированный список фактов и данных с указанием "
        "источников. Минимум 10 ключевых фактов."
    ),
    agent=researcher,
)

analysis_task = Task(
    description=(
        "На основе собранных исследователем данных проведи "
        "стратегический анализ. Определи: 1) главные тренды, "
        "2) риски и возможности, 3) прогноз развития на "
        "ближайшие 12 месяцев. Подкрепи выводы цифрами."
    ),
    expected_output=(
        "Аналитическая записка с разделами: тренды, риски, "
        "возможности, прогноз. Каждый вывод подкреплён данными."
    ),
    agent=analyst,
    context=[research_task],  # Зависит от результатов исследования
)

editing_task = Task(
    description=(
        "Возьми результаты исследования и анализа и создай "
        "финальный отчёт для CEO технологической компании. "
        "Отчёт должен быть не длиннее одной страницы, "
        "содержать executive summary, ключевые цифры и "
        "рекомендации к действию."
    ),
    expected_output=(
        "Краткий executive-отчёт на одну страницу с "
        "чёткой структурой и конкретными рекомендациями."
    ),
    agent=editor,
    context=[research_task, analysis_task],
)

# --- Собираем команду и запускаем ---

crew = Crew(
    agents=[researcher, analyst, editor],
    tasks=[research_task, analysis_task, editing_task],
    process=Process.sequential,  # Последовательное выполнение
    verbose=True,
)

# Запуск команды
result = crew.kickoff()

print("=" * 50)
print("ФИНАЛЬНЫЙ ОТЧЁТ:")
print("=" * 50)
print(result.raw)

Сравните с LangGraph: здесь мы не строим граф, а описываем команду в терминах ролей (role), целей (goal) и предысторий (backstory). Задачи (Task) связаны через параметр context, который указывает зависимости. Процесс sequential гарантирует выполнение задач в заданном порядке.

А если нам нужна иерархическая организация? Достаточно заменить буквально одну строку:

crew = Crew(
    agents=[researcher, analyst, editor],
    tasks=[research_task, analysis_task, editing_task],
    process=Process.hierarchical,  # Менеджер распределяет задачи
    manager_llm=ChatOpenAI(model="gpt-4o", temperature=0.1),
    verbose=True,
)

В иерархическом режиме CrewAI автоматически создаёт агента-менеджера, который решает, какому агенту передать очередную задачу. По духу это близко к паттерну Supervisor в LangGraph, но с меньшим контролем над логикой маршрутизации.

Мой честный вывод: CrewAI быстрее в прототипировании и интуитивнее для людей, мыслящих в терминах организаций. LangGraph даёт больше контроля и работает быстрее в production. Строите MVP — начните с CrewAI. Строите систему на тысячи запросов в день — берите LangGraph. Я сам прошёл этот путь: начал с CrewAI, потом мигрировал на LangGraph, когда стало важно контролировать каждый шаг.

Протоколы межагентного взаимодействия: MCP и A2A

До сих пор мы говорили об агентах внутри одной системы, одного фреймворка, одного приложения. Но что если ваши агенты используют разные LLM, разные фреймворки, и вообще развёрнуты на разных серверах? Тут на сцену выходят протоколы стандартизации — и в 2026 году два из них стали де-факто стандартами.

MCP (Model Context Protocol)

MCP — открытый стандарт от Anthropic для интеграции LLM с внешними инструментами и источниками данных. Если Function Calling — это способ вызвать функцию, то MCP — стандарт того, как описывать и подключать эти функции единообразно.

Ключевая идея: любой инструмент, база данных или API описывается в стандартном формате, который понимает любой LLM-клиент. Пишете MCP-сервер один раз — и он работает с Claude, GPT, Gemini и любой другой моделью, поддерживающей протокол. Это решает проблему, с которой мы все сталкивались: для каждого нового LLM приходилось переписывать интеграции. Занятие, мягко говоря, утомительное.

В 2025-2026 годах MCP получил массовую поддержку: OpenAI, Microsoft, Google, LangChain — все ключевые игроки приняли стандарт. Экосистема MCP-серверов растёт стремительно: подключение к файловой системе, базам данных, API SaaS-сервисов, браузерам — всё уже доступно в виде готовых MCP-серверов.

Архитектура MCP достаточно проста: есть MCP-хост (приложение, в котором работает LLM), MCP-клиент (компонент, управляющий подключениями) и MCP-серверы (лёгкие процессы, предоставляющие доступ к инструментам и данным). Серверы описывают свои возможности (tools, resources, prompts), а клиент автоматически обнаруживает их и предоставляет LLM.

# Пример: простой MCP-сервер для доступа к базе данных
# (используя Python SDK для MCP)

from mcp.server import Server
from mcp.types import Tool, TextContent

server = Server("database-server")


@server.tool()
async def query_database(sql: str) -> str:
    """Выполняет SQL-запрос к аналитической базе данных.

    Args:
        sql: SQL-запрос для выполнения (только SELECT)
    """
    # Валидация: разрешаем только SELECT-запросы
    if not sql.strip().upper().startswith("SELECT"):
        return "Ошибка: разрешены только SELECT-запросы"

    # В реальной системе здесь было бы подключение к БД
    return f"Результат запроса: [данные из БД по запросу '{sql}']"


@server.tool()
async def get_table_schema(table_name: str) -> str:
    """Возвращает схему указанной таблицы.

    Args:
        table_name: Имя таблицы
    """
    schemas = {
        "orders": "id INT, customer_id INT, amount DECIMAL, "
                  "created_at TIMESTAMP, status VARCHAR",
        "customers": "id INT, name VARCHAR, email VARCHAR, "
                     "plan VARCHAR, created_at TIMESTAMP",
    }
    return schemas.get(
        table_name,
        f"Таблица '{table_name}' не найдена"
    )

Ценность MCP для мульти-агентных систем в том, что агенты получают единообразный доступ к инструментам. Один и тот же MCP-сервер базы данных может использоваться агентом-исследователем (для извлечения данных), агентом-аналитиком (для проверки гипотез) и агентом-мониторинга (для отслеживания метрик). Никакого дублирования кода — и это, поверьте, экономит часы отладки.

A2A (Agent-to-Agent Protocol)

Если MCP стандартизирует взаимодействие «агент — инструмент», то A2A стандартизирует связь «агент — агент». Этот протокол, разработанный Google и переданный в Linux Foundation, определяет, как агенты на разных платформах и фреймворках могут обнаруживать друг друга и взаимодействовать.

Центральный элемент A2A — Agent Card: JSON-файл, описывающий возможности агента. Это как визитная карточка, которую агент публикует, чтобы другие знали, что он умеет, какие форматы данных принимает и как с ним связаться.

{
  "name": "financial-analyst",
  "description": "Анализирует финансовые данные и генерирует отчёты",
  "url": "https://agents.example.com/financial-analyst",
  "version": "1.2.0",
  "capabilities": {
    "streaming": true,
    "pushNotifications": true,
    "stateTransitionHistory": true
  },
  "skills": [
    {
      "id": "financial-analysis",
      "name": "Финансовый анализ",
      "description": "Анализ финансовых показателей компании",
      "inputModes": ["text/plain", "application/json"],
      "outputModes": ["application/json", "text/markdown"]
    },
    {
      "id": "report-generation",
      "name": "Генерация отчётов",
      "description": "Создание структурированных финансовых отчётов",
      "inputModes": ["application/json"],
      "outputModes": ["application/pdf", "text/markdown"]
    }
  ],
  "authentication": {
    "schemes": ["bearer"]
  }
}

В версии v0.3 A2A добавлена поддержка gRPC в дополнение к HTTP, что значительно снижает задержки при взаимодействии между агентами. Уже более 150 организаций поддержали протокол, включая крупнейших облачных провайдеров.

MCP + A2A вместе формируют полный стек стандартизации: MCP для «вертикальной» интеграции (агент → инструменты/данные), A2A для «горизонтальной» (агент ↔ агент). В production-системе вашему агенту нужны оба: MCP для доступа к базам данных, API и файлам, A2A для общения с агентами от других команд, отделов или даже организаций.

Паттерны проектирования production-систем

Построить работающую мульти-агентную систему — это, скажем так, полдела. Заставить её надёжно работать в production — совсем другая история. Вот паттерны, которые реально помогают в боевых условиях.

Обработка ошибок и устойчивость

В мульти-агентной системе ошибки неизбежны: LLM может сгаллюцинировать, API может вернуть таймаут, агент может зациклиться. Ключевой принцип: каждый агент должен уметь gracefully деградировать.

import asyncio
from typing import Any


class ResilientAgent:
    """Обёртка для агента с обработкой ошибок."""

    def __init__(
        self,
        agent: Any,
        max_retries: int = 3,
        timeout_seconds: int = 30,
        fallback_response: str = "Агент не смог обработать запрос",
    ):
        self.agent = agent
        self.max_retries = max_retries
        self.timeout_seconds = timeout_seconds
        self.fallback_response = fallback_response

    async def invoke(self, input_data: dict) -> dict:
        """Вызов агента с ретраями и таймаутом."""
        last_error = None

        for attempt in range(1, self.max_retries + 1):
            try:
                result = await asyncio.wait_for(
                    self.agent.ainvoke(input_data),
                    timeout=self.timeout_seconds,
                )
                return result

            except asyncio.TimeoutError:
                last_error = f"Таймаут (попытка {attempt})"
                # Экспоненциальный бэкофф
                await asyncio.sleep(2 ** attempt)

            except Exception as e:
                last_error = f"Ошибка (попытка {attempt}): {e}"
                await asyncio.sleep(2 ** attempt)

        # Все попытки исчерпаны — возвращаем fallback
        return {
            "messages": [{"content": self.fallback_response}],
            "error": last_error,
            "status": "degraded",
        }

Управление стоимостью

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

  • Устанавливайте лимиты итераций. Если супервайзер не завершил задачу за 5 итераций — что-то пошло не так. Лучше вернуть частичный результат, чем сжечь весь бюджет.
  • Используйте разные модели для разных агентов. Роутер или классификатор спокойно работают на дешёвой модели (GPT-4o-mini), а агент, генерирующий финальный ответ — на мощной (GPT-4o или Claude Opus).
  • Кэшируйте результаты агентов. Если агент-исследователь уже искал информацию по теме «рынок AI-агентов» 5 минут назад, зачем делать это снова?
  • Мониторьте расход токенов по агентам. Часто один «болтливый» агент съедает 80% бюджета. Найдите его и оптимизируйте промпт или ограничьте длину ответа.

Наблюдаемость (Observability)

В обычном приложении стектрейс ошибки показывает, где что сломалось. В мульти-агентной системе всё сложнее — нужно знать: какой агент был вызван, с каким контекстом, что он вернул, почему супервайзер решил передать задачу дальше и сколько токенов потратил каждый.

Минимальный набор метрик для production:

  • Количество вызовов каждого агента и среднее время выполнения
  • Количество итераций супервайзера до завершения задачи
  • Расход токенов (input/output) по каждому агенту
  • Частота ошибок и таймаутов по агентам
  • Полный трейс: последовательность вызовов агентов с их входами и выходами

LangGraph предоставляет встроенную поддержку трейсинга через LangSmith, CrewAI логирует каждый шаг при verbose=True, а OpenAI Agents SDK имеет полноценный Tracing API из коробки. Для production-систем рекомендую дополнительно подключить Langfuse или аналог — для долгосрочного хранения и анализа трейсов это незаменимый инструмент.

Guardrails: ограничители безопасности

Когда у вас несколько агентов, каждый с доступом к инструментам, поверхность атаки увеличивается кратно. Guardrails — это ограничители, которые проверяют вход и выход каждого агента на соответствие политикам безопасности.

from typing import Callable


class AgentGuardrail:
    """Ограничитель для валидации входов/выходов агента."""

    def __init__(self):
        self.input_validators: list[Callable] = []
        self.output_validators: list[Callable] = []

    def add_input_validator(self, validator: Callable):
        self.input_validators.append(validator)

    def add_output_validator(self, validator: Callable):
        self.output_validators.append(validator)

    def validate_input(self, input_data: str) -> tuple[bool, str]:
        for validator in self.input_validators:
            is_valid, message = validator(input_data)
            if not is_valid:
                return False, message
        return True, "OK"

    def validate_output(self, output_data: str) -> tuple[bool, str]:
        for validator in self.output_validators:
            is_valid, message = validator(output_data)
            if not is_valid:
                return False, message
        return True, "OK"


# Пример использования
def no_pii_validator(text: str) -> tuple[bool, str]:
    """Проверяет, что текст не содержит персональных данных."""
    import re
    # Простая проверка на email и телефоны
    if re.search(r'\b[\w.+-]+@[\w-]+\.[\w.]+\b', text):
        return False, "Обнаружен email-адрес в ответе"
    if re.search(r'\b\d{10,}\b', text):
        return False, "Обнаружен возможный номер телефона"
    return True, "OK"


def max_length_validator(max_tokens: int = 2000):
    """Фабрика валидаторов максимальной длины."""
    def validator(text: str) -> tuple[bool, str]:
        # Грубая оценка: 1 токен ~ 4 символа
        estimated_tokens = len(text) // 4
        if estimated_tokens > max_tokens:
            return False, f"Ответ слишком длинный: ~{estimated_tokens} токенов"
        return True, "OK"
    return validator


guardrail = AgentGuardrail()
guardrail.add_output_validator(no_pii_validator)
guardrail.add_output_validator(max_length_validator(2000))

В OpenAI Agents SDK guardrails встроены и определяются декларативно для каждого агента. В LangGraph их обычно реализуют как дополнительные узлы графа — «проверочные станции», через которые проходит результат агента перед передачей дальше.

Когда НЕ нужны мульти-агентные системы

Считаю важным закончить техническую часть этой статьи честным разговором о том, когда мульти-агентные системы — это избыточное решение. В текущем хайпе вокруг агентов легко увлечься и начать городить систему из пяти агентов там, где хватило бы одного промпта.

Не нужны мульти-агенты, когда задача решается одним хорошим промптом. Классификация тикетов, генерация ответов по шаблону, извлечение данных из текста — один агент с правильным промптом и набором инструментов справится прекрасно. Добавление супервайзера, координации и межагентного общения только увеличит латентность, стоимость и количество точек отказа.

Не нужны мульти-агенты, когда нет чёткого разделения ответственности. Если вы не можете объяснить одним предложением, за что отвечает каждый агент — скорее всего, вы искусственно разделяете задачу. Мульти-агентная архитектура работает, когда есть естественная декомпозиция: исследование, анализ, генерация, проверка. Не видите таких фаз — не изобретайте их.

Не нужны мульти-агенты, когда критична низкая латентность. Каждый дополнительный агент — это дополнительные вызовы LLM. Пользователь ждёт ответ в чате за 2 секунды, а цепочка из трёх агентов выдаёт результат через 15-20? Это неприемлемо.

Не нужны мульти-агенты, когда нет инфраструктуры для наблюдаемости. Отлаживать одного агента, который делает что-то не то, уже непросто. Отлаживать пять взаимодействующих агентов без трейсинга и логирования — практически невозможно. Нет инфраструктуры для мониторинга? Начните с одного агента.

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

Заключение и что дальше

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

Давайте подведём итоги.

Архитектура решает. Выбор паттерна (Supervisor, Hierarchical, Dispatcher, Sequential) определяет 80% успеха системы. Начинайте с Supervisor — он покрывает большинство сценариев.

Фреймворки зрелые. LangGraph для production с его графовой гибкостью, CrewAI для быстрого прототипирования с ролевой моделью, OpenAI Agents SDK для экосистемы OpenAI, Google ADK для межплатформенного взаимодействия через A2A. Выбор зависит от вашего стека и конкретной задачи.

Стандарты — это важно. MCP и A2A — не просто модные аббревиатуры, а реальные стандарты, которые определят, как AI-системы будут интегрироваться в ближайшие годы. Стоит вложить время в их понимание уже сейчас.

Production — это не demo. Обработка ошибок, управление стоимостью, наблюдаемость и guardrails — вот что отличает демо-проект на хакатоне от системы, обрабатывающей реальные запросы пользователей.

В следующих статьях серии мы продолжим углубляться в практические аспекты AI-инженерии. Мы уже разобрали Function Calling, RAG-пайплайны и мульти-агентные системы — фундаментальные блоки современных AI-приложений. Впереди — оценка качества LLM-систем, prompt engineering для production и многое другое.

Мульти-агентные системы — это не будущее. Это настоящее. И лучшее время начать строить их — прямо сейчас. Только, пожалуйста, начните с одного агента.

Об авторе Editorial Team

Our team of expert writers and editors.