Aller au contenu principal

Chaîner les agents en profondeur

Mis à jour le 28 juillet 2026

Des chaînes d’agents sans limite

L’API Agents de Mistral n’impose aucune limite de profondeur pour le chaînage des agents. Un agent peut transférer à un deuxième, qui transfère à un troisième, et ainsi de suite. Cette liberté ouvre la porte à des workflows complexes et modulaires, mais elle vous laisse aussi la responsabilité de la topologie : c’est vous qui décidez qui peut appeler qui, et cette carte détermine autant le comportement du système que les instructions de chaque agent.

Trois topologies et ce qu’elles impliquent

La chaîne linéaire est le pattern le plus simple : chaque agent passe au suivant, sans embranchement.

Agent A → Agent B → Agent C → Réponse

Elle convient aux traitements dont l’ordre est connu d’avance et toujours le même. Un enchaînement recherche puis analyse puis rédaction en est l’illustration typique : on ne rédige pas avant d’avoir analysé, et on n’analyse pas avant d’avoir cherché.

# Agent de recherche
research = client.beta.agents.create(
    model="mistral-large-latest",
    name="research",
    description="Recherche d'informations factuelles.",
    tools=[{"type": "web_search"}]
)

# Agent d'analyse
analyst = client.beta.agents.create(
    model="mistral-large-latest",
    name="analyst",
    description="Analyse de données et extraction d'insights.",
    tools=[{"type": "code_interpreter"}]
)

# Agent de rédaction
writer = client.beta.agents.create(
    model="mistral-large-latest",
    name="writer",
    description="Rédaction de rapports professionnels.",
    instructions="Rédigez un rapport structuré à partir des données analysées."
)

# Chaîner : research → analyst → writer
research = client.beta.agents.update(
    agent_id=research.id,
    handoffs=[analyst.id]
)

analyst = client.beta.agents.update(
    agent_id=analyst.id,
    handoffs=[writer.id]
)

Chaque agent ne connaît que son successeur immédiat : research ignore jusqu’à l’existence de writer. La chaîne se lit donc dans les appels update, et nulle part ailleurs.

La chaîne en étoile répond à un besoin inverse : un routeur central distribue vers des spécialistes qui, eux, ne se parlent pas.

          ┌→ Agent Web Search
Routeur ──┼→ Agent Calculateur
          └→ Agent Rédacteur
router = client.beta.agents.create(
    model="mistral-large-latest",
    name="router",
    description="Orchestre les requêtes.",
    handoffs=[research.id, analyst.id, writer.id]
)

Ici l’ordre n’est pas prédéterminé — c’est la requête qui décide de la destination. Cette forme convient aux assistants polyvalents, où chaque demande relève d’une compétence et d’une seule.

La topologie hybride combine les deux : le routeur distribue, et les spécialistes peuvent en plus se passer le relais entre eux.

          ┌→ Agent Research ──→ Agent Analyst
Routeur ──┤                          │
          └→ Agent Writer ←───────────┘
# Research peut transférer à Analyst
research = client.beta.agents.update(
    agent_id=research.id,
    handoffs=[analyst.id]
)

# Analyst peut transférer à Writer
analyst = client.beta.agents.update(
    agent_id=analyst.id,
    handoffs=[writer.id]
)

# Le routeur peut accéder à tous
router = client.beta.agents.update(
    agent_id=router.id,
    handoffs=[research.id, analyst.id, writer.id]
)

C’est la forme la plus puissante et la plus difficile à déboguer. Une même requête peut suivre des chemins différents d’une exécution à l’autre, ce qui rend la journalisation des handoffs indispensable dès qu’on quitte le bac à sable.

Deux pipelines de production

Le traitement de données illustre la chaîne linéaire dans son usage le plus naturel : collecter, nettoyer, visualiser. Les deux dernières étapes utilisent le même outil, mais les séparer garde chaque jeu d’instructions net — nettoyer et représenter ne sont pas le même métier.

# Étape 1 : Collecte
collector = client.beta.agents.create(
    model="mistral-large-latest",
    name="data-collector",
    description="Collecte des données depuis Internet.",
    tools=[{"type": "web_search"}]
)

# Étape 2 : Nettoyage et transformation
transformer = client.beta.agents.create(
    model="mistral-large-latest",
    name="data-transformer",
    description="Nettoie et transforme les données brutes.",
    tools=[{"type": "code_interpreter"}]
)

# Étape 3 : Analyse et visualisation
visualizer = client.beta.agents.create(
    model="mistral-large-latest",
    name="data-visualizer",
    description="Crée des visualisations et des graphiques.",
    tools=[{"type": "code_interpreter"}]
)

# Chaîner
collector = client.beta.agents.update(agent_id=collector.id, handoffs=[transformer.id])
transformer = client.beta.agents.update(agent_id=transformer.id, handoffs=[visualizer.id])

L’assistant de recherche académique suit la même ossature avec un maillon intermédiaire d’un autre genre. Le synthétiseur ne dispose d’aucun outil : sa valeur tient entièrement à ses instructions, qui lui demandent de confronter les sources — points communs, divergences, lacunes — plutôt que de les empiler.

# Chercheur
searcher = client.beta.agents.create(
    model="mistral-large-latest",
    name="academic-searcher",
    description="Recherche d'articles et de publications académiques.",
    tools=[{"type": "web_search"}]
)

# Synthétiseur
synthesizer = client.beta.agents.create(
    model="mistral-large-latest",
    name="synthesizer",
    description="Synthèse et comparaison de sources multiples.",
    instructions="Identifiez les points communs, les divergences et les lacunes."
)

# Rédacteur
academic_writer = client.beta.agents.create(
    model="mistral-large-latest",
    name="academic-writer",
    description="Rédaction académique structurée avec citations.",
    instructions="Rédigez au format académique avec introduction, méthodologie, résultats, discussion."
)

# Pipeline : searcher → synthesizer → writer
searcher = client.beta.agents.update(agent_id=searcher.id, handoffs=[synthesizer.id])
synthesizer = client.beta.agents.update(agent_id=synthesizer.id, handoffs=[academic_writer.id])

Garder la profondeur raisonnable

L’absence de limite technique n’est pas une invitation. En pratique, deux à quatre agents en chaîne couvrent la grande majorité des besoins, et au-delà de cinq la latence comme le coût augmentent nettement. La raison est mécanique : chaque agent ajoute ses propres tokens de contexte, instructions comprises, par-dessus un historique de conversation qui n’a fait que grossir depuis le premier relais. Un cinquième agent ne travaille pas sur la requête initiale mais sur tout ce que les quatre précédents ont produit.

Avant d’allonger une chaîne, demandez-vous donc si l’étape supplémentaire mérite un agent ou si elle tient dans les instructions d’un agent existant. Une consigne de mise en forme, par exemple, ne justifie presque jamais un maillon de plus.

Sachez enfin qu’un agent n’est pas restreint à une cible unique. Il peut en déclarer plusieurs et choisir selon le contexte.

analyst = client.beta.agents.update(
    agent_id=analyst.id,
    handoffs=[writer.id, visualizer.id, calculator.id]
)

Cet analyste orientera vers le rédacteur si le résultat est prêt à être raconté, vers le visualiseur si les données appellent un graphique, vers le calculateur si un chiffre manque encore. Le choix repose, comme toujours, sur les descriptions des trois cibles — c’est le seul élément dont il dispose pour trancher.

Points clés à retenir

  • Pas de limite de profondeur pour le chaînage d’agents
  • Trois patterns : linéaire (A→B→C), étoile (routeur→spécialistes), hybride (graphe)
  • Chaque agent peut avoir plusieurs cibles de handoff
  • En production, limitez à 2-4 agents en chaîne pour maîtriser latence et coûts
  • Les descriptions des agents sont cruciales pour un routage efficace