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.

Sorties structurées avec des API compatibles OpenAI : guide JSON Schema

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 :

  1. conservez une source de vérité unique et versionnée pour le JSON Schema ;
  2. changez uniquement l’enveloppe, pas le sens ;
  3. validez la réponse terminée ;
  4. appliquez ensuite les règles métier déterministes ;
  5. 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.