LLM: Ensuring JSON Reliability through Strict Contracts and Verification

Validating a JSON does not prevent a plausible value from being incorrect. A three-step approach—strict Pydantic contract, limited retries, and constrained decoding—should conclude with a comparison to the source text to accept, review, or reject an LLM output.
Why Schema Validation Is Not Enough
An output can conform to a schema while containing an erroneous value. The example presents a valid JSON that associates 12,500 cents with an invoice displaying 1,250, or 125 euros, without the parsing tool noticing. A correctly typed integer passes validation despite the inconsistency. Detection requires an explicit comparison to the original text by the application. This rule cannot be expressed in a JSON Schema: even when applied perfectly, the decoder can produce a total of 12,500 cents for a different numeric line.
The Application Requires Four Mandatory Fields for Output
The output contract includes four fields—invoice_id, currency, total_cents, and total_quote—and is the responsibility of the application, not the prompt. All keys are required; three of them can be null, allowing for the absence of information without omitting a key. The set of accepted currencies is limited to USD and EUR in the example, and amounts are stored as integers to avoid representations like 1,249.9999. Pydantic's strict mode disables coercion: a string '125000' fails with an integer type error, just like a boolean True that will not be converted to 1. The option extra='forbid' turns any unexpected key into an extra_forbidden error. When fed with four incorrect inputs, the model produces four distinct categories of errors. On the schema side, the export indicates four required properties and additionalProperties false.
Comparing to the Source Text: Essential Checks
Validation has two aspects: compliance with the contract, then correspondence to the original document. The quoted amount must appear word for word in the source when provided. The extracted identifier is compared to the expected value, and the indicated currency must be present in the text. Finally, the number of cents is compared to the figures retrieved from the quote. These checks shift confidence from mere form to alignment with the source.
Le brief IA que les pros lisent chaque soir
Les 7 actus IA du jour, décryptées en 5 min. 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
Accept, Review, or Reject: A Four-Outcome Pipeline
An evaluation flow distinguishes four statuses for a model response: accepted, needs_review, rejected, and shape_error. The process begins with JSON parsing and Pydantic validation; an error at this stage produces shape_error accompanied by reasons. The textual presence of the total quote in the source is then checked when provided. The invoice identifier is compared to the expected value, and the currency must indeed be mentioned in the source text. A close check confronts the total in cents with the figures extracted from the quote if both exist. Any inconsistency accumulates reasons and results in rejected, with the candidate object returned along with these reasons. If no inconsistencies are found but the currency or amount is missing, the result is needs_review. When all checks pass and the necessary fields are present, the output is accepted.
Controlled Generation: Limited Retries and Constrained Decoding
Second attempts only make sense if they can correct the observed failure, with a cap set at three retries. Constrained decoding reduces an entire class of errors by limiting tokens to structures permitted by the schema. The OpenAI API Responses allows for this control while maintaining downstream validation, and a simulated client facilitates the exercise of each failure path. A retry loop can only be triggered on shape errors and keep internal SDK retries under control. On a local server, vLLM combined with xgrammar aims for the same goal, and Python SDKs directly return parsed objects.
Case Study: A Structured Yet Misleading Invoice
The example of invoice identified as 2026-0417, addressed to Northwind Traders, shows a total of EUR 1,250.00 and a 30-day due date. A model can return an object containing the identifier, currency, total in cents, and the original quote. The discrepancy illustrated between 12,500 cents and a line priced at 1,250 shows that a perfectly structured output can be misleading. The demonstrations were conducted in Python 3.10.12 with Pydantic 2.14.1, with the code limited to field extraction without writing to systems. Structured outputs are becoming more common, which underscores the importance of control applied to the source text.
Brief IA — L'actualité IA en français
L'essentiel de l'actualité de l'intelligence artificielle, décrypté et expliqué chaque jour.