Valider un JSON n’empêche pas une valeur plausible d’être fausse. Une approche en trois temps — contrat Pydantic strict, réessais limités et décodage contraint — doit s’achever par une comparaison au texte source pour accepter, revoir ou rejeter une sortie de LLM.
Pourquoi la validation de schéma ne suffit pas
Une sortie peut respecter un schéma tout en intégrant une valeur erronée. L’exemple présente un JSON valide qui associe 12 500 cents à une facture affichant 1 250, soit 125 euros, sans que l’outil de parsing ne s’en aperçoive. Un entier correctement typé passe la validation malgré l’incohérence. La détection nécessite une comparaison explicite au texte d’origine par l’application. Cette règle ne peut pas être exprimée dans un JSON Schema : même appliqué à la perfection, le décodeur peut produire un total de 12 500 cents pour une ligne chiffrée différente.
L’application impose quatre champs obligatoires pour la sortie
Le contrat de sortie comporte quatre champs — invoice_id, currency, total_cents et total_quote — et relève de l’application, non du prompt. Toutes les clés sont requises ; trois d’entre elles peuvent être nulles, ce qui autorise l’absence d’information sans omission de clé. L’ensemble des devises admises est borné à USD et EUR dans l’exemple, et les montants sont stockés en entiers pour éviter des représentations comme 1 249,9999. Le mode strict de Pydantic désactive la coercition : une chaîne '125000' échoue avec une erreur de type entier, tout comme un booléen True qui ne sera pas converti en 1. L’option extra='forbid' transforme toute clé inattendue en erreur extra_forbidden. Alimenté avec quatre entrées incorrectes, le modèle produit quatre catégories d’erreurs distinctes. Côté schéma, l’export indique quatre propriétés requises et additionalProperties false.
Comparer au texte source : les vérifications indispensables
La validation comporte deux volets : la conformité au contrat, puis la correspondance au document d’origine. La citation du montant doit apparaître mot pour mot dans la source lorsqu’elle est fournie. L’identifiant extrait est confronté à la valeur attendue, et la devise indiquée doit être présente dans le texte. Enfin, le nombre de cents est comparé aux chiffres récupérés de la citation. Ces contrôles déplacent la confiance de la simple forme vers l’alignement avec la source.
La recherche en IA vous passionne ?
Les papers et avancées qui comptent, expliqués simplement, chaque soir. Gratuit.
Inclus dès l'inscription : notre sélection des meilleurs guides & comparatifs IA.
Choisissez votre rythme
Gratuit · Pas de spam · Désabonnement en 1 clic
Accepter, revoir ou rejeter : un pipeline à quatre issues
Un flux d’évaluation distingue quatre statuts pour une réponse de modèle : accepted, needs_review, rejected et shape_error. Le traitement commence par l’analyse JSON et la validation Pydantic ; une erreur à ce stade produit shape_error accompagné de motifs. La présence textuelle de la citation du total dans la source est ensuite contrôlée lorsqu’elle est fournie. L’identifiant de facture est comparé à la valeur attendue et la devise doit être effectivement mentionnée dans le texte source. Un contrôle rapproché confronte le total en cents aux chiffres extraits de la citation si les deux existent. Toute incohérence accumule des raisons et aboutit à rejected, l’objet candidat étant renvoyé avec ces raisons. Si aucune incohérence n’est trouvée mais que la devise ou le montant manque, le résultat est needs_review. Lorsque toutes les vérifications passent et que les champs nécessaires sont présents, la sortie est accepted.
Génération sous contrôle : réessais limités et décodage contraint
Les secondes tentatives n’ont de sens que si elles peuvent corriger l’échec observé, avec un plafond fixé à trois réessais. Le décodage contraint réduit une classe entière d’erreurs en limitant les tokens aux structures permises par le schéma. L’API Responses d’OpenAI permet ce contrôle tout en conservant la validation en aval, et un client simulé facilite l’exercice de chaque voie d’échec. Une boucle de réessai peut se déclencher uniquement sur des erreurs de forme et garder sous contrôle les réessais internes du SDK. Sur serveur local, vLLM associé à xgrammar vise le même objectif, et les SDK Python renvoient directement des objets analysés.
Cas d’école : une facture structurée mais trompeuse
L’exemple de facture identifiée 2026-0417, adressée à Northwind Traders, affiche un total EUR 1,250.00 et une échéance à 30 jours. Un modèle peut retourner un objet comportant l’identifiant, la devise, le total en cents et la citation d’origine. L’écart illustré entre 12 500 cents et une ligne chiffrée à 1 250 montre qu’une sortie parfaitement structurée peut être trompeuse. Les démonstrations ont été réalisées en Python 3.10.12 avec Pydantic 2.14.1, le code se limitant à l’extraction de champs sans écriture dans des systèmes. Les sorties structurées se généralisent, ce qui renforce l’intérêt d’un contrôle appliqué au texte source.






