L'appel d'outils programmatique permet à Claude d'écrire du code qui appelle vos outils programmatiquement dans un conteneur d'exécution de code, plutôt que de nécessiter des allers-retours à travers le modèle pour chaque invocation d'outil. Cela réduit la latence pour les flux de travail multi-outils et diminue la consommation de jetons en permettant à Claude de filtrer ou de traiter les données avant qu'elles n'atteignent la fenêtre de contexte du modèle.
L'appel d'outils programmatique est actuellement en bêta publique.
Pour utiliser cette fonctionnalité, ajoutez l'en-tête bêta "advanced-tool-use-2025-11-20" beta header à vos requêtes API.
Cette fonctionnalité nécessite que l'outil d'exécution de code soit activé.
L'appel d'outils programmatique est disponible sur les modèles suivants :
| Modèle | Version de l'outil |
|---|---|
Claude Opus 4.5 (claude-opus-4-5-20251101) | code_execution_20250825 |
Claude Sonnet 4.5 (claude-sonnet-4-5-20250929) | code_execution_20250825 |
L'appel d'outils programmatique est disponible via l'API Claude et Microsoft Foundry.
Voici un exemple simple où Claude interroge programmatiquement une base de données plusieurs fois et agrège les résultats :
Lorsque vous configurez un outil pour être appelable à partir de l'exécution de code et que Claude décide d'utiliser cet outil :
tool_useCette approche est particulièrement utile pour :
Les outils personnalisés sont convertis en fonctions Python asynchrones pour supporter l'appel parallèle d'outils. Lorsque Claude écrit du code qui appelle vos outils, il utilise await (par exemple, result = await query_database("<sql>")) et inclut automatiquement la fonction wrapper asynchrone appropriée.
Le wrapper asynchrone est omis des exemples de code dans cette documentation pour plus de clarté.
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_20250825"]
}Valeurs possibles :
["direct"] - Seul Claude peut appeler cet outil directement (par défaut si omis)["code_execution_20250825"] - Appelable uniquement à partir de l'exécution de code["direct", "code_execution_20250825"] - Appelable à la fois directement et à partir de l'exécution de codeNous recommandons de choisir soit ["direct"] soit ["code_execution_20250825"] pour chaque outil plutôt que d'activer les deux, car cela fournit une orientation plus claire à Claude sur la meilleure façon d'utiliser l'outil.
caller dans les réponsesChaque bloc d'utilisation d'outil inclut un champ caller indiquant comment il a été invoqué :
Invocation directe (utilisation d'outil 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_20250825",
"tool_id": "srvtoolu_abc123"
}
}Le tool_id référence l'outil d'exécution de code qui a effectué l'appel programmatique.
L'appel d'outils programmatique utilise les mêmes conteneurs que l'exécution de code :
containerLorsqu'un outil est appelé programmatiquement et que le conteneur attend votre résultat d'outil, vous devez répondre avant que le conteneur n'expire. Surveillez le champ expires_at. Si le conteneur expire, Claude peut traiter l'appel d'outil comme expiré et le réessayer.
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 permet 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 retourne du JSON, Claude tentera 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 programmatiquement.
Claude écrit du code qui appelle votre outil. L'API s'interrompt et retourne :
{
"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": "results = await query_database('<sql>')\ntop_customers = sorted(results, 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_20250825",
"tool_id": "srvtoolu_abc123"
}
}
],
"container": {
"id": "container_xyz789",
"expires_at": "2025-01-15T14:30:00Z"
},
"stop_reason": "tool_use"
}Incluez l'historique complet de la conversation plus votre résultat d'outil :
L'exécution du code continue et traite les résultats. Si des appels d'outils supplémentaires sont nécessaires, répétez l'étape 3 jusqu'à ce que tous les appels d'outils soient satisfaits.
Une fois que l'exécution du code est 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 by revenue:\n1. Customer C1: $45,000\n2. Customer C2: $38,000\n3. Customer C5: $32,000\n4. Customer C8: $28,500\n5. Customer C3: $24,000",
"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 :
# async wrapper omitted for clarity
regions = ["West", "East", "Central", "North", "South"]
results = {}
for region in regions:
data = await query_database(f"<sql for {region}>")
results[region] = sum(row["revenue"] for row in data)
# Process results programmatically
top_region = max(results.items(), key=lambda x: x[1])
print(f"Top region: {top_region[0]} with ${top_region[1]:,} in revenue")Ce modèle :
Claude peut arrêter le traitement dès que les critères de succès sont atteints :
# async wrapper omitted for clarity
endpoints = ["us-east", "eu-west", "apac"]
for endpoint in endpoints:
status = await check_health(endpoint)
if status == "healthy":
print(f"Found healthy endpoint: {endpoint}")
break # Stop early, don't check remaining# async wrapper omitted for clarity
file_info = await get_file_info(path)
if file_info["size"] < 10000:
content = await read_full_file(path)
else:
content = await read_file_summary(path)
print(content)# async wrapper omitted for clarity
logs = await fetch_logs(server_id)
errors = [log for log in logs if "ERROR" in log]
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_20250825",
"tool_id": "srvtoolu_xyz789"
}
}Votre résultat d'outil est retourné 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 est terminé :
{
"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 | Description | Solution |
|---|---|---|
invalid_tool_input | L'entrée de l'outil ne correspond pas au schéma | Validez le input_schema de votre outil |
tool_not_allowed | L'outil ne permet pas le type d'appelant demandé | Vérifiez que allowed_callers inclut les bons contextes |
missing_beta_header | En-tête bêta PTC non fourni | Ajoutez les deux en-têtes bêta à votre requête |
Si votre outil prend trop de temps pour répondre, l'exécution du code recevra une TimeoutError. Claude le voit dans stderr et réessayera généralement :
{
"type": "code_execution_tool_result",
"tool_use_id": "srvtoolu_abc123",
"content": {
"type": "code_execution_result",
"stdout": "",
"stderr": "TimeoutError: Calling tool ['query_database'] timed out.",
"return_code": 0,
"content": []
}
}Pour éviter les délais d'expiration :
expires_at dans les réponsesSi votre outil retourne une erreur :
# Provide error information in the tool result
{
"type": "tool_result",
"tool_use_id": "toolu_abc123",
"content": "Error: Query timeout - table lock exceeded 30 seconds"
}Le code de Claude recevra cette erreur et peut la gérer de manière appropriée.
strict: true ne sont pas supportés avec l'appel programmatiquetool_choicedisable_parallel_tool_use: true n'est pas supporté avec l'appel programmatiqueLes outils suivants ne peuvent actuellement pas être appelés programmatiquement, mais le support peut être ajouté dans les versions futures :
Lors de la réponse aux appels d'outils programmatiques, il existe des exigences strictes de formatage :
Réponses contenant uniquement des résultats d'outils : S'il y a 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 pas inclure de contenu textuel, même après les résultats des outils.
// ❌ INVALIDE - Impossible d'inclure du texte lors de la réponse aux 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?"} // This will cause an error
]
}
// ✅ VALIDE - Uniquement les résultats d'outils lors de la réponse aux 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 aux appels d'outils programmatiques (exécution de code). Pour les appels d'outils côté client réguliers, vous pouvez inclure du contenu textuel après les résultats des outils.
Les appels d'outils programmatiques sont soumis aux mêmes limites de débit que les appels d'outils réguliers. Chaque appel d'outil à partir de l'exécution de code compte comme une invocation distincte.
Lors de l'implémentation d'outils personnalisés qui seront appelés programmatiquement :
L'appel d'outils programmatique peut réduire considérablement la consommation de jetons :
Par exemple, appeler 10 outils directement utilise ~10x les jetons d'appeler les outils programmatiquement et retourner un résumé.
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 jetons pour les appels d'outils programmatiques : Les résultats des outils des invocations programmatiques ne comptent pas vers votre utilisation de jetons d'entrée/sortie. Seul le résultat final de l'exécution du code et la réponse de Claude comptent.
Bons cas d'usage :
Cas d'usage moins idéaux :
Erreur "Tool not allowed"
"allowed_callers": ["code_execution_20250825"]Expiration du conteneur
expires_at dans les réponsesProblèmes d'en-tête bêta
"advanced-tool-use-2025-11-20"Le résultat de l'outil n'est pas analysé correctement
caller pour confirmer l'invocation programmatiqueL'entraînement de Claude inclut une exposition extensive au code, ce qui le rend efficace pour raisonner et enchaîner les appels de fonction. Lorsque les outils sont présentés comme des fonctions appelables dans un environnement d'exécution de code, Claude peut exploiter cette force pour :
Cette approche permet des flux de travail qui seraient impraticables avec l'utilisation d'outils traditionnelle—comme le traitement de fichiers de plus de 1M jetons—en permettant à Claude de travailler avec les données programmatiquement plutôt que de charger tout dans le contexte de conversation.
L'appel d'outils programmatique est un modèle généralisable qui peut être implémenté en dehors de l'exécution de code gérée d'Anthropic. Voici un aperçu des approches :
Fournissez à Claude un outil d'exécution de code et décrivez les fonctions disponibles dans cet environnement. Lorsque Claude invoque l'outil avec du code, votre application l'exécute localement où ces fonctions sont définies.
Avantages :
Inconvénients :
À utiliser quand : Votre application peut exécuter en toute sécurité du code arbitraire, vous voulez une solution simple, et l'offre gérée d'Anthropic ne correspond pas à vos besoins.
Même approche du point de vue de Claude, mais le code s'exécute dans un conteneur en bac à sable avec des restrictions de sécurité (par exemple, pas d'accès réseau sortant). Si vos outils nécessitent des ressources externes, vous aurez besoin d'un protocole pour exécuter les appels d'outils en dehors du bac à sable.
Avantages :
Inconvénients :
À utiliser quand : La sécurité est critique et la solution gérée d'Anthropic ne correspond pas à vos exigences.
L'appel d'outils programmatique d'Anthropic est une version gérée de l'exécution en bac à sable avec un environnement Python opinionné accordé pour Claude. Anthropic gère la gestion des conteneurs, l'exécution du code et la communication sécurisée d'invocation d'outils.
Avantages :
Nous recommandons d'utiliser la solution gérée d'Anthropic si vous utilisez l'API Claude.
curl https://api.anthropic.com/v1/messages \
--header "x-api-key: $ANTHROPIC_API_KEY" \
--header "anthropic-version: 2023-06-01" \
--header "anthropic-beta: advanced-tool-use-2025-11-20" \
--header "content-type: application/json" \
--data '{
"model": "claude-sonnet-4-5",
"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_20250825",
"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_20250825"]
}
]
}'response = client.beta.messages.create(
model="claude-sonnet-4-5",
betas=["advanced-tool-use-2025-11-20"],
max_tokens=4096,
messages=[{
"role": "user",
"content": "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"
}],
tools=[
{
"type": "code_execution_20250825",
"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": {...},
"allowed_callers": ["code_execution_20250825"]
}
]
)response = client.beta.messages.create(
model="claude-sonnet-4-5",
betas=["advanced-tool-use-2025-11-20"],
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_20250825",
"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}, ...]"
}
]
}
],
tools=[...]
)Comprenez les principes fondamentaux de l'utilisation d'outils avec Claude.