Lección 3 — Orchestrer les appels

Appels parallèles et appels en chaîne

5 min de lectura

Este contenido aún no está traducido. Se muestra la versión original.

Appels parallèles et appels en chaîne

Deux formes d'orchestration

  • Appels parallèles : dans un même tour, le modèle demande plusieurs fonctions indépendantes (le solde de Camille et celui de Karim). Votre code reçoit une liste de function_calls.
  • Appels en chaîne (on dit aussi compositionnels) : la sortie d'un appel sert d'entrée au suivant (on cherche l'identifiant de Camille, puis on lit son solde). Cela demande plusieurs tours.

La question « Compare les soldes de RTT de Camille Martin et de Karim Benali » combine les deux :

flowchart LR
  Q["Question"] --> T1["Tour 1 (parallèle)"]
  T1 --> C1["chercher_employe('Camille Martin')"]
  T1 --> C2["chercher_employe('Karim Benali')"]
  C1 --> T2["Tour 2 (parallèle)"]
  C2 --> T2
  T2 --> S1["consulter_solde('E001')"]
  T2 --> S2["consulter_solde('E002')"]
  S1 --> R["Tour 3 : réponse en texte"]
  S2 --> R

Le passage du tour 1 au tour 2 est la chaîne ; à l'intérieur de chaque tour, les deux appels sont parallèles.

Ce que la boucle doit faire

Une boucle naïve qui ne traite que response.function_calls[0] perd le second appel. La boucle du lab traite toute la liste et renvoie toutes les réponses dans un seul message :

files/assistant.py (extrait)
for tour in range(MAX_TOURS):
    reponse = generer(client, historique, config)
    historique.append(reponse.candidates[0].content)
    appels = reponse.function_calls or []
    if not appels:
        return reponse.text or ""
    parts = [types.Part(function_response=types.FunctionResponse(
                 id=fc.id, name=fc.name, response=executer(fc, utilisateur, confirmer)))
             for fc in appels]
    historique.append(types.Content(role="user", parts=parts))   # UN message, N réponses
return "Je n'ai pas pu terminer en un nombre raisonnable d'étapes. Un humain RH va reprendre."
SituationCe que reçoit votre codeCe que vous renvoyez
Un appel1 function_call1 function_response
Appels parallèlesN function_call dans le même tourN function_response dans un Content, mêmes id
Chaîneun tour d'appels, puis un autre au tour suivantles réponses du tour, puis on relance le modèle
Réponse finaledu texte, aucun function_callrien : on sort de la boucle

La limite de tours

MAX_TOURS = 6 borne la chaîne. Sans limite, un modèle qui se trompe d'outil peut boucler en consommant des jetons. Au-delà, l'assistant rend la main à un humain au lieu d'inventer.

Le modèle renvoie deux function_calls dans le même tour. Que doit faire votre boucle ?

Pourquoi chercher_employe puis consulter_solde ne peuvent-ils pas être appelés en parallèle ?

Exercice : exécuter vraiment en parallèle

Modifiez la construction de parts pour exécuter les appels d'un tour en même temps avec ThreadPoolExecutor, en conservant l'ordre des réponses.

Voir la solution
from concurrent.futures import ThreadPoolExecutor

with ThreadPoolExecutor(max_workers=4) as pool:
    resultats = list(pool.map(lambda fc: executer(fc, utilisateur, confirmer), appels))
parts = [types.Part(function_response=types.FunctionResponse(id=fc.id, name=fc.name, response=r))
         for fc, r in zip(appels, resultats)]

pool.map conserve l'ordre. Deux précautions : le client httpx.Client est utilisable depuis plusieurs threads, mais la confirmation console ne l'est pas (deux input() simultanés). Exécutez donc en parallèle uniquement les outils de lecture, et les outils sensibles un par un.

Résultat obtenu

python e2e.py, scénario 2, exécuté le 2026-10-15 avec gemini-3.5-flash (utilisateur E004, manager de Camille et Karim) :

[E004] Compare les soldes de RTT de Camille Martin et de Karim Benali.   (mode AUTO)
  [tour 1] 2 appel(s) : chercher_employe({"nom": "Camille Martin"}), chercher_employe({"nom": "Karim Benali"})
  [tour 2] 2 appel(s) : consulter_solde({"employe_id": "E001"}), consulter_solde({"employe_id": "E002"})
  → Camille Martin dispose de **4 jours** de RTT, tandis que Karim Benali en a **9 jours**.

Le même scénario sur Vertex AI (gemini-2.5-flash, europe-west1) a produit exactement les mêmes 4 appels en 2 tours.

Je sais faire

  • Distinguer appels parallèles (même tour) et appels en chaîne (tours successifs)
  • Renvoyer N réponses dans un seul message avec les bons id
  • Borner la boucle avec un nombre maximal de tours
  • Exécuter réellement en parallèle les outils de lecture quand l'API est lente
Siguiente