Guide
Schéma JSON d'extraction : bien décrire les champs
Types, dates, montants, valeurs absentes, listes de lignes, descriptions : écrire le schéma JSON qui guide l'extraction d'un document par une IA.
Mis à jour le
Le schéma JSON est le contrat entre votre code et l'IA qui lit le document : il dit quels champs sortir, de quel type, et quoi faire quand une information manque. Un bon schéma d'extraction suit cinq règles : un champ par information, des types et formats précis, une valeur null prévue pour l'absent, des listes pour les lignes répétées, et une description en français clair pour chaque champ. Les paramètres d'API qui imposent ce schéma (Claude, Gemini, Mistral) sont expliqués sur Cercle IA Tech · API ; cette page traite de ce qu'on met dedans.
Règle 1 : un champ, une information
Évitez un champ fournisseur qui contiendrait « SARL Dupont, 12 rue…, SIRET… ». Séparez fournisseur_nom, fournisseur_adresse, fournisseur_siren. Chaque champ se mesure ensuite seul, ce qui rend la mesure de précision possible : on sait que le nom est juste à tant de pour cent et l'adresse à tant.
Règle 2 : des types et des formats précis
Les sorties structurées de Claude acceptent les types de base (objet, tableau, chaîne, entier, nombre, booléen, null), les énumérations, et des formats de chaîne dont date, date-time et email. Elles acceptent aussi des motifs (expressions régulières) simples. Servez-vous-en :
- Dates :
"format": "date"impose la forme AAAA-MM-JJ, quel que soit l'affichage du document (« 15 nov. 2026 », « 15/11/26 »). - Énumérations :
"enum": ["facture", "avoir"]plutôt qu'une chaîne libre. - Identifiants : un motif comme
^[0-9]{9}$pour un numéro SIREN.
Attention à ce qui n'est pas pris en charge, d'après la documentation d'Anthropic : bornes numériques (minimum, maximum, multipleOf), longueurs de chaîne (minLength, maxLength), schémas récursifs. Un schéma qui les utilise renvoie une erreur 400. Ces contrôles se font dans votre code.
Règle 3 : prévoir l'absent
C'est la règle la plus souvent oubliée. Si date_echeance est obligatoire et de type date, et que la facture n'en porte pas, le modèle doit quand même produire une date : il en invente une. Déclarez le champ obligatoire mais nullable, et dites dans sa description « null si la facture n'indique pas d'échéance ».
Microsoft fait la même distinction côté modèles spécialisés : un champ vide peut avoir un score de confiance élevé, qui signifie que le modèle est sûr qu'il n'y a pas de valeur.
Règle 4 : des listes pour les lignes
Les lignes d'une facture ou d'un bon de commande sont un tableau d'objets, chacun avec ses propres champs. Ne laissez jamais un objet ouvert sans propriétés : la documentation d'Anthropic prévient qu'un champ de type dict en Python est envoyé comme un objet aux propriétés vides, et que le modèle ne peut alors renvoyer que {}.
Règle 5 : décrire chaque champ
La documentation de Mistral sur les annotations le dit clairement : les descriptions des champs servent d'instructions pendant l'extraction. C'est là que vous mettez vos règles métier : « montant toutes taxes comprises, en euros, point décimal », « numéro tel qu'imprimé, sans espaces ».
Exemple : une facture
En Python, le SDK d'Anthropic accepte un modèle Pydantic (une bibliothèque de description de données) dans client.messages.parse(), le transforme en schéma, valide la réponse et la renvoie dans parsed_output :
from datetime import date
from typing import Literal
from pydantic import BaseModel, Field
class Ligne(BaseModel):
designation: str
quantite: float | None
prix_unitaire_ht: str | None = Field(description="Tel qu'imprimé, point décimal")
montant_ht: str | None
class Facture(BaseModel):
type_document: Literal["facture", "avoir"]
numero: str
date_emission: date
date_echeance: date | None = Field(description="null si absente")
fournisseur_nom: str
fournisseur_siren: str | None
total_ht: str | None
total_tva: str | None
total_ttc: str
lignes: list[Ligne]
reponse = client.messages.parse(
model="claude-opus-5-5",
max_tokens=4096,
messages=[{"role": "user", "content": [bloc_pdf, {"type": "text", "text": "Extrais cette facture."}]}],
output_format=Facture,
)
facture = reponse.parsed_output
Les montants sont ici des chaînes recopiées telles quelles : vous les convertissez ensuite en décimal dans votre code, ce qui évite toute approximation et permet de comparer exactement avec le document.
Après le schéma : les contrôles
Un JSON conforme n'est pas un JSON juste. Ajoutez, dans votre code :
- la validation du JSON reçu avec le même schéma ;
- les contrôles arithmétiques : somme des lignes, HT + TVA = TTC ;
- les contrôles métier : date d'échéance après la date d'émission, fournisseur connu de votre fichier.
Une facture qui échoue à un contrôle part en relecture : voir seuil de confiance et validation humaine.
Questions fréquentes
Faut-il rendre tous les champs obligatoires ?
Oui dans la structure, mais avec la possibilité de valoir null. Un champ obligatoire sans valeur « absent » pousse le modèle à inventer une valeur quand le document n'en contient pas.
Peut-on imposer un montant positif dans le schéma ?
Pas avec les sorties structurées de Claude : minimum, maximum et multipleOf ne sont pas pris en charge et renvoient une erreur 400. Faites ce contrôle dans votre code, après l'extraction.
Sources
Pages consultées pour écrire cet article :