Réduire le coût des flux de travail à forte utilisation d'outils
Un agent qui utilise des outils renvoie tout à nouveau à chaque requête. L'appel programmatique d'outils et la mémorisation des requêtes réduisent chacun une partie différente de son coût.
La démonstration de cette vidéo a été enregistrée en septembre 2026. Elle a été exécutée sur Claude Sonnet 5 (claude-sonnet-5). Les résultats peuvent différer sur des modèles plus récents.
Un agent qui utilise des outils renvoie tout à nouveau à chaque requête, de sorte que son coût augmente à chaque appel d'outil. Chaque requête transporte les définitions d'outils, l'invite système, la question et tous les résultats d'outils obtenus jusqu'à présent. Ce sont ses jetons d'entrée, et chacun d'eux est facturé.
L'appel programmatique d'outils et la mémorisation des requêtes réduisent tous deux ce coût.
Meridian est un cabinet de conseil en ingénierie fictif comptant 40 ingénieurs. Son agent a reçu une question : quels ingénieurs étaient en dessous de 70 % d'utilisation en juin 2026 ? L'agent disposait de deux outils. list_employees renvoie la liste du personnel, et get_employee_hours renvoie la feuille de temps d'un ingénieur.
Répondre à cette question a nécessité 42 requêtes et 1 124 799 jetons d'entrée de la part de l'agent. L'exécution complète a coûté 2,29 $ en jetons.
Mesurer les jetons d'entrée de chaque requête
Affichez usage.input_tokens à chaque retour de réponse, car ces chiffres vous montrent où se situe le coût.
resp = client.messages.create(...)
print(resp.usage.input_tokens, "input tokens")L'agent de Meridian exécute une boucle classique, où chaque réponse demande un appel d'outil. Voici deux de ses chiffres.
| Requête | Ce qu'elle transporte | Jetons d'entrée |
|---|---|---|
| Requête 1 | Définitions d'outils, invite système et question | 606 |
| Requête 37 | Idem, plus 36 résultats d'outils antérieurs | 47 905 |
La requête 1 transporte uniquement ce que chaque requête envoie. Les requêtes ultérieures ajoutent les appels d'outils et leurs résultats. Comparez les deux chiffres pour voir quelle partie a augmenté.
Empêcher les résultats d'outils d'atteindre ce que Claude lit
Avec l'appel programmatique d'outils(s’ouvre dans un nouvel onglet), Claude écrit un script qui appelle vos outils, et l'outil d'exécution de code l'exécute dans un conteneur. Seul ce que le script affiche atteint Claude. Les 40 feuilles de temps de Meridian restent avec le script, et Claude reçoit son court résultat affiché.
Vérifiez d'abord vos outils et votre modèle. En octobre 2026, l'appel programmatique d'outils ne prend pas en charge les outils marqués strict: true(s’ouvre dans un nouvel onglet). Il ne prend pas non plus en charge disable_parallel_tool_use, le paramètre tool_choice qui limite Claude à un seul appel d'outil par réponse. tool_choice ne peut pas forcer Claude à appeler un outil depuis le script.
Claude Haiku 4.5 ne prend pas en charge cette fonctionnalité. Cette fonctionnalité fonctionne sur Claude API, Claude Platform on AWS et les déploiements Microsoft Foundry hébergés sur Anthropic.
Activer l'appel programmatique d'outils nécessite quatre modifications.
- Ajoutez l'outil d'exécution de code à votre liste
tools. - Marquez les outils que le script peut appeler. Attribuez à chacun un champ
allowed_callersqui désigne l'outil d'exécution de code à partir de la versioncode_execution_20260120ou ultérieure(s’ouvre dans un nouvel onglet). - Renvoyez l'identifiant du conteneur. Lisez-le dans chaque réponse qui s'arrête pour un appel d'outil, et envoyez-le avec la requête qui renvoie les résultats de vos outils.
- Décrivez le résultat de chaque outil. Indiquez dans la description la forme qu'il prend, car le script doit l'analyser. Voici la description de Meridian pour
get_employee_hours.
Returns one engineer's hours for the month as JSON: {"name": str, "billable_hours": float, "utilization": float 0-1}
Voici la boucle de Meridian après ces modifications.
CODE_EXECUTION = "code_execution_20260120"
TOOLS = [
{"type": CODE_EXECUTION, "name": "code_execution"},
{**LIST_EMPLOYEES, "allowed_callers": [CODE_EXECUTION]},
{**GET_EMPLOYEE_HOURS, "allowed_callers": [CODE_EXECUTION]},
]
messages = [{"role": "user", "content": QUESTION}]
container = None
while True:
resp = client.messages.create(
model="claude-sonnet-5", max_tokens=4096,
tools=TOOLS, messages=messages, container=container,
)
print(resp.usage.input_tokens, "input tokens")
if resp.stop_reason not in ("tool_use", "pause_turn"):
break
container = resp.container.id
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason == "tool_use":
messages.append({"role": "user", "content": run_tools(resp)})
print("".join(b.text for b in resp.content if b.type == "text"))LIST_EMPLOYEESetGET_EMPLOYEE_HOURSsont les définitions d'outils de Meridian.- Votre propre
run_toolsexécute chaque appel d'outil et renvoie les résultats. - Lors d'un
pause_turn, la boucle renvoie la réponse et continue.
Lorsque le script appelle un outil, le stop_reason de la réponse est "tool_use". Votre code exécute l'outil, et le résultat va au script, pas à Claude. Le script peut exécuter des outils en parallèle, donc une seule réponse peut contenir plus d'un appel d'outil.
Voici la même question répondue des deux façons.
| Exécution | Requêtes | Appels d'outils | Jetons d'entrée | Coût en jetons |
|---|---|---|---|---|
| Boucle classique | 42 | 41 | 1 124 799 | 2,29 $ |
| Appel programmatique d'outils | 3 | 41 | 28 486 | 0,0667 $ |
Les deux exécutions ont utilisé la même question, les mêmes outils et claude-sonnet-5. Les coûts utilisent les tarifs en vigueur en septembre 2026(s’ouvre dans un nouvel onglet), et le temps d'exécution de code est facturé séparément des jetons.
L'appel programmatique d'outils convient aux recherches qui ne dépendent pas les unes des autres. Il aide peu lorsque Claude doit raisonner sur chaque résultat avant de procéder à l'appel d'outil suivant.
Mémoriser les définitions d'outils qui se répètent
Avec la mémorisation des requêtes, l'API stocke le préfixe de votre requête, la partie jusqu'à un point de mémorisation que vous marquez. Relire ce préfixe coûte beaucoup moins cher.
Un second agent Meridian dispose de 14 outils, et leurs définitions totalisent 3 305 jetons que chaque requête renvoie à nouveau.
Marquez le point de mémorisation en plaçant cache_control sur le dernier outil, et toute la liste est mise en mémoire. Cela tient en une seule ligne :
TOOLS[-1]["cache_control"] = {"type": "ephemeral"}Sur Claude Sonnet 5, la lecture du préfixe coûte un dixième du prix d'entrée normal(s’ouvre dans un nouvel onglet). Son écriture coûte 1,25 fois le prix d'entrée normal.
Le préfixe mis en mémoire dure cinq minutes par défaut, et chaque utilisation le renouvelle. Pour des requêtes plus espacées, ajoutez "ttl": "1h" à cache_control pour le conserver pendant une heure. L'écriture d'une mémorisation d'une heure coûte le double du prix d'entrée normal(s’ouvre dans un nouvel onglet).
Meridian a exécuté les huit mêmes questions avec et sans la mémorisation. Son coût total d'entrée est passé de 0,0554 $ à 0,0154 $.
Avec la mémorisation automatique(s’ouvre dans un nouvel onglet), vous placez un champ cache_control au niveau supérieur de la requête, et l'API place le point de mémorisation pour vous.
Surveillez trois points une fois la mémorisation activée :
- Modifiez une définition d'outil, et vous perdez toute la mémorisation.
- Sur Sonnet 5, un préfixe mis en mémoire doit comporter au moins 1 024 jetons. S'il est plus court, rien n'est mis en mémoire et aucune erreur ne le signale.
- Avec la mémorisation activée,
input_tokensexclut le préfixe mis en mémoire, donc le total réel d'une requête correspond à la somme deinput_tokens,cache_read_input_tokensetcache_creation_input_tokens.
Combiner les fonctionnalités là où elles conviennent
Ajoutez-les dans cet ordre.
- Commencez par la mémorisation. Cela tient en une seule ligne.
- Testez l'appel programmatique d'outils. Exécutez une partie de votre trafic habituel avec et sans
allowed_callers, puis comparez les jetons d'entrée facturés de chaque exécution.
Pour chacune des deux requêtes Meridian ci-dessous, repérez la partie qui contient le plus de jetons d'entrée, puis choisissez la fonctionnalité qui la réduit.
Points clés à retenir
- Chaque requête renvoie tout à nouveau, vous payez donc encore et encore pour d'anciens résultats d'outils.
- Affichez
usage.input_tokensà chaque retour de réponse, afin de savoir quelle partie de la requête coûte le plus cher. - Commencez par la mémorisation. Ajoutez
cache_controlau dernier outil de votre liste. - Lorsque vos appels d'outils ne dépendent pas les uns des autres, configurez l'appel programmatique d'outils avec l'outil d'exécution de code et
allowed_callers. Envoyez l'identifiant du conteneur avec chaque requête ultérieure.