Tool use et structured outputs
Un modèle qui ne sait produire que du texte est une impasse dès l'instant où vous avez besoin qu'il interroge une base de données en direct, appelle une APIAPIApplication Programming Interface : une interface standardisée qui permet aux applications de communiquer et d'échanger des données sans connaître leur fonctionnement interne respectif.Voir la définition complète → ou transmette du JSON propre au service suivant de votre pipelinepipelineL'ensemble des opportunités commerciales actives réparties selon les étapes du processus de vente, avec leur valeur potentielle cumulée et leur probabilité de conclusion.Voir la définition complète →. Le tool use et les structured outputs sont la façon de combler cet écart avec Claude : vous décrivez des capacités, Claude décide quand les invoquer, et vous récupérez des données que votre code peut réellement consommer.
Cette leçon couvre les deux mécaniques sur l'API Messages d'Anthropic, les formes de requête et de réponse que vous allez effectivement envoyer et parser, et la relation entre les deux techniques.
Ce que « tool use » signifie vraiment
Le tool use (parfois appelé function calling) est un protocole, pas de la magie. Claude n'exécute jamais votre code. Vous lui fournissez une liste de définitions d'outils, chacune avec un nom, une description et un JSON SchemaSchemaUn schema est le plan formel qui définit comment les données sont structurées, nommées, typées et reliées entre elles au sein d'une base de données, d'un fichier ou d'un message.Voir la définition complète → pour ses entrées. Quand Claude estime qu'un outil serait utile, il interrompt la génération de texte et émet à la place une requête structurée : « appelle get_weather avec {"location": "Paris"} ». Votre application exécute cette fonction, renvoie le résultat, et Claude continue.
Cet aller-retour, c'est la boucle de tool use. La comprendre, c'est tout l'enjeu.
Les quatre étapes de la boucle
- Vous envoyez un message utilisateur plus votre tableau
tools. - Claude répond avec
stop_reason: "tool_use"et un bloc de contenutool_use. - Vous exécutez l'outil et renvoyez la réponse sous forme de
tool_result. - Claude lit le résultat et produit sa réponse textuelle finale.
Une boucle get_weather concrète
Voici la boucle complète en Python avec le SDK officiel. Lisez-la une fois, puis nous détaillerons chaque forme.
import anthropic
client = anthropic.Anthropic()
tools = [{
"name": "get_weather",
"description": "Get current temperature for a given city.",
"input_schema": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City name, e.g. 'Paris'"}
},
"required": ["location"],
},
}]
def get_weather(location):
# Dans la vraie vie, appelez ici une API météo.
return {"location": location, "temp_c": 14, "conditions": "cloudy"}
messages = [{"role": "user", "content": "What's the weather in Paris right now?"}]
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=tools,
messages=messages,
)
# Étape 2 : Claude a demandé un outil.
if response.stop_reason == "tool_use":
tool_call = next(b for b in response.content if b.type == "tool_use")
result = get_weather(**tool_call.input)
# Étape 3 : ajoutez la requête de Claude ET votre résultat.
messages.append({"role": "assistant", "content": response.content})
messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": tool_call.id,
"content": str(result),
}],
})
# Étape 4 : Claude lit le résultat et rédige la réponse.
final = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=tools,
messages=messages,
)
print(final.content[0].text)Lire la forme de la réponse
Quand Claude veut un outil, response.content est une liste de blocs. Celui qui nous intéresse ressemble à ceci :
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "get_weather",
"input": {"location": "Paris"}
}Trois champs comptent. name vous indique quelle fonction exécuter. input est déjà un objet parsé conforme à votre schémamaUtiliser un logiciel pour automatiser les tâches et campagnes marketing répétitives, afin de personnaliser à grande échelle sur des canaux comme l'email, le web et le social.Voir la définition complète →, donc aucun parsing de chaîne. `id` est la référence que vous devez renvoyer.
Renvoyer le résultat
Le détail critique que l'on oublie : vous devez ajouter deux messages, dans l'ordre. D'abord le tour assistant de Claude lui-même (l'intégralité de response.content, y compris le bloc tool_use). Ensuite un tour user portant le tool_result. Le tool_use_id de votre résultat doit correspondre exactement à l'id envoyé par Claude, sinon la boucle casse.
Si votre outil échoue, mettez "is_error": true dans le bloc de résultat. Claude verra l'erreur et pourra s'excuser, réessayer avec d'autres entrées, ou choisir un autre outil.
Outils multiples et appels parallèles
Vous n'expédiez presque jamais un seul outil. Passez-en plusieurs dans le tableau tools et Claude route vers le bon en se fondant sur les descriptions. Rédigez ces descriptions comme de la documentation, car elles sont la seule chose que Claude utilise pour décider. « Get current temperaturetemperatureUn reglage qui controle le caractere aleatoire ou previsible des reponses d'un modele d'IA : bas pour la coherence, haut pour la creativite.Voir la définition complète → for a given city » bat « weather tool » à tous les coups.
Claude peut aussi demander plusieurs outils dans un même tour (parallel tool use). Dans ce cas, response.content contient plusieurs blocs tool_use. Exécutez-les tous, puis renvoyez l'ensemble des blocs `tool_result` dans un seul message user avant de rappeler l'API.
Pour boucler jusqu'à ce que Claude ait terminé (il peut enchaîner plusieurs outils), encapsulez l'appel dans une boucle `while response.stop_reason == "tool_use"` au lieu d'un simple `if`.
Structured outputs : récupérer du JSON propre
Le tool use résout « fais quelque chose ». Les structured outputs résolvent « donne-moi des données dans une forme exacte ». Imaginez que vous extrayiez des champs d'un e-mail de support et qu'il vous faille {"category": ..., "urgency": ..., "summary": ...} à chaque fois, sans prose, sans balises markdown.
L'astuce la plus fiable consiste à utiliser le mécanisme d'outils lui-même. Définissez un outil qui représente le schéma de sortie souhaité, puis forcez Claude à l'utiliser.
import anthropic
client = anthropic.Anthropic()
extract_tool = {
"name": "record_ticket",
"description": "Record the structured fields of a support ticket.",
"input_schema": {
"type": "object",
"properties": {
"category": {"type": "string", "enum": ["billing", "bug", "feature", "other"]},
"urgency": {"type": "string", "enum": ["low", "medium", "high"]},
"summary": {"type": "string", "description": "One sentence."},
},
"required": ["category", "urgency", "summary"],
},
}
email = "I was charged twice this month and need this fixed before Friday!"
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[extract_tool],
tool_choice={"type": "tool", "name": "record_ticket"},
messages=[{"role": "user", "content": email}],
)
ticket = next(b.input for b in response.content if b.type == "tool_use")
print(ticket)
# {'category': 'billing', 'urgency': 'high', 'summary': 'Customer charged twice and wants a fix by Friday.'}Pourquoi ça marche
Le paramètre tool_choice est le levier. Réglez-le sur {"type": "tool", "name": "record_ticket"} et vous forcez Claude à appeler cet outil précis, ce qui l'oblige à produire un input conforme à votre schéma. Ici, vous n'exécutez aucune fonction. Vous lisez simplement b.input, qui est déjà un objet validé. Aucun bloc de code à nettoyer, aucun JSON à moitié formé.
Les contraintes enum travaillent aussi pour vous. Elles empêchent Claude d'inventer un quatrième niveau d'urgence. Plus votre schéma est serré, plus vos sorties le sont.
Autres valeurs utiles de tool_choice :
{"type": "auto"}(par défaut) : Claude décide s'il utilise un outil.{"type": "any"}: Claude doit utiliser *un* outil mais choisit lequel.{"type": "tool", "name": "..."}: force un outil précis, comme ci-dessus.
La documentation d'Anthropic traite en détail les cas limites de schéma et le streaming. Voir le guide tool use pour la référence faisant autorité.
Claude Tool Use Explained
Vérification des acquis
1. Dans le protocole de tool use décrit, que se passe-t-il réellement quand Claude « utilise » un outil ?
2. Pourquoi le tool use et les structured outputs ont-ils de la valeur lorsqu'on intègre Claude dans un pipeline logiciel ?
3. Après avoir renvoyé un tool_result à Claude, que se passe-t-il à la dernière étape de la boucle de tool use ?
4. Sélectionnez TOUS les éléments qu'une définition d'outil doit contenir lorsque vous envoyez votre tableau tools à Claude.
Sélectionnez toutes les réponses correctes.
5. Sélectionnez TOUTES les affirmations qui décrivent correctement le comportement de la boucle de tool use.
Sélectionnez toutes les réponses correctes.
Le lien avec MCPMCPUn standard ouvert qui permet aux assistants IA de se connecter aux outils et données de l'entreprise de façon cohérente et gouvernée, sans intégration sur mesure à chaque fois.Voir la définition complète → et l'Agent SDK
Tout ce qui précède, c'est l'API brute. Vous définissez les outils en ligne et les exécutez vous-même. C'est parfait pour une poignée d'outils sur mesure dans un seul service.
Mais vous voudrez vite des outils réutilisables que n'importe quelle surface Claude peut appeler : l'application desktop, Claude Code, votre propre agent. C'est ce que standardise MCP (Model Context Protocol). Un serveur MCP expose des outils (ainsi que des ressources et des prompts) via un protocole défini : vous écrivez un outil une fois et le branchez sur plusieurs clients. Les applications Claude les présentent sous forme de Connectors, et il existe une marketplace de connecteurs pour les plus courants comme Google Drive ou GitHub.
La relation est nette : les outils MCP et les outils d'API sont la *même idée* à des échelles différentes. La liste d'outils d'un serveur MCP finit par devenir des entrées dans un tableau tools, et le handshake appel/résultat reproduit la boucle que vous venez d'apprendre. Découvrez le protocole sur modelcontextprotocol.io.
Le Claude Agent SDK se situe un niveau au-dessus. Il exécute la boucle de tool use pour vous, gère le contexte et prend en charge le comportement d'agent multi-étapes : vous décrivez des outils et des objectifs plutôt que de coder à la main la machinerie while stop_reason == "tool_use". Quand vous construisez un vrai agent, prenez le SDK. Quand vous avez besoin d'un contrôle chirurgical sur un échange unique, descendez à l'API Messages comme montré plus haut. Les deux parlent le même langage de tool use, et c'est précisément pour cela qu'apprendre la boucle brute est payant.
Pièges pratiques
Quelques points qui vous mordront en production :
- Budget de tokens. Les définitions d'outils vivent dans la fenêtre de contexte. Vingt outils verbeux coûtent de vrais tokenstokensUn token est l'unité de base de texte que traitent les modèles de langage : le plus souvent un fragment de mot, un mot entier ou un signe de ponctuation, plutôt qu'un simple caractère.Voir la définition complète → à chaque appel. Gardez des schémas légers et des descriptions affûtées.
- Validez tout de même les entrées. Claude respecte généralement votre schéma, mais vous exécutez du vrai code avec ces valeurs. Traitez
inputcomme n'importe quelle entrée utilisateur non fiable : vérifiez les types, bornez les plages, assainissez avant d'attaquer une base de données. - Un outil forcé ne peut pas aussi « réfléchir à voix haute ». Quand vous forcez
tool_choicesur un outil précis, Claude passe directement à l'appel. Si vous avez besoin de raisonnement d'abord, laissez-le surautoou découpez en deux appels. - Les erreurs sont un signal, pas un échec. Renvoyer
is_error: trueavec un message utile permet souvent à Claude de s'auto-corriger au tour suivant, ce qui est plus robuste que de faire planter votre boucle.
Points clés
- Le tool use est une boucle en quatre étapes : envoyer les outils, recevoir un bloc
tool_use, exécuter la fonction, renvoyer untool_resultavec letool_use_idcorrespondant. Renvoyez le tour assistant de Claude avant le résultat, sinon la boucle casse. - Pour du JSON garanti, forcez un outil. Définissez votre sortie comme un schéma d'outil, réglez
tool_choicesur cet outil, et lisez l'inputdéjà parsé. Utilisezenumetrequiredpour verrouiller la forme. - Rédigez les descriptions d'outils comme de la doc. Elles sont la seule chose que Claude utilise pour router : soyez précis et concret.
- Validez toujours les entrées d'outils dans votre code. Claude propose ; votre application exécute. Traitez les entrées comme non fiables.
- Montez en échelle de façon délibérée : API Messages brute pour un échange sur mesure, MCP pour des outils réutilisables entre applications, l'Agent SDK quand vous voulez que la boucle soit gérée pour vous. Tous parlent le même protocole.
À faire, tiré de cette leçon
Ces actions sont compilées dans le plan d'action du rôle.
- Forcez un schéma de tool quand vous avez besoin d'un JSON parsé garanti