Données structurées
Sur cette page
Le problème
Ce chapitre résout un problème très concret : la sortie d’un modèle est faite pour être lue par un humain, alors que votre code, lui, veut la parser. Les deux exigences se contredisent — le texte d’accompagnement qui rend la réponse agréable est précisément ce qui fait échouer json.loads().
Quand vous demandez à Claude de générer du JSON sans autre précaution, il peut envelopper sa réponse dans une phrase d’introduction, un bloc de code Markdown et un mot de conclusion. C’est confortable pour un lecteur, et c’est un échec immédiat pour un programme. Jusqu’en 2025, la parade classique combinait le pré-remplissage de la réponse et une séquence d’arrêt ; comme l’a montré la leçon précédente, le pré-remplissage renvoie désormais une erreur 400 sur les modèles actuels. La bonne nouvelle est que l’API propose maintenant un mécanisme fait exactement pour ce besoin.
La solution actuelle : les sorties structurées
Les sorties structurées contraignent la réponse à respecter un schéma JSON que vous fournissez. Il ne s’agit pas d’une consigne que le modèle pourrait oublier : Anthropic décrit un échantillonnage restreint aux sorties conformes au schéma. Vous décrivez la forme attendue dans output_config.format, avec type: "json_schema", et le texte retourné est un objet JSON valide.
Reprenons l’exemple historique de ce cours, la génération d’une règle AWS EventBridge :
import anthropic
import json
client = anthropic.Anthropic()
SCHEMA_REGLE = {
"type": "object",
"properties": {
"source": {"type": "array", "items": {"type": "string"}},
"detail-type": {"type": "array", "items": {"type": "string"}},
"detail": {
"type": "object",
"properties": {
"state": {"type": "array", "items": {"type": "string"}}
},
"required": ["state"],
"additionalProperties": False,
},
},
"required": ["source", "detail-type", "detail"],
"additionalProperties": False,
}
def generer_regle(description):
response = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=4096,
messages=[{
"role": "user",
"content": f"Génère une règle AWS EventBridge pour : {description}",
}],
output_config={"format": {"type": "json_schema", "schema": SCHEMA_REGLE}},
)
return json.loads(next(b.text for b in response.content if b.type == "text"))
regle = generer_regle("détecter les arrêts d'instances EC2")
print(json.dumps(regle, indent=2))
Le résultat attendu ressemble à ceci :
{
"source": ["aws.ec2"],
"detail-type": ["EC2 Instance State-change Notification"],
"detail": {"state": ["stopped", "stopping"]}
}
Deux détails comptent. D’abord, la documentation recommande d’ajouter "additionalProperties": false à chaque objet du schéma : c’est ce qui interdit les champs inventés. Ensuite, la forme est garantie, pas le fond. Un objet parfaitement conforme peut contenir une valeur fausse ; vos contrôles métier restent nécessaires.
La variante confortable : messages.parse() et Pydantic
Écrire un schéma JSON à la main devient vite fastidieux. Le SDK Python accepte directement un modèle Pydantic : la méthode client.messages.parse() le convertit en schéma, envoie la requête, valide la réponse et vous rend un objet Python dans parsed_output.
from pydantic import BaseModel
class Ville(BaseModel):
nom: str
population: int
region: str
class ListeVilles(BaseModel):
villes: list[Ville]
response = client.messages.parse(
model="claude-sonnet-5-5",
max_tokens=4096,
messages=[{"role": "user",
"content": "Donne cinq villes françaises avec leur population et leur région."}],
output_format=ListeVilles,
)
for ville in response.parsed_output.villes:
print(ville.nom, ville.population, ville.region)
Cette approche a un avantage pédagogique autant que pratique : le schéma devient du code typé, relu et versionné comme le reste de votre application, au lieu d’un dictionnaire recopié de leçon en leçon.
Et pour les formats qui ne sont pas du JSON ?
Les sorties structurées produisent du JSON. Pour du code Python, du CSV ou du HTML, la méthode la plus robuste consiste à faire porter le contenu par un champ texte d’un schéma — par exemple {"code": "..."} — puis à l’extraire. Pour un usage moins critique, une consigne précise suffit souvent : demandez le contenu seul entre balises (<csv>…</csv>), puis récupérez ce qui se trouve entre les balises, éventuellement en plaçant la balise fermante dans stop_sequences pour éviter tout texte après.
Si vous croisez l’ancienne technique
C’est celle que montre encore la leçon « Structured data » du cours officiel, sur l’exemple même de la règle EventBridge. Vous la rencontrerez aussi dans des tutoriels et des projets plus anciens : ce motif : un dernier message assistant contenant ```json suivi d’une séquence d’arrêt ```. Il fonctionnait parce que le modèle se croyait déjà à l’intérieur d’un bloc de code. Sur les modèles actuels, il est refusé ; sur les modèles plus anciens qui l’acceptent encore, comme Claude Haiku 4.5, il ne garantissait de toute façon pas la validité du JSON. La migration consiste à remplacer le couple pré-remplissage plus séquence d’arrêt par un schéma dans output_config.format.
À vous de jouer
Votre schéma. Écrivez le schéma d’une fiche produit (nom, prix en nombre, catégorie parmi trois valeurs, liste de mots-clés) et générez trois fiches à partir de descriptions libres. Vérifiez que chaque objet a exactement les champs prévus.
Passer à Pydantic. Réécrivez le même schéma en modèle Pydantic et utilisez client.messages.parse() ; comparez la quantité de code et ce que vous récupérez dans parsed_output.
Sources officielles : Structured data (Claude Academy) · Structured outputs (documentation Claude :
output_config.format,additionalProperties,messages.parse)
Points clés à retenir
- Les sorties structurées (
output_config.format,type: "json_schema") remplacent l’ancien couple pré-remplissage plus séquence d’arrêt - Ajoutez
"additionalProperties": falseà chaque objet pour interdire les champs non prévus client.messages.parse()accepte un modèle Pydantic et renvoie un objet validé dansparsed_output- Le format est garanti, pas l’exactitude des valeurs : gardez vos contrôles métier