À la fin de ce guide, vous serez en mesure d'appeler les sorties structurées d'OpenAI depuis votre propre code : fournir un schéma JSON au modèle, définir strict: true, et obtenir une réponse qui est garantie de correspondre à la forme que vous avez demandée. Vous enverrez une première requête, lirez la réponse, gérerez les cas limites, et générerez des collections de tests d'API dans Apidog qui affirment que la charge utile est réellement conforme.
Ce dont vous avez besoin avant de commencer
Les sorties structurées contraignent la génération du modèle afin que la sortie soit conforme à un schéma JSON que vous fournissez. Lorsque vous transmettez un schéma avec strict: true, le modèle ne peut pas émettre de champ qui le violerait. Chaque clé requise est présente, chaque type correspond, et chaque valeur d'énumération est l'une de celles que vous avez énumérées. Vous cessez d'écrire du code de parsing défensif et commencez à faire confiance à la charge utile.
C'est une véritable amélioration par rapport à l'alternative. Les invites en texte libre comme « répondre uniquement en JSON » fonctionnent jusqu'à ce qu'elles ne fonctionnent plus. Un détour de raisonnement et vous obtenez de la prose enveloppée autour de votre objet, ou une date là où vous attendiez un entier. Les sorties structurées transforment le contrat d'une instruction pleine d'espoir en une contrainte appliquée au moment du décodage.
Pour suivre, vous avez besoin de :
- Une clé API OpenAI définie comme
OPENAI_API_KEY. - Un modèle qui prend en charge l'application stricte des schémas (plus de détails sur les modèles ci-dessous).
- Un schéma JSON décrivant la forme que vous souhaitez en retour.
Choisissez le bon modèle
Les sorties structurées sont disponibles sur les modèles récents d'OpenAI, en commençant par la famille GPT-4o et en continuant avec la série GPT-5. La documentation d'OpenAI recommande actuellement de démarrer de nouveaux projets sur leur dernier fleuron (gpt-5.5 au moment de la rédaction). Les modèles plus anciens, et les modèles de l'ère gpt-3.5, supportent le mode JSON mais pas l'application stricte des schémas. Si vous dépendez de strict: true, confirmez que l'ID de modèle spécifique le prend en charge avant de déployer, car le support est lié aux versions des modèles et OpenAI les met à jour.
Il est utile de savoir quelle fonctionnalité vous utilisez réellement, car OpenAI en propose deux qui sont liées et faciles à confondre.
Le mode JSON (response_format: { "type": "json_object" }) garantit que la sortie est du JSON syntaxiquement valide. C'est tout. Il ne connaît pas vos champs, vos types ou vos clés requises. Vous devez toujours valider la forme vous-même.
Les sorties structurées (response_format avec type: "json_schema" et strict: true) garantissent que la sortie est du JSON valide et correspond à votre schéma. OpenAI décrit les sorties structurées comme l'évolution du mode JSON : les deux produisent du JSON valide, mais seules les sorties structurées imposent la conformité au schéma. Pour les nouveaux projets, les sorties structurées sont celles que vous voulez.
| Mode JSON | Sorties structurées (strict) | |
|---|---|---|
| Paramètre | response_format: {"type":"json_object"} |
response_format avec type: "json_schema", strict: true |
| JSON valide | Oui | Oui |
| Correspond à votre schéma | Non | Oui |
| Champs requis appliqués | Non | Oui |
| Types et énumérations appliqués | Non | Oui |
| Vous validez toujours en aval | Toujours | Recommandé (voir ci-dessous) |
Une note sur les API : le point de terminaison Chat Completions utilise response_format comme indiqué ci-dessus. La nouvelle API Responses exprime la même chose sous text.format avec type: "json_schema". Les règles du schéma sont identiques ; seul l'enveloppe diffère. Consultez la documentation actuelle pour le chemin exact du champ sur le point de terminaison que vous appelez.
Effectuez votre première requête
Supposons que vous extrayiez un ticket de support dans un enregistrement typé. Voici une requête Chat Completions avec un schéma strict.
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.5",
"messages": [
{ "role": "system", "content": "Extract the ticket into the schema." },
{ "role": "user", "content": "My checkout 500s every time I use a saved card. Started today. Account: acct_8842." }
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "support_ticket",
"strict": true,
"schema": {
"type": "object",
"properties": {
"summary": { "type": "string" },
"category": { "type": "string", "enum": ["billing", "bug", "account", "other"] },
"severity": { "type": "integer" },
"account_id": {
"anyOf": [ { "type": "string" }, { "type": "null" } ]
}
},
"required": ["summary", "category", "severity", "account_id"],
"additionalProperties": false
}
}
}
}'
Lisez la réponse
Le modèle renvoie un message dont le content est une chaîne JSON correspondant à ce schéma, par exemple :
{
"summary": "Checkout returns HTTP 500 when paying with a saved card",
"category": "bug",
"severity": 3,
"account_id": "acct_8842"
}
Remarquez que account_id utilise anyOf avec null. C'est ainsi que vous modélisez un champ facultatif, ce qui nous amène directement aux règles que vous devez suivre lorsque vous écrivez vos propres schémas.
Restez dans le sous-ensemble du schéma
Les sorties structurées acceptent un sous-ensemble du schéma JSON. Le sous-ensemble existe afin qu'OpenAI puisse appliquer les contraintes de manière fiable et mettre en cache le schéma compilé. Les règles à mémoriser :
- La racine doit être un objet. Vous ne pouvez pas faire du niveau supérieur un tableau ou une chaîne simple. Enveloppez une liste dans une propriété d'objet.
- Chaque propriété doit être listée dans
required. Il n'y a pas de « facultatif » au sens habituel. Pour rendre un champ annulable, donnez-luianyOfavec un typenull, comme dans l'exemple ci-dessus. additionalPropertiesdoit êtrefalsesur chaque objet. Cela empêche le modèle d'inventer des clés supplémentaires.- Des limites de taille s'appliquent. Un schéma peut contenir jusqu'à environ 100 propriétés d'objet avec jusqu'à 5 niveaux d'imbrication. Les schémas profondément imbriqués ou trop étendus sont rejetés, alors aplatissez-les si possible.
- Certains mots-clés ne sont pas appliqués. Les mots-clés de validation uniquement comme
pattern,format,minLengthetminimumne sont pas garantis par le modèle. Si vous avez besoin qu'une expression régulière ou une plage numérique soit respectée, vous devez toujours le vérifier vous-même après la réception de la réponse. - Latence du premier appel. La première requête avec un nouveau schéma prend du temps à être compilée (généralement quelques secondes, parfois jusqu'à une minute pour des schémas complexes). Après cela, elle est mise en cache et rapide.
Parce que les mots-clés de validation ne sont pas appliqués, « JSON garanti » ne signifie pas « valide métier garanti ». La structure est verrouillée. Les valeurs à l'intérieur méritent toujours un test. Si vous avez déjà modélisé des champs optionnels ou d'union avec oneOf/anyOf/allOf, le modèle mental est familier : un schéma contraint la forme, mais vous affirmez les vraies valeurs séparément.
Gérer les refus et la troncation
Il y a un cas où la sortie ne correspondra pas intentionnellement à votre schéma. Si le modèle refuse une requête non sécurisée, il renvoie un champ refusal sur le message au lieu d'un contenu de forme de schéma. Votre code devrait se ramifier à ce niveau avant le parsing :
msg = response.choices[0].message
if msg.refusal:
handle_refusal(msg.refusal)
else:
ticket = json.loads(msg.content)
Les refus sont désormais détectables par programme, ce qui est plus propre que de scanner le texte pour une excuse. Deux autres façons dont une réponse peut ne pas respecter le schéma : atteindre max_tokens au milieu d'un objet (le JSON est tronqué), ou utiliser des appels d'outils parallèles, que les sorties structurées ne supportent pas. Définissez parallel_tool_calls sur false lorsque vous combinez les deux.
Comment le tester dans Apidog
Le mode strict applique le schéma au moment de la génération. Il ne vous dispense pas de tester. Les modèles sont échangés, les schémas évoluent, un coéquipier modifie le tableau required, ou un chemin de refus change. Vous voulez un test qui échoue bruyamment lorsque la réponse ne correspond plus au contrat. C'est là qu'Apidog intervient.

Pour être précis sur la division du travail : le mode strict d'OpenAI est ce qui produit du JSON valide selon le schéma. Apidog n'applique pas le schéma au niveau du modèle. Ce qu'Apidog fait, c'est valider la réponse que vous avez reçue par rapport au schéma que vous attendez, afin que vous détectiez les dérives en CI au lieu de la production.
Voici le flux de travail :
- Envoyez la requête. Construisez l'appel Chat Completions dans Apidog avec votre bloc
response_format. Enregistrez-le dans une collection pour qu'il soit reproductible. - Affirmez la forme. Ajoutez des assertions de réponse dans Apidog. Vérifiez que
categoryest l'une de vos valeurs d'énumération, queseverityest un entier, queaccount_idest une chaîne ou null. Apidog peut valider la réponse par rapport au schéma JSON, de sorte que vous attachez le schéma exact et faites échouer l'exécution lorsque la charge utile dévie. - Exécutez-le en CI. Placez la collection dans votre pipeline afin que chaque changement de modèle ou de prompt revérifie la conformité. Une rupture de schéma silencieuse devient une construction rouge.
- Simulez le contrat. Avant que l'appel réel n'existe, ou pour tester les consommateurs en aval sans dépenser de jetons, mettez en place une API mock qui renvoie des exemples de réponses valides selon le schéma. Votre frontend et vos tests s'exécutent sur une forme stable pendant que l'intégration se consolide.
Ce dernier point est sous-estimé. Vous pouvez développer et tester tout ce qui consomme la sortie structurée par rapport à une maquette qui respecte le même schéma, puis échanger l'appel OpenAI en direct lorsque vous êtes prêt. Téléchargez Apidog et vous pourrez construire la requête, les assertions et la maquette en un seul endroit.
Questions fréquemment posées
Le mode JSON est-il déprécié maintenant que les sorties structurées existent ? Le mode JSON fonctionne toujours et garantit toujours un JSON valide. Il n'applique simplement pas de schéma. Pour le nouveau code, les sorties structurées avec strict: true sont le choix le plus robuste. N'utilisez le mode JSON simple que sur les modèles qui ne supportent pas les schémas stricts, ou lorsque vous n'avez vraiment pas de forme fixe.
La racine de mon schéma peut-elle être un tableau ? Non. Le niveau supérieur doit être un objet. Enveloppez votre liste dans une propriété, comme { "items": [...] }, et mettez items dans required. Cela surprend beaucoup de monde au début.
Comment rendre un champ facultatif ? Les sorties structurées exigent que chaque propriété soit dans required, il n'y a donc pas de champ facultatif classique. Modélisez « manquant » comme annulable : utilisez anyOf avec une string (ou tout autre type) et un null. La clé est toujours présente ; sa valeur peut être null.
Le mode strict signifie-t-il que je peux ignorer entièrement la validation ? La structure est garantie, vous pouvez donc ignorer les vérifications de forme. Mais les mots-clés comme pattern, format et les plages numériques ne sont pas appliqués par le modèle, et les refus ou la troncation peuvent toujours produire des réponses non conformes aux spécifications. Un test de conformité conserve toujours sa pertinence. Si vous débutez avec ce format, ce manuel d'introduction au schéma JSON couvre les bases, et vous pouvez exécuter la vérification à chaque déploiement.
Quels modèles dois-je utiliser ? Les sorties structurées fonctionnent sur GPT-4o et les versions ultérieures, y compris la série GPT-5. La documentation d'OpenAI oriente les nouveaux projets vers leur fleuron actuel. Confirmez que l'ID de modèle exact prend en charge le mode strict avant de vous y fier, car le support suit les versions des modèles.
En résumé
Vous avez maintenant le cycle complet : choisissez un modèle qui prend en charge le mode strict, envoyez une requête Chat Completions avec json_schema et strict: true, gardez votre schéma dans le sous-ensemble pris en charge, branchez-vous sur refusal, et rappelez-vous que les règles au niveau des valeurs doivent toujours être vérifiées. Prouvez-le ensuite par un test : construisez la requête dans Apidog, affirmez la réponse par rapport à votre schéma, et simulez-la afin que le reste de votre stack puisse avancer pendant que l'intégration se stabilise. Le modèle promet la forme. Vos tests prouvent qu'elle est restée ainsi.
