L'appel d'outils programmatique permet à Claude d'écrire du code qui appelle vos outils de manière programmatique au sein d'un conteneur d'exécution de code, plutôt que de nécessiter des allers-retours avec le modèle pour chaque invocation d'outil. Cela réduit la « latency » (latence) pour les workflows multi-outils et diminue la consommation de tokens en permettant à Claude de filtrer ou de traiter les données avant qu'elles n'atteignent la « context window » (fenêtre de contexte) du modèle. Sur des benchmarks de recherche agentique comme BrowseComp et DeepSearchQA, qui testent la recherche web en plusieurs étapes et la récupération d'informations complexes, l'ajout de l'appel d'outils programmatique par-dessus des outils de recherche basiques a amélioré les performances de 11 % en moyenne tout en utilisant 24 % de tokens d'entrée en moins (voir Improved web search with dynamic filtering).
Prenons l'exemple de la vérification de la conformité budgétaire pour 20 employés : l'approche traditionnelle nécessite 20 allers-retours distincts avec le modèle, intégrant au passage des milliers de lignes de dépenses dans le contexte. Avec l'appel d'outils programmatique, un seul script exécute les 20 recherches, filtre les résultats et ne renvoie que les employés ayant dépassé leurs limites, réduisant ce sur quoi Claude doit raisonner de plusieurs centaines de kilo-octets à une poignée de lignes.
Pour un examen plus approfondi des coûts d'inférence et de contexte que l'appel d'outils programmatique permet de réduire, consultez Advanced tool use.
Cette fonctionnalité nécessite que l'outil d'exécution de code soit activé.
Cette fonctionnalité n'est pas éligible à la Zero Data Retention (ZDR). Les données sont conservées conformément à la politique de conservation standard de la fonctionnalité.
L'appel d'outils programmatique nécessite code_execution_20260120 ou une version ultérieure, qui est prise en charge sur les modèles suivants :
| Modèle |
|---|
| Claude Fable 5 (claude-fable-5) |
| Claude Mythos 5 (claude-mythos-5) |
| Claude Opus 4.8 (claude-opus-4-8) |
| Claude Opus 4.7 (claude-opus-4-7) |
| Claude Opus 4.6 (claude-opus-4-6) |
| Claude Sonnet 5 (claude-sonnet-5) |
| Claude Sonnet 4.6 (claude-sonnet-4-6) |
| Claude Opus 4.5 (claude-opus-4-5-20251101) |
| Claude Sonnet 4.5 (claude-sonnet-4-5-20250929) |
Pour la matrice complète des versions de l'outil d'exécution de code, consultez le tableau de compatibilité des modèles de l'outil d'exécution de code. L'appel d'outils programmatique est disponible sur l'API Claude, Claude Platform on AWS et Microsoft Foundry. Sur Microsoft Foundry, l'appel d'outils programmatique nécessite un déploiement Hosted on Anthropic. Il n'est actuellement pas disponible sur Amazon Bedrock ni sur Google Cloud.
Voici un exemple où Claude interroge de manière programmatique une base de données plusieurs fois et agrège les résultats :
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
messages=[
{
"role": "user",
"content": "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue",
}
],
tools=[
{"type": "code_execution_20260120", "name": "code_execution"},
{
"name": "query_database",
"description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
"input_schema": {
"type": "object",
"properties": {
"sql": {"type": "string", "description": "SQL query to execute"}
},
"required": ["sql"],
},
"allowed_callers": ["code_execution_20260120"],
},
],
)
print(response)La réponse s'arrête avec stop_reason: "tool_use", un ID container et un bloc tool_use pour query_database dont le champ caller identifie l'exécution de code qui l'a appelé. Renvoyez le résultat comme indiqué à l'Étape 3 de l'exemple de workflow afin que le code puisse se terminer.
Lorsque vous configurez un outil pour qu'il soit appelable depuis l'exécution de code et que Claude décide d'utiliser cet outil :
tool_useCette approche est particulièrement utile pour :
Les outils qui autorisent un appelant d'exécution de code sont exposés au code de Claude sous forme de fonctions Python asynchrones, de sorte que Claude peut les exécuter en parallèle avec asyncio.gather. Chaque fonction prend un seul dictionnaire d'arguments et renvoie une chaîne de caractères : le texte du tool_result que vous renvoyez. Le code de Claude attend ces fonctions avec un await de niveau supérieur et analyse les résultats dont il a besoin sous forme de données structurées, par exemple rows = json.loads(await query_database({"sql": "<sql>"})).
allowed_callersLe champ allowed_callers spécifie quels contextes peuvent invoquer un outil :
{
"name": "query_database",
"description": "Execute a SQL query against the database",
"input_schema": {
// ...
},
"allowed_callers": ["code_execution_20260120"]
}Valeurs possibles :
["direct"] - Claude est guidé pour appeler cet outil directement (valeur par défaut si omis)["code_execution_20260120"] - Claude est guidé pour appeler cet outil uniquement depuis l'exécution de code["direct", "code_execution_20260120"] - Claude peut appeler cet outil directement ou depuis l'exécution de code"code_execution_20260120" et "code_execution_20260521" sont tous deux acceptés dans allowed_callers et sont interchangeables : une requête utilisant l'une ou l'autre version de l'outil d'exécution de code satisfait les outils qui listent l'un ou l'autre appelant. Les blocs de réponse étiquettent toujours l'appelant comme code_execution_20260120, quelle que soit la version déclarée dans la requête.
Choisissez soit ["direct"] soit ["code_execution_20260120"] pour chaque outil plutôt que d'activer les deux, car cela fournit des indications plus claires à Claude sur la meilleure façon d'utiliser l'outil.
allowed_callers contrôle la manière dont l'outil est présenté à Claude et est validé par rapport à tool_choice, mais ce n'est pas un blocage strict au niveau de l'API sur l'invocation directe. Claude est fortement guidé pour le respecter, mais votre client doit tout de même être prêt à gérer un tool_use direct pour tout outil qu'il définit. Ne vous fiez pas à allowed_callers comme frontière de sécurité.
caller dans les réponsesChaque bloc d'utilisation d'outils inclut un champ caller indiquant comment il a été invoqué :
Invocation directe (utilisation d'outils traditionnelle) :
{
"type": "tool_use",
"id": "toolu_abc123",
"name": "query_database",
"input": { "sql": "<sql>" },
"caller": { "type": "direct" }
}Invocation programmatique :
{
"type": "tool_use",
"id": "toolu_xyz789",
"name": "query_database",
"input": { "sql": "<sql>" },
"caller": {
"type": "code_execution_20260120",
"tool_id": "srvtoolu_abc123"
}
}Le tool_id est l'id du bloc server_tool_use d'exécution de code qui a effectué l'appel, ce qui vous permet de faire correspondre chaque tool_use programmatique à l'exécution de code qui l'a produit.
L'appel d'outils programmatique utilise les mêmes conteneurs que l'exécution de code :
container, accompagné d'un horodatage expires_atexpires_at vous indique combien de temps il reste au conteneur. Les conteneurs inactifs sont actuellement récupérés après environ 5 minutes, et aucun conteneur ne peut être réutilisé plus de 30 jours après sa création.Pendant que le code de Claude attend un résultat d'outil programmatique, l'appel en attente expire après environ 4 minutes et lève une TimeoutError dans le code. Renvoyez chaque résultat d'outil bien avant l'horodatage expires_at de la réponse en pause. Voir Expiration du conteneur pendant un appel d'outil.
Voici comment fonctionne un flux complet d'appel d'outils programmatique :
Envoyez une requête avec l'exécution de code et un outil qui autorise l'appel programmatique. Pour activer l'appel programmatique, ajoutez le champ allowed_callers à votre définition d'outil.
Fournissez des descriptions détaillées du format de sortie de votre outil dans la description de l'outil. Si vous spécifiez que l'outil renvoie du JSON, Claude tente de désérialiser et de traiter le résultat dans le code. Plus vous fournissez de détails sur le schéma de sortie, mieux Claude peut gérer la réponse de manière programmatique.
La forme de la requête est identique à l'exemple de Démarrage rapide : incluez code_execution dans votre liste d'outils, ajoutez allowed_callers: ["code_execution_20260120"] à tout outil que vous souhaitez que Claude invoque depuis le code, et envoyez votre message utilisateur. Les étapes restantes de ce workflow utilisent le message utilisateur "Query customer purchase history from the last quarter and identify our top 5 customers by revenue".
Claude écrit du code qui appelle votre outil. L'API se met en pause et renvoie :
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "I'll query the purchase history and analyze the results."
},
{
"type": "server_tool_use",
"id": "srvtoolu_abc123",
"name": "code_execution",
"input": {
"code": "import json\n\nrows = json.loads(await query_database({'sql': '<sql>'}))\ntop_customers = sorted(rows, key=lambda x: x['revenue'], reverse=True)[:5]\nprint(f'Top 5 customers: {top_customers}')"
}
},
{
"type": "tool_use",
"id": "toolu_def456",
"name": "query_database",
"input": { "sql": "<sql>" },
"caller": {
"type": "code_execution_20260120",
"tool_id": "srvtoolu_abc123"
}
}
],
"container": {
"id": "container_xyz789",
"expires_at": "2026-01-20T14:30:00Z"
},
"stop_reason": "tool_use"
}Envoyez l'historique complet de la conversation ainsi que votre résultat d'outil. Trois détails sont importants pour cette requête :
tool_result. Voir Restrictions de formatage des messages.container de la réponse en pause. L'API rejette une continuation qui comporte des appels d'outils programmatiques en attente mais aucun ID de conteneur.tools que la requête d'origine. L'outil d'exécution de code doit toujours être présent pour que le code en pause puisse reprendre, et les outils que vous envoyez dans cette requête sont les définitions que Claude et le code en cours d'exécution peuvent utiliser pour le reste du tour.response = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
container="container_xyz789", # Reuse the container
messages=[
{
"role": "user",
"content": "Query customer purchase history from the last quarter and identify our top 5 customers by revenue",
},
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "I'll query the purchase history and analyze the results.",
},
{
"type": "server_tool_use",
"id": "srvtoolu_abc123",
"name": "code_execution",
"input": {"code": "..."},
},
{
"type": "tool_use",
"id": "toolu_def456",
"name": "query_database",
"input": {"sql": "<sql>"},
"caller": {
"type": "code_execution_20260120",
"tool_id": "srvtoolu_abc123",
},
},
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_def456",
"content": '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]',
}
],
},
],
# Même tableau d'outils que la requête d'origine
tools=[
{"type": "code_execution_20260120", "name": "code_execution"},
{
"name": "query_database",
"description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
"input_schema": {
"type": "object",
"properties": {
"sql": {"type": "string", "description": "SQL query to execute"}
},
"required": ["sql"],
},
"allowed_callers": ["code_execution_20260120"],
},
],
)
print(response)Le code reprend là où il s'était mis en pause et traite votre résultat. Chaque réponse de continuation soit se met à nouveau en pause avec d'autres blocs tool_use programmatiques, soit termine l'exécution de code et laisse Claude poursuivre le tour (Étape 5). Vérifiez stop_reason et le champ caller de chaque bloc tool_use pour distinguer les deux cas : une réponse qui se met en pause pour vous a stop_reason: "tool_use" et un bloc tool_use dont le caller nomme une version d'exécution de code, et vous répétez l'Étape 3 avec un tool_result pour chaque appel programmatique en attente dans un seul message utilisateur.
Une fois l'exécution de code terminée, Claude fournit la réponse finale :
{
"content": [
{
"type": "code_execution_tool_result",
"tool_use_id": "srvtoolu_abc123",
"content": {
"type": "code_execution_result",
"stdout": "Top 5 customers: [{'customer_id': 'C1', 'revenue': 45000}, {'customer_id': 'C2', 'revenue': 38000}, {'customer_id': 'C5', 'revenue': 32000}, {'customer_id': 'C8', 'revenue': 28500}, {'customer_id': 'C3', 'revenue': 24000}]",
"stderr": "",
"return_code": 0,
"content": []
}
},
{
"type": "text",
"text": "I've analyzed the purchase history from last quarter. Your top 5 customers generated $167,500 in total revenue, with Customer C1 leading at $45,000."
}
],
"stop_reason": "end_turn"
}Claude peut écrire du code qui traite efficacement plusieurs éléments :
regions = ["West", "East", "Central", "North", "South"]
results = {}
for region in regions:
rows = json.loads(await query_database({"sql": f"<sql for {region}>"}))
results[region] = sum(row["revenue"] for row in rows)
# Traiter les résultats par programmation
top_region = max(results.items(), key=lambda x: x[1])
print(f"Top region: {top_region[0]} with ${top_region[1]:,} in revenue")Ce pattern :
Claude peut arrêter le traitement dès que les critères de réussite sont satisfaits :
endpoints = ["us-east", "eu-west", "apac"]
for endpoint in endpoints:
status = await check_health({"endpoint": endpoint})
if status == "healthy":
print(f"Found healthy endpoint: {endpoint}")
break # Stop early, don't check remainingpath = "/tmp/example.txt"
file_info = json.loads(await get_file_info({"path": path}))
if file_info["size"] < 10000:
content = await read_full_file({"path": path})
else:
content = await read_file_summary({"path": path})
print(content)server_id = "srv-01"
log_text = await fetch_logs({"server_id": server_id})
errors = [line for line in log_text.splitlines() if "ERROR" in line]
print(f"Found {len(errors)} errors")
for error in errors[-10:]: # Only return last 10 errors
print(error)Lorsque l'exécution de code appelle un outil :
{
"type": "tool_use",
"id": "toolu_abc123",
"name": "query_database",
"input": { "sql": "<sql>" },
"caller": {
"type": "code_execution_20260120",
"tool_id": "srvtoolu_xyz789"
}
}Votre résultat d'outil est retransmis au code en cours d'exécution :
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_abc123",
"content": "[{\"customer_id\": \"C1\", \"revenue\": 45000, \"orders\": 23}, {\"customer_id\": \"C2\", \"revenue\": 38000, \"orders\": 18}, ...]"
}
]
}Lorsque tous les appels d'outils sont satisfaits et que le code se termine :
{
"type": "code_execution_tool_result",
"tool_use_id": "srvtoolu_xyz789",
"content": {
"type": "code_execution_result",
"stdout": "Analysis complete. Top 5 customers identified from 847 total records.",
"stderr": "",
"return_code": 0,
"content": []
}
}| Erreur | Où elle apparaît | Description | Solution |
|---|---|---|---|
invalid_tool_input | error_code sur le bloc d'erreur code_execution_tool_result dans la réponse | Des paramètres non valides ont été transmis à l'outil d'exécution de code | Voir les erreurs de l'outil d'exécution de code |
invalid_request_error (sur tool_choice) | Réponse d'erreur HTTP 400 | tool_choice nomme un outil dont allowed_callers n'inclut pas "direct" | Soit ajoutez "direct" à allowed_callers de cet outil, soit retirez l'outil de tool_choice et laissez Claude l'invoquer depuis le code |
Si votre résultat d'outil n'arrive pas dans un délai d'environ 4 minutes, l'appel en attente lève une TimeoutError dans le code en cours d'exécution de Claude. Claude voit l'erreur dans stderr et réessaie généralement l'appel :
{
"type": "code_execution_tool_result",
"tool_use_id": "srvtoolu_abc123",
"content": {
"type": "code_execution_result",
"stdout": "",
"stderr": "TimeoutError: Calling tool ['query_database'] timed out (no response after 270s).",
"return_code": 0,
"content": []
}
}Pour éviter les expirations :
expires_at dans les réponsesSi votre outil renvoie une erreur :
{
"type": "tool_result",
"tool_use_id": "toolu_abc123",
"content": "Error: Query timeout - table lock exceeded 30 seconds"
}Le code de Claude reçoit cette erreur et peut la gérer de manière appropriée.
strict: true ne sont pas pris en charge avec l'appel programmatiquetool_choicedisable_parallel_tool_use: true n'est pas pris en charge avec l'appel programmatiqueLes outils personnalisés dont l'input_schema contient une $ref récursive (un cycle de référence, comme un schéma qui se référence lui-même) ne peuvent pas être activés pour l'appel programmatique. Inclure une version de l'outil d'exécution de code dans allowed_callers pour un tel outil provoque l'échec de la requête avec une erreur 400 invalid_request_error dont le message contient Circular $ref detected. Le même schéma est accepté pour l'appel d'outil direct.
Pour contourner ce problème, effectuez l'une des opérations suivantes :
allowed_callers (ou en le définissant sur ["direct"]). Les autres outils de la même requête peuvent toujours utiliser l'appel programmatique.description du niveau le plus interne, ou remplacez la propriété récursive par un simple {"type": "object"} dont la description explique la forme attendue.Les outils suivants ne peuvent pas être appelés de manière programmatique :
Lorsque vous répondez à des appels d'outils programmatiques, des exigences strictes de formatage s'appliquent :
Réponses contenant uniquement des résultats d'outils : S'il existe des appels d'outils programmatiques en attente de résultats, votre message de réponse doit contenir uniquement des blocs tool_result. Vous ne pouvez inclure aucun contenu textuel, même après les résultats d'outils.
Non valide - Impossible d'inclure du texte lors de la réponse à des appels d'outils programmatiques :
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01",
"content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}]"
},
{ "type": "text", "text": "What should I do next?" }
]
}Valide - Uniquement des résultats d'outils lors de la réponse à des appels d'outils programmatiques :
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01",
"content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}]"
}
]
}Cette restriction s'applique uniquement lors de la réponse à des appels d'outils programmatiques (exécution de code). Pour les appels d'outils côté client classiques, vous pouvez inclure du contenu textuel après les résultats d'outils.
Contenu de résultat d'outil uniquement textuel : Le content de chaque tool_result qui répond à un appel programmatique doit être une chaîne de caractères ou des blocs text. Les types de blocs de contenu image, document et autres sont rejetés.
Les appels d'outils programmatiques sont soumis aux mêmes limites de débit que les appels d'outils classiques. Chaque appel d'outil depuis l'exécution de code compte comme une invocation distincte.
Lors de l'implémentation d'outils définis par l'utilisateur qui seront appelés de manière programmatique :
L'appel d'outils programmatique réduit la consommation de tokens de trois manières :
Par exemple, appeler 10 outils directement utilise environ 10 fois plus de tokens que de les appeler de manière programmatique et de renvoyer un résumé.
Dans les évaluations internes d'Anthropic sur un modèle Claude de production :
tools contient de 10 à 49 définitions d'outils constatent des économies de tokens typiques de 20 % à 40 % avec l'appel d'outils programmatique activé.Les économies réelles varient selon la forme de la charge de travail. Voir Quand utiliser l'appel programmatique.
L'appel d'outils programmatique utilise la même tarification que l'exécution de code. Consultez la tarification de l'exécution de code pour plus de détails.
Comptage des tokens pour les appels d'outils programmatiques : les résultats d'outils provenant d'invocations programmatiques ne comptent pas dans votre utilisation de tokens d'entrée/sortie. Seuls le résultat final de l'exécution de code et la réponse de Claude comptent.
L'appel d'outils programmatique échange une petite surcharge fixe (démarrage du conteneur, génération du script) contre d'importantes économies sur les tokens de résultats d'outils et les allers-retours avec le modèle. La rentabilité de cet échange dépend de la forme de la charge de travail.
Bien adapté :
Peu adapté :
En cas de doute, mesurez les tokens d'entrée facturés avec et sans allowed_callers sur un échantillon représentatif de votre trafic avant de l'activer largement.
invalid_request_error lors de la définition de tool_choice
tool_choice ne peut pas nommer un outil dont allowed_callers omet "direct". Soit ajoutez "direct" à allowed_callers de cet outil, soit retirez l'outil de tool_choice et laissez Claude l'invoquer depuis le code.Expiration du conteneur
expires_at de la réponse en pause. Le code de Claude cesse d'attendre un résultat après environ 4 minutes, et les conteneurs inactifs sont actuellement récupérés après environ 5 minutes.Résultat d'outil non analysé correctement
caller pour confirmer l'invocation programmatiqueClaude est entraîné sur de grandes quantités de code, donc présenter les outils comme des fonctions Python appelables lui permet d'exploiter cette force :
L'appel d'outils programmatique est un pattern généralisable qui peut également être implémenté sur votre propre infrastructure. Voici comment les approches se comparent :
Fournissez à Claude un outil d'exécution de code et décrivez quelles fonctions sont disponibles dans cet environnement. Lorsque Claude invoque l'outil avec du code, votre application l'exécute localement là où ces fonctions sont définies.
Avantages :
Inconvénients :
À utiliser lorsque : Votre application peut exécuter du code arbitraire en toute sécurité, vous souhaitez l'implémentation la plus simple, et l'offre gérée d'Anthropic ne répond pas à vos besoins.
Même approche du point de vue de Claude, mais le code s'exécute dans un conteneur sandboxé avec des restrictions de sécurité (par exemple, pas de sortie réseau). Si vos outils nécessitent des ressources externes, vous aurez besoin d'un protocole pour exécuter les appels d'outils en dehors du sandbox.
Avantages :
Inconvénients :
À utiliser lorsque : La sécurité est critique et la solution gérée d'Anthropic ne répond pas à vos exigences.
L'appel d'outils programmatique d'Anthropic est une version gérée de l'exécution sandboxée avec un environnement Python préconfiguré et optimisé pour Claude. Anthropic gère la gestion des conteneurs, l'exécution du code et la communication sécurisée des invocations d'outils.
Avantages :
Envisagez d'utiliser la solution gérée d'Anthropic si vous utilisez l'API Claude, Claude Platform on AWS ou Microsoft Foundry. Sur Microsoft Foundry, l'appel d'outils programmatique nécessite un déploiement Hosted on Anthropic.
L'appel d'outils programmatique est construit sur l'infrastructure d'exécution de code et utilise les mêmes conteneurs sandbox. Les données des conteneurs, y compris les artefacts d'exécution et les sorties, sont conservées jusqu'à 30 jours.
Pour l'éligibilité ZDR sur toutes les fonctionnalités, consultez API et conservation des données.
Diffusez les entrées d'outils sans mise en mémoire tampon JSON côté serveur pour les applications sensibles à la latence.
Exécutez du code Python et bash dans un conteneur sandboxé pour analyser des données, générer des fichiers et itérer sur des solutions.
Connectez Claude à des outils et API externes. Découvrez où les outils s'exécutent, quand Claude les appelle et quel outil convient à votre tâche.
Spécifiez des schémas d'outils, rédigez des descriptions efficaces et contrôlez quand Claude appelle vos outils.
Was this page helpful?