Réduire le coût des flux riches en outils
Sur cette page
Objectifs
À l’issue de cette leçon, vous serez capable de :
- Mesurer les jetons d’entrée de chaque requête pour localiser le coût
- Activer l’appel programmatique d’outils pour garder les résultats intermédiaires hors du contexte
- Mettre en cache les définitions d’outils
Pourquoi un agent outillé coûte de plus en plus cher
Un agent qui utilise des outils renvoie tout à chaque requête : les définitions d’outils, le prompt système, la question, et tous les résultats d’outils obtenus jusque-là. Ce sont ses jetons d’entrée, et chacun est facturé. Le coût croît donc à chaque appel.
Exemple : Ingénova veut la liste des ingénieurs dont le taux de facturation du mois est sous un seuil. Deux outils : lister_ingenieurs renvoie l’effectif, heures_ingenieur renvoie la feuille de temps d’une personne. En boucle classique, l’agent appelle heures_ingenieur quarante fois ; chaque feuille de temps entre dans le contexte, et chaque requête suivante la relit. La quarantième requête transporte les trente-neuf feuilles précédentes, pour produire au final une liste de quelques noms.
D’abord, mesurer
Affichez usage.input_tokens à chaque réponse :
reponse = client.messages.create(...)
print(reponse.usage.input_tokens, "jetons d'entrée")
La première requête ne contient que ce que toutes envoient ; les suivantes s’alourdissent des appels et de leurs résultats. Comparer les deux montre quelle part grossit.
Garder les résultats hors du contexte : l’appel programmatique d’outils
Avec l’appel programmatique d’outils (programmatic tool calling), Claude écrit un script qui appelle vos outils, et l’outil d’exécution de code l’exécute dans un conteneur. Quand le script appelle un outil, le conteneur se met en pause, votre code exécute l’appel, et le résultat revient au script, pas au contexte de Claude. Seul ce que le script affiche atteint Claude : les quarante feuilles de temps restent dans le script, Claude reçoit sa courte sortie.
Quatre changements :
- Ajoutez l’outil d’exécution de code, en version
code_execution_20260120ou plus récente. - Marquez les outils que le script peut appeler avec un champ
allowed_callersqui nomme cette version de l’outil d’exécution de code. - Renvoyez l’identifiant du conteneur. Lisez-le dans chaque réponse qui s’arrête pour un appel d’outil, et renvoyez-le avec la requête qui porte vos résultats : tant qu’un appel programmatique attend votre résultat, l’API rejette une requête sans lui. Ce message ne doit contenir que des blocs
tool_result, et la requête doit reprendre le même tableautools. - Décrivez la forme du résultat de chaque outil dans sa description : le script doit l’analyser, et ne peut analyser que ce qu’il connaît.
EXEC = "code_execution_20260120"
OUTILS = [
{"type": EXEC, "name": "code_execution"},
{**LISTER_INGENIEURS, "allowed_callers": [EXEC]},
{**HEURES_INGENIEUR, "allowed_callers": [EXEC]},
]
# Description de heures_ingenieur, par exemple :
# « Renvoie les heures du mois d'un ingénieur en JSON :
# {"nom": str, "heures_facturables": float, "taux": float entre 0 et 1} »
Le gain est maximal quand les appels sont indépendants les uns des autres, comme ces quarante recherches ; quand chaque appel exige que Claude raisonne sur le résultat précédent, il est bien moindre.
Une précaution : d’après la documentation, allowed_callers guide fortement Claude, mais n’interdit pas au niveau de l’API un appel direct. Votre boucle doit donc savoir traiter aussi un tool_use ordinaire pour ces outils.
Vérifiez vos outils et votre modèle d’abord. Les outils en strict: true ne peuvent pas être appelés de façon programmatique ; tool_choice ne peut pas forcer un appel programmatique ; disable_parallel_tool_use n’est pas compatible ; les outils d’un connecteur MCP et computer use ne peuvent pas être appelés depuis le script. Claude Haiku 4.5 ne prend pas en charge la fonction. Elle est disponible sur l’API Claude, Claude Platform on AWS et les déploiements Microsoft Foundry hébergés par Anthropic.
Ne pas repayer les définitions : la mise en cache
Les définitions d’outils repartent à chaque requête : un agent à quatorze outils les repaie à chaque tour. Placez cache_control sur le dernier outil de la liste : toutes les définitions jusqu’à celui-ci sont mises en cache comme un seul préfixe.
OUTILS[-1]["cache_control"] = {"type": "ephemeral"}
Plus simple encore : un champ cache_control au niveau de la requête active la mise en cache automatique, qui place le point d’arrêt sur le dernier bloc et le fait avancer avec la conversation. Le cache porte sur le préfixe complet, dans cet ordre : tools, puis system, puis messages. Modifier une définition d’outil invalide donc tout ce qui suit : stabilisez vos définitions avant de compter sur le cache.
À vous de jouer
Localiser et réduire le coût.
- Journalisez
usage.input_tokenssur une session réelle de votre agent, requête par requête. - Si une série d’appels indépendants gonfle le contexte, essayez l’appel programmatique d’outils sur ces outils-là.
- Ajoutez
cache_controlau dernier outil, et comparez le coût d’entrée sur une dizaine de requêtes, avant et après.
Sources officielles : Programmatic tool calling (documentation Claude : mise en place, restrictions, modèles, plateformes) · Prompt caching (documentation Claude : mise en cache automatique, ordre du préfixe) · Code execution tool
Points clés à retenir
- Chaque requête renvoie tout l’historique : mesurez
usage.input_tokenspour voir ce qui grossit - L’appel programmatique d’outils fait passer les résultats intermédiaires par un script, et seule sa sortie atteint Claude
allowed_callers, l’identifiant du conteneur, et des descriptions qui donnent la forme des résultatscache_controlsur le dernier outil met en cache toutes les définitions ; ne modifiez pas les outils à la légère