
Bonnes pratiques du tool calling agent : pourquoi votre agent choisit le mauvais outil
Les bonnes pratiques du tool calling agent sont ce qui sépare une démo fonctionnelle d'un agent qui appelle silencieusement le mauvais outil en production. L'équipe ingénierie d'Anthropic a mesuré qu'une seule description réécrite faisait passer un résultat d'outil de 206 tokens à 72, et Claude Code plafonne désormais chaque réponse d'outil à 25 000 tokens car l'hémorragie est bien réelle. Votre agent échoue de quatre façons : mauvais outil, mauvais arguments, boucle incontrôlée, fuite de tokens. Chacune a un correctif que vous pouvez déployer cette semaine.
Points clés :
- Le tool calling agent échoue de quatre façons exactement : mauvais outil, mauvais arguments, boucle incontrôlée et fuite de tokens.
- Les descriptions d'outils sont la seule instruction que le modèle voit au moment de la sélection ; elles corrigent la plupart des appels erronés.
- Des schémas plats, adaptés à la tâche, avec des entrées validées éliminent l'essentiel des erreurs d'arguments.
- Des réponses d'outils concises et une boucle d'évaluation à chaque modification gardent le coût en tokens et les régressions mesurables.
Pourquoi le tool calling agent échoue-t-il en production ?
Le tool calling agent échoue de quatre façons : le modèle choisit le mauvais outil, écrit de mauvais arguments, tourne en boucle incontrôlée ou saigne des tokens via des réponses trop volumineuses. Chaque défaillance touche une étape différente de la boucle d'appel, donc l'ordre de correction compte. Commencez par la sélection, car un mauvais choix d'outil empoisonne toutes les étapes suivantes.
| Mode de défaillance | Où cela se produit dans la boucle | Pratique qui corrige | Effort |
|---|---|---|---|
| Mauvais outil | Le modèle sélectionne dans la liste d'outils | 1 (descriptions) + 4 (namespacing, filtrage) | Faible |
| Mauvais arguments | Le modèle écrit le JSON du tool_call | 2 (schémas plats) + 6 (validation) | Faible-Moyen |
| Boucle incontrôlée | Le tool_result revient au modèle en cycle | 3 (outils atomiques) + 7 (validation humaine) | Moyen |
| Fuite de tokens | Le tool_result retourne dans la fenêtre de contexte | 5 (résultats concis) + 8 (boucle d'éval) | Faible-Moyen |
La prescription complète en un coup d'œil :
| Pratique | Défaillance corrigée | Effort |
|---|---|---|
| 1. Écrire des descriptions exploitables par le modèle | Mauvais outil | Faible |
| 2. Garder des schémas plats et adaptés à la tâche | Mauvais arguments | Faible |
| 3. Regrouper les séquences multi-étapes en outils atomiques | Boucles incontrôlées | Moyen |
| 4. Namespacer, élaguer et filtrer les outils dynamiquement | Mauvais outil | Moyen |
| 5. Retourner des résultats concis et riches en signal | Fuite de tokens | Faible |
| 6. Valider chaque appel et rendre les erreurs formatrices | Mauvais arguments | Moyen |
| 7. Soumettre les actions destructives à une validation humaine | Boucles incontrôlées, sécurité | Moyen |
| 8. Lancer une boucle d'évaluation à chaque modification d'outil | Les quatre, en tant que régressions | Moyen |
Suivez cet ordre. Les pratiques 1 et 2 prennent un après-midi et éliminent la majorité des erreurs de mauvais outil et de mauvais arguments que vous observez aujourd'hui. Une description d'outil n'est pas une documentation. C'est la seule instruction que le modèle reçoit au moment de la sélection.
Phase 1 : Concevoir des outils que le modèle peut réellement utiliser
Les gains de fiabilité les moins coûteux en tool calling agent se trouvent dans vos définitions d'outils, pas dans vos prompts ni dans le choix du modèle. Le modèle ne lit jamais votre documentation API ni votre README. Il voit un nom, une chaîne de description et un schéma JSON, et décide à partir de ces trois éléments seuls. Réussissez-les et la précision de sélection progresse avant même de toucher à quoi que ce soit d'autre.
Pratique 1 : Écrire des descriptions exploitables par le modèle
Rédigez les descriptions d'outils comme des instructions destinées au modèle, pas comme une documentation API. Une description qui satisfait un développeur humain (« wrapper REST pour l'endpoint users ») ne donne au modèle aucune base de décision. Le guide ingénierie d'Anthropic sur l'écriture d'outils et leurs bonnes pratiques de définition d'outils recommandent le même schéma : indiquez quand utiliser l'outil, ce qu'il retourne, et quand NE PAS l'utiliser.
{
"name": "get_user",
"description": "Fetches a user profile. Use ONLY when you already have a user_id. Do NOT use to search or list users; call search_users instead. Returns name, email, plan. Errors if user_id is not a valid UUID."
}contre la version que la plupart des équipes livrent :
{
"name": "get_user",
"description": "Gets a user."
}Deux règles font l'essentiel du travail ici. Premièrement, nommez les paramètres de façon univoque : user_id, jamais user ni id, car user invite le modèle à passer un nom ou un email là où un UUID est attendu. Deuxièmement, formulez les exclusions explicitement. « Do NOT use to search users » prévient plus d'appels erronés que n'importe quelle quantité de description positive, car les modèles confondent les outils qui se chevauchent bien plus souvent qu'ils ne comprennent mal un outil unique et clairement délimité. Pour les mécanismes côté fournisseur qui amènent ces définitions aux API OpenAI, Anthropic et Google, consultez notre guide du function calling multi-fournisseurs.
Pratique 2 : Garder des schémas plats et adaptés à la tâche
Gardez les schémas d'entrée plats, avec chaque champ dont la tâche a réellement besoin et aucun dont elle n'a pas besoin. Les objets imbriqués avec des branches optionnelles sont le terreau des erreurs d'arguments : le modèle doit inférer une structure dont il ne voit jamais d'exemple. Le guide function calling d'OpenAI accepte n'importe quel JSON Schema, mais permissif n'est pas synonyme de fiable.
{
"name": "create_ticket",
"parameters": {
"type": "object",
"properties": {
"ticket": {
"type": "object",
"properties": {
"details": {
"type": "object",
"properties": {
"title": { "type": "string" },
"meta": { "type": "object" }
}
}
}
}
}
}
}Aplatissez-le pour la tâche :
{
"name": "create_ticket",
"parameters": {
"type": "object",
"properties": {
"title": { "type": "string" },
"priority": { "type": "string", "enum": ["low", "medium", "high"] },
"assignee_id": { "type": "string" }
},
"required": ["title", "priority"]
}
}Les enums battent le texte libre pour tout champ à ensemble borné de valeurs. Les tableaux required battent l'optionnel partout. Si le modèle a presque toujours besoin d'un champ, rendez-le obligatoire dans le schéma de l'outil même si votre API le déclare optionnel. Vous ne reflétez pas votre API. Vous concevez une surface qu'un modèle spécifique peut remplir correctement.
Phase 2 : Gérer le jeu d'outils, pas seulement les outils
La qualité individuelle des outils ne suffit plus dès qu'un agent porte plus d'une poignée d'outils, car les erreurs de sélection croissent avec la taille de la liste que le modèle lit.
Pratique 3 : Regrouper les séquences API multi-étapes en outils atomiques
Fusionnez toute séquence fixe d'appels API en un seul outil atomique. Le billet ingénierie d'Anthropic utilise schedule_event et get_customer_context comme modèles : un appel qui fait tout le travail bat trois appels que l'agent doit enchaîner correctement à chaque fois. Chaque maillon d'une chaîne est un tour supplémentaire où le modèle peut caler, réessayer à tort ou boucler.
# What the agent does WITHOUT an atomic tool: 3 calls, 3 chances to fail
calendar = call_tool("list_calendars", {})
free = call_tool("find_free_slot", {"calendar_id": calendar["items"][0]["id"], "duration": 30})
call_tool("create_event", {"calendar_id": calendar["items"][0]["id"], "start": free["start"]})
# One atomic tool: the sequence lives in your code, not the model's head
call_tool("schedule_event", {"duration": 30, "attendees": ["[email protected]"]})La règle empirique : si le modèle doit toujours appeler B après A, alors A et B sont un seul outil déguisé en deux.
Pratique 4 : Namespacer, élaguer et filtrer les outils dynamiquement
Namespacez chaque nom d'outil et ne montrez à chaque agent que le sous-ensemble dont sa tâche actuelle a besoin. Les noms génériques entrent en collision dès que vous connectez deux intégrations. Imaginez un agent branché sur deux serveurs MCP qui exposent tous deux un outil appelé search : deux verbes identiques, aucun moyen de les distinguer. Anthropic documente des gains mesurables en évaluation grâce au namespacing par préfixe :
| Avant | Après (préfixe) | Après (suffixe) |
|---|---|---|
search | asana_projects_search | search_asana_projects |
create | asana_tasks_create | create_asana_tasks |
search (second serveur) | github_repos_search | search_github_repos |
L'élagage compte autant que le nommage. Un agent de support n'a pas besoin de ses outils de facturation chargés pendant qu'il répond à une question de mot de passe. Le schéma planner-worker, où un planificateur route une tâche vers un worker qui ne charge que les outils pertinents, est le correctif standard ; le guide de chargement dynamique d'outils de LangGraph détaille l'implémentation. Combien d'outils est trop ? Considérez 5 à 10 par agent comme une plage de travail, pas une loi : la précision se dégrade à mesure que la liste grandit, et le remède est le filtrage, pas un modèle plus gros. Si vous choisissez la couche de routage et de filtrage elle-même, comparez vos options dans notre comparatif des meilleures bibliothèques de function calling.
Phase 3 : Contrôler ce qui revient et ce qui sort
La boucle fonctionne dans les deux sens, et la plupart des équipes n'ingénierent que la moitié sortante. Ce que vos outils retournent détermine quelle partie de la fenêtre de contexte survit jusqu'au tour suivant, et ce que votre validation rejette détermine si le modèle apprend de ses erreurs ou les répète.
Pratique 5 : Retourner des résultats concis et riches en signal
Retournez le plus petit résultat exploitable par le modèle, avec des identifiants lisibles plutôt que des IDs bruts. Le billet ingénierie d'Anthropic documente un outil dont le résultat par défaut atteignait 206 tokens ; un réglage response_format concis a réduit le même résultat à 72 tokens, soit environ un tiers de la taille. Multipliez cela par des dizaines d'appels par tâche et cela détermine si votre agent termine tout court.
// Before: 206 tokens (shape per Anthropic's documented example)
{
"status": "success",
"data": {
"id": "8f14e45f-ceea-3f9c-a2f3-90c1b5e0a7d2",
"object": "task", "created_at": "2026-07-02T09:14:00Z",
"updated_at": "2026-07-11T16:40:12Z", "completed_at": null,
"assignee": {"id": "c9a1...f2", "object": "user"},
"projects": [{"id": "b7d3...91", "object": "project"}],
"permalink": "https://app.asana.com/0/.../f"
}
}
// After: 72 tokens
{ "task": "Fix login redirect", "assignee": "Dana Kim", "project": "Web App", "due": "2026-07-20" }Deux autres détails de la même source : Anthropic prend en charge un enum response_format (detailed versus concise) sur les définitions d'outils, ce qui vous permet de déclarer la forme souhaitée plutôt que de parser un flux ininterrompu. Et Claude Code plafonne les réponses d'outils à 25 000 tokens, un plafond dur qui tronque les résultats boursouflés de toute façon. Anthropic rapporte également, comme leur constat, que résoudre les UUIDs en noms sémantiques a mesurablement réduit les hallucinations de récupération, c'est pourquoi le payload « après » ci-dessus dit « Dana Kim » et non c9a1...f2. Les réponses volumineuses sont aussi un problème de coût ; consultez notre guide pour réduire les coûts API LLM pour la vue d'ensemble.
Pratique 6 : Valider chaque appel et rendre les erreurs formatrices
Validez chaque appel d'outil côté serveur et retournez des erreurs qui contiennent le correctif. L'article de Martin Fowler sur le function calling le formule sans détour : ne faites jamais confiance à la sortie du modèle. Il passera des chaînes là où des enums sont attendus et inventera des IDs qui n'existent pas.
def create_ticket(args):
if args.get("priority") not in {"low", "medium", "high"}:
return {"error": f"priority must be one of: low, medium, high. Got '{args.get('priority')}'. Pass priority='medium' for normal issues."}
if not is_valid_uuid(args.get("assignee_id")):
return {"error": "assignee_id must be a UUID. Call list_team_members to get valid IDs, then retry."}
return db.create_ticket(**args)La chaîne d'erreur est tout l'enjeu. Comparez :
# Unhelpful: the model retries the same bad call
{"error": "invalid input"}
# Helpful: the model knows exactly what to change
{"error": "priority must be one of: low, medium, high. Got 'urgent'. Use 'high'."}Chaque erreur de validation que votre outil retourne est un prompt que vous écrivez pour la prochaine tentative du modèle. Les erreurs qui nomment la contrainte et pointent vers l'outil correctif transforment une boucle de retry en une récupération en un seul essai. C'est aussi votre première ligne de défense en sécurité ; notre guide des guardrails LLM couvre le sujet en profondeur.
Phase 4 : Comment sécuriser, puis rendre mesurable ?
Sécurité et mesure sont la même phase car une action destructive sans garde-fou et une régression non mesurée se manifestent toutes deux comme des incidents que vous n'avez pas vus venir. Protégez les actions irréversibles, puis instrumentez tout pour que la prochaine modification d'outil soit une décision étayée, pas un espoir.
Pratique 7 : Soumettre les actions destructives à une validation humaine
Séparez les outils de lecture des outils d'écriture et placez une confirmation humaine sur tout ce qui est destructif. Les annotations d'outils de la spécification MCP existent précisément pour cela : destructiveHint marque les outils qui effectuent des mises à jour destructives, et openWorldHint signale les outils qui touchent des systèmes externes, afin que les clients puissent demander confirmation avant exécution. Utilisez-les.
Le mode de défaillance n'est pas hypothétique. Laurent Kubaski a documenté un cas, dans son billet de juillet 2025 sur le tool calling avec le rapport original lié, où un utilisateur a demandé à Copilot dans Excel d'agir sur la ligne 4 et l'agent a agi sur la ligne 8. Aucune confirmation ne se trouvait entre la mauvaise ligne et l'écriture. Le correctif est le schéma qu'AWS documente pour Bedrock Agents : l'agent prépare l'action, la retourne pour approbation, et n'exécute qu'après confirmation humaine. Cursor fait de même pour les éditions de fichiers. Limitez les identifiants en lecture seule quand la lecture suffit à la tâche, et traitez les confirmations comme faisant partie de votre surface d'injection, le sujet de notre guide sur la prévention de l'injection de prompt.
Pratique 8 : Lancer une boucle d'évaluation à chaque modification d'outil
Exécutez une petite suite d'évaluation avant et après chaque modification d'outil, et lisez les métriques dans un ordre fixe. Le guide d'optimisation de Paragon propose un cadre à quatre métriques qui vaut la peine d'être adopté :
| Métrique (selon Paragon) | Ce qu'elle détecte | Comment mesurer |
|---|---|---|
| Correction de l'outil | Appels du mauvais outil | L'agent a-t-il appelé le bon outil pour la tâche ? |
| Précision des entrées | Mauvais arguments | Les arguments étaient-ils valides et complets ? |
| Accomplissement de la tâche | Défaillance de bout en bout | L'objectif de l'utilisateur a-t-il été atteint ? |
| Efficacité de la tâche | Fuite de tokens, boucles | Nombre d'appels et de tokens ? |
Le cookbook d'évaluation d'outils d'Anthropic, construit sur de vraies évaluations MCP Slack et Asana, montre à quoi ressemblent de bonnes et de mauvaises tâches d'évaluation :
# Weak: vague, many valid paths, impossible to score
"Use the Asana tools to organize some work."
# Strong: one correct tool, checkable arguments, binary outcome
"Create a task titled 'Renew TLS cert' in project 'Infra' assigned to [email protected], due 2026-08-15. Expect exactly one create_task call with those four fields."Notre interprétation, étiquetée comme telle : les chiffres publiés vous donnent l'ordre de travail. Vérifiez la correction de l'outil en premier, car les propres mesures d'Anthropic montrent que les changements de description et de nommage la déplacent directement (la réécriture de 206 à 72 tokens, le constat sur les hallucinations UUID-vers-nom), et gardez l'efficacité de la tâche pour la fin, puisqu'elle reflète surtout des défaillances que les trois premières métriques ont déjà détectées. Pour la suite de départ, concevez 15 à 30 tâches, deux ou trois par outil, chacune avec un seul appel attendu et une condition de réussite binaire. Cette taille suffit à détecter une régression issue d'une réécriture de description sans une semaine d'étiquetage, et nous lisons la configuration Slack et Asana du cookbook comme la preuve qu'une suite aussi petite est le point de départ prévu, pas un raccourci. Les mécanismes plus profonds se trouvent dans notre guide sur l'évaluation des agents IA en production, et si vos résultats d'évaluation disent que les outils eux-mêmes vont bien mais que l'orchestration non, c'est le moment de reconsidérer votre choix de framework face aux meilleurs frameworks d'agents IA.
Tool calling agent vs MCP : quelle différence ?
MCP est un standard de transport et de registre, pas une couche de fiabilité, donc les mêmes huit pratiques s'appliquent que vos outils arrivent via MCP ou soient définis en ligne. Le tool calling natif est le contrat modèle-fournisseur : comment le modèle émet un tool_call et lit un tool_result. MCP standardise la façon dont les outils parviennent au modèle ; il ne fait rien quant à savoir si le modèle choisit le bon.
| Le tool calling natif gère | MCP ajoute | Ni l'un ni l'autre ne gère |
|---|---|---|
| Format des messages tool_call / tool_result | Un protocole partagé pour que tout client atteigne tout serveur | Qualité des descriptions |
| Schémas spécifiques au fournisseur | Découverte et registre d'outils | Conception des schémas, validation |
| Négociation d'appels parallèles | Annotations comme destructiveHint | Validation humaine, évaluations, hygiène des réponses |
Un serveur MCP qui expose un outil nommé search avec la description « searches things » échoue de manière identique à une fonction en ligne définie de la même façon. Corrigez la définition, puis préoccupez-vous du transport. Notre guide du Model Context Protocol couvre le côté protocole de bout en bout.
Comment Techsy applique ces huit pratiques
Sur chaque build d'agent client, nous appliquons trois de ces pratiques avant toute mise en production : des descriptions rédigées comme des instructions (Pratique 1), des gardes de validation sur chaque outil d'écriture (Pratique 6), et une suite d'évaluation qui s'exécute avant le déploiement, pas après un incident (Pratique 8). Ces trois-là couvrent les appels du mauvais outil, les appels avec mauvais arguments, et les régressions qui réintroduisent les deux, ce qui est le point de départ de chaque incident d'agent en production que nous avons déboggé. Les cinq autres pratiques suivent à mesure que l'agent grandit. Si votre agent a dépassé le stade de la démo et choisit les mauvais outils, obtenez une consultation gratuite et nous vous dirons laquelle des huit corriger en premier.
À propos de l'auteur
Mert Batur est Co-Fondateur de Techsy.io, où l'équipe livre des agents IA, des systèmes d'automatisation et des pipelines voix/SDR pour des clients B2B. Il écrit sur la stack d'outillage LLM que l'équipe Techsy utilise réellement en production. Retrouvez-le sur LinkedIn.
Questions fréquemment posées
Qu'est-ce que le tool calling agent ?
Le tool calling agent est le mécanisme par lequel un LLM décide d'invoquer une fonction externe, émet un tool_call structuré, et attend que votre code retourne un tool_result sur lequel il peut raisonner. C'est ce qui transforme un modèle de chat en un agent capable d'interroger des bases de données, d'appeler des API et d'effectuer des actions : le modèle choisit l'outil et les arguments, votre exécuteur les lance.
Comment fonctionne la boucle de tool calling agent ?
La boucle comporte cinq étapes : la requête utilisateur parvient au modèle, le modèle sélectionne un outil et écrit un tool_call, votre exécuteur le lance, un tool_result revient au modèle, et le modèle répond ou émet un nouvel appel. Ce cycle se répète jusqu'à ce que la tâche soit terminée. Les quatre modes de défaillance de ce guide se situent chacun à une étape spécifique de cette boucle.
Pourquoi mon agent choisit-il le mauvais outil ?
Généralement parce que deux outils se chevauchent et que leurs descriptions ne disent pas lequel est lequel. Le modèle sélectionne à partir des noms et descriptions seuls, donc « gets a user » contre « finds users » paraît interchangeable. Corrigez cela avec des lignes d'exclusion (« do NOT use to search »), des noms namespacés et moins d'outils en contexte. Le test de Kubaski sur quatre modèles a montré que même des modèles performants se trompent de route sur des listes ambiguës.
Comment forcer un agent de tool calling à structurer sa sortie ?
Contraignez le schéma, pas le prompt. Utilisez des enums pour les champs bornés, des tableaux required pour tout ce dont la tâche a besoin, et des objets plats plutôt qu'imbriqués. Pour la réponse finale plutôt que l'appel d'outil, des fonctionnalités fournisseur comme les structured outputs d'OpenAI et les modes tool-choice d'Anthropic forcent une forme spécifique. Notre guide des sorties structurées LLM couvre les deux approches avec du code.
Tool calling agent vs MCP : quelle différence ?
Le tool calling natif est le contrat entre votre code et un fournisseur de modèle : le format des messages tool_call et tool_result. MCP est une couche protocolaire qui standardise la façon dont les outils sont découverts et livrés à tout client compatible. MCP change la tuyauterie, pas la fiabilité. Un outil mal décrit échoue de la même façon par l'un ou l'autre chemin, comme notre guide du Model Context Protocol l'explique.
Combien d'outils est trop pour un agent LLM ?
Considérez 5 à 10 outils par agent comme une plage de travail, pas une loi. La précision de sélection se dégrade à mesure que la liste visible grandit, surtout quand les noms ou descriptions se chevauchent. Le correctif n'est pas un modèle plus gros mais le filtrage : ne chargez que le sous-ensemble dont la tâche actuelle a besoin, via une séparation planner-worker. Namespacez tout pour que deux intégrations n'exposent jamais un search nu.
Quel est le meilleur modèle pour le tool calling ?
Il n'y a pas de réponse unique, et les benchmarks publiés vieillissent mal dans ce domaine. Les modèles frontier d'OpenAI, Anthropic et Google réussissent tous les tâches de base d'utilisation d'outils, tandis que des modèles plus petits associés à des outils bien conçus complètent souvent les tâches presque aussi fréquemment pour une fraction du coût en tokens. Construisez la suite d'évaluation de 15 à 30 tâches de la Pratique 8 et testez les candidats contre vos propres outils.
Comment réduire le coût en tokens du tool calling ?
Coupez ce qui revient. Retournez des résultats concis et riches en signal plutôt que des payloads API bruts : Anthropic a documenté une réduction de 206 à 72 tokens grâce à un seul changement de response_format. Résolvez les UUIDs en noms, supprimez les champs que le modèle n'utilise jamais, et rappelez-vous que chaque résultat d'outil réintègre la fenêtre de contexte à chaque tour suivant. Moins d'appels, via des outils atomiques, retire des résultats entiers de la facture.
Comment évaluer la qualité du tool calling ?
Notez quatre métriques dans l'ordre : correction de l'outil (bon outil ?), précision des entrées (arguments valides ?), accomplissement de la tâche (objectif atteint ?), et efficacité de la tâche (nombre de tokens et d'appels ?). Rédigez 15 à 30 tâches, chacune attendant un appel spécifique avec des arguments vérifiables et une condition de réussite binaire. Exécutez la suite avant et après chaque modification d'outil pour qu'une réécriture de description ne soit jamais livrée sans mesure.
Conclusion
Diagnostiquez avant d'optimiser. Votre agent choisit le mauvais outil pour l'une de quatre raisons, et trois des huit pratiques ci-dessus, les descriptions, les schémas plats et le filtrage, corrigent les défaillances de sélection qui causent la plupart des incidents en production. Commencez là, car elles coûtent un après-midi et c'est grâce à elles que ce problème est corrigeable. Gardez les erreurs de validation informatives, soumettez toute action destructive à une validation humaine, et lancez la boucle d'évaluation à chaque modification pour mesurer avant de changer de modèle. Le problème du mauvais outil n'est pas un problème de modèle. C'est un problème de conception d'outils, et la conception vous appartient.