← all posts
// ocr · ocr-models

OCR models for invoices and receipts: choosing an OCR-capable model

A photographed receipt, creased three times and shot at an angle under a ceiling light, is not much of a problem for a person. It becomes one the moment a pipeline has to decide what belongs on the page, in what order, and whether the digits it just pulled out are the ones actually printed there.

The documents in front of you are supplier invoices, retail receipts, credit notes, and expense photos taken by someone in a hurry. The downstream system needs vendor, dates, totals, taxes, currency, line items, and coordinates into the source image, inside a schema something else validates against. The pages fight you the ordinary way: crumpling, fading thermal paper, a shadow across a logo, a phone held at an angle, a subtotal that shows up three times before the real total does.

An OCR engine, a layout-aware document parser, and a vision-language model are not competing products chasing the same job. They sit at different layers of one pipeline, and treating them as interchangeable is how a team ends up asking a language model to guarantee accuracy it was never built to guarantee.

What decides your candidate is boring: script, layout, handwriting, resolution, output shape, and where the box is allowed to run. Start with OCR, then vendor templates, anchors, and arithmetic checks. Bring a generative or multimodal model in only where it earns its keep, on messy handwriting, irregular layouts, or linking a label to a value three fields away. It does not replace the cheap stages that already work because building it is more interesting.

Run the three engines on the same stack first

Before ranking anything, run a classical OCR engine, a layout-aware parser, and an OCR-capable VLM against the same labeled pages, not three separate samples letting each shine on its own turf. Treat the original file as immutable and assign a page and document ID before any processing touches it. Crop or rotate the source first and you lose the ability to prove what was on the page.

What I keep in the trail for every page:

  • source hash, page and document ID, capture device
  • original dimensions, orientation, and every preprocessing version applied
  • which model and runtime revision touched the page
  • raw text, regions, reading order, and confidence
  • the normalized field next to any reviewer correction
  • latency, memory, and per-page cost

Never let normalization overwrite what was read. If a character could be O or 0, I or 1, a decimal point, a minus sign, a unit, or a diacritic, store what the recognizer saw and what the business rule proposed as two separate values.

The wrong total looks exactly like a right one

The failure that costs you money is not garbled text. It is a syntactically valid amount lifted from the subtotal, the balance-forward line, or the row just above the one you wanted, looking at home in the field. A vision-language model picked for scoring well on a visual benchmark is the wrong tool for this: that benchmark rewards plausible answers, and plausible is what a damaged surname, a part number, or a total becomes when the model fills the gap with something familiar instead of admitting it cannot read the pixel.

Character error rate and word error rate are worth tracking, but they treat a missing comma and a wrong account number as the same mistake, which they are not. Add exact-match scoring for the fields that matter: identifiers, dates, amounts, warnings, units. Where the document has a table, score field association and table geometry on their own, separate from whether the characters came out right. The gate that matters is field and line-item accuracy, arithmetic reconciliation, duplicate detection, and how often the exception queue fires, not a paragraph score that reads well on a slide.

Teach the pipeline to say it does not know

Build a real path for the system to abstain. A low-resolution region, a clipped page, glare on a barcode, handwriting nobody could read, totals that contradict each other: each should raise an exception, not a guess a human catches later by accident. Confidence scores are specific to the model and often calibrated badly, so I do not lean on them alone. Combine them with image-quality checks, format validators, cross-field arithmetic, known dictionaries, and disagreement between two independent recognition passes.

Provenance is what turns a review queue from retyping into verification. Store the page number and the bounding polygon for every field that matters, then put the cropped region next to the proposed value. A reviewer settles an ambiguous digit in seconds when the relevant patch of page sits right there. Take the coordinates away and the review means scanning the page again, or digging out a physical document already filed.

Keep the model on a short leash past the read

An OCR-capable VLM earns its place when it links a label to a value three fields away, reconstructs a table fragmented across a page break, or explains why two totals disagree. Ask it to separate what it observed from what it is inferring, and never let its output write to a database or trigger a tool call without schema validation and business rules outside the model. Text printed inside a document is untrusted input, not permission to rewrite your extraction instructions or call something on its own.

Multi-page documents need the same discipline: preserve page order and the identity of a repeated header, and do not hand the model a loose bundle of pages and hope it keeps invoices, statements, and sections apart. Split deterministically, attach identifiers, and state whether a table or paragraph may continue across a page boundary. The rule I keep coming back to: run the simplest recognizer that preserves text and layout, and escalate the ambiguous region, not the whole page. Version the model, preprocessing, dictionaries, schema, and validation together, and replay a stratified set, clean pages, ordinary noise, ugly layouts, critical fields, a few cases built to be impossible, whenever one changes.

Running this locally keeps documents under your control and gets cheap at high, steady volume, though you are now counting storage, backups, accelerator time, and the maintenance of owning the stack. A hosted document API or a frontier vision model buys elasticity and a higher ceiling for odd exceptions, at the cost of upload time, retention, residency, rate limits, and a running per-page or per-token bill. Hybrid routing, local for the bulk, hosted for whatever the local path kicks back, works fine when the privacy rules are firm and the escalation path is visible.

What I still do not have a clean answer for is versioning the hosted side. I can pin my own preprocessing, schema, and validation rules down to the commit. I cannot pin a vendor's frontier model the way I pin an on-disk GGUF on a local box. It updates under me without notice sometimes, and a replay set that passes clean today can start drifting next month without a line of my own code changing. That gap stays open.

#ocr-models#document-ai#vision