Aller au contenu principal

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

  1. Le routeur reçoit la requête
  2. Il décide de transférer à l’agent recherche → Mistral exécute le transfert
  3. L’agent recherche fait son travail et transfère au calculateur → Mistral exécute
  4. Le calculateur produit le résultat
  5. 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

  1. Le routeur reçoit la requête
  2. Il décide de transférer → Vous recevez un événement agent.handoff
  3. C’est à vous de continuer la conversation avec l’agent cible
  4. 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