Aller au contenu principal

Pipeline multi-outils

Orchestrer des outils en séquence

L’agent météo de la leçon précédente utilisait des outils indépendants. Dans un pipeline multi-outils, les résultats d’un outil alimentent l’appel suivant. Le modèle orchestre la séquence automatiquement — votre rôle est de fournir les outils et d’exécuter les appels.

Architecture d’un pipeline

Un pipeline typique suit ce schéma :

Recherche → Analyse → Action → Notification

Chaque étape produit des données consommées par la suivante. Le modèle gère cette orchestration naturellement grâce au contexte de conversation.

Exemple : pipeline de veille concurrentielle

Imaginons un pipeline qui surveille les prix des concurrents et génère un rapport :

tools = [
    {
        "type": "function",
        "function": {
            "name": "scrape_competitor_prices",
            "description": "Récupérer les prix actuels d'un concurrent "
                          "pour une liste de produits. Retourne un tableau "
                          "de {produit, prix, disponibilité}.",
            "parameters": {
                "type": "object",
                "properties": {
                    "competitor": {
                        "type": "string",
                        "description": "Nom du concurrent"
                    },
                    "products": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Liste des produits à vérifier"
                    }
                },
                "required": ["competitor", "products"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "compare_with_our_prices",
            "description": "Comparer les prix concurrents avec nos prix. "
                          "Retourne les écarts en pourcentage et les "
                          "recommandations d'ajustement.",
            "parameters": {
                "type": "object",
                "properties": {
                    "competitor_prices": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "product": {"type": "string"},
                                "price": {"type": "number"}
                            }
                        }
                    }
                },
                "required": ["competitor_prices"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "generate_report",
            "description": "Générer un rapport PDF avec les résultats de "
                          "l'analyse comparative. Retourne l'URL du rapport.",
            "parameters": {
                "type": "object",
                "properties": {
                    "title": {"type": "string"},
                    "data": {"type": "object"},
                    "format": {
                        "type": "string",
                        "enum": ["pdf", "csv", "json"]
                    }
                },
                "required": ["title", "data"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "send_notification",
            "description": "Envoyer une notification par email ou Slack "
                          "avec un résumé et un lien vers le rapport.",
            "parameters": {
                "type": "object",
                "properties": {
                    "channel": {
                        "type": "string",
                        "enum": ["email", "slack"]
                    },
                    "recipient": {"type": "string"},
                    "message": {"type": "string"},
                    "attachment_url": {"type": "string"}
                },
                "required": ["channel", "recipient", "message"]
            }
        }
    }
]

Exécution du pipeline

Quand l’utilisateur demande « Analyse les prix de ConcurrentX pour nos 5 produits phares et envoie le rapport à l’équipe commerciale », le modèle orchestre :

Tour 1 : scrape_competitor_prices(competitor="ConcurrentX", products=[...])
Tour 2 : compare_with_our_prices(competitor_prices=[résultats du tour 1])
Tour 3 : generate_report(title="Veille prix ConcurrentX", data={...})
Tour 4 : send_notification(channel="slack", recipient="#commercial", ...)

Chaque tour utilise les résultats du précédent. Le modèle passe naturellement les données d’un outil au suivant.

Combinaison outils serveur + client dans un pipeline

Les pipelines les plus puissants combinent outils serveur et client :

tools = [
    {"type": "web_search"},  # Serveur : recherche web
    {
        "type": "function",
        "function": {
            "name": "extract_data",
            "description": "Extraire des données structurées d'un texte brut",
            "parameters": { ... }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "save_to_crm",
            "description": "Sauvegarder les données extraites dans le CRM",
            "parameters": { ... }
        }
    }
]

Flux : le modèle fait une recherche web (automatique côté serveur), puis appelle votre fonction d’extraction (côté client), puis sauvegarde dans le CRM (côté client).

Pattern : fan-out / fan-in

Certains pipelines nécessitent un pattern fan-out (plusieurs appels parallèles) suivi d’un fan-in (agrégation des résultats) :

         ┌→ scrape_site_A ─┐
Requête ─┤→ scrape_site_B ─┤→ aggregate_results → generate_report
         └→ scrape_site_C ─┘

Le modèle gère cela naturellement avec les appels parallèles :

Tour 1 : [scrape_site_A, scrape_site_B, scrape_site_C]  (parallèle)
Tour 2 : aggregate_results(data=[résultat_A, résultat_B, résultat_C])
Tour 3 : generate_report(aggregated_data={...})

Gestion des échecs dans un pipeline

Un pipeline robuste gère les échecs à chaque étape :

def execute_with_retry(name, args, max_retries=2):
    for attempt in range(max_retries + 1):
        try:
            result = execute_function(name, args)
            if "error" not in result:
                return result
        except Exception:
            pass

        if attempt < max_retries:
            time.sleep(1)  # Attente avant réessai

    return {
        "error": f"Échec après {max_retries + 1} tentatives",
        "function": name,
        "partial_data": None
    }

Quand une étape échoue, le modèle peut :

  • Réessayer avec des paramètres ajustés
  • Sauter l’étape et continuer avec des données partielles
  • Informer l’utilisateur et demander des instructions

Points clés à retenir

  • Un pipeline multi-outils enchaîne les résultats d’un outil au suivant
  • Le modèle orchestre la séquence automatiquement grâce au contexte
  • Le pattern fan-out/fan-in combine appels parallèles et agrégation
  • Combinez outils serveur (web_search) et client (vos fonctions) pour des pipelines hybrides
  • Gérez les échecs à chaque étape avec retry et fallback
  • Chaque outil du pipeline doit avoir une responsabilité claire et unique