Aller au contenu principal

JSON mode et schema enforcement

JSON mode et schema enforcement

Le Structured Output d’OpenAI garantit que la réponse du modèle est un JSON valide conforme à un schéma que vous définissez. Fini le parsing fragile avec des regex ou les erreurs de format — le modèle est contraint au niveau de la génération elle-même.

JSON mode vs Structured Output

OpenAI propose deux niveaux de contrainte :

  • JSON mode : garantit un JSON valide, mais sans contrainte de structure
  • Structured Output : garantit un JSON conforme à un JSON Schema spécifique
from openai import OpenAI

client = OpenAI()

# JSON mode simple (JSON valide, structure libre)
response = client.responses.create(
    model="gpt-5.3",
    instructions="Réponds toujours en JSON.",
    input="Liste 3 langages de programmation avec leur année de création.",
    text={"format": {"type": "json_object"}}
)

import json
data = json.loads(response.output_text)
print(data)

Structured Output avec JSON Schema

C’est la fonctionnalité la plus puissante. Vous définissez un schéma JSON, et l’API garantit que la sortie le respecte :

response = client.responses.create(
    model="gpt-5.3",
    input="Analyse le sentiment de : 'Le produit est excellent "
          "mais la livraison était catastrophique.'",
    text={
        "format": {
            "type": "json_schema",
            "name": "sentiment_analysis",
            "schema": {
                "type": "object",
                "properties": {
                    "sentiment": {
                        "type": "string",
                        "enum": ["positif", "negatif", "mixte", "neutre"]
                    },
                    "score": {
                        "type": "number",
                        "description": "Score de -1.0 (très négatif) à 1.0 (très positif)"
                    },
                    "aspects": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "aspect": {"type": "string"},
                                "sentiment": {
                                    "type": "string",
                                    "enum": ["positif", "negatif", "neutre"]
                                }
                            },
                            "required": ["aspect", "sentiment"],
                            "additionalProperties": False
                        }
                    },
                    "resume": {"type": "string"}
                },
                "required": ["sentiment", "score", "aspects", "resume"],
                "additionalProperties": False
            },
            "strict": True
        }
    }
)

result = json.loads(response.output_text)
# Garanti : result a exactement les champs définis
print(f"Sentiment : {result['sentiment']}")
print(f"Score : {result['score']}")
for aspect in result["aspects"]:
    print(f"  - {aspect['aspect']}: {aspect['sentiment']}")

Règles du Structured Output strict

Le mode strict: true impose des contraintes sur le schéma :

  • Tous les champs doivent être dans required
  • additionalProperties doit être false sur chaque objet
  • Les types supportés : string, number, integer, boolean, array, object, null
  • Les enum sont supportés pour contraindre les valeurs
  • Pas de pattern ni de minLength/maxLength (la validation fine se fait côté client)

Helper pour construire les schémas

def structured_query(prompt: str, schema: dict,
                     schema_name: str = "response",
                     model: str = "gpt-5.3",
                     system: str = "") -> dict:
    """Wrapper pour les requêtes Structured Output."""
    response = client.responses.create(
        model=model,
        instructions=system or "Réponds en JSON selon le schéma fourni.",
        input=prompt,
        text={
            "format": {
                "type": "json_schema",
                "name": schema_name,
                "schema": schema,
                "strict": True
            }
        },
        temperature=0.1
    )
    return json.loads(response.output_text)

Exemple : extraction de données structurées

invoice_schema = {
    "type": "object",
    "properties": {
        "numero_facture": {"type": "string"},
        "date": {"type": "string"},
        "fournisseur": {
            "type": "object",
            "properties": {
                "nom": {"type": "string"},
                "siret": {"type": "string"},
                "adresse": {"type": "string"}
            },
            "required": ["nom", "siret", "adresse"],
            "additionalProperties": False
        },
        "lignes": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "description": {"type": "string"},
                    "quantite": {"type": "integer"},
                    "prix_unitaire_ht": {"type": "number"},
                    "tva_pourcent": {"type": "number"}
                },
                "required": ["description", "quantite",
                             "prix_unitaire_ht", "tva_pourcent"],
                "additionalProperties": False
            }
        },
        "total_ht": {"type": "number"},
        "total_ttc": {"type": "number"}
    },
    "required": ["numero_facture", "date", "fournisseur",
                  "lignes", "total_ht", "total_ttc"],
    "additionalProperties": False
}

facture_text = """
Facture N° 2026-0042
Date : 15/03/2026
Fournisseur : TechServ SARL, SIRET 123 456 789 00012
12 rue de la Paix, 75002 Paris

- Développement API REST x1 : 3500.00 EUR HT (TVA 20%)
- Hébergement cloud (3 mois) x1 : 450.00 EUR HT (TVA 20%)
- Support technique x10h : 150.00 EUR HT/h (TVA 20%)

Total HT : 5450.00 EUR
Total TTC : 6540.00 EUR
"""

result = structured_query(
    facture_text,
    invoice_schema,
    schema_name="invoice",
    system="Extrais les données de cette facture."
)

Mise en pratique

  1. Définissez un schéma JSON pour extraire les informations clés d’un CV (nom, expériences, compétences, formation)
  2. Testez avec 3 CV différents en texte brut
  3. Vérifiez que la sortie respecte systématiquement le schéma
  4. Comparez avec une extraction sans Structured Output

Points clés à retenir

  • Le Structured Output garantit un JSON conforme au schéma au niveau de la génération
  • Utilisez strict: true pour la conformité maximale
  • Tous les champs doivent être required avec additionalProperties: false
  • Idéal pour l’extraction de données, la classification, les pipelines de traitement
  • La validation fine (longueur, pattern) se fait côté client après réception