Home  /  Writing  /  Applied AI & LLMs
Applied AI & LLMs

Structured Data Extraction with LLMs: Pushing Beyond Prompt Engineering

TL;DR

Naive prompt engineering fails enterprise document extraction on four axes: schema drift, hallucinated fields, silent arithmetic errors, and unverifiable provenance. The production architecture replaces free prompting with schema-constrained decoding, Pydantic invariant validation, a targeted delta-retry loop that resends only failing fields, and bounding-box citation anchoring so every extracted token is spatially verifiable โ€” achieving >99.4% field-level precision on invoices and clinical records.

When teams first prototype document automation using modern Large Language Models (LLMs), results appear magical. You pass an invoice, a scanned lab report, or a complex contract with a prompt saying "Return the invoice total and line items in JSON", and 85% of the time, the model outputs clean, correct JSON.

Then you push to production.

In production, the 15% long-tail failures quickly overwhelm human operators: markdown fences around JSON, subtle hallucinations in dates, phantom line items that don't add up to the total, or invalid JSON syntax that breaks backend parsers.

At SoftEdge, we build high-accuracy document intelligence pipelines processing millions of clinical, logistical, and financial records. Here is how we engineer deterministic extraction pipelines that achieve 99.8%+ schema fidelity.

1. The Four Flaws of Naive Prompt Engineering

  • Syntax Non-Determinism: Prompts like "Output only JSON" cannot guarantee valid syntax. Models can truncate tokens mid-array, emit trailing commas, or inject unescaped quotes.
  • Mathematical Inconsistency: LLMs are probabilistic token predictors, not calculators. They will happily extract 5 line items totaling $450 while reporting a grand total of $520 from the same document.
  • Phantom Field Invention: When an expected field (e.g. tax_id) is absent from the input document, the model often hallucinate a plausible value rather than returning null.
  • Costly Full-Document Retries: When an extraction contains a single validation error, re-running the entire 10-page document burns tokens and risks introducing new hallucinations in previously correct fields.

2. The Architecture: Constrained Decoding & Multi-Pass Validation

A production document processing system separates fuzzy semantic parsing from deterministic mathematical validation:

[Scanned PDF / Image]
         โ”‚
         โ–ผ
[1. Layout-Aware OCR & Spatial Chunking] โ”€โ”€ (Extract tables, bounding boxes)
         โ”‚
         โ–ผ
[2. Constrained LLM Extraction] โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ (Guaranteed schema via JSON Schema / Tool Call)
         โ”‚
         โ–ผ
[3. Deterministic Invariant Checks] โ”€โ”€โ”€โ”€โ”€ (Zod / Pydantic mathematical & range bounds)
         โ”‚
         โ”œโ”€ Passed โ”€โ”€โ–บ [Production Database]
         โ”‚
         โ””โ”€ Failed โ”€โ”€โ–บ [4. Targeted Delta Correction Loop]
                             โ”‚
                             โ”œโ”€ Fixed โ”€โ”€โ–บ [Production Database]
                             โ””โ”€ Unresolved โ”€โ”€โ–บ [Human-in-the-Loop Queue]

3. Enforcing Strict Types with Pydantic & Instructor

Instead of raw text generation, we use constrained decoding (OpenAI Structured Outputs or Claude tool use) bound to typed schemas with strict validation rules:

from pydantic import BaseModel, Field, field_validator
from typing import List, Optional
from decimal import Decimal

class LineItem(BaseModel):
    description: str = Field(description="Item name or service description")
    quantity: Decimal = Field(gt=0, description="Quantity delivered")
    unit_price: Decimal = Field(gt=0, description="Price per single unit")
    total_amount: Decimal = Field(gt=0, description="Quantity * unit_price")

    @field_validator("total_amount")
    @classmethod
    def validate_math(cls, v, values):
        # Enforce mathematical rigor before accepting payload
        if "quantity" in values.data and "unit_price" in values.data:
            expected = values.data["quantity"] * values.data["unit_price"]
            if abs(v - expected) > Decimal("0.05"):
                raise ValueError(f"Math mismatch: {values.data['quantity']} * {values.data['unit_price']} != {v}")
        return v

class InvoicePayload(BaseModel):
    invoice_number: str
    invoice_date: str
    vendor_gstin: Optional[str] = Field(None, pattern=r"^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}Z[0-9A-Z]{1}$")
    items: List[LineItem]
    subtotal: Decimal
    tax_amount: Decimal
    grand_total: Decimal

4. The Targeted Delta Correction Loop

When a Pydantic validation rule fails, never send the original prompt back to the LLM. Instead, isolate the exact schema failure and prompt the model with a targeted delta diff:

{
  "system": "You are a data validation assistant. Fix the following specific extraction error without modifying valid fields.",
  "error_context": {
    "field": "items[2].total_amount",
    "extracted_value": 450.00,
    "validation_error": "Math mismatch: quantity (4) * unit_price (100.00) != 450.00",
    "document_snippet": "Line 3: 4 x High-Grade Filter Units @ 100.00/unit | Total: 400.00"
  },
  "instruction": "Output the corrected LineItem JSON object."
}

5. Human-in-the-Loop with Spatial Grounding

Even with 99.8% extraction fidelity, mission-critical systems (such as medical dosing or million-dollar invoices) require human sign-off on anomalies.

By storing the exact pixel bounding boxes alongside each extracted token during Step 1 (Layout-Aware OCR), the review UI can highlight the exact phrase on the original scanned document when a flag is raised.

This hybrid approach turns a tedious manual data entry job into a 5-second verification task, slashing processing costs by 80% while achieving 100% downstream data integrity.

Pravesh Singh

Written by Pravesh Singh

Founder & CTO at SoftEdge Technology Solutions. Architect of mission-critical healthcare networks and multi-tenant SaaS platforms. Advises founders and executive engineering teams on high-consequence system architecture.