Sorties structurées avec des API compatibles OpenAI : guide JSON Schema
Guide pratique pour appliquer des schémas JSON stricts à Responses et Chat Completions, valider les résultats, traiter les échecs et tester chaque route.

Structured Outputs permet de demander un JSON conforme à un schéma défini, au lieu de simplement demander au modèle de « répondre en JSON ». Avec une API compatible avec OpenAI, le même schéma JSON peut être utilisé via Responses ou Chat Completions, mais les enveloppes diffèrent et la prise en charge doit être vérifiée pour le modèle et le point de terminaison exacts.
Une mise en œuvre sûre en production comporte trois couches : utiliser un schéma strict lorsqu’il est pris en charge, analyser et valider de nouveau le résultat dans l’application, puis appliquer des règles métier déterministes. La conformité au schéma réduit les erreurs de format ; elle ne garantit pas l’exactitude sémantique ou factuelle.
Structured Outputs n’est pas le mode JSON
| Méthode | JSON valide | Schéma imposé | Usage courant |
|---|---|---|---|
| Invite seule | Non garanti | Non | Prototype tolérant les erreurs d’analyse |
| Mode JSON | Oui si pris en charge et si la génération se termine | Non | JSON flexible validé par l’application |
Structured Outputs avec strict: true |
Oui, sous réserve de gérer la fin et les refus | Oui, dans le sous-ensemble pris en charge | Extraction typée et processus applicatifs |
Le guide OpenAI sur Structured Outputs recommande cette méthode plutôt que le mode JSON quand le modèle et le point de terminaison la prennent en charge. Le format structuré sert à produire un objet de réponse prévisible ; Function Calling demande une action à l’application. Les deux peuvent partager un schéma, mais pas le contrat des identifiants d’appel et des messages de résultat.
Définir le schéma avant de choisir le point de terminaison
La classification d’un ticket d’assistance nécessite quatre champs :
{
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["billing", "technical", "account"]
},
"priority": {
"type": "integer",
"minimum": 1,
"maximum": 3
},
"requires_human": {
"type": "boolean"
},
"summary": {
"type": "string"
}
},
"required": ["category", "priority", "requires_human", "summary"],
"additionalProperties": false
}
Rendre toutes les propriétés obligatoires et utiliser additionalProperties: false stabilise l’objet consommé en aval. Cela ne rend pas tous les mots-clés de JSON Schema portables. OpenAI documente un sous-ensemble ; un autre fournisseur peut en prendre en charge un autre, ou ne pas proposer de mode strict pour les schémas.
Envoyer le schéma avec Responses API
Responses place le schéma sous text.format :
export MODELFLARE_API_KEY="<YOUR_API_KEY>"
export MODEL_ID="<MODEL_WITH_VERIFIED_STRUCTURED_OUTPUT_SUPPORT>"
curl -sS https://modelflare.dev/v1/responses \
-H "Authorization: Bearer $MODELFLARE_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"$MODEL_ID\",
\"input\": \"Le client a été débité deux fois et demande un remboursement.\",
\"text\": {
\"format\": {
\"type\": \"json_schema\",
\"name\": \"support_ticket\",
\"schema\": {
\"type\": \"object\",
\"properties\": {
\"category\": {
\"type\": \"string\",
\"enum\": [\"billing\", \"technical\", \"account\"]
},
\"priority\": {
\"type\": \"integer\",
\"minimum\": 1,
\"maximum\": 3
},
\"requires_human\": { \"type\": \"boolean\" },
\"summary\": { \"type\": \"string\" }
},
\"required\": [\"category\", \"priority\", \"requires_human\", \"summary\"],
\"additionalProperties\": false
},
\"strict\": true
}
}
}"
Envoyez ce corps de requête à POST https://modelflare.dev/v1/responses avec Authorization: Bearer <YOUR_API_KEY>. Le contenu généré se trouve dans des éléments de sortie typés. Un SDK peut fournir un outil pour récupérer le texte ou la sortie déjà analysée ; un client HTTP doit néanmoins repérer le texte complet et l’analyser explicitement comme du JSON.
Envoyer le même schéma avec Chat Completions
Chat Completions utilise response_format.json_schema :
curl -sS https://modelflare.dev/v1/chat/completions \
-H "Authorization: Bearer $MODELFLARE_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"$MODEL_ID\",
\"messages\": [
{
\"role\": \"user\",
\"content\": \"Le client a été débité deux fois et demande un remboursement.\"
}
],
\"response_format\": {
\"type\": \"json_schema\",
\"json_schema\": {
\"name\": \"support_ticket\",
\"schema\": {
\"type\": \"object\",
\"properties\": {
\"category\": {
\"type\": \"string\",
\"enum\": [\"billing\", \"technical\", \"account\"]
},
\"priority\": {
\"type\": \"integer\",
\"minimum\": 1,
\"maximum\": 3
},
\"requires_human\": { \"type\": \"boolean\" },
\"summary\": { \"type\": \"string\" }
},
\"required\": [\"category\", \"priority\", \"requires_human\", \"summary\"],
\"additionalProperties\": false
},
\"strict\": true
}
}
}"
Le JSON se trouve généralement sous forme de chaîne dans choices[0].message.content et doit être analysé.
| Objectif | Responses API | Chat Completions |
|---|---|---|
| Conteneur | text.format |
response_format.json_schema |
| Type | text.format.type |
response_format.type |
| Nom | text.format.name |
response_format.json_schema.name |
| Schéma | text.format.schema |
response_format.json_schema.schema |
| Mode strict | text.format.strict |
response_format.json_schema.strict |
| Résultat | Éléments de sortie / outil du SDK | choices[0].message.content |
La couche de compatibilité Modelflare convertit les deux enveloppes sur les routes OpenAI/Codex prises en charge. Elle ne crée toutefois pas la fonction Structured Outputs dans un modèle en amont qui en est dépourvu. Pour les familles transmises telles quelles à Chat Completions, le contrat du fournisseur reste la source de vérité.
Valider séparément structure et sens
{
"category": "billing",
"priority": 2,
"requires_human": true,
"summary": "Le client signale un double débit et demande un remboursement."
}
Validation structurelle
Un validateur JSON Schema vérifie les propriétés obligatoires, l’absence de propriétés inattendues, les types, les énumérations et les plages de valeurs. Même lorsque le fournisseur promet une conformité stricte, cette validation protège contre une route non prise en charge, une erreur d’intégration, une sortie tronquée ou une évolution future du contrat.
Validation sémantique et métier
Le schéma ne sait pas si le client a réellement été débité deux fois, si priority: 2 est correct ni qui peut autoriser un remboursement. Traitez l’objet comme une proposition de classification, comparez-le aux données de référence et imposez les autorisations et les limites financières dans du code déterministe. Un objet valide ne doit jamais contourner les contrôles d’accès, la facturation ou la sécurité.
Gérer les sorties incomplètes ou exceptionnelles
Refus
Vérifiez l’état de la réponse et la représentation du refus avant de rechercher le JSON. Un refus de sécurité n’est pas une erreur d’analyse.
Troncature et limites de sortie
Si la génération s’arrête avant la fin de l’objet, le schéma ne peut pas reconstituer la partie manquante. Contrôlez l’état d’achèvement et le motif d’arrêt, puis configurez une limite de sortie suffisante mais bornée.
Mots-clés non pris en charge
Commencez avec les objets, tableaux, types primitifs, énumérations, propriétés obligatoires et propriétés supplémentaires explicites. Vérifiez la documentation avant d’utiliser les références, la récursion, les unions complexes ou les validations avancées.
Latence à la première utilisation du schéma
Certains fournisseurs prétraitent et mettent en cache un nouveau schéma. Réutilisez des schémas stables et versionnés, puis mesurez séparément la première utilisation et le régime établi.
Modèle ou route incompatible
Un point de terminaison peut accepter Chat Completions, refuser json_schema ou ignorer strict. Une réponse 200 contenant du JSON ne prouve pas la conformité stricte. Testez aussi les entrées invalides et les cas limites.
Exécuter une matrice de compatibilité
| Test | Preuve à conserver |
|---|---|
| Objet minimal avec champs obligatoires | État, modèle, route, objet analysé et résultat de validation |
| Chaque valeur d’énumération | Production et analyse de chaque valeur |
| Information absente | Valeur de repli bornée ou clarification |
| Entrée sensible | Représentation du refus et traitement par l’application |
| Limite de sortie faible | État d’achèvement et gestion de la troncature |
| Fonction non prise en charge | Erreur explicite ou contrainte ignorée |
| Enveloppes Responses et Chat | Objets applicatifs équivalents |
| Schéma stable répété | Première utilisation comparée au régime établi |
Conservez le schéma, l’invite, la région, le mode de diffusion et la limite de sortie constants lors d’une comparaison, puis notez la date du test.
Choisir le point de terminaison après avoir testé le processus
Responses convient aux éléments de sortie typés, aux événements diffusés en continu et aux processus d’outils plus larges. Chat Completions convient à une intégration stable par messages lorsque response_format est pris en charge sur la route. Voir Responses API ou Chat Completions.
Dans tous les cas :
- conservez une source de vérité unique et versionnée pour le JSON Schema ;
- changez uniquement l’enveloppe, pas le sens ;
- validez la réponse terminée ;
- appliquez ensuite les règles métier déterministes ;
- surveillez séparément les erreurs d’analyse, les refus, les troncatures et les incompatibilités.
Pour la migration, utilisez le guide des API compatibles avec OpenAI ; pour les flux incomplets, le guide de la diffusion en continu des API d’IA. Consultez Modèles et tarifs, puis testez Structured Outputs sur la route exacte de la clé API.
Structured Outputs transforme la réponse en interface applicative plus fiable, mais ne remplace ni la vérification factuelle, ni les contrôles d’accès, ni la logique de facturation. La « compatibilité OpenAI » reste une affirmation à tester fonction par fonction.