Applied AI · AvancĂ© 🔮 · Session 4
📝 Guide du professeur
← Retour au programme 📄 Source .md

Applied AI — Niveau AvancĂ©

Session 4 : Architecture multi-agents

Programme : Applied AI — Formation professionnelle en intelligence artificielle Instructeur : Yann Isola Niveau : AvancĂ© — Architectes solutions prĂ©parant la certification Claude Certified Architect DurĂ©e recommandĂ©e : 3 h 30 (2 h de cours magistral + 1 h 30 d’exercices pratiques) PrĂ©requis : Sessions 1 Ă  3 du niveau avancĂ© (orchestration, outils/function calling, gestion de contexte)


Objectifs pédagogiques

À l’issue de cette session, les participants seront capables de :

  1. Choisir et justifier une stratégie de décomposition de tùches (verticale, horizontale, récursive) selon la complexité, le budget de tokens et le bénéfice de spécialisation.
  2. Concevoir une politique d’escalade complĂšte avec Human-in-the-Loop (HITL — humain dans la boucle) : dĂ©clencheurs, motifs d’escalade, intĂ©gration du feedback humain et gestion des SLA (Service Level Agreement — accord de niveau de service).
  3. ImplĂ©menter les patrons de gestion d’erreurs propres aux systĂšmes multi-agents : retry idempotent, checkpointing d’état, circuit breaker (disjoncteur logiciel), dĂ©gradation gracieuse et files de lettres mortes (DLQ — Dead Letter Queue).
  4. Instrumenter un systÚme multi-agents avec du traçage distribué et des identifiants de corrélation.

Plan de la session

Bloc Durée Contenu
1 40 min Stratégies de décomposition de tùches (Chapitre 8)
2 40 min Escalade et Human-in-the-Loop (Chapitre 9)
3 40 min Gestion d’erreurs multi-agents (Chapitre 10)
4 90 min Exercices pratiques + démonstration interactive (page web)
5 10 min Quiz de validation et synthĂšse

Bloc 1 — StratĂ©gies de dĂ©composition de tĂąches

1.1 Pourquoi décomposer ?

Un agent unique confronté à une tùche complexe rencontre trois murs :

La décomposition transforme un problÚme monolithique en un graphe de sous-tùches confiées à des agents dédiés, coordonnés par un orchestrateur.

Point pĂ©dagogique : insistez sur le fait que la dĂ©composition n’est pas gratuite. Chaque agent supplĂ©mentaire ajoute de la latence, du coĂ»t en tokens et de la complexitĂ© opĂ©rationnelle. La question n’est jamais « peut-on dĂ©composer ? » mais « le gain dĂ©passe-t-il le coĂ»t ? ».

1.2 Décomposition verticale (par profondeur)

Principe : découper le flux de travail en étapes séquentielles de nature différente. Le motif canonique :

Planification → ExĂ©cution → VĂ©rification

Avantages :

Limites :

Exemple d’implĂ©mentation (pseudocode Python) :

class VerticalPipeline:
    def __init__(self, planner, executor, verifier, max_repairs=2):
        self.planner = planner        # Agent LLM avec prompt "planificateur"
        self.executor = executor      # Agent LLM avec accĂšs aux outils
        self.verifier = verifier      # Agent LLM avec prompt "auditeur"
        self.max_repairs = max_repairs

    def run(self, task: str) -> Result:
        plan = self.planner.plan(task)          # → liste d'Ă©tapes + critĂšres
        result = self.executor.execute(plan)    # → artefacts produits
        for attempt in range(self.max_repairs):
            report = self.verifier.check(result, plan.success_criteria)
            if report.ok:
                return Result(status="success", artifacts=result)
            # Le rapport d'audit devient une consigne de réparation
            result = self.executor.repair(result, report.issues)
        return Result(status="needs_human_review", artifacts=result)

Notez la sortie needs_human_review : la dĂ©composition verticale s’articule naturellement avec l’escalade (Bloc 2).

1.3 Décomposition horizontale (par domaine)

Principe : dĂ©couper par domaine de compĂ©tence. Chaque agent est propriĂ©taire d’un domaine et le traite de bout en bout.

Exemple — analyse d’un dossier de conformitĂ© financiĂšre :

                    ┌──────────────────┐
                    │  Orchestrateur   │
                    └────────┬─────────┘
         ┌──────────────┬────┮─────────┬───────────────┐
         ▌              ▌              ▌               ▌
  Agent juridique  Agent fiscal   Agent risque   Agent rédaction
  (réglementation) (imposition)   (scoring)      (synthÚse finale)

Avantages :

Limites :

1.4 Décomposition récursive

Principe : chaque agent peut lui-mĂȘme dĂ©composer sa sous-tĂąche et dĂ©lĂ©guer Ă  des sous-agents, formant un arbre de dĂ©lĂ©gation.

Orchestrateur racine
├── Agent A (sous-tñche 1)
│   ├── Sous-agent A1
│   └── Sous-agent A2
│       └── Sous-sous-agent A2a
└── Agent B (sous-tñche 2)

RÚgles de sécurité indispensables :

  1. Profondeur maximale (max_depth) : sans limite, un agent peut crĂ©er une rĂ©cursion infinie de dĂ©lĂ©gations. Valeur typique : 2 Ă  3 niveaux. ⚠ (valeur indicative, Ă  calibrer selon votre charge)
  2. Budget de tokens hĂ©ritĂ© : chaque niveau reçoit une fraction du budget parent. Si le parent a 100 000 tokens, il n’en dĂ©lĂšgue par exemple que 30 000 par enfant.
  3. Contrat de résultat : chaque sous-agent retourne un format structuré (JSON avec statut, artefacts, coût consommé), jamais du texte libre non contraint.

Quand la rĂ©cursion brille : les problĂšmes Ă  structure fractale — revue de code d’un monorepo (chaque module se dĂ©compose en fichiers), due diligence documentaire (chaque dossier se dĂ©compose en piĂšces), gĂ©nĂ©ration de sites (chaque page se dĂ©compose en sections).

1.5 Quand décomposer ? Les trois critÚres de décision

CritĂšre Question Ă  poser Seuil indicatif
Seuil de complexitĂ© La tĂąche comporte-t-elle plus de N Ă©tapes hĂ©tĂ©rogĂšnes ? Un seul prompt systĂšme peut-il couvrir tous les cas ? > 5–7 Ă©tapes distinctes ⚠
Budget de tokens Le contexte nĂ©cessaire (documents + historique + outils) dĂ©passe-t-il ~60–70 % de la fenĂȘtre ? ⚠ Saturation prĂ©visible → dĂ©composer
Bénéfice de spécialisation Des prompts spécialisés amélioreraient-ils mesurablement la qualité par domaine ? Gain qualité > surcoût orchestration

Arbre de décision à présenter au tableau :

  1. La tĂąche tient-elle confortablement dans un seul contexte avec une qualitĂ© acceptable ? → Ne dĂ©composez pas. (L’architecture la plus robuste est celle qui n’existe pas.)
  2. Les Ă©tapes sont-elles de natures diffĂ©rentes (planifier vs exĂ©cuter vs vĂ©rifier) ? → Verticale.
  3. Les sous-problĂšmes relĂšvent-ils de domaines diffĂ©rents et parallĂ©lisables ? → Horizontale.
  4. La structure est-elle imprĂ©visible ou fractale ? → RĂ©cursive, avec garde-fous stricts.
  5. Cas rĂ©els : souvent hybride — un pipeline vertical dont l’étape d’exĂ©cution est horizontale.

PiĂšge de certification : les questions d’examen opposent souvent verticale et horizontale sur un cas ambigu. Le discriminant fiable : sĂ©quentialitĂ© de natures diffĂ©rentes → verticale ; parallĂ©lisme de domaines → horizontale.


Bloc 2 — Escalade et Human-in-the-Loop (HITL)

2.1 Pourquoi l’escalade est une exigence d’architecture, pas une option

Aucun systĂšme d’agents n’atteint 100 % d’autonomie fiable. L’architecte doit concevoir dĂšs le dĂ©part les chemins par lesquels le systĂšme rend la main Ă  l’humain. Un systĂšme sans escalade explicite escalade quand mĂȘme — mais de façon chaotique : tickets support, incidents, perte de confiance.

HITL (Human-in-the-Loop — humain dans la boucle) dĂ©signe l’ensemble des mĂ©canismes par lesquels un humain valide, corrige ou reprend le travail d’un agent.

2.2 Les trois dĂ©clencheurs d’escalade

a) Confiance sous le seuil

L’agent (ou un modĂšle Ă©valuateur) produit un score de confiance sur sa propre sortie. Sous un seuil dĂ©fini, la tĂąche est escaladĂ©e.

CONFIDENCE_THRESHOLD = 0.75  # ⚠ Ă  calibrer sur donnĂ©es rĂ©elles, jamais au doigt mouillĂ©

assessment = judge_agent.evaluate(answer, context)
if assessment.confidence < CONFIDENCE_THRESHOLD:
    escalate(task, reason="low_confidence", score=assessment.confidence)

Point critique Ă  enseigner : les LLM (Large Language Models — grands modĂšles de langage) sont mal calibrĂ©s sur leur propre confiance auto-dĂ©clarĂ©e. Bonnes pratiques :

b) Détection hors périmÚtre (out-of-scope)

L’agent reconnaĂźt que la demande sort de son domaine autorisĂ© : sujet non couvert, langue non supportĂ©e, demande de conseil rĂ©glementĂ© (juridique, mĂ©dical, financier), tentative de contournement.

ImplĂ©mentation typique : un classifieur de pĂ©rimĂštre en amont (petit modĂšle rapide) + une consigne d’auto-dĂ©tection dans le prompt systĂšme de l’agent (dĂ©fense en profondeur — deux couches valent mieux qu’une).

c) Niveau de risque

Certaines actions sont escaladĂ©es par nature, indĂ©pendamment de la confiance : virement au-delĂ  d’un montant, suppression de donnĂ©es, communication externe engageante, modification de production. On dĂ©finit une matrice de risque :

Impact \ Réversibilité Réversible Irréversible
Faible Autonome Autonome + journalisation renforcée
Moyen Autonome + revue a posteriori Approbation humaine préalable
ÉlevĂ© Approbation humaine prĂ©alable Approbation humaine + double validation

2.3 Les trois patrons d’escalade

Patron 1 — Pause-and-ask (pause et question)

L’agent suspend son exĂ©cution, pose une question prĂ©cise Ă  l’humain, attend la rĂ©ponse, puis reprend. Synchrone du point de vue de la tĂąche.

Patron 2 — Queue-for-review (file de revue)

L’agent termine son travail mais le rĂ©sultat est placĂ© dans une file de validation avant publication/exĂ©cution. Asynchrone, l’agent est libĂ©rĂ© immĂ©diatement.

Patron 3 — Fallback-to-human (transfert à l’humain)

L’agent abandonne la tĂąche et la transfĂšre intĂ©gralement Ă  un humain, avec tout le contexte accumulĂ©. C’est le filet de sĂ©curitĂ© terminal.

2.4 Intégration du feedback humain

L’escalade n’est pas seulement un filet de sĂ©curitĂ© — c’est un capteur d’apprentissage. Chaque correction humaine est une donnĂ©e.

Boucle de feedback en quatre temps :

  1. Capture : chaque décision humaine (approbation, rejet, correction) est journalisée de façon structurée : {task_id, sortie_agent, action_humaine, sortie_corrigée, motif}.
  2. AgrĂ©gation : analyse pĂ©riodique des corrections par catĂ©gorie — quels types de tĂąches sont le plus souvent corrigĂ©s ? Quels motifs reviennent ?
  3. Injection : les enseignements retournent dans le systÚme par trois canaux, du plus léger au plus lourd :
    • Prompt systĂšme : ajout de rĂšgles et contre-exemples tirĂ©s des corrections rĂ©currentes.
    • Exemples few-shot / base de connaissances : les paires (cas → correction validĂ©e) alimentent la rĂ©cupĂ©ration de contexte (RAG — Retrieval-Augmented Generation, gĂ©nĂ©ration augmentĂ©e par rĂ©cupĂ©ration).
    • Fine-tuning (ajustement fin du modĂšle) : uniquement si le volume de corrections est suffisant et le comportement cible stable. ⚠ CoĂ»teux, Ă  réévaluer Ă  chaque Ă©volution de modĂšle de base.
  4. Mesure : le taux de correction par catĂ©gorie doit baisser aprĂšs injection. Sinon, la boucle ne boucle pas — c’est du théùtre de feedback.

Point d’insistance pĂ©dagogique : beaucoup d’organisations capturent le feedback mais ne l’injectent jamais. La question d’audit Ă  poser : « montrez-moi la derniĂšre modification de prompt motivĂ©e par une correction humaine, et sa date ».

2.5 Gestion des SLA d’escalade

Une escalade sans SLA (Service Level Agreement — accord de niveau de service) est une escalade vers un trou noir.

Composants d’une politique de SLA :

  1. Timeout d’escalade : si aucun humain ne rĂ©pond dans le dĂ©lai, une action par dĂ©faut s’applique. Trois stratĂ©gies de timeout :

    • Fail-safe (sĂ©curitĂ© par dĂ©faut) : la tĂąche est annulĂ©e ou mise en attente prolongĂ©e — pour les actions risquĂ©es.
    • Fail-operational : l’agent applique l’option conservatrice prĂ©-approuvĂ©e — pour les tĂąches Ă  faible enjeu.
    • RĂ©-escalade : la demande monte d’un niveau (n+1 hiĂ©rarchique, Ă©quipe d’astreinte).
  2. Files de priorité : toutes les escalades ne se valent pas. File typique à trois niveaux :

PrioritĂ© Exemple DĂ©lai cible ⚠ (indicatif)
P1 — Critique Transaction bloquĂ©e, client en dĂ©tresse, risque lĂ©gal < 15 min
P2 — Standard Validation de contenu, ambiguĂŻtĂ© non bloquante < 4 h
P3 — DiffĂ©rable Revue par Ă©chantillonnage, amĂ©lioration continue < 48 h
  1. Routage par compĂ©tence : l’escalade juridique va au juriste, pas au support gĂ©nĂ©raliste. Le paquet d’escalade porte des Ă©tiquettes (domaine, langue, urgence) exploitĂ©es par le routeur.

  2. Tableaux de bord : taux d’escalade, temps de premiĂšre rĂ©ponse humaine, taux de dĂ©passement de SLA, rĂ©partition par motif. Ce sont des mĂ©triques d’architecture, pas seulement d’exploitation.


Bloc 3 — Gestion d’erreurs dans les systùmes multi-agents

3.1 La propagation d’erreurs : l’effet domino

Dans un systĂšme multi-agents, une erreur locale devient systĂ©mique par cascade Ă  travers l’orchestrateur :

Sous-agent C échoue
      ↓
Agent B attend C → timeout → B Ă©choue
      ↓
L'orchestrateur reçoit deux Ă©checs corrĂ©lĂ©s → abandonne la mission entiĂšre
      ↓
Résultat : 45 minutes de travail des agents A, D, E jetées à la poubelle

Trois principes anti-cascade :

  1. Isolation (bulkheads — cloisons Ă©tanches) : l’échec d’une branche ne doit pas invalider les branches indĂ©pendantes. L’orchestrateur agrĂšge les rĂ©sultats partiels : « 4 analyses sur 5 livrĂ©es, l’analyse fiscale a Ă©chouĂ© ».
  2. Timeouts systématiques : tout appel inter-agents porte un délai maximal. Un agent qui attend indéfiniment est une panne silencieuse.
  3. Typologie d’erreurs : distinguer les erreurs rĂ©essayables (timeout rĂ©seau, rate limit — limite de dĂ©bit d’API, surcharge temporaire) des erreurs fatales (entrĂ©e invalide, permission refusĂ©e, contrainte mĂ©tier violĂ©e). RĂ©essayer une erreur fatale gaspille du budget et retarde l’escalade.
class AgentError(Exception):
    retryable: bool

class RateLimitError(AgentError):   retryable = True
class ToolTimeoutError(AgentError): retryable = True
class InvalidInputError(AgentError): retryable = False
class PolicyViolationError(AgentError): retryable = False

3.2 Stratégies de retry (nouvelle tentative)

a) La condition prĂ©alable : l’idempotence des outils

Un outil est idempotent si l’exĂ©cuter deux fois produit le mĂȘme effet qu’une fois. Sans idempotence, le retry est dangereux : rejouer « crĂ©er une facture » aprĂšs un timeout ambigu peut crĂ©er un doublon (le timeout ne dit pas si la premiĂšre tentative a abouti cĂŽtĂ© serveur).

Technique standard : la clĂ© d’idempotence — le client gĂ©nĂšre un identifiant unique par intention d’opĂ©ration ; le serveur dĂ©duplique.

import uuid

def create_invoice(client_id: str, amount: float) -> Invoice:
    idem_key = f"inv-{uuid.uuid4()}"          # générée UNE fois par intention
    for attempt in range(3):
        try:
            return api.post("/invoices",
                            json={"client_id": client_id, "amount": amount},
                            headers={"Idempotency-Key": idem_key})
        except TransientError:
            sleep(backoff(attempt))            # backoff exponentiel + jitter
    raise ToolFailedError("create_invoice", idem_key)

def backoff(attempt: int) -> float:
    """Backoff exponentiel avec jitter (gigue aléatoire) pour éviter
    que tous les agents ne rĂ©essaient au mĂȘme instant (thundering herd)."""
    import random
    return min(30, (2 ** attempt)) * random.uniform(0.5, 1.5)

RĂšgle d’architecte : dans la spĂ©cification de chaque outil exposĂ© aux agents, documenter explicitement idempotent: true/false. L’orchestrateur n’autorise le retry automatique que sur les outils marquĂ©s idempotents.

b) Checkpointing d’état (points de sauvegarde)

Pour les tĂąches longues, sauvegarder l’état Ă  chaque jalon permet de reprendre aprĂšs Ă©chec sans tout rejouer :

class CheckpointedMission:
    def run(self, mission_id: str):
        state = self.store.load(mission_id) or MissionState.initial()
        for step in self.plan.steps:
            if step.id in state.completed_steps:
                continue                       # déjà fait : on saute
            result = self.execute(step, state)
            state.record(step.id, result)
            self.store.save(mission_id, state)  # checkpoint aprĂšs CHAQUE jalon

Le checkpoint contient : Ă©tapes accomplies, artefacts produits, budget consommĂ©, et le contexte minimal nĂ©cessaire Ă  la reprise (pas tout l’historique de conversation — le rĂ©sumer).

c) Rollback partiel (annulation partielle)

Quand une Ă©tape Ă©choue au milieu d’une sĂ©quence avec effets de bord, on annule les effets de la sĂ©quence en cours sans dĂ©truire le travail des sĂ©quences validĂ©es. Patron : compensation (chaque action possĂšde une action inverse enregistrĂ©e). InspirĂ© du patron Saga des architectures microservices :

Étape 1 : rĂ©server stock       → compensation : libĂ©rer stock
Étape 2 : dĂ©biter compte       → compensation : recrĂ©diter compte
Étape 3 : crĂ©er expĂ©dition ✗ ÉCHEC
→ Rejouer les compensations 2 puis 1 (ordre inverse), Ă©tat cohĂ©rent restaurĂ©.

3.3 Le patron Circuit Breaker (disjoncteur logiciel)

ProblĂšme : un service externe (API d’outil, sous-agent) tombe en panne. Sans protection, chaque tĂąche continue de l’appeler, subit le timeout complet, gaspille tokens et latence, et surcharge le service dĂ©jĂ  agonisant.

Solution : un disjoncteur avec trois états, comme un disjoncteur électrique :

                 N échecs consécutifs
   ┌─────────┐ ─────────────────────â–ș ┌─────────┐
   │  FERMÉ  │                        │ OUVERT  │
   │(closed) │ ◄──── succùs ────┐     │ (open)  │
   └─────────┘                  │     └────┬────┘
   appels passent               │          │ aprĂšs dĂ©lai de refroidissement
   normalement                  │          â–Œ (cooldown)
                          ┌─────┮───────────┐
                          │   SEMI-OUVERT   │──── Ă©chec ────â–ș retour Ă  OUVERT
                          │   (half-open)   │
                          └─────────────────┘
                          laisse passer UN appel d'essai
import time

class CircuitBreaker:
    def __init__(self, failure_threshold=5, cooldown_s=30):
        self.failure_threshold = failure_threshold
        self.cooldown_s = cooldown_s
        self.failures = 0
        self.state = "closed"
        self.opened_at = None

    def call(self, fn, *args, **kwargs):
        if self.state == "open":
            if time.time() - self.opened_at >= self.cooldown_s:
                self.state = "half_open"       # tentative d'essai autorisée
            else:
                raise CircuitOpenError("appel rejeté : circuit ouvert")
        try:
            result = fn(*args, **kwargs)
        except TransientError:
            self._on_failure()
            raise
        self._on_success()
        return result

    def _on_failure(self):
        self.failures += 1
        if self.state == "half_open" or self.failures >= self.failure_threshold:
            self.state = "open"
            self.opened_at = time.time()

    def _on_success(self):
        self.failures = 0
        self.state = "closed"

SpĂ©cificitĂ© multi-agents : placer un disjoncteur par dĂ©pendance (un par outil externe, un par sous-agent), jamais un disjoncteur global. Quand un disjoncteur s’ouvre, l’orchestrateur doit le savoir pour activer la dĂ©gradation gracieuse (§3.4) plutĂŽt que de laisser les tĂąches s’écraser contre lui.

3.4 Dégradation gracieuse

Principe : face Ă  une panne partielle, rĂ©duire la capacitĂ© plutĂŽt qu’échouer complĂštement. Le systĂšme livre un service diminuĂ© mais honnĂȘte.

Échelle de dĂ©gradation (Ă  concevoir a priori, pas dans la panique) :

Niveau Situation Comportement
0 — Nominal Tout fonctionne Service complet
1 — DĂ©gradĂ© lĂ©ger Un outil d’enrichissement en panne RĂ©ponse sans l’enrichissement, mention explicite du manque
2 — DĂ©gradĂ© fort Sous-agent spĂ©cialisĂ© indisponible RĂ©ponse gĂ©nĂ©rique par l’agent principal + avertissement + proposition d’escalade
3 — Minimal ModĂšle principal indisponible Bascule sur modĂšle de secours plus petit, pĂ©rimĂštre restreint ⚠
4 — Refus honnĂȘte Rien ne fonctionne Message d’indisponibilitĂ© + capture de la demande pour traitement diffĂ©rĂ©

Deux rĂšgles absolues :

  1. Transparence : ne jamais livrer une rĂ©ponse dĂ©gradĂ©e en la prĂ©sentant comme complĂšte. « L’analyse fiscale n’a pas pu ĂȘtre rĂ©alisĂ©e (service indisponible) ; voici les 4 autres volets » — c’est acceptable. Le silence sur le manque ne l’est pas.
  2. DĂ©gradation ≠ baisse de sĂ©curitĂ© : les garde-fous (filtres, validations, escalades) ne se dĂ©gradent jamais. On dĂ©grade la capacitĂ©, pas le contrĂŽle.

3.5 Dead Letter Queue (DLQ — file de lettres mortes)

Principe : une tĂąche qui a Ă©puisĂ© ses retries et ne peut ĂȘtre traitĂ©e n’est jamais silencieusement supprimĂ©e. Elle est dĂ©posĂ©e dans une file dĂ©diĂ©e — la file de lettres mortes — avec tout son contexte de diagnostic.

Contenu d’une entrĂ©e DLQ bien formĂ©e :

{
  "task_id": "task-8842",
  "correlation_id": "corr-a1b9f3",
  "deposited_at": "2026-07-02T14:31:07Z",
  "attempts": 3,
  "last_error": {"type": "ToolTimeoutError", "tool": "search_registry", "timeout_s": 60},
  "agent_chain": ["orchestrator", "agent-juridique", "sub-agent-registre"],
  "payload": { "...la tĂąche originale intacte..." },
  "state_checkpoint_ref": "ckpt://missions/8842/step-3"
}

Exploitation de la DLQ :

3.6 Observabilité : traçage distribué et identifiants de corrélation

Dans un systĂšme oĂč une demande traverse un orchestrateur, trois agents et sept appels d’outils, rĂ©pondre Ă  « pourquoi cette rĂ©ponse est-elle fausse ? » sans traçage relĂšve de l’archĂ©ologie.

a) Identifiant de corrélation (correlation ID)

Un identifiant unique est gĂ©nĂ©rĂ© Ă  l’entrĂ©e de la demande et propagĂ© Ă  travers chaque agent, chaque appel d’outil, chaque message de file. Toute ligne de journal le porte.

import contextvars, uuid

correlation_id = contextvars.ContextVar("correlation_id")

def handle_request(request):
    cid = request.headers.get("X-Correlation-ID") or f"corr-{uuid.uuid4().hex[:8]}"
    correlation_id.set(cid)
    log.info("request.received", cid=cid, task=request.task)
    return orchestrator.run(request, cid=cid)   # propagation explicite aux sous-agents

RĂšgle : grep corr-a1b9f3 logs/* doit reconstituer l’intĂ©gralitĂ© du parcours d’une demande. Si un composant « perd » l’identifiant, l’observabilitĂ© est cassĂ©e Ă  cet endroit prĂ©cis.

b) Traçage distribué (distributed tracing)

Au-delĂ  des logs : chaque opĂ©ration devient un span (segment chronomĂ©trĂ©) rattachĂ© Ă  une trace (l’arbre complet de la demande). Standard de facto : OpenTelemetry (spĂ©cification ouverte d’observabilitĂ©).

Trace corr-a1b9f3 (durée totale : 42,3 s)
└── span orchestrator.run                    [42,3 s]
    ├── span planner.plan                    [3,1 s]  ✓
    ├── span agent-juridique.analyze         [18,2 s] ✓
    │   ├── span tool.search_registry        [12,0 s] ✓  ← goulot identifiĂ©
    │   └── span llm.generate                [5,9 s]  ✓
    ├── span agent-fiscal.analyze            [17,8 s] ✗ TIMEOUT
    │   └── span tool.tax_api                [15,0 s] ✗  ← cause racine
    └── span redactor.merge                  [2,4 s]  ✓ (mode dĂ©gradĂ© niveau 1)

Attributs de span spĂ©cifiques aux agents LLM Ă  capturer : modĂšle utilisĂ©, tokens entrĂ©e/sortie, coĂ»t estimĂ©, nom de l’outil, dĂ©cision d’escalade, Ă©tat du disjoncteur, version du prompt systĂšme. Ces attributs transforment le traçage en outil d’optimisation de coĂ»ts et de qualitĂ©, pas seulement de dĂ©bogage.

Question d’audit d’architecture (Ă  poser telle quelle en entretien de certification) : « Montrez-moi la trace complĂšte d’une demande qui a Ă©chouĂ© la semaine derniĂšre, du point d’entrĂ©e jusqu’à la DLQ. » Si l’équipe ne peut pas, l’observabilitĂ© est dĂ©clarative, pas rĂ©elle.


Synthùse : la grille de l’architecte

Domaine Question de conception Artefact livrable
DĂ©composition Verticale, horizontale, rĂ©cursive — et pourquoi ? Diagramme d’architecture + justification des 3 critĂšres
Escalade Quels dĂ©clencheurs, quels patrons, quels SLA ? Politique d’escalade + matrice de risque
Erreurs Que se passe-t-il quand X tombe ? (pour chaque X) Carte des modes de panne + échelle de dégradation
Retry Quels outils sont idempotents ? SpĂ©cification d’outils annotĂ©e
ObservabilitĂ© Peut-on rejouer l’histoire d’une demande ? SchĂ©ma de propagation du correlation ID

Message final aux futurs certifiĂ©s : un systĂšme multi-agents n’est pas jugĂ© sur son comportement quand tout va bien — n’importe quelle dĂ©mo y arrive. Il est jugĂ© sur son comportement quand un outil timeout, quand un agent hallucine, quand un humain ne rĂ©pond pas. La certification Ă©value prĂ©cisĂ©ment cela : l’architecture des mauvais jours.


Notes pour l’instructeur