Architecture multi-agents IA
Modèles & production (2026)

Six modèles · LangGraph/CrewAI/AutoGen · MCP+A2A · Observabilité

Architecture multi-agents IA modèles et guide production 2026
Concentrer retrieval, code et revue dans un seul agent LLM mène à l'échelle à overflow de contexte, latence séquentielle et points de défaillance uniques. Pour ingénieurs et architectes IA : ① quatre goulots et trois modes de contrôle MAS ; ② matrice LangGraph / CrewAI / AutoGen ; ③ six modèles + MCP+A2A avec code ; ④ PostgresSaver, circuit breaker, budget tokens ; ⑤ données MAST, cinq pièges et runbook production en six étapes.
01

Pourquoi un seul agent LLM casse à l'échelle production

L'agent monolithique — un LLM pour retrieval, raisonnement, code et validation — se démo facilement et se casse en production. Les problèmes sont structurels. En 2026, la plupart des équipes qui ont tenté de scaler un seul agent ont heurté les mêmes quatre murs.

01

Plafond de contexte : L'état intermédiaire remplit la fenêtre ; la qualité du raisonnement chute sur les workflows longs.

02

Dilution jack-of-all-trades : Un agent qui fait retrieval, génération et audit ne fait rien de tout cela correctement.

03

Pas de concurrence : Étapes séquentielles = latence totale = somme de chaque étape.

04

Point de défaillance unique : Un mauvais appel modèle ou timeout outil stoppe toute la pipeline.

05

Preuves terrain : L'Agent Bake-Off interne Google (MLflow 2026) a réduit le traitement d'une heure à dix minutes — gain ×6 après décomposition. AdaptOrch (2026) : la topologie d'orchestration bat le choix du modèle, +12–23 % sur SWE-bench.

Un système multi-agents (MAS) regroupe des agents indépendants qui collaborent via protocoles et orchestration définis pour accomplir ce qu'un seul agent ne peut pas faire efficacement. Chaque agent doit avoir une responsabilité unique, ses outils, un état isolé et être remplaçable indépendamment.

PropriétéSignification en production
Responsabilité uniqueUn rôle clair : retrieval, raisonnement, génération ou validation
Outils dédiésAccès aux outils nécessaires via MCP Server
État isoléContexte et mémoire propres ; pas de pollution croisée
RemplaçableÉchanger un worker sans recâbler tout le graphe

Trois topologies de contrôle : Centralisée — orchestrateur unique (auditable, goulot). Décentralisée — réseau peer-to-peer (résiliente, difficile à déboguer). Hiérarchique — orchestrateur → team leads → workers (équilibre contrôle/échelle).

ModeStructureAvantagesInconvénients
CentraliséOrchestrateur pilote A/B/CAuditable, contrôlableGoulot central
DécentraliséMesh peer-to-peerHaute élasticité, faible latenceDebug difficile, non déterministe
HiérarchiqueOrchestrateur → Team Lead → WorkerContrôle et échelle équilibrésComplexité de design moyenne

En production, l'architecture multi-agents est presque toujours le bon choix. La vraie question est le pattern d'orchestration — pas le modèle de fondation.

02

LangGraph vs CrewAI vs AutoGen : comparatif et choix

Le bon framework évite des mois de code d'orchestration maison. Matrice : paradigme, langages, courbe d'apprentissage, état, HITL, observabilité, production, prototypage, Azure et cas d'usage.

DimensionLangGraphCrewAIAutoGen (Microsoft)
ParadigmeGraphe d'étatsÉquipes par rôlesMulti-agents conversationnels
LangagesPython / JS/TSPythonPython / .NET
Courbe d'apprentissageRaideDouceMoyenne
ÉtatNatifÀ implémenterLimité
Human-in-the-LoopNatif interrupt()À implémenterPris en charge
ObservabilitéLangSmithLimitéAzure Monitor
Maturité prod⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Prototype rapide⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Azure⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Idéal pourWorkflows stateful complexesPipelines de contenu par rôlesCollaboration et débat

Recommandations :

LG

LangGraph :Fiabilité production (finance, santé, conformité), persistance d'état, HITL fin, branches conditionnelles.

CR

CrewAI :Prototype en 1–2 jours ; équipe qui pense en rôles ; contenu et rapports.

AG

AutoGen :Stack Microsoft/Azure ; débat multi-tours ; recherche et modes dialogués.

La topologie d'orchestration compte plus que le modèle — d'abord le pattern et le framework, puis le modèle.

03

Six modèles d'orchestration et protocoles MCP+A2A

Ces six modèles couvrent plus de 95 % des déploiements. Modèle 1 — Pipeline séquentielle : sortie de A → entrée de B ; linéaire ; idéal pour contenu, revue de code.

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()

Modèle 2 — Fan-out/fan-in parallèle : sous-tâches indépendantes ; latence = max(T1…Tn). Send API LangGraph + reducer Annotated[list, operator.add].

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()

Modèle 3 — Supervisor-worker : routage d'intention ; workers spécialisés. Fast-path mots-clés + routage LLM.

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()}

Modèle 4 — Swarm : peer-to-peer sans coordinateur ; limites de rounds obligatoires. Exemple 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)

Modèle 5 — Blackboard : espace partagé ; jobs async longs. Modèle 6 — Hybride : routeur d'intention + supervisor + fan-out + QA — typique enterprise.

MCP + A2A (Agentic AI Foundation) : MCP vertical Agent ↔ outils/API ; A2A horizontal — délégation et discovery.

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 sur /.well-known/agent.json ; délégation 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

Runbook production en six étapes

01

Choix et topologie :Arbre de décision pipeline/fan-out/hiérarchie/blackboard/hybride ; 3–8 agents.

02

Persistance :PostgresSaver, recovery et thread_id par session.

03

Human-in-the-loop :interrupt() sur actions à risque — secteurs régulés et EU AI Act.

04

Circuit breaker :CircuitBreaker sur appels externes.

05

Budget tokens :TokenBudgetManager avant chaque appel.

06

Observabilité :OpenTelemetry, MONITORING_METRICS, échantillonnage LLM-as-Judge.

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"il ne reste que {remaining} tokens dans le budget"
            )
        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

Données d'observabilité, pièges et tendances 2026

MAST a analysé 1642 traces multi-agents :

TypePartDescription
Conception système41.77%Étapes dupliquées, mauvais outils, overflow, pas de terminaison
Désalignement36.94%Perte de contexte ; hallucinations comme faits
Validation21.30%Arrêt prématuré, validation incomplète
A

57 % vs 8 % :57 % en prod, 8 % avec observabilité LLM — HTTP 200 avec sorties fausses.

B

Google Bake-Off ×6 : Architecture multi-agents distribuée : traitement réduit d'une heure à dix minutes ; sous-agents upgradeables indépendamment.

C

AdaptOrch 12–23 % :Bonne topologie +12–23 % sur SWE-bench vs changement de modèle.

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)

Cinq pièges et parades :

1

Pollution de contexte :Hallucinations propagées. Fix : validate_agent_output à chaque handoff.

2

Boucles infinies :Retries incontrôlés. Fix : plafonds stricts.

3

Sur-ingénierie :Deux étapes → huit agents. Fix : pipeline d'abord ; 3–8 agents.

4

Fossé démo-prod :Entrées edge en prod. Fix : ProductionGuardrails, PII.

5

Sync parallèle :Supervisor trop tôt. 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
La tâche a-t-elle des dépendances linéaires claires ?
├─ Oui → Sous-tâches parallélisables ?
│        ├─ Non → [Pipeline séquentielle]
│        └─ Oui → [Fan-out + pipeline hybride]
└─ Non → Un agent décisionnaire ?
         ├─ Oui → Besoin de sous-équipes ?
         │        ├─ Non → [Supervisor-worker]
         │        └─ Oui → [Hiérarchique]
         └─ Non → Tâche async longue ?
                  ├─ Oui → [Blackboard]
                  └─ Non → ≤ 5 agents ?
                           ├─ Oui → [Swarm avec terminaison]
                           └─ Non → [Repasser en hiérarchique]

Cinq points clés :① Topologie > modèle ; ② pipeline d'abord ; ③ MCP+A2A standard ; ④ observabilité obligatoire ; ⑤ 3–8 agents.

Tendances 2026 :Orchestration fédérée, agents multimodaux, topologie adaptive, EU AI Act et pistes d'audit.

Attention : L'orchestration multi-agents sur laptop échoue au sleep, manque de RAM et jitter réseau ; un VPS Linux bon marché ne fait ni Xcode ni l'inférence Apple Silicon nativement. L'architecture multi-agents est un atout clé en 2026 — la production exige un hôte stable.

Pour orchestration 7×24, PostgresSaver, MCP et Cursor/Claude Code, la location Mac Mini cloud MESHLAUNCH convient : Apple Silicon dédié, facturation flexible. Voir tarifs et centre d'aide.

FAQ

État, HITL, conformité → LangGraph ; prototype 1–2 j → CrewAI ; Azure → AutoGen. Hébergement : page tarifs.

MCP vertical ; A2A horizontal avec Agent Cards et JSON-RPC 2.0. Adoptez les deux en greenfield.

PostgreSQL, OpenTelemetry, budget tokens, circuit breakers, hôte 7×24. Mac Mini pour LangGraph, MCP, vecteurs. Déploiement : centre d'aide.