Vizion Web
IA & LLM

Sortie structurée

Définition

Mode dans lequel le LLM renvoie une réponse au format JSON respectant un schéma défini à l'avance. Indispensable pour l'extraction de données fiable et l'intégration dans un produit.

Le principe

Sans contrainte, un LLM répond en texte libre, ce qui complique son intégration dans un produit. La sortie structurée force la réponse à respecter un schéma JSON précis : champs, types, valeurs autorisées, champs obligatoires, contraintes (longueur, range, regex). Le modèle ne peut pas dériver, ne peut pas inventer un format, ne peut pas ajouter de prose autour. Côté code, on récupère un objet JSON parfaitement conforme au schéma déclaré, qu'on peut directement passer à du code typé sans parsing défensif. C'est ce qui transforme un LLM d'un générateur de texte en un service métier intégrable.

Structured Outputs versus JSON mode

OpenAI propose deux niveaux. Le JSON mode garantit que la sortie est un JSON valide syntaxiquement, mais ne contrôle pas le schéma : champs manquants ou inventés sont possibles. Le Structured Outputs (depuis GPT-4o) garantit 100% de conformité à un schéma JSON Schema fourni : impossible de générer une sortie hors schéma. Anthropic ne propose pas l'équivalent direct, mais utilise les tools : on déclare un tool avec un schéma JSON, et le tool_use renvoyé est garanti conforme. Pour les schémas complexes, on déclare en Zod côté TypeScript, on convertit en JSON Schema avec zod-to-json-schema, et on valide une dernière fois après réception.

À quoi ça sert

Les cas d'usage sont nombreux. L'extraction de données : extraire d'une facture {fournisseur, date, lignes, total} dans un format strict. La classification : classer un ticket support en {catégorie, priorité, sentiment} parmi des valeurs définies. La transformation : convertir un texte libre en formulaire rempli. La structuration de raisonnement : forcer le modèle à raisonner en {hypothèse, analyse, conclusion}. La génération de configuration : produire un objet de paramètres pour un outil. Pour tout ce qui alimente une base ou déclenche du code, la sortie structurée est non négociable.

Comment écrire un schéma

Un bon schéma respecte plusieurs principes. Des noms de champs clairs et explicites (invoice_date plutôt que d). Des descriptions sur chaque champ qui guident le modèle (description : la date d'émission de la facture au format YYYY-MM-DD). Des contraintes strictes : enum pour les valeurs autorisées, type pour les types, required pour les champs obligatoires. On évite les schémas trop profonds (au-delà de 3 niveaux d'imbrication, la qualité baisse). On préfère les structures plates avec des références. Et on documente côté backend ce que chaque champ représente, parce que le schéma seul ne suffit pas à comprendre l'intention métier.

Quand l'utiliser

La sortie structurée s'impose pour tout appel dont la réponse alimente du code ou une base. À l'inverse, pour de la génération créative (article de blog, e-mail commercial, réponse à un utilisateur), elle ajoute de la rigidité sans gain. On garde alors le texte libre, parfois avec un format Markdown qu'on parse. Sur un produit mature, on combine les deux : structured output pour les actions métier (extraction, classification, validation), texte libre pour la couche de communication avec l'utilisateur. La frontière est claire et évite les ambiguïtés.

Les pièges à éviter

Trois pièges. Croire qu'un schéma valide garantit une sémantique correcte : un montant peut être un nombre valide mais incohérent avec la facture. On revalide en métier côté serveur. Faire des schémas trop ambitieux qui demandent au modèle de générer trop de champs en un seul appel : on découpe en plusieurs appels chaînés si besoin. Et oublier les cas d'erreur : si le modèle ne sait pas extraire, qu'est-ce qu'il renvoie ? On prévoit explicitement un champ confidence ou un schéma alternatif pour signaler l'échec, plutôt que de laisser le modèle inventer pour respecter le schéma.