TATECHATLAS
◎ Français
Intelligence artificielle

Pourquoi la validation par JSON Schema est essentielle pour les sorties de LLM

Un guide technique expliquant pourquoi un JSON syntaxiquement correct provenant des grands modèles de langage (LLM) est insuffisant pour les systèmes de production et comment le JSON Schema fournit les garanties structurelles et de type nécessaires.

Dans ce guide

Analysez la réponse du modèle, puis validez l’objet obtenu selon un schéma explicite avant de l’utiliser. L’analyse JSON vérifie la lisibilité, sans imposer les champs obligatoires ni les types attendus. Utilisez required pour la présence, type pour les types et additionalProperties: false pour refuser les champs inattendus. Traitez les réponses invalides comme des erreurs. Ces contrôles imposent la structure déclarée, sans garantir la véracité de la réponse ni toutes les règles métier.

Le modèle mental : Syntaxe vs Schéma

Pour résoudre le problème des sorties de LLM peu fiables, il faut distinguer la syntaxe du schéma. La syntaxe fait référence aux règles du format JSON lui-même : chaque accolade ouvrante doit avoir une accolade fermante, et les clés doivent être entourées de guillemets doubles. Un analyseur comme json.loads() de Python ne vérifie que ces règles.

Un schéma, en revanche, définit la signification sémantique et la structure des données. Alors que la syntaxe garantit que le fichier est lisible, le schéma garantit que le contenu est utilisable. Un LLM peut facilement produire un objet JSON syntaxiquement parfait mais logiquement inutile parce qu'il ne fournit pas l'information spécifique requise par votre application.

Exemple : null, champ absent et chaîne valide

Considérons une application qui attend un profil utilisateur. Le système exige un champ 'email' sous forme de chaîne de caractères. Un LLM pourrait générer le JSON suivant :

JSON d'entrée : {"name": "John Doe", "email": null}

Dans ce cas, le JSON est syntaxiquement parfait. L'analyseur convertira avec succès cela en un dictionnaire Python. Cependant, si votre code tente d'appeler.split('@') sur le champ email, l'application plantera avec une AttributeError car elle aura reçu un NoneType au lieu d'une chaîne.

En appliquant un JSON Schema qui définit 'email' comme une chaîne obligatoire, l'étape de validation détecterait cette erreur avant que les données n'atteignent votre logique métier.

# Install in your environment: python -m pip install jsonschema
import json
from jsonschema import Draft202012Validator

schema = {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "email": {"type": "string"}
    },
    "required": ["name", "email"],
    "additionalProperties": False
}
Draft202012Validator.check_schema(schema)
validator = Draft202012Validator(schema)
samples = [
    '{"name": "Ada", "email": null}',
    '{"name": "Ada"}',
    '{"name": "Ada", "email": "ada@example.com"}'
]
for text in samples:
    data = json.loads(text)
    print("accepted" if validator.is_valid(data) else "rejected")
# Expected illustrative output:
# rejected
# rejected
# accepted

Résultat attendu

Pour les trois entrées, la sortie illustrative est rejected, rejected, accepted. Dans la première, email existe mais JSON null devient None en Python et ne respecte pas le type string. La deuxième omet email : required la refuse. La troisième respecte ce schéma. La valeur "not-an-email" serait également acceptée : l’exemple vérifie le type chaîne, pas une adresse. Dans la bibliothèque Python jsonschema, déclarer format ne suffit pas à activer son contrôle ; configurez un vérificateur de formats si nécessaire.

Diagnostic : Pourquoi les LLM échouent à la validation

Les LLM échouent à la validation pour plusieurs raisons. Premièrement, ils peuvent halluciner des noms de champs, utilisant 'user_email' au lieu de 'email'. Deuxièmement, ils peuvent avoir des difficultés avec les types complexes, comme renvoyer la chaîne '10' lorsqu'un nombre 10 est requis. Troisièmement, ils peuvent omettre des champs entièrement si le prompt est ambigu. Enfin, ils peuvent inclure des valeurs non standard comme NaN ou Infinity, qui, bien que parfois acceptées par certains analyseurs, ne sont pas conformes à la spécification JSON stricte (RFC 7159).

Erreurs communes

Une erreur courante est de supposer que parce qu'un analyseur n'a pas renvoyé d'erreur, les données sont sûres à utiliser. Une autre erreur est de ne pas tenir compte de la valeur 'null' ; en JSON, une clé peut exister mais avoir une valeur null, ce qui est fondamentalement différent de l'absence de la clé. Les développeurs oublient aussi souvent de limiter le nombre de propriétés, permettant au LLM de renvoyer des objets massifs et encombrants qui consomment une mémoire et un CPU excessifs lors du traitement.

Critères de décision pour la validation

Définissez le contrat réel : champs obligatoires et types explicites. Pour refuser les champs inattendus, utilisez additionalProperties: false ; properties seul ne les interdit pas. Ajoutez des bornes ou des motifs seulement s’ils répondent à un besoin. Limitez séparément la taille de la réponse avant son analyse. Python json.loads accepte NaN et Infinity par défaut ; utilisez parse_constant pour lever une erreur si un JSON strict est nécessaire. Ces contrôles ne remplacent ni les autorisations ni la validation métier.

Limites de portée

La validation par JSON Schema est une vérification structurelle, pas logique. Elle peut garantir qu'un champ 'prix' est un nombre, mais elle ne peut pas garantir que le prix est correct ou qu'il correspond au prix dans votre base de données. De plus, la validation de schéma ne protège pas contre les attaques par épuisement de ressources (DoS) si le LLM produit une chaîne JSON de plusieurs gigaoctets ; vous devez implémenter des limites de taille sur la chaîne d'entrée avant de commencer l'analyse.

Résumé des exigences

Pour implémenter cela efficacement, assurez-vous d'avoir : 1. Un JSON Schema défini pour chaque réponse attendue du LLM. 2. Une bibliothèque de validation (comme jsonschema pour Python). 3. Une stratégie pour gérer les erreurs de validation (par exemple, réessayer le prompt du LLM ou renvoyer une erreur à l'utilisateur). 4. Des limites de taille d'entrée pour éviter l'épuisement de la mémoire lors de la phase d'analyse initiale.

Points à vérifier

  • Le schéma définit-il tous les champs requis?
  • Les types (string vs nombre) sont-ils explicitement imposés?
  • Y a-t-il une limite sur la taille de la chaîne d'entrée avant l'analyse?
  • L'analyseur est-il configuré pour gérer ou rejeter NaN/Infinity?

JSON Schema ne peut pas valider la cohérence de la logique métier (par exemple, s'assurer que 'date_debut' est avant 'date_fin') ni l'exactitude factuelle du contenu.

Sources

  1. Python: json ↗
  2. JSON Schema: objects and required properties ↗
  3. Python jsonschema: installation and format checking ↗
Retour en haut ↑