Exécution serveur vs client
Deux façons de gérer les handoffs
Quand un agent transfère le contrôle à un autre agent, l’API Mistral propose deux modes d’exécution : serveur (automatique) et client (manuel). Le choix entre les deux dépend de votre besoin de contrôle.
Mode serveur (défaut)
En mode serveur, Mistral gère tout le flux automatiquement :
response = client.beta.conversations.start(
agent_id=router_agent.id,
inputs="Analyse et calcule les tendances du marché.",
handoff_execution="server" # Défaut — peut être omis
)
Comportement
- Le routeur reçoit la requête
- Il décide de transférer à l’agent recherche → Mistral exécute le transfert
- L’agent recherche fait son travail et transfère au calculateur → Mistral exécute
- Le calculateur produit le résultat
- Vous recevez la réponse finale avec tous les outputs intermédiaires
Avantages
- Simple — Pas de logique de contrôle à implémenter
- Rapide — Tout s’exécute côté Mistral sans allers-retours réseau
- Fiable — Mistral gère les erreurs et les timeouts
Inconvénients
- Pas de contrôle intermédiaire — Vous ne pouvez pas valider ou modifier les handoffs en cours
- Coût opaque — Tous les agents s’exécutent sans que vous puissiez interrompre
- Pas de logique custom — Impossible d’ajouter du logging ou de la validation entre les étapes
Mode client
En mode client, vous recevez les événements de handoff et décidez quoi faire :
response = client.beta.conversations.start(
agent_id=router_agent.id,
inputs="Analyse le marché du cloud.",
handoff_execution="client"
)
Comportement
- Le routeur reçoit la requête
- Il décide de transférer → Vous recevez un événement
agent.handoff - C’est à vous de continuer la conversation avec l’agent cible
- Vous pouvez valider, logger, modifier, ou refuser le transfert
Traiter les événements manuellement
response = client.beta.conversations.start(
agent_id=router_agent.id,
inputs="Cherche les dernières actualités tech.",
handoff_execution="client"
)
for entry in response.outputs:
if entry.type == "agent.handoff":
target_agent_id = entry.to_agent
print(f"Handoff demandé vers : {target_agent_id}")
# Valider et continuer avec l'agent cible
next_response = client.beta.conversations.append(
conversation_id=response.conversation_id,
agent_id=target_agent_id,
inputs="Continue avec le contexte précédent."
)
# Traiter la réponse de l'agent cible
for next_entry in next_response.outputs:
print(f"{next_entry.type}: {next_entry.content}")
Pattern complet avec boucle
def execute_with_control(router_id, query):
"""Exécute un workflow multi-agents avec contrôle à chaque étape."""
response = client.beta.conversations.start(
agent_id=router_id,
inputs=query,
handoff_execution="client"
)
conversation_id = response.conversation_id
results = []
while True:
handoff_found = False
for entry in response.outputs:
if entry.type == "agent.handoff":
handoff_found = True
target = entry.to_agent
print(f"[LOG] Handoff vers {target}")
# Ici vous pouvez ajouter : validation, logging, métriques
response = client.beta.conversations.append(
conversation_id=conversation_id,
agent_id=target,
inputs="Poursuis le traitement."
)
conversation_id = response.conversation_id
break
elif entry.type == "message.output":
results.append(entry.content)
if not handoff_found:
break
return results
Quand choisir quel mode ?
Mode serveur — pour la production standard
- Workflows prédictibles où vous faites confiance aux agents
- Prototypage rapide
- Applications sans besoin de contrôle intermédiaire
Mode client — pour le contrôle avancé
- Validation humaine — Un humain doit approuver certains transferts
- Logging et audit — Vous tracez chaque étape pour la compliance
- Routage conditionnel — Vous ajoutez de la logique métier entre les handoffs
- Rate limiting — Vous contrôlez le nombre d’agents exécutés
- Fallback — Vous gérez les erreurs avec une logique custom
Exemple : validation humaine
def workflow_avec_validation(router_id, query):
response = client.beta.conversations.start(
agent_id=router_id,
inputs=query,
handoff_execution="client"
)
for entry in response.outputs:
if entry.type == "agent.handoff":
target = entry.to_agent
approval = input(f"Autoriser le transfert vers {target} ? (o/n) ")
if approval.lower() == "o":
response = client.beta.conversations.append(
conversation_id=response.conversation_id,
agent_id=target,
inputs="Continue."
)
else:
print("Transfert refusé.")
break
Points clés à retenir
- Mode serveur = tout automatique, simple et rapide, pas de contrôle intermédiaire
- Mode client = vous recevez les événements de handoff et décidez quoi faire
- Le mode client permet validation, logging, routage conditionnel et gestion d’erreurs
- Pour la plupart des cas, le mode serveur suffit — passez au mode client quand vous avez besoin de contrôle
- Les deux modes supportent les mêmes chaînes d’agents, seul le contrôle diffère