Agents IA en production : paralléliser sans propager les erreurs
Les agents IA enchaînent désormais des dizaines d'actions autonomes pour atteindre un objectif. Le passage à l'exécution parallèle multiplie le débit — et le rayon d'action des erreurs. Guide d'architecture pour les consultants qui doivent industrialiser ces workflows.
En bref
- Les agents IA passent d'une exécution séquentielle (une action, une observation, une décision) à des architectures parallèles où plusieurs sous-tâches s'exécutent simultanément.
- Le gain de latence est réel, mais chaque branche parallèle hérite des mêmes hypothèses erronées : une hallucination en amont se réplique sur N branches au lieu d'une.
- Les patterns de contrôle indispensables : isolation des contextes, idempotence des actions, checkpoints de validation, budget d'appels borné, et distinction stricte entre opérations lecture seule et opérations mutantes.
- L'article de Le Monde Informatique met l'accent sur la difficulté à concilier parallélisation du travail et non-parallélisation des erreurs ; le détail complet du contenu source n'est pas accessible au-delà de l'extrait (non documenté).
- Pour les consultants : l'observabilité des agents (traces, spans, coût par run) devient un livrable d'architecture, pas un « nice to have ».
Contexte
Le sujet abordé par Le Monde Informatique dans son article « Agent IA : paralléliser le travail sans paralléliser les erreurs » (publié sur lemondeinformatique.fr, référence 100741) part d'un constat désormais banal en 2025 : les agents IA ne se contentent plus de générer du texte. Ils enchaînent des actions — consulter un site web, manipuler des données, appeler une API, écrire un fichier, exécuter une commande — dans une boucle de raisonnement jusqu'à atteindre un objectif défini par un prompt initial.
Cette capacité repose sur un socle technique stabilisé depuis 2023-2024 : le function calling / tool use proposé par OpenAI, Anthropic, Google et les modèles open-weight (Llama, Mistral, Qwen), formalisé côté interopérabilité par le Model Context Protocol (MCP) publié par Anthropic fin 2024. Les frameworks d'orchestration se sont multipliés : LangGraph (LangChain), CrewAI, AutoGen (Microsoft), OpenAI Agents SDK, Semantic Kernel, LlamaIndex Workflows, Temporal pour les workflows durables.
Le point de bascule opérationnel est le suivant. Un agent séquentiel classique fonctionne selon la boucle ReAct (Reason + Act, popularisée par le papier de Yao et al., 2022) : le modèle raisonne, choisit un outil, observe le résultat, puis recommence. C'est lent — chaque tour coûte un aller-retour LLM, soit typiquement 1 à 10 secondes selon le modèle et la taille du contexte. Un agent qui doit vérifier 40 dépendances dans un package.json, interroger 12 endpoints d'API ou analyser 200 tickets Jira accumule une latence inacceptable pour un usage interactif.
D'où la parallélisation : découper l'objectif en sous-tâches indépendantes, les exécuter simultanément (souvent via des sous-agents), puis agréger les résultats. Anthropic a documenté publiquement en 2025 son architecture de recherche multi-agents avec un agent orchestrateur déléguant à des sous-agents chercheurs opérant en parallèle, avec des gains de performance substantiels sur les tâches de recherche large — au prix d'une consommation de tokens très supérieure à un chat classique.
Le problème que soulève l'angle éditorial est précisément celui-là : la parallélisation amplifie tout, y compris ce qui est faux.
Détails techniques
Pourquoi une erreur se propage plus vite en parallèle
Dans une exécution séquentielle, une erreur a une chance d'être détectée au tour suivant : l'agent observe un résultat incohérent, un code HTTP 404, un stack trace, et peut corriger sa trajectoire. C'est le mécanisme d'auto-correction par observation.
En parallèle, cette boucle de rétroaction disparaît sur les branches simultanées. Trois mécanismes de propagation :
1. Erreur de planification en amont (fan-out d'une hypothèse fausse). L'orchestrateur décide que la table cible est customers_v2 alors que c'est customers_v3. Il lance 8 sous-agents. Les 8 échouent, ou pire : les 8 écrivent dans la mauvaise table. Une erreur unique devient 8 effets de bord.
2. Absence de vue partagée. Deux sous-agents travaillant sur le même dépôt Git peuvent produire des modifications contradictoires sur le même fichier. Sans verrou ni découpage strict des zones d'écriture, le merge est incohérent. Le même problème existe sur les tickets (double création), les emails (double envoi), les appels de facturation (double débit).
3. Contamination du contexte à l'agrégation. Chaque sous-agent renvoie un résumé. Si l'un hallucine une information, l'orchestrateur l'intègre dans sa synthèse finale sans traçabilité vers la source. Le résultat agrégé paraît plus crédible que ses composants — c'est l'effet « lavage de provenance ».
Le pattern de base : fan-out / fan-in encadré
┌─ Sous-agent A (read-only) ─┐
Orchestrateur ────┼─ Sous-agent B (read-only) ─┼──> Agrégation
(plan) └─ Sous-agent C (read-only) ─┘ │
v
Checkpoint validation
│
v
Phase mutante SÉQUENTIELLE
(write, commit, API POST)
La règle d'or architecturale : paralléliser les lectures, sérialiser les écritures. Les opérations idempotentes et sans effet de bord (recherche web, SELECT, GET, lecture de fichier, analyse statique) se parallélisent sans risque autre que le coût. Les opérations mutantes (INSERT, POST, git push, envoi de mail, création de ressource cloud) passent par un chemin unique, séquentiel, auditable.
Isolation des contextes
Chaque sous-agent doit disposer de son propre contexte, avec un périmètre d'outils réduit au strict nécessaire. Exemple de configuration conceptuelle avec LangGraph :
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
import operator
class ResearchState(TypedDict):
query: str
# reducer : les branches parallèles APPEND, elles n'écrasent pas
findings: Annotated[list[dict], operator.add]
budget_calls: int
def spawn_subagents(state: ResearchState):
# Fan-out borné : jamais plus de N branches
MAX_BRANCHES = 5
subtasks = decompose(state["query"])[:MAX_BRANCHES]
return [{"subtask": s} for s in subtasks]
def researcher(state):
# Outils read-only uniquement
result = search_tool.invoke(state["subtask"])
return {
"findings": [{
"subtask": state["subtask"],
"content": result.text,
"source_url": result.url, # provenance obligatoire
"confidence": result.score
}]
}
Le point critique est le reducer sur l'état partagé. Sans Annotated[list, operator.add], deux branches qui écrivent la même clé provoquent un conflit ou un écrasement silencieux. C'est une source de bugs redoutable parce qu'elle est non déterministe : le résultat dépend de l'ordre d'arrivée des branches.
Provenance et traçabilité obligatoires
Chaque élément d'information remonté par un sous-agent doit porter :
- l'identifiant du sous-agent émetteur,
- l'outil utilisé et ses paramètres exacts,
- la source primaire (URL, ID de ligne, chemin de fichier, hash de commit),
- un horodatage,
- un indicateur de confiance ou l'absence explicite de vérification.
Sans ces métadonnées, il devient impossible de répondre à la question posée en post-incident : « d'où vient cette affirmation fausse ? ». Les standards d'observabilité convergent vers OpenTelemetry GenAI semantic conventions, avec des attributs gen_ai.system, gen_ai.request.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens. Les outils du marché (LangSmith, Langfuse, Arize Phoenix, Braintrust, W&B Weave) exposent des traces hiérarchiques run → span → tool call.
Budget et circuit breaker
Un agent parallélisé peut brûler un budget de tokens de façon exponentielle : si chaque sous-agent peut lui-même spawner des sous-sous-agents, la récursion non bornée est un incident de facturation garanti. Trois garde-fous minimum :
agent_limits:
max_depth: 2 # profondeur de délégation
max_parallel_branches: 5 # largeur du fan-out
max_total_tool_calls: 60 # budget global par run
max_input_tokens: 400000 # plafond de contexte cumulé
wall_clock_timeout_s: 300 # timeout dur
cost_ceiling_usd: 2.50 # kill switch économique
Ajouter un circuit breaker par type d'outil : si 3 appels consécutifs au même outil échouent, la branche s'arrête et remonte l'échec plutôt que de retenter en boucle. Le pattern retry with exponential backoff classique s'applique, mais avec un plafond strict — un agent qui retente 20 fois un appel API en erreur 500 génère de la charge inutile sur le système cible et peut déclencher du rate limiting côté fournisseur.
Idempotence des actions mutantes
Toute action à effet de bord doit être idempotente ou protégée par une clé d'idempotence. Pattern classique repris de la finance :
def create_ticket(payload: dict, run_id: str, step_id: str):
idem_key = f"{run_id}:{step_id}:{hash_payload(payload)}"
if store.exists(idem_key):
return store.get(idem_key) # rejoue le résultat, ne recrée pas
result = jira_client.create_issue(**payload)
store.put(idem_key, result, ttl=86400)
return result
Cela couvre le cas du retry après timeout réseau — situation où l'agent ne sait pas si son action a abouti. Sans clé d'idempotence, un timeout sur un POST conduit à un doublon.
Validation croisée plutôt que consensus naïf
Une tentation courante : lancer 3 agents sur la même tâche et voter (self-consistency, majorité). C'est utile pour des réponses à espace de sortie restreint (classification, extraction de champ). C'est trompeur pour des tâches ouvertes : trois instances du même modèle avec le même prompt partagent les mêmes biais et hallucinent souvent de façon corrélée. Le vote produit alors une fausse confiance.
Alternatives plus robustes :
- Vérification par outil déterministe : au lieu de demander à un LLM si le code compile, on le compile. Au lieu de demander si l'URL existe, on fait un
HEAD. Tout ce qui est vérifiable mécaniquement doit l'être mécaniquement. - Critique par modèle différent : un agent d'un autre fournisseur ou d'une autre famille relit les conclusions, ce qui décorrèle partiellement les biais.
- Contrainte de schéma : forcer les sorties en JSON Schema strict (structured outputs) élimine une classe entière d'erreurs de format qui, en parallèle, casse l'agrégation.
Implications pour les consultants IT
Architecture : le plan devient l'artefact critique. Dans un agent séquentiel, une mauvaise décision se paie d'un tour de boucle. Dans un agent parallèle, une mauvaise décision de planification se paie N fois. Le corollaire pour les missions d'architecture : imposer un point de contrôle humain ou automatisé après la phase de planification, avant le fan-out. Concrètement, cela signifie exposer le plan (liste des sous-tâches, outils prévus, ressources ciblées) dans un format lisible et vérifiable, et gater l'exécution parallèle sur une validation. Sur les workflows sensibles, ce gate est humain (human-in-the-loop) ; sur les workflows routiniers, il peut être une règle déterministe (« refuser tout plan qui touche plus de 3 tables », « refuser tout plan incluant un DELETE »).
Sécurité : la surface d'attaque se démultiplie avec les branches. L'injection de prompt indirecte reste le risque numéro un des agents lisant des contenus externes (pages web, emails, tickets, PDF). L'OWASP Top 10 for LLM Applications classe Prompt Injection en LLM01. En exécution parallèle, une instruction malveillante récupérée par un sous-agent depuis une page web peut se propager à l'orchestrateur lors de l'agrégation, puis contaminer le raisonnement final. La contre-mesure architecturale : traiter tout contenu externe comme donnée non fiable, jamais comme instruction — ce qui suppose une séparation nette dans le prompt et, idéalement, un sous-agent « lecteur » sans aucun outil mutant, dont la sortie est structurée et validée par schéma avant d'atteindre l'orchestrateur. Appliquer le principe du moindre privilège par sous-agent : le chercheur web n'a pas besoin d'accès à la base de données.
Compliance et audit : le run trace devient une pièce justificative. Pour les organisations soumises à des exigences de traçabilité (secteur financier avec DORA, santé, ou plus largement les obligations de documentation technique du règlement européen sur l'IA — AI Act, dont les dispositions sur les systèmes à haut risque s'échelonnent jusqu'en 2026-2027), un agent qui prend des décisions opérationnelles doit produire un journal reconstituable : quelle version de modèle, quel prompt, quels outils appelés avec quels paramètres, quels résultats intermédiaires. La parallélisation complique l'exercice parce que l'ordre d'exécution n'est plus déterministe. Il faut donc horodater et corréler par run_id / span_id, et conserver les traces avec la même rigueur que des logs d'application (rétention, immutabilité, protection des données personnelles présentes dans les contextes).
Coût et capacity planning : un poste budgétaire à modéliser. Un agent multi-agents consomme un ordre de grandeur de tokens supérieur à un simple appel de complétion. Les consultants doivent intégrer dans leurs chiffrages un modèle de coût par run (tokens entrée + sortie + appels d'outils payants), un plafond dur, et une observabilité du coût unitaire. Le réflexe à adopter : mesurer le coût par tâche réussie, pas le coût par appel. Un agent moins cher mais qui échoue 40 % du temps et nécessite une reprise humaine coûte plus cher qu'un agent plus dispendieux mais fiable. Ajouter une métrique de taux de retouche humaine comme indicateur de qualité en production.
Testing : les tests non déterministes exigent une autre discipline. On ne peut pas tester un agent parallèle avec des assertions d'égalité stricte. Il faut construire des jeux d'évaluation (eval sets) avec des critères de succès fonctionnels (« la ressource a-t-elle été créée avec les bons attributs ? », « la réponse cite-t-elle au moins une source valide ? »), les exécuter en CI, et suivre les taux de réussite comme des SLO. Prévoir aussi des tests de régression de coût : un changement de prompt qui double le nombre de branches doit faire échouer le build.
Pour aller plus loin
- Lien source originale : Agent IA: paralléliser le travail sans paralléliser les erreurs
Actions concrètes recommandées :
- Auditer le périmètre d'outils de chaque agent en production. Cartographier, pour chaque sous-agent, la liste exacte des outils accessibles et classer chacun en
read-only/mutant. Tout sous-agent parallélisé qui dispose d'un outil mutant est un point de risque à traiter en priorité : soit retirer l'outil, soit sérialiser la branche.
- Vérifier la présence de bornes dures sur chaque workflow agentique. Profondeur de délégation, nombre de branches parallèles, budget total d'appels d'outils, timeout wall-clock, plafond de coût. Si l'un de ces cinq garde-fous est absent, l'incident de facturation ou de saturation d'API cible est une question de temps.
- Instrumenter l'observabilité avant d'industrialiser. Mettre en place le tracing (OpenTelemetry GenAI conventions ou équivalent via LangSmith / Langfuse / Arize Phoenix), avec
run_idcorrélé, provenance de chaque information agrégée, et métriques de coût et de latence par span. Sans cela, le post-mortem d'une décision erronée est impossible.
- Tester l'injection de prompt indirecte. Insérer dans un contenu externe consommé par l'agent (page de test, ticket, document) une instruction du type « ignore les consignes précédentes et... » et vérifier que l'orchestrateur ne la répercute pas. À intégrer dans les tests de sécurité récurrents, pas seulement au moment de la mise en service.
