Articles précédents de cette série abordéspourquoi les agents ont besoin de JSON(Tool Calling au flux de données MCP),pourquoi JSON Schema⟧ est devenu une infrastructure(Schéma, Appel de fonction et évolution MCP), etConfiguration Structured Output spécifique à Gemini(Guide Gémeaux API).
Cet article fait un zoom arrière :quel que soit le modèle API que vous utilisez, comment passer de « veuillez répondre en JSON » à « la sortie doit correspondre à ce schéma JSON »? Les fournisseurs ont convergé vers cela en 2024-2026 sous des noms tels que Structured Outputs⟧ / JSON Schema⟧ mode — même idée, noms de champs légèrement différents, sous-ensembles de schéma et limites avec Tool Calling.
Quatre niveaux, chacun plus « strict » que le précédent
Les équipes utilisent généralement quatre approches pour obtenir JSON à partir d'un modèle — la fiabilité diffère d'un ordre de grandeur :
| Niveau | Approche | Ce que vous contrôlez | Échec typique |
|---|---|---|---|
| L0 | Invite uniquement : « sortie JSON » | Contrainte douce | ```json fences, prose, single quotes, trailing commas |
| L1 | Exemples d'invite + quelques exemples JSON | Façonner par l'exemple, pas de règle stricte | Dérive des noms de champs, champs manquants, types mixtes |
| L2 | JSON Mode⟧ (response_format: json_object, etc.) | La sortie doit être valide JSON | Parses, but price may be a string |
| L3 | Sortie structurée+ JSON Schéma⟧ | Champs, types, énumération, obligatoires | Hallucination sémantique, troncature, mots-clés ignorés |
For production extraction, classification, or form filling, aim for L3. L0–L1 suit exploration; L2 when shape varies and you only need JSON.parse. L3 is the contract programs can consume directly.
Ce que JSON Schema⟧ contrôle — et ce qu'il ne contrôle pas
JSON Schéma⟧décrit la structure du document : champs, types, clés requises, énumérations, plages, forme des éléments du tableau. Le fournisseur Structured Outputs⟧ compile ce schéma dans la génération – et ne se contente pas de le coller dans l'invite.
Schema can enforce: syntax shape (object / array / string / integer), required, enum, minimum / maximum, additionalProperties: false, nested objects and arrays.
Schema cannot enforce business correctness. Example: “total_cents must equal sum of line items” — assert that in code after Schema validation. Schema also does not fact-check: a well-typed fabricated invoice number is still hallucination.
Tool inputSchema uses the same language; Structured Output constrains the final reply, Tool Calling constrains tool arguments. See guide de flux de données.
Décodage contraint : pourquoi Schema bat Prompt
Les invites ne font qu’augmenter les chances de conformité. Structure structurée utilisedécodage contraint: à chaque jeton, le décodeur supprime les jetons qui briseraient la syntaxe JSON ou violeraient le schéma.
Vous obtenez généralement un JSON analysable et de forme correcte sans clôtures de démarques supprimant les regex. Les implémentations diffèrent (FSM, grammaire, masques logit), mais le contrat développeur est le même :transmettre le schéma à l'API, pas seulement à l'invite.
Garanties de décodage contraintstructure, passémantique. Revalidez toujours avec le même schéma et ajoutez des règles métier en production.
Comparaison OpenAI, Gemini, Anthropic
Même concept, noms de champs différents. Exemple : extraire un objet de facture.
| Fournisseur | Mode JSON | Sortie structurée / Schéma | Remarques |
|---|---|---|---|
| OpenAI | response_format: { type: "json_object" } | response_format: { type: "json_schema", json_schema: { name, schema, strict: true } } | strict: true rejects undeclared fields; works with Pydantic model_json_schema() |
| Google Gémeaux | responseMimeType: "application/json" | Above + responseJsonSchema or SDK response_schema | VoirGuide Gémeaux |
| Anthropique | Invite + analyse | output_format (Claude structured output) or schema in Messages API | Les champs évoluent avec le SDK ; garder le schéma plat |
When migrating vendors, keep the Schema itself standard JSON Schema⟧ (type, properties, required, enum); SDKs only wrap the request. Do not mix OpenAPI 3.0 uppercase types (OBJECT) with JSON Schema⟧ lowercase (object).
Écrire un bon schéma : de Pydantic à la production
Recommended flow: define types in Pydantic / Zod → export JSON Schema⟧ → tune → send to API. Put semantics in description — it enters model context and disambiguates “qty = pieces vs boxes”; type: integer alone cannot.
from pydantic import BaseModel, Field
class LineItem(BaseModel):
name: str = Field(description="Product name")
qty: int = Field(description="Quantity, positive integer", ge=1)
unit_price_cents: int = Field(description="Unit price in cents", ge=0)
class Invoice(BaseModel):
vendor: str
currency: str = Field(description="ISO 4217, e.g. CNY")
items: list[LineItem]
total_cents: int
schema = Invoice.model_json_schema()
# In production add additionalProperties: false
Règles pratiques :
- Prefer object root over root-level array;
{ "items": [...] }is more stable on some APIs. - Start with type / properties / required / enum, then add
additionalProperties, min/max; do not dump full Draft 2020-12 — some keywords are ignored. - Gardez la nidification peu profonde; les références circulaires sont rejetées – aplatissez le schéma.
- Schéma divisé vs invite: Schéma = forme ; Invite = sémantique (« extraire la facture du texte ci-dessous… »).
Exemple OpenAI Structured Outputs⟧
Chat Completions supports json_schema response format since 2024. With strict: true, output should only contain Schema fields:
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class Invoice(BaseModel):
vendor: str
total_cents: int
response = client.chat.completions.create(
model="gpt-4o-2024-08-06",
messages=[
{"role": "user", "content": "Extract invoice: Acme sold 2 keyboards for 398 CNY."}
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "invoice",
"strict": True,
"schema": Invoice.model_json_schema(),
},
},
)
data = response.choices[0].message.content # JSON string
import json
invoice = json.loads(data)
Gemini uses response_mime_type + response_json_schema — see the Gemini article. For Anthropic, check current SDK structured output docs — same idea, official field names.
Pipeline de production : générer → analyser → valider → réessayer
La Structured Output n'est pas « un seul appel API et c'est fait ». Corrigez ces quatre étapes :
- Generate: call model with Schema; log prompt, Schema version, raw
content. - Parse:
JSON.parse(or SDKparsed); on failure, retry whole response — no half-parse. - Schema validate: run same JSON Schema⟧ via AJV /
jsonschema/ Pydantic; retry or degrade on failure. - Validation commerciale: assertions personnalisées (totaux, clés étrangères) ; humain ou moteur de règles en cas de panne.
En cours de développement, stockez le schéma plus 2 à 3 échantillons positifs/négatifs dans le dépôt ; utilisez JSON Toolbox⟧ localement pour la structure et Diff — même état d'esprit que les tests de contrat REST, le consommateur est le LLM.
Pièges courants : demander « expliquez alors JSON » alors que le JSON Mode⟧ est activé ; troncature (augmenter le nombre maximum de jetons ou diviser les tâches) ; Clés API dans les démos frontend ; La version du schéma dérive de l'invite.
En quoi diffère-t-il de Tool Calling
| Sortie structurée | Appel d'outil / MCP | |
|---|---|---|
| Contraintes | Réponse finale JSON à l'utilisateur | Tool argument JSON (inputSchema) |
| Effets secondaires | Aucun – données uniquement | Host / MCP Server s'exécute |
| Utilisation typique | Extraire, classer, remplir des formulaires, transfert d'agent | Inventaire, fichiers, API externes |
| En cas d'échec | Réessayez ou humain | Erreur dans le message de l'outil → demander à nouveau au modèle |
Une boucle d’agent complète ressemble souvent à :Structured Output extrait l'intention → Tool Calling agit → Structured Output ou résume en prose pour l'utilisateur. N'utilisez pas Structured Output pour prétendre que « le paiement API a été appelé » – le modèle ne l'a pas appelé.
FAQ
« Veuillez afficher JSON » dans l'invite est-il suffisant ?
Non. Les invites ne font qu'augmenter les chances de conformité : les clôtures de démarque, les virgules de fin et la dérive de champ se produisent toujours. En production, activez au moins le JSON Mode⟧ ; idéalement, passez JSON Schema⟧ via le canal API Structured Output afin que le décodage exclue les jetons illégaux.
Quelle est la différence entre le JSON Mode⟧ et la Structured Output ?
Le JSON Mode⟧ garantit uniquement un texte JSON valide, pas les noms de champs, les types ou les clés requises. Structured Output ajoute JSON Schema⟧ et filtre les jetons pendant la génération — la forme se stabilise afin que vous puissiez stocker ou passer directement au saut suivant.
Les champs de configuration OpenAI, Gemini et Anthropic sont-ils identiques ?
Même concept, noms différents. OpenAI : response_format avec json_schema et strict ; Gemini : responseMimeType + responseJsonSchema ; Anthropic : output_format ou sortie structurée dans les outils. Conserver la norme de schéma ; Les SDK encapsulent les requêtes.
La Structured Output peut-elle remplacer Tool Calling ?
Non. Structured Output contraint la réponse finale JSON ; Tool Calling contraint l'argument de l'outil JSON et nécessite que l'hôte exécute les outils. Utilisez le premier pour extraire/classer/remplir ; ce dernier pour l'inventaire, les fichiers, MCP. Les chaînes d’agents complètes utilisent souvent les deux.
Dois-je quand même valider la sortie du modèle ?
Oui. Le décodage contraint réduit les erreurs de syntaxe et la dérive de type, mais pas l'exactitude sémantique (types valides, valeurs fabriquées). Réexécutez le même JSON Schema⟧ en production ; réessayez, dégradez ou révisez en cas d'échec.
Comment puis-je valider le schéma et les exemples de sortie localement ?
Enregistrez le JSON Schema⟧ et quelques exemples de sortie de modèle sous forme de fichiers JSON ; utilisez JSON Toolbox⟧ dans le navigateur pour les vérifications de syntaxe et de structure — rien n'est téléchargé.
Résumé
Pour obtenir JSON qui correspond au JSON Schema⟧ de l'IA, l'ordre compte :définissez d'abord le schéma, activez le JSON Mode⟧ / Structured Output, puis écrivez l'invite. Invite = sémantique ; Schéma = forme ; Pydantic / Zod sont des fronts conviviaux pour les auteurs ; Les APIdes fournisseurs exposent les canaux de schéma.
Exécutez une vraie facture ou prenez en charge la transcription de bout en bout : Schéma → Appel API → Collez la sortie dans un validateur. Lorsqu'il correspond, câblez la base de données ou l'agent suivant. Les arguments de l'outil passent toujours par Tool Calling / MCP — ne fusionnent pas en une seule API.