Structured outputs est une fonctionnalité des LLM APIs qui impose à la réponse d’un modèle de respecter un JSON Schema fourni. Grâce au décodage contraint, l’API compile votre schéma en une grammaire ou une machine à états qui limite la génération de tokens, évitant les erreurs de syntaxe et les champs manquants dans les API d’OpenAI, Anthropic et Google.
Que sont les Structured Outputs dans une LLM API ?
Dans une LLM API, structured outputs contraint les tokens générés par un modèle afin que la réponse finale corresponde à un JSON Schema fourni par le développeur. Anthropic et Google décrivent le mécanisme sous-jacent comme un décodage contraint : avant l’échantillonnage, l’API compile votre schéma en une grammaire ou une machine à états finis qui masque tout token suivant susceptible de violer la structure, les noms de clés ou les types de valeurs du schéma.
Sans structured outputs, demander dans un prompt à un modèle de langage de répondre en JSON donne des résultats irréguliers en production. La documentation d’Anthropic souligne quatre types d’échecs courants lorsque l’on se fie uniquement aux instructions du prompt : erreurs d’analyse dues à une syntaxe JSON invalide, champs obligatoires manquants, types de données incohérents et violations du schéma nécessitant une gestion des erreurs et de nouvelles tentatives. En pratique, voici des exemples génériques :
- Erreurs d’analyse dues à une syntaxe JSON invalide : des accolades non fermées, des virgules finales ou du texte Markdown autour des données peuvent par exemple perturber un analyseur JSON.
- Champs obligatoires manquants : un modèle peut par exemple omettre une clé attendue par le code applicatif en aval.
- Types de données incohérents : un champ numérique peut par exemple arriver sous forme de chaîne, ou une valeur unique remplacer un tableau.
- Violations du schéma nécessitant une gestion des erreurs et de nouvelles tentatives : des clés non demandées ou des valeurs hors limites imposent par exemple des boucles de nouvelle tentative et du code de validation défensif.
Le décodage contraint évite les instructions de formatage insistantes dans votre prompt. Pour aligner les types de l’application sur le schéma transmis à l’API, OpenAI et Google proposent des outils SDK natifs acceptant les classes Pydantic BaseModel en Python et les objets Zod en JavaScript ; le SDK Python d’Anthropic accepte quant à lui un modèle Pydantic via client.messages.parse() et analyse la réponse dans ce type.
En quoi Structured Outputs diffère-t-il de JSON mode et du JSON demandé uniquement par prompt ?
Structured outputs garantit le respect exact de votre JSON Schema, tandis que JSON mode et les instructions données uniquement par prompt ne peuvent imposer des noms de propriétés précis, des structures imbriquées ou des champs obligatoires.
JSON mode était l’étape intermédiaire avant les contraintes complètes de schéma. Chez OpenAI, activer JSON mode via { "type": "json_object" } garantit que le modèle produit du JSON syntaxiquement valide, à condition que la requête ne rencontre pas un cas limite, comme l’épuisement des tokens de sortie au milieu d’un objet. La documentation d’OpenAI précise toutefois des réserves : vous devez inclure une instruction de sortie JSON quelque part dans le contexte de la conversation, faute de quoi l’API renvoie une erreur si le mot JSON est absent ; le modèle peut sinon générer un flux interminable d’espaces jusqu’à la limite de tokens.
OpenAI présente structured outputs comme l’évolution de JSON mode et recommande de l’utiliser chaque fois qu’il est pris en charge, en réservant JSON mode aux anciens modèles comme gpt-4-turbo et ses prédécesseurs.
| Fonction | JSON par prompt seul | JSON mode | Structured Outputs |
|---|---|---|---|
| Syntaxe JSON valide garantie | Non | Oui, sauf troncature | Oui, sauf refus ou troncature |
| Impose le schéma et les types exacts | Non | Non | Oui |
| Nécessite une instruction JSON dans le prompt | Oui | Oui, exigée par OpenAI | Non |
| Élimine les nouvelles tentatives de formatage | Non | Partiellement | Oui, pour la structure du schéma |
| Analyse native Pydantic et Zod | Manuelle | Manuelle | Prise en charge par les SDK des fournisseurs |
Structured Outputs et Function Calling : quand utiliser chacun ?
Structured outputs formate la réponse finale du modèle à votre application ou à l’utilisateur final, tandis que function calling relie le modèle à des outils, API et sources de données externes pendant l’exécution.
Les développeurs confondent souvent ces deux fonctions, car elles reposent toutes deux sur des définitions JSON Schema. OpenAI et Google établissent la même distinction architecturale :
- Utilisez structured outputs lorsque le message final de l’assistant doit être correctement formaté pour votre interface, votre base de données ou votre pipeline en aval, par exemple pour l’extraction de données ou la classification structurée.
- Utilisez function calling (tool use) lorsque le modèle doit demander une action, consulter des données en temps réel ou appeler une routine backend avant de pouvoir répondre. Pour approfondir la place des définitions d’outils dans les protocoles modernes, consultez notre guide sur tool calling et MCP.
OpenAI propose des schémas stricts sous deux formes distinctes : function calling avec des schémas stricts pour connecter le modèle aux outils ou aux données, et un format de réponse json_schema pour structurer la réponse à l’utilisateur. Anthropic sépare ses deux fonctionnalités entre output_config.format pour la réponse finale de Claude et strict: true sur chaque outil pour garantir la validité des noms d’outils et des arguments d’entrée ; il prend explicitement en charge leur utilisation conjointe dans une seule requête. Cette combinaison est particulièrement pratique dans les flux de travail d’agents IA, où les appels d’outils intermédiaires et le résumé final doivent respecter des contrats stricts.
Comment OpenAI, Anthropic et Google implémentent Structured Outputs
En novembre 2026, OpenAI, Anthropic et Google implémentent chacun structured outputs par compilation de schéma, mais leurs paramètres de requête, mots-clés JSON Schema pris en charge et limites de complexité diffèrent.
| Fournisseur | Activation | Outils SDK pour les schémas | Principales règles de schéma | Principales limites |
|---|---|---|---|---|
| OpenAI | Responses API text.format ou Chat Completions response_format avec type: "json_schema" et strict: true |
Pydantic BaseModel (Python), Zod (JS) |
La racine doit être un objet, pas anyOf ; tous les champs dans required ; additionalProperties: false obligatoire ; clés émises dans l’ordre du schéma |
Jusqu’à 5 000 propriétés, 10 niveaux d’imbrication, 120 000 caractères pour les noms/enums, 1 000 valeurs enum |
| Anthropic Claude | output_config.format avec type: "json_schema", plus strict: true sur les outils |
client.messages.parse() avec Pydantic (Python) |
Prend en charge $ref/$defs, anyOf et allOf (avec limites) ; additionalProperties: false obligatoire ; aucune borne numérique ou de longueur de chaîne |
Max. 20 outils stricts, 24 paramètres facultatifs, 16 paramètres union, délai de compilation de 180s ; cache de grammaire de 24 heures |
| Google Gemini API | Configuration de réponse avec type texte, mime_type: "application/json" et schéma |
Pydantic (Python), Zod (JS) | Prend en charge minimum/maximum, minItems/maxItems, prefixItems ; supprime silencieusement les bornes non prises en charge |
Les schémas volumineux ou très imbriqués échouent avec 400 INVALID_ARGUMENT |
OpenAI
OpenAI prend en charge structured outputs à partir de GPT-4o et recommande gpt-6-astra pour les nouveaux projets. Appeler l’API avec strict: true et un mot-clé non pris en charge comme allOf, not, if/then/else, dependentRequired ou dependentSchemas renvoie une erreur au lieu d’échouer silencieusement. OpenAI prend en charge les formats de chaîne date-time, time, date, duration, email, hostname, ipv4, ipv6 et uuid, ainsi que les bornes numériques (minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf) et de tableaux (minItems, maxItems).
Anthropic Claude
Anthropic prend en charge structured outputs pour tous les modèles de la Messages API, mais pas dans Managed Agents. Lorsque vous utilisez client.messages.parse() dans le SDK Python, les contraintes non prises en charge comme minimum, maximum, minLength et maxLength sont automatiquement déplacées dans les descriptions des champs afin que Claude en comprenne l’intention, et le SDK valide localement les données renvoyées par rapport à votre modèle Pydantic d’origine.
Claude met les grammaires compilées en cache pendant 24 heures après leur dernière utilisation ; modifier la structure du schéma ou l’ensemble d’outils invalide ce cache, contrairement à la modification des noms ou descriptions de champs. Claude reçoit aussi un prompt système automatique expliquant le format JSON : le nombre de tokens d’entrée augmente donc légèrement, et modifier output_config.format invalide le cache de prompt de la conversation. Les propriétés obligatoires sont émises en premier, puis les facultatives. Structured outputs fonctionne avec le streaming, le comptage de tokens et Batch processing (avec la remise de 50 % d’Anthropic). Cependant, associer des sorties JSON à Citations renvoie une erreur 400, et structured outputs est incompatible avec le préremplissage des messages.
Google Gemini API
Google met en avant l’extraction de données, la classification structurée et les flux de travail agentiques comme principaux cas d’usage de structured outputs dans Gemini. Contrairement à OpenAI et Anthropic, Gemini supprime et ignore silencieusement plusieurs mots-clés sans signaler d’erreur, notamment minLength, maxLength, minProperties, maxProperties, uniqueItems, contains, minContains et maxContains. Vous devriez toujours exécuter Pydantic model_validate_json() ou Zod .parse() sur les réponses de Gemini pour appliquer ces contraintes dans le code de l’application. Si Gemini renvoie 400 INVALID_ARGUMENT pour un schéma trop complexe, Google conseille d’aplatir les imbrications, de réduire les champs facultatifs ou les enums, de raccourcir les noms de propriétés et de déplacer les règles non structurelles dans les descriptions de champs.
Comment concevoir un JSON Schema fiable pour les LLM
Un JSON Schema fiable pour structured outputs des LLM reste plat, marque les champs comme obligatoires et utilise des types acceptant null au lieu de clés facultatives. Concevoir des schémas selon des règles communes aux fournisseurs aide à éviter les erreurs de compilation et les rejets inattendus à l’exécution.
Utilisez cette liste avant de déployer un schéma pour OpenAI, Claude ou Gemini :
- Limitez l’imbrication : aplatissez les objets très imbriqués lorsque possible pour rester bien en dessous du plafond de 10 niveaux d’OpenAI et éviter les rejets de compilation de Gemini ou Claude.
- Rendez chaque champ obligatoire : inscrivez chaque clé d’objet dans
required, car OpenAI applique strictement cette règle et Claude limite le total des paramètres facultatifs par requête à 24. - Utilisez des unions acceptant null pour les données manquantes : représentez les valeurs facultatives avec
"type": ["string", "null"]au lieu d’omettre des clés derequired. - Verrouillez les objets : définissez
"additionalProperties": falsesur chaque définition d’objet, comme l’exigent OpenAI et Anthropic. - Limitez les choix fixes avec des enums : remplacez les catégories de chaînes libres par des tableaux
enumexplicites lorsque seul un ensemble connu de libellés est valide. - Rédigez des descriptions claires : placez les règles métier et les contraintes ignorées, comme les longueurs de caractères souhaitées ou les instructions de repli, dans la
descriptionde chaque propriété.
Voici un exemple de schéma pour classer un ticket d’assistance client. Il respecte les règles communes ci-dessus : une racine objet, tous les champs obligatoires, un champ acceptant null pour les métadonnées facultatives, additionalProperties: false et un enum pour l’acheminement.
{
"type": "object",
"additionalProperties": false,
"required": ["category", "urgency", "summary", "order_id"],
"properties": {
"category": {
"type": "string",
"enum": ["billing", "bug_report", "account_access", "other"],
"description": "Primary topic of the support message."
},
"urgency": {
"type": "string",
"enum": ["low", "normal", "high"],
"description": "Escalation priority based on user impact."
},
"summary": {
"type": "string",
"description": "One-sentence summary of the issue in 25 words or fewer."
},
"order_id": {
"type": ["string", "null"],
"description": "Order identifier if present in the message, otherwise null."
}
}
}
Quels problèmes peuvent encore survenir avec Structured Outputs ?
Structured outputs garantit une syntaxe valide selon votre schéma, mais les applications en production rencontrent encore des refus, des troncatures de tokens, des valeurs hallucinées, des variations de casse des enums, une latence à la première requête et des entrées utilisateur non fiables. Considérer la conformité au schéma comme une vérification syntaxique plutôt que comme une garantie de vérité ou de sécurité évite des erreurs silencieuses en production.
Refus de sécurité et troncature à la limite de tokens
Les modèles peuvent toujours refuser des requêtes utilisateur dangereuses ou interrompre la génération à la limite de tokens de sortie. Chez OpenAI, un refus de sécurité remplit un champ distinct refusal qui ne respecte pas votre JSON Schema. Chez Anthropic Claude, un refus renvoie HTTP 200 avec stop_reason défini sur "refusal" (et reste facturé) et supplante votre schéma ; de même, atteindre la limite de sortie renvoie stop_reason "max_tokens" avec du JSON incomplet. Vérifiez toujours les indicateurs de refus et les raisons d’arrêt avant d’appeler JSON.parse() ou un validateur.
Valeurs conformes au schéma mais factuellement erronées
Le décodage contraint oblige le modèle à remplir votre schéma même lorsque le texte source ne contient pas de réponse ou contredit les hypothèses du schéma. Une réponse peut réussir toutes les vérifications de type et d’enum tout en contenant des dates inventées, de mauvaises catégories ou des suppositions plausibles. OpenAI conseille d’indiquer au modèle dans le prompt quoi renvoyer lorsque l’entrée est incompatible avec le schéma, par exemple null ou des champs vides ; Google invite les développeurs à valider les valeurs dans le code selon les règles métier. Pour comprendre pourquoi des réponses assurées peuvent rester erronées, consultez notre guide sur les taux d’hallucination de l’IA.
Casse des enums chez Claude et latence de compilation
Deux particularités opérationnelles prennent les équipes au dépourvu lors des déploiements :
- Casse des enums chez Claude : Anthropic précise que la casse des enums n’est pas garantie pendant le décodage contraint ; comparez donc les chaînes enum renvoyées sans tenir compte de la casse dans votre logique applicative.
- Délai de compilation à la première requête : Claude ajoute de la latence lors de la première compilation d’un nouveau schéma en grammaire avant sa mise en cache pendant 24 heures ; OpenAI signale un délai similaire de traitement du schéma à la première requête pour les modèles affinés.
Prompt Injection dans les valeurs de champs
Contraindre la structure de sortie ne neutralise pas les instructions malveillantes cachées dans un texte non fiable qui est résumé ou extrait dans un champ de chaîne JSON. Un modèle peut renvoyer consciencieusement du JSON valide dont le champ summary ou notes contient des instructions injectées ou du contenu trompeur destiné aux outils en aval ou aux réviseurs humains. Traitez chaque valeur de champ analysée comme une entrée non fiable et consultez notre introduction sur la Prompt Injection avant de transmettre des champs extraits à des actions automatisées.
Questions fréquentes
Structured outputs ralentit-il les réponses des LLM ?
Structured outputs peut ajouter de la latence à la première requête avec un nouveau schéma, tandis que les requêtes ultérieures mises en cache s’exécutent sans coût de compilation. Anthropic conserve les grammaires compilées de Claude pendant 24 heures après leur dernière utilisation, sauf si vous modifiez la structure du schéma ou les définitions d’outils. OpenAI ne signale une latence supplémentaire de traitement du schéma à la première requête que pour les modèles affinés.
Un LLM peut-il encore halluciner avec structured outputs ?
Oui, un LLM peut encore halluciner des valeurs tout en renvoyant du JSON conforme au schéma à 100 %. Le décodage contraint limite la syntaxe des tokens et les types de champs, pas l’exactitude factuelle. Si l’entrée manque d’informations obligatoires, le modèle peut inventer des valeurs pour satisfaire les clés requises, sauf si vous autorisez des champs acceptant null et lui indiquez quand renvoyer null.
Faut-il utiliser Pydantic ou Zod avec les API structured output ?
Les outils SDK natifs de schéma aident à aligner les types de l’application et les schémas API. OpenAI et Google prennent en charge Pydantic en Python et Zod en JavaScript, tandis que le SDK Python d’Anthropic prend en charge Pydantic via client.messages.parse(). Ces outils convertissent vos modèles en JSON Schema, analysent les réponses en objets typés et valident des contraintes comme les longueurs de chaînes que Gemini supprime ou qu’Anthropic déplace dans les descriptions de champs.
Que se passe-t-il si un modèle refuse une requête avec structured outputs activé ?
Lorsqu’un modèle refuse une requête pour des raisons de sécurité, le refus supplante votre JSON Schema. OpenAI place l’explication dans un champ refusal dédié au lieu de suivre le schéma, tandis qu’Anthropic renvoie HTTP 200 avec stop_reason défini sur "refusal". Votre application doit examiner ces champs avant de tenter d’analyser le JSON.
Pourquoi Claude ou Gemini rejette-t-il mon JSON Schema avec une erreur 400 ?
Claude et Gemini rejettent avec une erreur 400 les schémas qui dépassent leurs limites internes de complexité de grammaire ou de machine à états. Claude renvoie aussi une erreur 400 si vous incluez des fonctionnalités de schéma non prises en charge, comme les schémas récursifs ou les bornes numériques, ou si vous associez les sorties JSON à Citations. Aplatir les objets imbriqués, raccourcir les noms et réduire les paramètres facultatifs ou union résout généralement les rejets de compilation.



