Мультиагентная ИИ-архитектура
Паттерны и продакшен (2026)

Шесть паттернов · LangGraph/CrewAI/AutoGen · MCP+A2A · Observability

Мультиагентная ИИ-архитектура паттерны и продакшен 2026
Если retrieval, код и review сидят в одном LLM-агенте, при масштабе неизбежны переполнение контекста, серийная latency и single point of failure. Для AI-инженеров и архитекторов: ① четыре bottleneck одного агента и три режима MAS; ② матрица LangGraph / CrewAI / AutoGen; ③ шесть паттернов + MCP+A2A с кодом; ④ PostgresSaver, circuit breaker, token budget; ⑤ данные MAST, пять подводных камней и шестишаговый production runbook.
01

Почему один LLM-агент ломается в продакшене

Монолитный агент — один LLM для retrieval, рассуждений, кода и проверки — легко демонстрируется и ломается при масштабировании. Проблемы структурные. К 2026 году большинство команд, пытавшихся масштабировать одного агента, упирались в одни и те же четыре ограничения.

01

Потолок контекста: Промежуточное состояние заполняет окно; качество рассуждений падает на длинных workflow.

02

Размытие ролей: Один агент для retrieval, генерации и аудита не делает ничего из этого хорошо.

03

Нет параллелизма: Последовательные шаги — суммарная latency равна сумме всех шагов.

04

Единая точка отказа: Один неудачный вызов модели или timeout инструмента останавливает всю pipeline.

05

Данные с продакшена: Внутренний Agent Bake-Off Google (MLflow 2026) сократил обработку с часа до десяти минут — ×6 после декомпозиции. AdaptOrch (2026): топология оркестрации важнее выбора модели, +12–23 % на SWE-bench.

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

Свойство агентаЗначение в продакшене
Одна ответственностьОдна задача: retrieval, рассуждение, генерация или валидация
ИнструментыДоступ только к нужным инструментам через MCP Server
Изоляция состоянияСвой контекст и память; без загрязнения других агентов
ЗаменяемостьМенять worker-агента без перепрошивки всего графа

Три топологии управления: Централизованная — оркестратор маршрутизирует всё (аудит, но узкое место). Децентрализованная — peer-сеть (устойчивость, сложный debug). Иерархическая — top orchestrator → team leads → workers.

РежимСтруктураПлюсыМинусы
ЦентрализованныйOrchestrator управляет A/B/CАудируемость, контрольУзкое место в центре
ДецентрализованныйPeer-to-peer meshЭластичность, низкая latencyСложный debug, недетерминизм
ИерархическийTop Orchestrator → Team Lead → WorkerБаланс контроля и масштабаСредняя сложность дизайна

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

02

LangGraph vs CrewAI vs AutoGen: сравнение и выбор

Правильный фреймворк экономит месяцы своей оркестрации. Матрица: парадигма, языки, кривая обучения, state, HITL, observability, production, прототип, Azure, сценарии.

ИзмерениеLangGraphCrewAIAutoGen (Microsoft)
ПарадигмаГраф состоянийКоманды по ролямДиалоговые multi-agent
ЯзыкиPython / JS/TSPythonPython / .NET
Кривая обученияКрутаяПологаяСредняя
StateНативноСамимОграничено
Human-in-the-LoopНативный interrupt()СамимПоддерживается
ObservabilityLangSmithОграниченоAzure Monitor
Production-ready⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Быстрый прототип⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Azure⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Лучше дляСложные stateful workflowRole-based content pipelinesДиалог и дебаты

Рекомендации:

LG

LangGraph:Надёжность prod (финансы, медицина, compliance), персистентность, HITL, ветвления.

CR

CrewAI:Прототип за 1–2 дня; команда думает ролями; контент и отчёты.

AG

AutoGen:Microsoft/Azure; многораундовые дебаты; исследования.

Топология оркестрации важнее модели — сначала pattern и framework, потом модель.

03

Шесть паттернов оркестрации и MCP+A2A

Шесть паттернов покрывают >95 % prod. Паттерн 1 — Последовательный pipeline: выход A → вход B; линейно; контент, code review.

python
from langgraph.graph import StateGraph, START, END
from typing import TypedDict

class PipelineState(TypedDict):
    query: str
    retrieved_docs: str
    analysis: str
    final_report: str

def retrieval_agent(state: PipelineState):
    docs = search_knowledge_base(state["query"])
    return {"retrieved_docs": docs}

def analysis_agent(state: PipelineState):
    result = llm.invoke(f"Analyze the following:{state['retrieved_docs']}")
    return {"analysis": result.content}

def writer_agent(state: PipelineState):
    report = llm.invoke(f"Write report from analysis:{state['analysis']}")
    return {"final_report": report.content}

builder = StateGraph(PipelineState)
builder.add_node("retriever", retrieval_agent)
builder.add_node("analyzer", analysis_agent)
builder.add_node("writer", writer_agent)
builder.add_edge(START, "retriever")
builder.add_edge("retriever", "analyzer")
builder.add_edge("analyzer", "writer")
builder.add_edge("writer", END)
pipeline = builder.compile()

Паттерн 2 — Параллельный fan-out/fan-in: независимые подзадачи; latency = max(T1…Tn). LangGraph Send API + reducer.

python
from langgraph.types import Send
from langgraph.graph import StateGraph, START, END
from typing import TypedDict, Annotated
import operator

class ResearchState(TypedDict):
    query: str
    research_results: Annotated[list, operator.add]
    final_synthesis: str

def supervisor(state: ResearchState):
    subtasks = [
        {"query": state["query"], "source": "academic"},
        {"query": state["query"], "source": "industry"},
        {"query": state["query"], "source": "news"},
    ]
    return [Send("research_worker", task) for task in subtasks]

def research_worker(state: dict):
    result = search_by_source(state["query"], state["source"])
    return {"research_results": [result]}

def synthesizer(state: ResearchState):
    combined = "\n".join(state["research_results"])
    synthesis = llm.invoke(f"Synthesize research results:{combined}")
    return {"final_synthesis": synthesis.content}

builder = StateGraph(ResearchState)
builder.add_node("research_worker", research_worker)
builder.add_node("synthesizer", synthesizer)
builder.add_conditional_edges(START, supervisor, ["research_worker"])
builder.add_edge("research_worker", "synthesizer")
builder.add_edge("synthesizer", END)
graph = builder.compile()

Паттерн 3 — Supervisor-worker: маршрутизация intent; специализированные workers. Keyword fast-path + LLM routing.

python
KEYWORD_ROUTING = {
    "code": "code_agent", "code": "code_agent",
    "search": "search_agent", "query": "search_agent",
    "data": "data_agent",
}

def supervisor_with_fast_path(state):
    query = state["query"].lower()
    for keyword, agent_name in KEYWORD_ROUTING.items():
        if keyword in query:
            return {"next": agent_name}
    routing_prompt = f"""
    User request:{state['query']}
    Available agents:code_agent, search_agent, data_agent
    Return best agent name only。
    """
    decision = llm.invoke(routing_prompt)
    return {"next": decision.content.strip()}

Паттерн 4 — Swarm: peer-to-peer без координатора; жёсткий лимит раундов. AutoGen GroupChat:

python
import autogen

reviewer_1 = autogen.AssistantAgent(
    name="SecurityReviewer",
    system_message="Security expert focused on vulnerabilities."
)
reviewer_2 = autogen.AssistantAgent(
    name="PerformanceReviewer",
    system_message="Performance expert focused on efficiency."
)
human_proxy = autogen.UserProxyAgent(
    name="CodeAuthor",
    human_input_mode="NEVER",
    max_consecutive_auto_reply=2,
    is_termination_msg=lambda x: "APPROVED" in x.get("content", "")
)
groupchat = autogen.GroupChat(
    agents=[human_proxy, reviewer_1, reviewer_2],
    messages=[],
    max_round=6
)
manager = autogen.GroupChatManager(groupchat=groupchat)

Паттерн 5 — Blackboard: общее workspace; долгие async jobs. Паттерн 6 — Hybrid: intent router + supervisor + fan-out + QA.

MCP + A2A (Agentic AI Foundation): MCP вертикально Agent ↔ tools/API; A2A горизонтально — делегирование.

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

app = Server("data-agent-mcp")

@app.list_tools()
async def list_tools():
    return [
        Tool(
            name="query_customer_db",
            description="Query customer DB by id, name, or email",
            inputSchema={
                "type": "object",
                "properties": {
                    "field": {"type": "string", "enum": ["id", "name", "email"]},
                    "value": {"type": "string"}
                },
                "required": ["field", "value"]
            }
        )
    ]

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "query_customer_db":
        result = db.query(arguments["field"], arguments["value"])
        return [TextContent(type="text", text=str(result))]

Agent Card A2A на /.well-known/agent.json; делегирование JSON-RPC 2.0:

python
import httpx

async def discover_and_delegate(agent_url: str, task: str):
    card_response = await httpx.get(f"{agent_url}/.well-known/agent.json")
    agent_card = card_response.json()
    available_skills = [s["id"] for s in agent_card["skills"]]
    if "web_research" not in available_skills:
        raise ValueError(f"Agent {agent_card['name']} lacks web_research skill")
    payload = {
        "jsonrpc": "2.0",
        "method": "message/send",
        "id": "task-001",
        "params": {
            "message": {
                "role": "user",
                "parts": [{"type": "text", "text": task}]
            }
        }
    }
    response = await httpx.post(agent_card["url"], json=payload)
    return response.json()
04

Шестишаговый production runbook

01

Выбор и топология:Decision tree: pipeline/fan-out/hierarchy/blackboard/hybrid; 3–8 агентов.

02

Персистентность:PostgresSaver, recovery, thread_id на сессию.

03

Human-in-the-loop:interrupt() для high-risk — compliance и EU AI Act.

04

Circuit breaker:CircuitBreaker на внешние вызовы.

05

Token budget:TokenBudgetManager перед каждым вызовом.

06

Observability:OpenTelemetry, MONITORING_METRICS, LLM-as-Judge sampling.

python
from langgraph.checkpoint.postgres import PostgresSaver
from langgraph.types import interrupt

with PostgresSaver.from_conn_string("postgresql://user:pass@localhost/agentdb") as checkpointer:
    graph = builder.compile(checkpointer=checkpointer)
    config = {"configurable": {"thread_id": "user-session-12345"}}
    result = graph.invoke({"query": "Analyze Q2 report"}, config)

def high_risk_action_agent(state):
    proposed_action = plan_action(state)
    human_decision = interrupt({
        "proposed_action": proposed_action,
        "risk_level": "HIGH",
        "message": "This modifies production DB. Confirm?"
    })
    if human_decision["approved"]:
        return execute_action(proposed_action)
    return {"status": "cancelled", "reason": human_decision.get("reason")}
python
import time
from functools import wraps

class CircuitBreaker:
    def __init__(self, failure_threshold=5, recovery_timeout=60):
        self.failure_count = 0
        self.failure_threshold = failure_threshold
        self.recovery_timeout = recovery_timeout
        self.state = "CLOSED"
        self.last_failure_time = None

    def __call__(self, func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            if self.state == "OPEN":
                if time.time() - self.last_failure_time > self.recovery_timeout:
                    self.state = "HALF_OPEN"
                else:
                    raise Exception("Circuit breaker OPEN - Agent temporarily unavailable")
            try:
                result = await func(*args, **kwargs)
                if self.state == "HALF_OPEN":
                    self.state = "CLOSED"
                    self.failure_count = 0
                return result
            except Exception:
                self.failure_count += 1
                self.last_failure_time = time.time()
                if self.failure_count >= self.failure_threshold:
                    self.state = "OPEN"
                raise
        return wrapper

class TokenBudgetManager:
    def __init__(self, total_budget: int = 100_000):
        self.total_budget = total_budget
        self.used_tokens = 0
        self.agent_usage = {}

    def check_budget(self, agent_name: str, estimated_tokens: int) -> bool:
        remaining = self.total_budget - self.used_tokens
        if estimated_tokens > remaining:
            raise BudgetExceededException(
                f"Agent {agent_name} requests {estimated_tokens} tokens,"
                f"в бюджете осталось только {remaining} tokens"
            )
        return True

    def record_usage(self, agent_name: str, actual_tokens: int):
        self.used_tokens += actual_tokens
        self.agent_usage[agent_name] = self.agent_usage.get(agent_name, 0) + actual_tokens
05

Данные observability, подводные камни и тренды 2026

MAST проанализировал 1642 multi-agent traces:

ТипДоляОписание
Дизайн системы41.77%Повторы, неверные tools, overflow, нет termination
Misalignment36.94%Потеря контекста; галлюцинации как факты
Валидация21.30%Ранний stop, неполная проверка
A

57 % vs 8 %:57 % в prod, 8 % с LLM observability — HTTP 200 при неверном output.

B

Google Bake-Off ×6: Распределённая мультиагентная архитектура сократила обработку с часа до десяти минут; sub-агенты обновляются независимо.

C

AdaptOrch 12–23 %:Верная топология +12–23 % на SWE-bench vs смена модели.

python
from opentelemetry import trace
import uuid

tracer = trace.get_tracer("multi-agent-system")

def traced_agent_call(agent_name: str, task: dict, correlation_id: str = None):
    if not correlation_id:
        correlation_id = str(uuid.uuid4())
    with tracer.start_as_current_span(f"agent.{agent_name}") as span:
        span.set_attribute("agent.name", agent_name)
        span.set_attribute("correlation.id", correlation_id)
        span.set_attribute("task.type", task.get("type", "unknown"))
        try:
            result = agent_registry[agent_name].run(task)
            span.set_attribute("agent.tokens_used", result.get("tokens", 0))
            span.set_attribute("agent.status", "success")
            return result
        except Exception as e:
            span.set_attribute("agent.status", "error")
            span.set_attribute("error.message", str(e))
            raise

MONITORING_METRICS = {
    "task_success_rate": "task_success_rate target >85%",
    "e2e_latency_p95": "e2e_latency_p95 target <30s",
    "total_cost_per_task": "avg token cost per task",
    "agent_error_rate": "agent_error_rate target <5%",
    "agent_retry_count": "retry count high needs investigation",
    "tool_call_budget_usage": "tool call budget ratio",
    "output_quality_score": "output quality score",
    "goal_alignment_score": "goal alignment score",
    "hallucination_rate": "hallucination rate",
}

def evaluate_agent_output(original_task: str, agent_output: str) -> dict:
    evaluation_prompt = f"""
    Original task: {original_task}
    Agent output: {agent_output}
    Rate completeness, accuracy, relevance, hallucination (1-5 each).
    Return JSON only: {{"completeness": x, "accuracy": x, "relevance": x,
    "hallucination_detected": true/false, "comments": "..."}}
    """
    evaluation = llm.invoke(evaluation_prompt)
    return json.loads(evaluation.content)

Пять подводных камней:

1

Загрязнение контекста:Галлюцинации A → B/C. Fix: validate_agent_output на каждом handoff.

2

Бесконечные циклы:Runaway retries. Fix: жёсткие лимиты.

3

Over-engineering:Два шага → восемь агентов. Fix: pipeline сначала; 3–8 агентов.

4

Разрыв demo-prod:Edge inputs в prod. Fix: ProductionGuardrails, PII.

5

Параллельный sync:Supervisor раньше медленных веток. Fix: defer=True.

python
def validate_agent_output(output: dict, schema: dict) -> bool:
    jsonschema.validate(output, schema)
    if output.get("confidence_score", 1.0) < 0.7:
        raise LowConfidenceError(f"Agent output confidence too low: {output['confidence_score']}")
    required_fields = schema.get("required", [])
    missing = [f for f in required_fields if not output.get(f)]
    if missing:
        raise MissingFieldsError(f"Missing required output fields: {missing}")
    return True

MAX_ITERATIONS = 10
MAX_TOOL_CALLS_PER_AGENT = 20
MAX_TOTAL_TOKENS = 50_000

class ProductionGuardrails:
    def validate_input(self, user_input: str) -> str:
        if len(user_input) > 10000:
            raise InputTooLongError("Input exceeds 10000 chars")
        injection_patterns = ["ignore previous instructions", "forget everything"]
        for pattern in injection_patterns:
            if pattern.lower() in user_input.lower():
                raise PromptInjectionError("Prompt injection detected")
        return user_input.strip()

    def validate_output(self, output: str) -> str:
        output = self.pii_filter.redact(output)
        if self.content_classifier.is_harmful(output):
            raise HarmfulContentError("Harmful content in output")
        return output

builder.add_node("supervisor", supervisor_node, defer=True)
text
Есть ли чёткие линейные зависимости?
├─ Да → Подзадачи параллельны?
│        ├─ Нет → [Последовательный pipeline]
│        └─ Да → [Fan-out + pipeline hybrid]
└─ Нет → Есть агент-решатель?
         ├─ Да → Нужны sub-teams?
         │        ├─ Нет → [Supervisor-worker]
         │        └─ Да → [Иерархия]
         └─ Нет → Долгая async задача?
                  ├─ Да → [Blackboard]
                  └─ Нет → ≤ 5 агентов?
                           ├─ Да → [Swarm с termination]
                           └─ Нет → [Иерархия]

Пять ключевых тезисов:① Топология > модель; ② pipeline first; ③ MCP+A2A стандарт; ④ observability must; ⑤ 3–8 агентов.

Тренды 2026:Федеративная оркестрация, мультимодальные агенты, adaptive topology, EU AI Act audit trails.

Важно: Оркестрация на ноутбуке ломается из-за сна, нехватки RAM и сетевого jitter; дешёвый Linux VPS не запускает Xcode и Apple Silicon inference нативно. Мультиагентная архитектура — ключевая компетенция 2026, но продакшену нужен стабильный хост.

Для 7×24 оркестрации, PostgresSaver, MCP и Cursor/Claude Code — аренда Mac Mini cloud MESHLAUNCH: dedicated Apple Silicon, гибкий billing. Тарифы и центр помощи.

Часто задаваемые вопросы

State, HITL, compliance → LangGraph; прототип 1–2 д → CrewAI; Azure → AutoGen. Хостинг: страница тарифов.

MCP вертикально; A2A горизонтально с Agent Cards и JSON-RPC 2.0. Оба под Agentic AI Foundation.

PostgreSQL, OpenTelemetry, token budget, circuit breakers, хост 7×24. Mac Mini для LangGraph, MCP, vectors. Деплой: центр помощи.