D’emblée : Structured Output n’est pas le prompt « renvoyez du JSON ». C’est l’API qui, à l’étape de décodage, bloque les tokens illégaux avec un JSON Schema, pour que la réponse finale puisse être parsée par un programme. GPT, Gemini et Claude en ont fait une fonctionnalité de premier plan non parce que l’expression fait bien sur une slide, mais parce que les agents, l’extraction et le remplissage de formulaires doivent brancher le modèle dans une pipeline. La prose échoue à JSON.parse. Elle échoue encore plus nettement au schema aval.
Cet article est daté du 8 septembre 2026. Les trois peuvent désormais contraindre le JSON final destiné à l’utilisateur ou au service suivant : OpenAI via response_format.json_schema (strict), Gemini via responseMimeType + responseJsonSchema, Claude via output_config.format en GA (l’ancien output_format beta fonctionne encore pendant la transition). Comment remplir les champs, et où les sous-ensembles divergent, nous l’avons déjà détaillé en août. Cet article répond à deux questions : ce que c’est, et pourquoi les trois ont dû le livrer. Pour le mode d’emploi, voir Du prompt au Structured Output. Pour OpenAI vs Gemini, voir la comparaison des API Structured Output.
Ce qu’est Structured Output
Structured Output signifie : vous fournissez un JSON Schema, et la réponse finale du modèle doit être un JSON qui y correspond. La garantie intervient pendant la génération de chaque token, pas après que le modèle « essaie de ressembler à du JSON ». Les noms divergent : OpenAI dit Structured Outputs, Google dit Structured Output, Anthropic écrit structured outputs / JSON outputs. Le s en trop est une affaire de marque. Le travail est le même.
Pensez compilateur et vérificateur de types. Un prompt est un commentaire — le modèle peut écouter. Un schema est le système de types — un nom de champ erroné, un required manquant, une chaîne là où un nombre est attendu ne sont tout simplement pas émis. Ce que votre programme reçoit est un objet, pas de la prose enveloppée dans une barrière ```json.
| Formulation | Ce que cela signifie vraiment | Lecture erronée courante |
|---|---|---|
| Structured Output | Décodage contraint de la réponse finale par rapport à un JSON Schema | Le modèle est devenu plus intelligent, ou « il sait écrire du JSON » |
| JSON Schema | Le contrat pour les champs, les types, required, les enums | Un prompt plus long |
| Décodage contraint | Les tokens illégaux sont filtrés à la génération | Un nettoyage regex après coup |
| strict / contrainte dure | L’API garantit la forme sur un sous-ensemble de schema plus strict | Les faits sont vrais et les nombres ne sont pas inventés |
Un schema lisible par les trois est en général plat : object à la racine, properties / required explicites, additionalProperties: false. Sous OpenAI strict, « optionnel » se traduit souvent par nullable plutôt que par une omission de required. Les sous-ensembles ne sont pas identiques ; prenez d’abord l’intersection.
{
"type": "object",
"additionalProperties": false,
"properties": {
"task": { "type": "string", "enum": ["extract", "classify", "summarize"] },
"ok": { "type": "boolean" },
"fields": {
"type": "object",
"additionalProperties": false,
"properties": {
"orderId": { "type": "string" },
"total": { "type": "number" },
"note": { "type": ["string", "null"] }
},
"required": ["orderId", "total", "note"]
}
},
"required": ["task", "ok", "fields"]
}
Ce n’est ni JSON Mode, ni Tool Calling
Trois noms se retrouvent aplatis en un seul. Ils ne sont pas la même couche :
| Capacité | Ce qu’elle garantit | Ce qu’elle ne garantit pas |
|---|---|---|
| Prompt : « renvoyez du JSON » | Une probabilité plus élevée | La syntaxe, les noms de champs, les listes required |
| JSON Mode | Le texte est du JSON parsable | La forme, les types, les enums |
| Structured Output | La réponse finale correspond au schema | Ni la vérité sémantique, ni qu’un outil a tourné |
| Tool Calling | Les arguments d’outil correspondent à un schema et le host les exécute | La forme de la réponse destinée à l’utilisateur |
JSON Mode ne garantit que des accolades appariées et un JSON.parse réussi. Le modèle peut encore inventer order_id alors que vous avez demandé orderId, ou émettre le montant en chaîne. En production, « ça parse » n’est pas « ça s’insère ».
Tool Calling / Function Calling contraint la main qui saisit un outil, pas la dernière phrase à l’utilisateur. Les consultations de stock, les écritures de fichiers, les tools/call MCP relèvent du schema d’outil. Extraire un e-mail, classer un ticket, émettre du JSON pour une API aval relèvent de Structured Output. Un agent complet active souvent les deux — les arguments côté tools, la réponse finale sur un schema de sortie. Pour le découpage en couches, voir Qu’est-ce que MCP et le flux de données JSON des agents.
Pourquoi les trois ont commencé à le prendre en charge
En 2023, on pouvait encore miser sur un prompt. En 2026, un agent embarque le modèle dans une boucle : la sortie atterrit dans une base, dans l’outil suivant, ou dans le modèle d’un autre fournisseur. Les trois laboratoires n’ont pas coordonné un cycle de communiqués. Ils ont heurté la même pression produit et le même contrat — JSON Schema.
- Le consommateur aval est un programme, pas un lecteur. Le chat peut être de la prose. Une pipeline a besoin d’objets. Une virgule manquante, un champ renommé, et la file de retries de la nuit déborde. Les fournisseurs préfèrent couper les chemins illégaux dans le décodeur plutôt que de voir chaque client écrire un réparateur.
- Les agents ont fait de la forme stable une exigence. Dans une boucle multi-étapes, le JSON du tour précédent est l’entrée de ce tour. Une dérive, et tout ce qui suit est faux. Tool Calling répond à « comment tendre la main ». Structured Output répond à « comment rendre la conclusion ». Les deux ont besoin d’un schema — voir si JSON Schema devient le contrat Agent.
- Les prompts ont prouvé qu’ils ne suffisaient pas. « JSON uniquement, pas de markdown » tient la route sur un banc de test, puis omet des champs, ajoute des barrières et paraphrase les enums dès que le contexte s’allonge, que les outils réinjectent, ou que les langues se mélangent. Le décodage contraint transforme « parfois » en un 400 d’API ou une erreur de schema retentable.
- JSON Schema était déjà le plus petit dénominateur commun. OpenAPI,
inputSchemaMCP, exports Pydantic / Zod — tout cela. Un IDL privé côté modèle forcerait le Host à traduire deux fois. Brancher la réponse finale sur le même schema, c’est ce qui rend les changements de fournisseur bon marché. - La course est devenue « cela peut-il partir en production », plus « sait-il discuter ». Dès qu’un fournisseur a livré une contrainte dure, les passerelles, les frameworks d’agents et les listes d’achat l’ont inscrit comme obligatoire. Les deux autres suivent, ou ils ne se branchent pas sur le même graphe. En septembre 2026, une API phare sans Structured Output se vend mal à quiconque insère des lignes.
C’est pourquoi les dates se serrent : OpenAI a passé Structured Outputs en GA en août 2024 ; Gemini a intégré MIME + schema dans la configuration de génération ; Claude était encore sur un en-tête beta fin 2025 et livre désormais output_config.format comme champ stable. Les noms n’ont jamais coincidé. La pression, si.
Comment GPT, Gemini et Claude l’activent
Alignez le concept. Ne collez pas les champs d’un fournisseur à l’autre. Le tableau est ce que vous pouvez mettre dans un document au 8 septembre 2026 — pas un tutoriel SDK complet.
| Fournisseur | Point d’entrée | Où accrocher le schema | Points de vigilance 2026 |
|---|---|---|---|
| OpenAI (GPT-5.5 et assimilés) | response_format sur Chat Completions ; text.format sur l’API Responses | type: json_schema + strict: true | Sous strict, chaque object attend additionalProperties: false et les propriétés sont en général toutes dans required ; l’optionnel devient nullable |
| Google (Gemini 3.7 Flash et assimilés) | MIME + schema sur la configuration de génération | responseMimeType: application/json + responseJsonSchema (le SDK dit souvent response_schema) | Pas d’interrupteur nommé strict ; l’ancien responseSchema utilisait les types OpenAPI en majuscules ; le canal plus récent utilise JSON Schema en minuscules |
| Anthropic (Claude 4.6 / 4.8 et assimilés) | output_config.format sur l’API Messages | type: json_schema + schema | GA — plus besoin de l’en-tête structured-outputs-2025-11-13 ; l’ancien output_format fonctionne encore pendant la transition. Le strict: true côté outil est du Tool Calling, pas la réponse finale |
Les enveloppes diffèrent. Le corps du schema devrait être le même fichier. Changer de modèle change l’enveloppe, pas orderId ni required. Un croquis Claude (champs de spec ; remplacez par votre schema métier) :
{
"model": "claude-sonnet-4-6",
"max_tokens": 1024,
"messages": [
{"role": "user", "content": "Extract orderId and total from the order text"}
],
"output_config": {
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"orderId": { "type": "string" },
"total": { "type": "number" }
},
"required": ["orderId", "total"]
}
}
}
}
OpenAI place le même schema dans response_format.json_schema et active strict. Gemini le place dans responseJsonSchema et déclare le type MIME JSON. Le face-à-face Python complet est toujours dans OpenAI vs Gemini. Les surfaces produit (ChatGPT / claude.ai / l’application web Gemini) n’exposent pas toujours la même contrainte dure. Rédigez le SLA par rapport à l’API que vous appelez réellement.
Ce que le décodage contraint bloque réellement
Sans Structured Output, le modèle échantillonne tout le vocabulaire et espère que le prompt le fera ressembler à du JSON. Avec Structured Output, le décodeur maintient un préfixe légal d’après le schema : le token suivant ne peut être que quelque chose encore valide — un ", orderId, true ou }. Les chemins illégaux voient leur probabilité mise à zéro.
Il bloque la forme : virgules finales, barrières markdown, champs required manquants, dérive de type, clés en trop lorsque additionalProperties est false. Il ne bloque pas l’invention : total est un number et le nombre peut être inventé ; une valeur enum légale peut quand même être la mauvaise. En production, on fait encore passer le même schema dans un validateur ; en cas d’échec, on retente, on dégrade, ou on passe à un humain. Le décodage contraint réduit les incidents de parse, pas les hallucinations.
Une fenêtre plus grande ne change rien à cela. 1M tokens n’élargissent que ce qui est visible ; ils ne contraignent pas la forme de la sortie. Si vous fourrez un dump, il vous faut encore un schema — voir les fenêtres de contexte 1M tokens.
Que faire maintenant
- Écrivez le schema avant de choisir un modèle. Les noms de champs, les listes required et les enums sont le contrat produit. GPT / Gemini / Claude sont des backends interchangeables. Gardez le contrat dans le dépôt, pas dans le prompt.
- Extraction, classification, remplissage de formulaires → Structured Output. Effets de bord → Tool Calling. Ne faites pas semblant que Structured Output a déjà appelé l’API de stock. La réutilisation inter-processus, c’est le moment d’ajouter MCP.
- Prenez l’intersection des schemas entre fournisseurs : objects plats,
additionalProperties: false,$refpeu profonds, pas deanyOfà la racine. OpenAI strict transforme « optionnel » en nullable. Ne maintenez pas trois tables de champs qui dérivent. - Le passage de l’API n’est pas le dernier contrôle. Enregistrez le schema et deux ou trois fixtures bonnes / mauvaises en JSON ; validez et Diff sur ce site. Rien n’est envoyé. C’est la deuxième barrière après le décodage contraint.
- Renvoyez les échecs sous forme structurée : si le parse ou le second validateur échoue, renvoyez un objet (quel champ, type attendu). Ne versez pas une stack brute dans le tour suivant.
FAQ
Structured Output, c’est seulement « faire renvoyer du JSON au modèle » ?
Non. Un prompt ou JSON Mode peut émettre du texte JSON. Structured Output filtre les tokens par rapport à un JSON Schema à l’étape de décodage. Les noms de champs, les types et les listes required sont imposés par l’API, pas par le bon vouloir du modèle.
Pourquoi GPT, Gemini et Claude l’ont-ils tous livré — un seul fournisseur ne suffisait-il pas ?
Les clients veulent un basculement multi-modèles et comparer les prix. Les passerelles et les frameworks d’agents câblent déjà « schema en entrée, JSON en sortie ». Un fournisseur sans contrainte dure ne se branche pas sur cette pipeline. La pression concurrentielle et le besoin d’ingénierie sont le même fait.
Claude a-t-il encore besoin d’un faux outil pour faire semblant d’avoir Structured Output ?
Pas comme chemin principal. En 2026, l’API Messages livre une sortie JSON Schema via output_config.format. Le strict au niveau outil ne couvre toujours que les arguments d’outil. L’ancien en-tête beta et output_format restent dans une fenêtre de transition ; le nouveau code doit utiliser output_config.
Si Structured Output est activé, dois-je encore valider ?
Oui. Il garantit la forme et les types, pas des valeurs vraies ni des règles métier. Relancez le même schema dans l’application ; en cas d’échec, retentez ou escaladez. Dans le navigateur, contrôlez d’abord les fixtures avec la boîte à outils JSON.
Comment choisir entre ceci, MCP et Tool Calling ?
Réponse finale pour un programme : Structured Output. Action externe : Tool Calling. Outils dans un autre processus, réutilisés entre Hosts : MCP. On peut empiler les trois. Ne laissez pas une couche se faire passer pour une autre.
Un même JSON Schema peut-il être envoyé tel quel aux trois ?
Le corps peut être partagé ; l’enveloppe de requête, non. Un object plat, sans propriétés supplémentaires, les optionnels en nullables, l’emporte le plus souvent. Le sous-ensemble strict d’OpenAI est le plus serré — passez-le d’abord, puis donnez le même fichier à Gemini / Claude, plutôt que trois schemas qui dérivent.
À retenir
Structured Output est la prise des API phares 2026 : la réponse finale est décodée par rapport à un JSON Schema, pour que les programmes cessent de parier sur les accolades d’un prompt. GPT, Gemini et Claude l’ont tous livré parce que les agents et l’extraction ont inscrit « forme stable » dans les tests d’acceptation, et que JSON Schema était le contrat que les trois parlaient déjà. Ce n’est pas JSON Mode. Cela ne remplace ni Tool Calling ni MCP.
Changez de modèle, ne changez que les champs d’enveloppe. Gardez les noms de champs et required dans le dépôt, et validez les échantillons en local contre le même schema avant de passer en production. Comment configurer chaque API, et comment cela se découpe de la couche outils, ce site l’a déjà couvert. Cet article ne fait que rendre le « quoi » et le « pourquoi » incontestables.