Aller au contenu principal
Leçon 6 sur 16 · L'utilisation d'outils (tool use) avec la Messages API

Sorties structurées : du JSON garanti

Leçon 6 sur 16 Mis à jour le 5 novembre 2026 Développeur
Sur cette page
  1. Objectifs
  2. Le besoin
  3. L’ancienne méthode : un outil prétexte, forcé
  4. La méthode actuelle : les sorties JSON
  5. Ce qu’il faut savoir
  6. Sorties JSON ou strict tool use ?
  7. À vous de jouer
  8. Points clés à retenir

Objectifs

À l’issue de cette leçon, vous serez capable de :

  • Obtenir une réponse JSON conforme à un schéma avec les sorties JSON (output_config.format)
  • Reconnaître l’ancienne méthode de l’outil « prétexte », et savoir pourquoi elle ne fonctionne plus sur les modèles récents
  • Connaître les limites des sorties structurées

Le besoin

Quand vous demandez du JSON à un modèle en langage naturel, vous obtenez souvent du JSON valide, parfois précédé d’un « Voici le résultat : », parfois enveloppé dans un bloc de code, parfois avec une clé renommée. Votre parseur casse une fois sur vingt, ce qui est intenable dans une chaîne de traitement automatisée.

L’ancienne méthode : un outil prétexte, forcé

Pendant longtemps, l’astuce consistait à détourner le tool use : définir un outil « fictif » dont le schéma correspond au JSON voulu (par exemple print_sentiment_scores), forcer son appel avec tool_choice: {"type": "tool", ...}, lire les données dans input, et ne jamais exécuter aucune fonction. Vous la croiserez dans du code existant.

Elle repose sur l’appel forcé, que Claude Opus 5.5, Sonnet 5.5, Fable 5.1 et Mythos 5.1 refusent (erreur 400, leçon 5). Pour obtenir une réponse dans une forme JSON fixe, la documentation officielle renvoie désormais aux sorties structurées.

La méthode actuelle : les sorties JSON

Les sorties structurées contraignent la réponse de Claude à un schéma, par décodage contraint : la réponse est toujours du JSON valide, avec les champs obligatoires et les types attendus. Elles regroupent deux fonctions complémentaires :

Sorties JSON et strict tool use Deux colonnes : les sorties JSON (output_config.format) contraignent la réponse de Claude, avec client.messages.parse en Python ; le strict tool use (strict: true) contraint les entrées des appels d'outils. Les deux reposent sur le décodage contraint. SORTIES STRUCTURÉES Sorties JSON et strict tool use Sorties JSON Paramètre output_config.format Contraint La réponse de Claude elle-même. En Python client.messages.parse() et un modèle Pydantic. Strict tool use Paramètre "strict": true dans la définition de l'outil. Contraint Les entrées des appels d'outils. Pour aller plus loin Leçon 8. Les deux reposent sur le décodage contraint, sur tous les modèles, et se combinent dans une même requête.
D'après la page Structured outputs (documentation Claude).
  • les sorties JSON (output_config.format) : la réponse de Claude elle-même suit votre schéma ;
  • le strict tool use ("strict": true) : les entrées des appels d’outils suivent leur schéma (leçon 8).

Les sorties structurées sont disponibles sur tous les modèles, en version stable : aucun en-tête bêta n’est nécessaire.

Exemple : analyse de sentiment, avec un schéma JSON

Le schéma part dans output_config.format, avec type: "json_schema". Chaque objet du schéma porte additionalProperties: false, et la plage de valeurs est indiquée dans les descriptions : les contraintes numériques comme minimum ou maximum ne font pas partie des schémas pris en charge.

import json
from anthropic import Anthropic

client = Anthropic()

response = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=4096,
    messages=[{
        "role": "user",
        "content": "Analyse le sentiment de ce texte : « Ce produit est absolument horrible, je suis très déçu. »"
    }],
    output_config={
        "format": {
            "type": "json_schema",
            "schema": {
                "type": "object",
                "properties": {
                    "positive_score": {"type": "number", "description": "Score de sentiment positif, de 0 à 1"},
                    "negative_score": {"type": "number", "description": "Score de sentiment négatif, de 0 à 1"},
                    "neutral_score": {"type": "number", "description": "Score de sentiment neutre, de 0 à 1"}
                },
                "required": ["positive_score", "negative_score", "neutral_score"],
                "additionalProperties": False
            }
        }
    },
)

# Le JSON arrive dans le bloc de texte de la réponse
texte = next(b.text for b in response.content if b.type == "text")
scores = json.loads(texte)

Exemple : extraction d’entités, avec un modèle Pydantic

En Python, la méthode recommandée par la documentation est client.messages.parse() avec un modèle Pydantic passé en output_format : le SDK transforme le schéma, l’envoie dans output_config.format, valide la réponse et renvoie l’objet dans parsed_output.

from pydantic import BaseModel

class Entites(BaseModel):
    personnes: list[str]
    organisations: list[str]
    lieux: list[str]

texte = "Marie Curie a reçu le prix Nobel à Stockholm, décerné par l'Académie royale des sciences de Suède."

response = client.messages.parse(
    model="claude-sonnet-5-5",
    max_tokens=4096,
    messages=[{"role": "user", "content": f"Extrais les personnes, organisations et lieux de ce texte : {texte}"}],
    output_format=Entites,
)
entites = response.parsed_output  # une instance de Entites
print(entites.lieux)

Les trois listes sont toujours présentes, éventuellement vides : plus de test d’existence de clé dans le code appelant.

Ce qu’il faut savoir

  • Première requête plus lente. La première fois qu’un schéma est utilisé, sa grammaire est compilée ; elle reste ensuite en cache 24 heures après sa dernière utilisation.
  • Quelques jetons de plus. Claude reçoit automatiquement un prompt système supplémentaire qui décrit le format attendu. Changer output_config.format invalide le cache de prompt de la conversation.
  • Vérifiez stop_reason. En cas de refus ("refusal") ou de réponse coupée par la limite de jetons ("max_tokens"), la sortie peut ne pas respecter le schéma ; dans le second cas, relancez avec un max_tokens plus élevé.
  • La casse des valeurs enum n’est pas garantie. Comparez-les sans tenir compte des majuscules, et évitez des valeurs qui ne diffèrent que par la casse.
  • Incompatibilités. Les sorties JSON ne se combinent ni avec les citations (erreur 400) ni avec le pré-remplissage de la réponse.

Sorties JSON ou strict tool use ?

Les deux répondent à des besoins différents, et se combinent dans une même requête :

Vous voulez…Utilisez
Que la réponse de Claude suive un format JSON (extraction, classement, rapport)Les sorties JSON : output_config.format
Que les entrées des appels d’outils respectent leur schémaLe strict tool use : "strict": true (leçon 8)

À vous de jouer

Un traducteur multilingue. Écrivez une fonction translate qui, pour une phrase donnée, renvoie sa traduction en anglais, espagnol, français, japonais et arabe, dans un objet aux cinq champs obligatoires.

Voir la solution
from pydantic import BaseModel

class Traduction(BaseModel):
    english: str
    spanish: str
    french: str
    japanese: str
    arabic: str

def translate(phrase):
    response = client.messages.parse(
        model="claude-sonnet-5-5",
        max_tokens=4096,
        messages=[{
            "role": "user",
            "content": f"Traduis cette phrase en anglais, espagnol, français, japonais et arabe : « {phrase} »"
        }],
        output_format=Traduction,
    )
    return response.parsed_output

print(translate("Combien ça coûte ?"))

Sources officielles : Structured outputs (documentation Claude : output_config.format, messages.parse, limites, incompatibilités) · Define tools — Forcing tool use

Points clés à retenir

  • L’outil « prétexte » forcé ne fonctionne plus sur les modèles qui refusent l’appel forcé
  • Les sorties JSON (output_config.format) garantissent une réponse conforme au schéma, sur tous les modèles
  • En Python, client.messages.parse() avec un modèle Pydantic renvoie directement l’objet dans parsed_output
  • Vérifiez stop_reason, comparez les enum sans tenir compte de la casse, et pas de citations avec les sorties JSON

Crédits et licence — Leçon réécrite par Corsen à partir du notebook « 03_structured_outputs » du tutoriel Tool use d’Anthropic (dépôt GitHub anthropics/courses, publié sous licence CC BY-NC 4.0), et mise à jour d’après la documentation officielle citée ci-dessus.