Parallel Tool Calls
Les parallel tool calls (appels d’outils parallèles) désignent la capacité d’un LLM à générer plusieurs requêtes d’exécution d’outils en une seule étape de raisonnement, permettant leur exécution simultanée plutôt que séquentielle.
- Catégorie
- Mécanisme d’interaction LLM / outils externes
- Aussi appelé
- Parallel function calling, appels de fonctions parallèles
- Fournisseurs
- OpenAI (GPT-4o, GPT-5.x), Anthropic (Claude 4.x), Google (Gemini 3.x)
- Prérequis
- API avec paramètre
tools, fonctions indépendantes entre elles - Gain typique
- Latence réduite de 50 à 80 %, coût API réduit de 30 à 40 %
- Verdict
- Indispensable pour tout agent IA en production qui appelle plus d’un outil par tour
Principe : pourquoi paralléliser les appels d’outils ?
Quand un agent IA doit répondre à une question complexe, il a souvent besoin de données provenant de plusieurs sources : une API météo, un calendrier, une base de données de produits. En mode séquentiel classique, chaque appel attend le résultat du précédent avant de lancer le suivant. Quatre appels de 300 ms chacun donnent 1,2 seconde de latence incompressible.
Avec les parallel tool calls, le modèle identifie en une seule passe de raisonnement tous les outils nécessaires et génère leurs appels simultanément. Le temps total tombe alors à la durée du plus long appel individuel : environ 300 ms au lieu de 1,2 seconde. Pour l’utilisateur final, la différence entre une réponse en 3 secondes et une réponse en 500 ms est perceptible et impacte directement l’adoption du produit.
Ce n’est pas qu’une question de vitesse. Chaque tour de conversation consomme des tokens (le prompt complet est renvoyé à chaque itération). Réduire le nombre de tours réduit mécaniquement la consommation de tokens et donc le coût API. Les recherches récentes sur les agents de deep research montrent qu’avec 3 appels parallèles par tour au lieu d’1, le coût total peut chuter d’environ 36 % et le temps d’exécution de plus de 40 %.
Comment fonctionnent les parallel tool calls
Le flux séquentiel classique
Dans le mode séquentiel, le cycle se répète à chaque étape :
| Étape | Action | Acteur |
|---|---|---|
| 1 | Le modèle produit un raisonnement R₁ et un appel d’outil A₁ | LLM |
| 2 | L’environnement exécute A₁ et retourne le résultat O₁ | Votre code |
| 3 | Le modèle produit R₂ et A₂ en intégrant O₁ dans son contexte | LLM |
| 4 | L’environnement exécute A₂ et retourne O₂ | Votre code |
| … | Répétition jusqu’à la réponse finale | LLM |
Chaque aller-retour (étapes 1-2) implique un appel API complet au LLM, avec le prompt entier recontextualisé. Pour N outils, vous avez N tours, N appels API, et une latence égale à la somme de toutes les exécutions plus tous les temps d’inférence.
Le flux parallèle
Avec les parallel tool calls, le modèle génère en un seul tour un ensemble de M appels d’outils {A₁, A₂, …, Aₘ} plutôt qu’un seul. Votre couche d’orchestration les lance tous en même temps. Les résultats {O₁, O₂, …, Oₘ} sont collectés et renvoyés au modèle en un seul bloc. Le modèle produit alors sa réponse finale (ou un nouveau lot d’appels si nécessaire).
Concrètement, le schéma passe de :
Prompt → LLM → Outil 1 → LLM → Outil 2 → LLM → Outil 3 → LLM → Réponse
(7 appels API, latence = somme de tout)
À :
Prompt → LLM → [Outil 1 + Outil 2 + Outil 3] → LLM → Réponse
(2 appels API, latence = max(outil1, outil2, outil3) + inférence)
La condition d’indépendance
Les parallel tool calls ne fonctionnent que pour des outils indépendants les uns des autres. Si l’outil B a besoin du résultat de l’outil A pour fonctionner, ils doivent être appelés séquentiellement. Le modèle est censé détecter ces dépendances automatiquement, mais en pratique, la qualité de cette détection varie selon les fournisseurs et les modèles.
Exemples d’appels parallélisables :
| Scénario | Outils appelés en parallèle | Pourquoi c’est indépendant |
|---|---|---|
| Comparer la météo de 3 villes | get_weather("Paris"), get_weather("Tokyo"), get_weather("NYC") |
Chaque ville est une requête isolée |
| Tableau de bord agent | get_calendar(), get_emails(), get_tasks() |
Trois sources de données sans dépendance |
| Recherche multi-sources | search_web("sujet"), search_docs("sujet") |
Deux bases de connaissances distinctes |
Exemples non parallélisables : rechercher un utilisateur par email (find_user), puis récupérer ses commandes avec l’ID retourné (get_orders(user_id)). Le second appel dépend du premier.
Implémentation par fournisseur
OpenAI (GPT-4o, GPT-5.x)
OpenAI a introduit les parallel tool calls avec les modèles GPT-4o et les active par défaut. Le paramètre parallel_tool_calls contrôle ce comportement :
response = client.chat.completions.create(
model="gpt-5.4",
messages=messages,
tools=tools,
parallel_tool_calls=True # activé par défaut
)Pour forcer le mode séquentiel (un seul outil par tour maximum), passez parallel_tool_calls=False.
parallel_tool_calls=True est passé à ces modèles. Si vous utilisez un modèle de raisonnement OpenAI, testez la compatibilité avant de déployer.
Quand le modèle décide d’appeler plusieurs outils, la réponse contient un tableau tool_calls avec plusieurs entrées, chacune ayant son propre id. Votre code doit exécuter chaque appel, puis renvoyer les résultats en associant chaque réponse à l’id correspondant :
# Exécution parallèle des tool calls
import asyncio
async def execute_tools(tool_calls):
tasks = []
for tc in tool_calls:
func_name = tc.function.name
args = json.loads(tc.function.arguments)
tasks.append(run_tool(func_name, args))
return await asyncio.gather(*tasks)
# Renvoi des résultats au modèle
results = asyncio.run(execute_tools(response.choices[0].message.tool_calls))
for tc, result in zip(tool_calls, results):
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": json.dumps(result)
})Anthropic (Claude 4.x)
Chez Anthropic, les modèles Claude 4 (Opus 4.6, Sonnet 4.6) supportent nativement les parallel tool calls. Le comportement est activé par défaut. Pour le désactiver, vous utilisez le paramètre tool_choice avec disable_parallel_tool_use: true :
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=4096,
tools=tools,
tool_choice={"type": "auto", "disable_parallel_tool_use": True},
messages=messages
)L’API Anthropic retourne des blocs tool_use multiples dans le contenu de la réponse. Chaque bloc contient un id unique. Vous renvoyez les résultats comme des blocs tool_result avec le même id.
Anthropic propose également le « Programmatic Tool Calling » : au lieu d’un aller-retour par outil, Claude écrit du code Python qui orchestre lui-même les appels d’outils en interne, avec des boucles, du traitement conditionnel et de l’exécution parallèle via await. Cette approche réduit encore davantage le nombre de tours et la consommation de tokens.
Google (Gemini 3.x)
Les modèles Gemini supportent les parallel function calls depuis Gemini 1.5 Pro (mai 2024). Avec Gemini 3 Flash et Gemini 3.1 Pro Preview, le mécanisme est mature et ne nécessite aucune configuration spéciale dans les déclarations de fonctions.
Quand Gemini détecte que plusieurs fonctions sont nécessaires et indépendantes, il retourne plusieurs functionCall dans une seule réponse. Depuis Gemini 3, chaque appel possède un identifiant unique (id) qui facilite le mapping des résultats, particulièrement utile pour les exécutions asynchrones.
import google.generativeai as genai
model = genai.GenerativeModel("gemini-3-flash")
response = model.generate_content(
"Quel temps fait-il à Paris et à Tokyo ?",
tools=[weather_tool]
)
# Gemini peut retourner 2 function calls en parallèle
for fn_call in response.candidates[0].function_calls():
print(f"Fonction : {fn_call.name}, Args : {fn_call.args}")Gemini 3 introduit un système de « thought signatures » : des représentations chiffrées du raisonnement interne du modèle qui doivent être renvoyées dans les tours suivants. Pour les parallel function calls, seul le premier functionCall de la liste contient la signature. Vous devez retourner les résultats dans l’ordre exact reçu, sinon l’API retourne une erreur 400.
Comparaison des implémentations
| Critère | OpenAI | Anthropic (Claude) | Google (Gemini) |
|---|---|---|---|
| Activé par défaut | Oui | Oui (Claude 4.x) | Oui (Gemini 3.x) |
| Paramètre de contrôle | parallel_tool_calls: bool |
disable_parallel_tool_use: bool |
Pas de paramètre dédié |
| Identifiant par appel | Oui (tool_call_id) |
Oui (id dans tool_use) |
Oui (id depuis Gemini 3) |
| Modèles de raisonnement | Support limité (o3, o4-mini) | Support complet (Opus 4.6) | Support complet (Gemini 3.1 Pro) |
| Max fonctions déclarées | Non documenté explicitement | Non documenté explicitement | Jusqu’à 128 |
| Orchestration avancée | Via code client | Programmatic Tool Calling (code Python interne) | Context circulation + built-in tools combo |
| Contrainte spéciale | Aucune | Aucune | Thought signatures obligatoires (Gemini 3) |
Cas d’usage concrets
Agent de recherche approfondie (Deep Research)
Les agents de deep research illustrent parfaitement l’intérêt des parallel tool calls. Un agent qui doit compiler un rapport en interrogeant 20 sources web peut, avec des appels séquentiels, nécessiter 20 tours de conversation, chacun recontextualisant l’intégralité du prompt et des résultats précédents. Les recherches sur le pattern « Wide and Deep » montrent qu’en groupant 3 appels de recherche par tour, la précision reste identique ou supérieure, le coût baisse d’un tiers et le temps d’exécution de 40 %.
Assistant d’entreprise multi-connecteurs
Un assistant qui répond à « Prépare le briefing du matin » doit interroger simultanément le calendrier, les emails, le CRM et le système de tickets. Sans parallel tool calls, cette opération prend 4 tours complets. Avec, un seul tour suffit pour lancer les 4 requêtes, et le modèle compose sa synthèse à partir de tous les résultats collectés.
Comparaison de produits en temps réel
Un chatbot e-commerce qui doit comparer les prix et disponibilités de 5 produits peut lancer 5 appels get_product_info en parallèle. L’utilisateur obtient un tableau comparatif en une fraction du temps qu’il faudrait en mode séquentiel.
Systèmes multi-agents
Certains frameworks récents poussent le concept encore plus loin. Kimi-K2.5 (Moonshot AI) peut orchestrer jusqu’à 100 sous-agents exécutant jusqu’à 1 500 appels d’outils en parallèle, avec un gain de vitesse annoncé de 4,5x par rapport à l’exécution mono-agent. Ce modèle est entraîné avec le Parallel-Agent Reinforcement Learning (PARL) pour réduire ce que les chercheurs appellent le « serial collapse » : la tendance des modèles à retomber dans un mode séquentiel même quand le parallélisme est possible.
Bonnes pratiques d’implémentation
Exécuter réellement en parallèle côté client
Le modèle vous donne un lot d’appels. Si votre code les exécute un par un avec une boucle for synchrone, vous perdez tout le bénéfice. Utilisez asyncio.gather() en Python, Promise.all() en JavaScript, ou des goroutines en Go pour exécuter réellement les appels en concurrence.
// JavaScript — exécution concurrente des tool calls
const results = await Promise.all(
toolCalls.map(tc => executeFunction(tc.function.name, tc.function.arguments))
);
// Renvoi de tous les résultats en un seul message
const toolMessages = toolCalls.map((tc, i) => ({
role: "tool",
tool_call_id: tc.id,
content: JSON.stringify(results[i])
}));Gérer les erreurs individuelles
Quand vous lancez 4 outils en parallèle, l’un d’eux peut échouer (timeout, erreur 500, quota dépassé). Votre code doit capturer l’erreur par outil et renvoyer un message d’erreur structuré au modèle pour cet outil spécifique, tout en retournant les résultats valides des autres. Le modèle peut alors adapter sa réponse en conséquence ou retenter l’appel échoué.
async def safe_execute(tool_call):
try:
result = await run_tool(tool_call.function.name,
json.loads(tool_call.function.arguments))
return {"tool_call_id": tool_call.id, "content": json.dumps(result)}
except Exception as e:
return {
"tool_call_id": tool_call.id,
"content": json.dumps({"error": str(e)}),
"is_error": True # Anthropic supporte ce champ
}
results = await asyncio.gather(*[safe_execute(tc) for tc in tool_calls])Quand désactiver le parallélisme
Dans certains cas, forcer le mode séquentiel est préférable :
| Situation | Raison de désactiver |
|---|---|
| Outils avec effets de bord (écriture en base, envoi d’email) | L’ordre d’exécution peut compter |
| Structured outputs stricts | Certains modèles génèrent des arguments moins fiables en mode parallèle |
| Chaîne de dépendances | Le modèle peut mal détecter les dépendances et lancer des appels qui nécessitent le résultat d’un autre |
| Debugging / traçabilité | Les traces séquentielles sont plus lisibles pour l’audit |
Optimiser les descriptions de fonctions
La qualité des descriptions de vos outils influence directement la capacité du modèle à identifier quels outils appeler et lesquels peuvent être parallélisés. Soyez explicite sur l’indépendance des fonctions dans vos descriptions. Si deux fonctions sont toujours appelées ensemble et sont indépendantes, mentionnez-le.
Surveiller les coûts et la latence
Les parallel tool calls réduisent le nombre de tours, mais chaque tour peut être plus « lourd » en tokens d’entrée (puisque tous les résultats sont renvoyés en même temps). Mesurez le coût total par requête utilisateur, pas juste le nombre d’appels API. Dans la majorité des cas, le bilan est largement positif, mais des outils retournant des résultats volumineux peuvent inverser le rapport coût/bénéfice.
Limites et pièges courants
Le « faux parallélisme »
Certains modèles annoncent des appels parallèles mais génèrent des appels avec des dépendances implicites. Par exemple, un modèle peut appeler search_user(email) et get_orders(user_id=123) dans le même tour, en « devinant » l’ID utilisateur. Ce comportement est dangereux en production. Implémentez des validations côté client pour détecter les arguments qui semblent inventés.
Complexité du streaming
En mode streaming, les parallel tool calls ajoutent de la complexité. Chez OpenAI, les chunks de plusieurs tool calls arrivent entrelacés, identifiés par des index. Votre parseur de stream doit assembler correctement chaque appel à partir de fragments distribués sur plusieurs chunks. Plusieurs développeurs rapportent des difficultés à gérer ce cas proprement.
Rate limiting
Si vos outils appellent des API tierces avec des limites de débit, lancer 10 appels simultanés peut déclencher un rate limit. Implémentez un système de concurrence limitée (asyncio.Semaphore en Python, ou un pool de workers) pour contrôler le nombre d’appels simultanés tout en bénéficiant du parallélisme.
Relations avec d’autres concepts
Les parallel tool calls s’inscrivent dans l’écosystème plus large du tool use (utilisation d’outils) et du function calling (appel de fonctions). Là où le function calling définit le mécanisme de base (le modèle demande l’exécution d’une fonction), les parallel tool calls en sont l’extension naturelle pour les scénarios multi-outils.
Ce mécanisme est fondamental pour les agents IA, qui enchaînent des séquences complexes d’actions. Il est complémentaire du chain-of-thought, qui structure le raisonnement interne du modèle, et du concept de planning, où l’agent décompose une tâche en sous-tâches. Les parallel tool calls permettent d’exécuter efficacement les sous-tâches identifiées par le planificateur.
La tendance actuelle est à la convergence : les fournisseurs combinent parallel tool calls, outils intégrés (recherche web, exécution de code) et outils custom dans des pipelines unifiés. Google a annoncé en mars 2026 la possibilité de combiner outils intégrés (Google Search, Google Maps) et fonctions custom dans une même requête, avec une « context circulation » qui préserve les résultats d’outils pour les étapes suivantes.
Verdict
Les parallel tool calls ne sont pas un « nice to have ». C’est une optimisation structurelle qui divise la latence et le coût de tout agent multi-outils. Si vous construisez un agent IA en production et que vos outils sont indépendants les uns des autres, activer et exploiter correctement les appels parallèles est la première optimisation à implémenter, avant même de toucher au prompt engineering ou au choix de modèle.
Les trois grands fournisseurs (OpenAI, Anthropic, Google) supportent cette fonctionnalité de manière mature. Le choix entre eux sur ce critère spécifique dépend surtout de votre stack existante. Anthropic se distingue avec le Programmatic Tool Calling qui va un cran plus loin. Google impose la contrainte des thought signatures. OpenAI reste le plus simple à implémenter mais montre des lacunes sur les modèles de raisonnement.
Questions fréquentes
Quelle est la différence entre parallel tool calls et function calling ?
Le function calling est le mécanisme général qui permet à un LLM de demander l’exécution d’une fonction externe. Les parallel tool calls sont une extension de ce mécanisme : au lieu de demander une seule fonction par tour de conversation, le modèle peut demander plusieurs fonctions simultanément. Tous les parallel tool calls sont du function calling, mais tout function calling n’est pas parallèle.
Les parallel tool calls fonctionnent-ils avec tous les modèles ?
Non. Chez OpenAI, les modèles GPT-4o et GPT-5.x les supportent, mais les modèles de raisonnement (série « o ») ont un support limité. Chez Anthropic, les modèles Claude 4 (Opus 4.6, Sonnet 4.6) les supportent nativement, alors que Claude 3.7 Sonnet était moins fiable sur ce point. Chez Google, le support est disponible depuis Gemini 1.5 Pro (mai 2024) et est mature sur Gemini 3.x. Vérifiez toujours la documentation de votre modèle spécifique.
Comment savoir si mes outils peuvent être appelés en parallèle ?
La règle est simple : si l’outil B n’a pas besoin du résultat de l’outil A pour fonctionner, ils sont parallélisables. Par exemple, récupérer la météo dans deux villes est parallélisable. Récupérer un utilisateur par email puis ses commandes par ID ne l’est pas. Le modèle tente de détecter ces dépendances automatiquement, mais vous pouvez aussi le guider en décrivant explicitement l’indépendance dans vos descriptions d’outils.
Les parallel tool calls augmentent-ils la consommation de tokens ?
Par tour, oui : tous les résultats sont renvoyés dans un seul message, ce qui peut être volumineux. Mais sur l’ensemble de la conversation, la consommation totale diminue parce que vous faites moins de tours, et chaque tour évite de recontextualiser l’historique complet. Le bilan net est presque toujours positif, avec des réductions de coût de 30 à 40 % dans les cas typiques.
Peut-on combiner parallel tool calls et streaming ?
Oui, les trois fournisseurs le supportent, mais l’implémentation est plus complexe. En streaming, les fragments des différents appels d’outils arrivent entrelacés. Vous devez identifier chaque fragment par son index ou son ID, assembler les appels complets, les exécuter, puis renvoyer les résultats. C’est faisable mais nécessite un parseur robuste. Si vous débutez, commencez par une implémentation non-streaming pour valider votre logique avant d’ajouter le streaming.