Aller au contenu
2.13Intermédiaire7 min

Structured output des LLM avec JSON Schema : des réponses fiables

Sebastian KarallMis à jour le 28 octobre 2026
Définition

Les sorties structurées avec JSON Schema sont une technique qui oblige un LLM à produire sa réponse exactement selon un schéma JSON prédéfini. Au lieu de texte libre, le modèle renvoie un objet lisible par machine et validable. Les pipelines d'agents deviennent ainsi fiables, car les étapes suivantes du programme peuvent s'appuyer sur une structure de données garantie.

L’essentiel

  • Les sorties structurées imposent un schéma JSON fixe et remplacent le parsing de texte libre, source d'erreurs, par une structure de données garantie et validable.
  • Il existe trois niveaux de garantie : prompt seul (aucune garantie), mode JSON (JSON valide, mais pas ton schéma) et constrained decoding ou Structured Outputs (schéma strictement imposé).
  • Le constrained decoding garantit la syntaxe et la conformité au schéma, mais pas l'exactitude du contenu. Une validation métier et une stratégie de relance restent obligatoires.
  • Chez Anthropic Claude, les Structured Outputs imposent le schéma, soit sous forme de JSON Output (output_config.format), soit via Strict Tool Use (strict: true). Chez OpenAI, cela passe par les Structured Outputs en mode strict. Le tool use classique sans strict ne garantit pas le schéma.
  • Pour les agents multi-étapes, c'est essentiel : chaque étape peu fiable se multiplie sur toute la chaîne et fait chuter le taux de réussite de bout en bout.
  • La validation avec Pydantic ou Zod, combinée à un nombre limité de relances avec retour d'erreur, est le standard pratique pour des pipelines robustes.

Les sorties structurées avec JSON Schema sont une technique qui oblige un LLM à produire sa réponse exactement selon un schéma JSON prédéfini. Au lieu de texte libre, le modèle renvoie un objet lisible par machine et validable. Les pipelines d'agents deviennent ainsi fiables, car les étapes suivantes du programme peuvent s'appuyer sur une structure de données garantie au lieu de parser un texte libre source d'erreurs.

  • Quoi ? Le modèle renvoie du JSON selon un schéma fixe, pas du texte libre. Champs, types et valeurs autorisées sont définis.
  • Pourquoi ? Les programmes peuvent traiter le résultat directement, sans logique fragile à base de regex ou de chaînes de caractères. C'est la base d'agents fiables.
  • Comment ? Via les fonctions des fournisseurs, comme les Structured Outputs d'OpenAI et d'Anthropic, ou via le constrained decoding pour les modèles open-weight, complétés par une validation et des relances.

Pourquoi le parsing de texte libre échoue dans les pipelines d'agents

Par défaut, un modèle de langage produit du texte pour des lecteurs humains. C'est idéal pour un chatbot, mais problématique pour un pipeline automatisé. Dès qu'un programme doit extraire une valeur de la réponse, par exemple une catégorie, une date, un montant ou une liste, commence le travail fragile du parsing. Le modèle écrit tantôt "Die Kategorie ist Rechnung.", tantôt "Kategorie: Rechnung", tantôt il ajoute une explication devant. Chacune de ces variantes casse une logique d'extraction naïve.

Dans les agents multi-étapes, le problème s'aggrave fortement, car le manque de fiabilité se multiplie tout au long de la chaîne. Un exemple chiffré : si chaque étape a un taux de réussite de parsing de 95 %, le taux de réussite de bout en bout d'une chaîne de dix étapes tombe à 0,95 puissance 10, soit environ 60 %. Si les sorties structurées portent chaque étape à 99,5 %, la même chaîne atteint environ 95 %. De cet effet multiplicateur découle la thèse centrale de cet article : les sorties structurées ne sont pas une fonction de confort, mais la condition pour que les pipelines d'agents soient tout simplement prêts pour la production.

Les trois niveaux de garantie en bref

Toutes les méthodes qui promettent du JSON n'offrent pas la même garantie. Il faut distinguer trois niveaux, et la différence détermine la fiabilité.

Prompt seul. Tu demandes poliment au modèle de produire du JSON. Cela marche souvent, mais pas toujours. Le modèle peut ajouter des blocs de code Markdown, omettre des champs ou, en cas de doute, repasser au texte libre. Aucune garantie.

Mode JSON. Le fournisseur garantit que la sortie est du JSON syntaxiquement valide. Cela élimine les erreurs de syntaxe, mais ne dit rien de la structure : des champs peuvent manquer, avoir un mauvais type ou apparaître en trop. Garantie partielle.

Constrained decoding / Structured Outputs. Ici, le processus de génération est restreint au niveau des tokens, de sorte que seuls les tokens conformes au schéma peuvent être générés. Le modèle ne peut plus du tout sortir d'un résultat conforme au schéma. Champs obligatoires, types et valeurs d'enum autorisées sont garantis. Cette technique sous-tend OpenAI Structured Outputs (mode strict) et les Structured Outputs d'Anthropic, c'est-à-dire les JSON Outputs via output_config.format et le Strict Tool Use avec strict: true. Le tool use classique sans strict ne garantit pas le schéma. Pour les modèles open-weight, des bibliothèques et des stacks d'inférence remplissent la même fonction grâce à des contraintes de grammaire.

Comparatif : méthode, garantie, compromis

Méthode

Garantie

Compromis

Prompt seul ("réponds en JSON")

Aucune. Le modèle peut dévier ou renvoyer du texte libre

Zéro effort d'implémentation, mais peu fiable en production

Mode JSON

JSON syntaxiquement valide, mais pas ton schéma

Élimine les erreurs de syntaxe, mais pas les champs manquants ou mal typés

Structured Outputs / strict (OpenAI)

Schéma strictement imposé (champs, types, enums)

La première requête par schéma peut coûter de la latence pour la compilation du schéma ; limites du sous-ensemble de schéma pris en charge

JSON Outputs / Strict Tool Use (Anthropic Claude)

Schéma imposé par constrained decoding (output_config.format ou strict: true)

La première requête par schéma coûte de la latence pour la compilation de la grammaire ; limites du sous-ensemble de schéma pris en charge

Constrained decoding (open-weight, stacks locales)

La grammaire impose la conformité au schéma au niveau des tokens

Exige la maîtrise de la stack d'inférence ; la complexité du schéma influe sur la vitesse

Schéma + validation + relance (Pydantic/Zod)

Forme garantie plus contrôle sémantique

Plus de code et de logique, mais la variante la plus robuste pour les pipelines critiques

L'enseignement décisif de ce tableau : le constrained decoding garantit la forme, pas le contenu. Le modèle livre à coup sûr un objet valide avec le champ rechnungsdatum, mais aucune méthode de décodage ne peut garantir que la valeur saisie corresponde réellement à la date figurant sur le document. C'est pourquoi la validation métier et la stratégie de relance restent indispensables.

Ce que proposent les fournisseurs en 2026

Les grands fournisseurs lient désormais la réponse à un schéma JSON, mais diffèrent par leurs paramètres et leurs limites.

  • OpenAI : Structured Outputs avec strict: true, comme format de réponse de type json_schema ou dans le function calling. Le mode JSON (json_object), en revanche, ne fournit que du JSON valide, sans respecter le schéma.
  • Anthropic Claude : JSON Outputs via output_config.format ou Strict Tool Use avec strict: true, tous deux par échantillonnage contraint par grammaire. Sans strict, Claude peut renvoyer de mauvais types lors du tool use ("2" au lieu de 2) ou omettre des champs obligatoires. L'API ne prend en charge ni les schémas récursifs ni les contraintes comme minimum ou maxLength. Les limites de longueur, comme dans l'exemple ci-dessous, vont donc dans la description et dans la validation.
  • Google Gemini : l'API accepte un schéma JSON avec le type MIME application/json comme format de réponse. Google recommande lui-même de vérifier malgré tout les valeurs dans l'application.
  • Modèles open-weight : ici, c'est la stack d'inférence qui impose le schéma par grammaire. vLLM accepte un schéma JSON directement dans son serveur compatible OpenAI, et llama.cpp traduit une partie de JSON Schema en grammaires GBNF. Si tu gères ta propre stack, tu configures le constrained decoding indépendamment de l'API d'un fournisseur.

Point important en pratique : de nombreux fournisseurs d'inférence proposent des endpoints compatibles OpenAI, mais mettent en œuvre les sorties structurées de manière différente. Avant de t'engager, vérifie si le fournisseur concerné applique réellement le mode strict ou les contraintes de schéma, ou s'il ne propose que le mode JSON.

Exemple de schéma et stratégie de relance

Un exemple concret rend le principe tangible. Un agent doit classer les demandes de support entrantes et en extraire les champs les plus importants. Le schéma JSON (simplifié) se présente ainsi :

```json
{
"type": "object",
"properties": {
"kategorie": {
"type": "string",
"enum": ["rechnung", "technik", "vertrag", "sonstiges"],
"description": "Catégorie principale de la demande"
},
"dringlichkeit": {
"type": "string",
"enum": ["niedrig", "mittel", "hoch"]
},
"kundennummer": {
"type": ["string", "null"],
"description": "Numéro client s'il figure dans le texte, sinon null"
},
"zusammenfassung": {
"type": "string",
"description": "Une phrase, 200 caractères maximum"
}
},
"required": ["kategorie", "dringlichkeit", "kundennummer", "zusammenfassung"],
"additionalProperties": false
}
```

Deux choix de conception sont ici essentiels. D'abord, des enums plutôt que du texte libre pour kategorie et dringlichkeit : on exclut ainsi que le modèle invente "Rechnungswesen" ou "sehr hoch", ce qui casserait une logique de routage en aval. Ensuite, additionalProperties: false, pour qu'aucun champ supplémentaire indésirable n'apparaisse. Les champs description agissent comme une instruction implicite pour le modèle.

Une stratégie de relance bornée s'appuie sur ce schéma. Le pseudo-code appelle le LLM trois fois au maximum :

```
versuch = 0
while versuch < 3:
antwort = llm.call(prompt, schema=support_schema) # sortie structurée
objekt = parse_json(antwort) # la forme est garantie
fehler = validiere(objekt) # contrôle sémantique
if not fehler:
return objekt
prompt += f"\nCorrige : {fehler}" # retour d'erreur
versuch += 1
eskaliere_an_mensch(antwort) # repli après 3 tentatives
```

L'essentiel : même avec une forme garantie conforme au schéma, validiere() vérifie la sémantique, par exemple si le champ kundennummer correspond au format attendu ou si le champ zusammenfassung respecte la limite de longueur. En cas d'échec, l'erreur concrète est renvoyée au modèle comme retour. Trois tentatives constituent une limite raisonnable ; au-delà, on escalade vers un humain au lieu de boucler indéfiniment et de brûler du budget.

Validation avec Pydantic et Zod : le standard en pratique

En pratique, personne n'écrit de schémas JSON à la main. En Python, on définit un modèle Pydantic ; en TypeScript, un schéma Zod. Les deux génèrent le schéma JSON pour la requête au LLM et prennent directement en charge la validation de la réponse. Le bénéfice est double : la même définition pilote la génération et contrôle le résultat, ce qui évite les incohérences. Erreurs de type, champs obligatoires manquants ou plages de valeurs non respectées apparaissent immédiatement au parsing sous forme de message d'erreur clair, réutilisable comme retour pour la relance.

Des frameworks comme Pydantic AI intègrent déjà cette boucle : ils vérifient la réponse par rapport au modèle Pydantic et demandent au modèle une nouvelle tentative en cas d'erreur de validation, avec une limite configurable. Pour le routage multi-fournisseurs, il existe des outils comme LiteLLM et OpenRouter. La même requête structurée peut ainsi être envoyée à différents modèles. Cela réduit la dépendance à un fournisseur et permet de basculer sur un second modèle si un fournisseur ne livre pas la sortie structurée de manière fiable.

Pièges fréquents

  • Des schémas trop complexes. Les structures profondément imbriquées avec de nombreux champs facultatifs augmentent le taux d'erreur et la latence. Aussi strict que nécessaire, aussi simple que possible.
  • Confondre forme et contenu. Un objet conforme au schéma n'est pas automatiquement juste sur le fond. Les valeurs hallucinées mais correctement typées sont la catégorie d'erreurs la plus dangereuse, car elles passent inaperçues.
  • Des relances illimitées. Sans plafond, tu risques des boucles infinies et une explosion des coûts. Toujours des relances bornées, avec l'escalade comme solution de repli.
  • Ignorer les différences entre fournisseurs. Tous les endpoints compatibles OpenAI n'imposent pas vraiment le schéma de façon stricte. Teste avant la mise en production.

Pour les agences et les décideurs B2B

Si tu prévois un agent en production ou une application RAG en Europe, tu as intérêt à ancrer les sorties structurées dès le départ comme principe d'architecture, et non comme réparation après coup. C'est précisément là que se joue la différence entre un projet d'IA qui devient un outil fiable et une démo qui reste imprévisible. Agence basée à Vienne, Blck Alpaca accompagne des entreprises de toute l'Europe dans la mise en place de pipelines RAG et d'agents robustes, de la définition du schéma à la validation et à la logique de relance, jusqu'au choix du fournisseur et aux questions de souveraineté. Contacte-nous si ton projet RAG ou d'agents a besoin de sorties fiables et lisibles par machine plutôt que de texte libre approximatif.

Résumer avec l’IAChatGPTClaudePerplexity

Ouvre le chat avec un prompt prêt à l’emploi.

Questions fréquentes

Quelle est la différence entre le mode JSON et les Structured Outputs ?
Le mode JSON garantit seulement que la réponse est du JSON syntaxiquement valide, mais pas qu'elle respecte ton schéma. Des champs peuvent manquer, avoir un mauvais type ou apparaître en trop. Les Structured Outputs (avec constrained decoding et mode strict) imposent en plus la structure exacte du schéma : champs obligatoires, types et valeurs d'enum autorisées sont garantis. Pour les pipelines d'agents, seule la seconde option est vraiment fiable.
Le constrained decoding garantit-il un contenu correct ?
Non. Le constrained decoding garantit uniquement la forme : la sortie est du JSON valide et conforme au schéma. Que les valeurs soient justes sur le fond, par exemple qu'une date de facture extraite corresponde bien à la date réelle, la méthode ne peut pas l'assurer. C'est pourquoi tout pipeline de production a besoin en plus d'une validation sémantique (contrôles de plausibilité, plages de valeurs, vérifications croisées) et d'une logique de relance.
Comment fonctionnent les sorties structurées avec Anthropic Claude ?
Anthropic propose deux approches qui imposent le schéma par constrained decoding. Avec les JSON Outputs, tu passes le schéma JSON dans le paramètre output_config.format, et Claude répond en JSON selon ce schéma. Avec le Strict Tool Use, tu définis un outil avec input_schema, tu fixes strict: true et tu laisses le modèle appeler cet outil. Les arguments de l'appel d'outil constituent alors ton objet structuré. Sans strict, Claude ne respecte le schéma lors du tool use qu'au mieux de ses capacités et peut par exemple renvoyer "2" au lieu de 2 ou omettre des champs obligatoires.
Ai-je besoin de sorties structurées même pour des applications simples ?
Dès que la sortie du LLM est traitée par un programme, et pas seulement lue par un humain, un schéma vaut la peine. Pour une seule étape de classification ou d'extraction, il évite des erreurs de parsing. Pour les agents multi-étapes, il est pratiquement indispensable, car les taux d'erreur se multiplient sur toute la chaîne. Les applications de chat ou de génération de texte destinées uniquement à des lecteurs humains n'en ont pas besoin.
Quel rôle joue la conception du schéma dans la fiabilité ?
Un rôle important. Des schémas étroits et sans ambiguïté, avec des enums plutôt que du texte libre, des descriptions de champs claires et des champs obligatoires bien choisis, réduisent nettement les erreurs. Des schémas trop complexes, profondément imbriqués ou ambigus augmentent le taux d'erreur et la latence. Un bon schéma est aussi strict que nécessaire et aussi simple que possible, et il utilise les descriptions comme instruction implicite pour le modèle.

Envie d’aller plus loin ?

Reçois les nouvelles analyses directement dans ta boîte mail ou découvre comment nous mettons ce savoir au service des entreprises.