Données structurées avec les outils
Sur cette page
Un outil a une propriété utile en dehors de toute action : Claude remplit ses arguments selon un schéma. Les anciennes versions du cours s’en servaient pour extraire des données structurées, avec un outil fictif que l’on obligeait Claude à appeler. Cette leçon montre ce qui reste valable de cette technique, ce qui a changé, et l’outil adapté à chaque besoin.
L’idée d’origine, et ce qui a changé
La technique tenait en trois temps : définir un outil dont le schéma décrit les données voulues, forcer son appel avec tool_choice, puis lire les données dans l’input du bloc tool_use, sans jamais exécuter l’outil. Deux évolutions de l’API la modifient :
- Les sorties structurées existent. Pour obtenir un objet JSON conforme à un schéma,
output_config.formatcontraint directement la réponse (leçon 13). C’est l’outil prévu pour ce besoin. - Forcer un outil n’est plus possible partout. Sur Claude Opus 5.5, Sonnet 5.5, Fable 5.1 et Mythos 5.1, un
tool_choicede typeanyoutoolrenvoie une erreur 400. Sur les modèles qui l’acceptent, comme Claude Opus 5 ou Haiku 5.5, un appel forcé saute la réflexion : la réponse commence directement par l’appel d’outil.
Les quatre valeurs de tool_choice
| Valeur | Comportement |
|---|---|
{"type": "auto"} | Claude décide s’il appelle un outil. Valeur par défaut quand des outils sont fournis. |
{"type": "any"} | Claude doit appeler un outil, au choix. Refusé par Opus 5.5, Sonnet 5.5, Fable 5.1 et Mythos 5.1. |
{"type": "tool", "name": "…"} | Claude doit appeler cet outil précis. Mêmes restrictions. |
{"type": "none"} | Claude ne peut appeler aucun outil. Valeur par défaut sans outils. |
Garantir le schéma : le mode strict
Le mode strict garantit que les arguments d’un appel respectent le schéma. On ajoute "strict": True à la définition, et "additionalProperties": False à chaque objet du schéma. L’API restreint alors la génération aux sorties conformes : plus de "2" à la place de 2, plus de champ requis oublié, et le nom de l’outil est toujours valide.
save_article_summary_schema = ToolParam({
"name": "save_article_summary",
"description": (
"Enregistre la fiche de synthèse d'un article : titre, auteur et idées clés. "
"Utilisez cet outil une fois l'article lu, pour toute demande de synthèse ou de fiche. "
"Chaque idée clé tient en une phrase. "
"Si l'auteur n'est pas indiqué dans l'article, écrivez « inconnu »."
),
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"title": {"type": "string", "description": "Titre exact de l'article."},
"author": {"type": "string", "description": "Auteur de l'article, ou « inconnu »."},
"key_insights": {
"type": "array",
"items": {"type": "string"},
"description": "Les idées clés, une phrase chacune.",
},
},
"required": ["title", "author", "key_insights"],
"additionalProperties": False,
},
})
Le mode strict accepte un sous-ensemble de JSON Schema : les types de base, enum, const, anyOf, les références internes $ref, et quelques formats de chaîne comme date, email ou uri. Les contraintes numériques (minimum, maximum), les contraintes de longueur (minLength, maxLength, et minItems au-delà de 1) et les schémas récursifs ne sont pas pris en charge : un schéma qui en contient est refusé avec une erreur 400 qui donne le détail.
Sans forcer l’outil : auto, une consigne, une vérification
Sur les modèles qui refusent l’appel forcé, on garde auto, on demande l’outil dans le message, et on vérifie qu’il a bien été appelé :
messages = [{
"role": "user",
"content": f"<article>\n{article}\n</article>\n\n"
"Fais la fiche de synthèse de cet article avec l'outil save_article_summary.",
}]
response = chat(messages, tools=[save_article_summary_schema])
tool_use = next(
(block for block in response.content
if block.type == "tool_use" and block.name == "save_article_summary"),
None,
)
if tool_use is None:
raise RuntimeError("Claude n'a pas appelé save_article_summary : relancez ou reformulez la demande.")
summary = tool_use.input # {"title": "…", "author": "…", "key_insights": ["…", "…"]}
auto ne garantit pas l’appel, d’où la vérification ; quand l’appel a lieu, le mode strict garantit la forme de input. auto a un autre avantage : Claude peut réfléchir avant d’appeler l’outil, ce qu’un appel forcé empêche. Si vous arrêtez la conversation là, rien n’oblige à renvoyer un tool_result. Si vous la poursuivez, la règle de la leçon 36 s’applique : chaque tool_use reçoit son résultat, par exemple « Fiche enregistrée ».
Outil strict ou sorties structurées ?
- Vous voulez seulement un objet JSON en réponse, sans action : prenez les sorties structurées (
output_config.format, leçon 13). La réponse elle-même est l’objet, sans appel à vérifier. - Vous voulez que Claude agisse avec des arguments fiables (enregistrer, réserver, envoyer) : prenez un outil avec
strict: true. - Les deux à la fois : une même requête peut combiner des outils stricts et
output_config.formatpour la réponse finale.
À vous de jouer
Deux versions de la même extraction. Écrivez l’extraction de la fiche d’article de deux façons : avec l’outil strict ci-dessus, puis avec output_config.format et le même schéma (leçon 13). Comparez la quantité de code, et ce qui se passe quand l’article ne mentionne pas d’auteur.
Sources officielles : Strict tool use (documentation Claude) · Define tools (documentation Claude :
tool_choiceet ses restrictions) · Structured outputs (documentation Claude : sous-ensemble de JSON Schema)
Points clés à retenir
- Les sorties structurées (
output_config.format) sont l’outil prévu pour obtenir un objet JSON. tool_choicede typeanyoutoolest refusé par Opus 5.5, Sonnet 5.5, Fable 5.1 et Mythos 5.1 ; ailleurs, un appel forcé saute la réflexion.strict: trueetadditionalProperties: falsegarantissent des arguments conformes au schéma.- Avec
auto, demandez l’outil dans le message et vérifiez qu’il a été appelé. - Données seules : sorties structurées. Action fiable : outil strict. Les deux se combinent.