OCR in 2026: klassieke pipelines, VLMs en Document AI
Automatische vertaling Dit artikel is automatisch vertaald vanuit de oorspronkelijke Engelse versie.
Artikelupdate
Oorspronkelijk gepubliceerd op 4 maart 2026. Gereviewd en bijgewerkt op 6 september 2026. De update voegt nieuwere OCR- en vision-modelkandidaten, benchmarkreferenties en richtlijnen voor het interpreteren van documentextractieresultaten toe.
OCR-leaderboards zijn het niet eens omdat ze verschillende documenten, outputs en judges testen. De versiegebonden benchmarktabel van OmniDocBench en de live voorkeursstemmen van OCR Arena kunnen tot verschillende rangordes leiden; de scores zijn niet onderling uitwisselbaar, maar het verschil is nuttig. Voor een production-keuze heb je documenten en metrics uit de daadwerkelijke workload nodig.
Vision-language models (VLMs) kunnen omgaan met layout, handschrift, tabellen en gedegradeerde afbeeldingen die een gewone text-recognition-pipeline laten falen. Traditionele engines blijven concurrerend op schone afdrukken, vooral wanneer CPU-latency en operationele kosten belangrijk zijn. De gedateerde snapshot hieronder bevat PaddleOCR-VL 1.6 en dots.mocr, met verschillende trade-offs op het gebied van hardware, privacy en output. Controleer elk project voordat je een actuele keuze maakt.
Begeleidende repo: The OCR Gauntlet bevat drie instructieve notebooks en vijf gedownloade samples. Het is een smoke demo, geen gevalideerde ranglijst van engines. In de geïnspecteerde revision selecteren Docling-labels niet betrouwbaar de geadverteerde pipeline, bevatten referenties voor receipt recognition annotatiesleutels, verdwijnen failures uit de gemiddelden en gebruikt het Gemini-request
gemini-2.5-flashterwijl het notebook dit labelt als Gemini 3 Flash. Ook de ANLS- en kosten-scenario’s voor volledige pagina’s moeten afzonderlijk worden geïnterpreteerd. Deze implementatiedefecten moeten worden hersteld voordat je de scores gebruikt om een model te kiezen.
Zie voor de compacte versie over modelselectie Best OCR Models in 2026: Classical OCR, PaddleOCR-VL, VLMs.
OCR bepaalt nu de downstream-kwaliteit
OCR vormt al lange tijd de basis voor archieven, postsystemen, accessibility-tools en documentmanagement. RAG en document agents hebben de failure modes ervan zichtbaar gemaakt voor een bredere groep engineers: een downstream-model kan tekst of tablestructuur die bij extraction is weggegooid niet herstellen.
De retrievalkwaliteit van je RAG-systeem wordt begrensd door de OCR-kwaliteit. Als extraction een table verminkt, een datum verkeerd leest of een paragraaf laat vallen, kunnen latere wijzigingen in chunking en embedding de ontbrekende informatie niet herstellen. Zulke errors kunnen een contractclausule verbergen, een factuurtotaal wijzigen of een medisch dossier corrupt maken.
OCR is daarom onderdeel van retrieval- en agent-infrastructuur, naast parsing, chunking, embedding en indexing. De errors ervan moeten afzonderlijk worden geëvalueerd in plaats van te worden opgenomen in één end-to-end score.
Wat OCR betekent in het tijdperk van foundation models
OCR zet tekst in een afbeelding om in machineleesbare characters. Document AI is het bredere systeem eromheen: layout analysis, table- en formula parsing, field extraction, semantic reasoning, provenance en validation. Sommige papers gebruiken “OCR-2.0” voor end-to-end models die verschillende van deze stages combineren, maar dat label mag het onderscheid tussen recognition en document understanding niet uitwissen.
De traditionele OCR-pipeline heeft drie kernstages:
- Text detection: lokaliseer regions die text bevatten (bijv. CRAFT, DBNet).
- Text recognition: zet gedetecteerde regions om in character sequences (bijv. CRNN).
- Post-processing: spell-checking en correctie met een language model.
Dit werkt goed voor schone documenten, maar errors in detection, recognition en post-processing kunnen zich opstapelen. Meet zowel character accuracy als downstream field accuracy, zodat een leesbare pagina geen verkeerd totaal of identifier verbergt.
Sommige end-to-end VLM-paden brengen een groter deel van deze pipeline onder in een vision encoder plus language decoder. Models zoals GOT-OCR 2.0 kunnen text en structure samen emitten, terwijl algemene VLMs fields ook naar een gevraagd schema kunnen mappen. De trade-offs zijn workload-specifieke latency, GPU- of API-kosten en het risico op plausibele text die niet in de afbeelding voorkomt.
Praktische kanttekening: een image-only model heeft gerasterde pagina’s nodig, terwijl een service die PDF accepteert de conversie intern kan afhandelen. Deskewing, rescaling en cleanup zijn pipeline-specifieke experimenten, geen verplichte verbeteringen. AWS Textract adviseert ondersteunde inputs te behouden in plaats van ze zonder onderscheid te converteren of downsamplen. Output parsing en validation blijven de verantwoordelijkheid van de applicatie.
Wat OCR-benchmarks meten en missen
De volgende datasets illustreren hoe OCR-taken verschillende metrics opleveren. Datasetgroottes en metrics beschrijven de genoemde datasetversie; gebruik voor model-scores de actuele leaderboard van elk project.
| Dataset | Year | Test Size | Languages | Primary Metric |
|---|---|---|---|---|
| FUNSD | 2019 | 50 docs | English | F1 |
| SROIE | 2019 | 400 test images | English | F1 |
| CORD | 2019 | 100 receipts | Indonesian | F1 |
| IAM | 1999 | Split-dependent | English | CER |
| OCRBench v2 | 2024 | 10,000 QA pairs | EN + CN | Score /100 |
| OmniDocBench v1.6 | 2026 | 1,651 pages | EN + CN | Composite |
Het aantal regels in IAM hangt af van de gekozen writer split en het recognition-protocol; hier wordt geen vast aantal testregels verondersteld.
De kloof tussen “benchmark” en “arena”
Geautomatiseerde benchmarkranglijsten kunnen botsen met menselijke voorkeuren omdat de inputdistributie en beoordelingscriteria verschillen.
In de OCR Arena stemmen users blind op head-to-head outputs. De live rangorde verandert naarmate nieuwe battles binnenkomen en is daarom geen reproduceerbare historische benchmark-snapshot. De versiegebonden OmniDocBench-tabel verderop in dit artikel beantwoordt een andere vraag met datasetmetrics. Combineer de twee leaderboards niet tot één score.
Waarschijnlijke oorzaken zijn de documentmix, outputformattering, language coverage en judge-criteria. Gepubliceerde getallen zijn nuttig voor screening, maar de uiteindelijke selectie vereist een held-out set uit de target-workload.
Traditionele OCR-engines: nog steeds relevant
Als traditionele engines slechter zijn op complexe data, waarom zou je ze dan gebruiken? Omdat ze snel en goedkoop zijn op schone, gestructureerde data.
Traditionele engines zijn nuttige baselines omdat ze lokaal op CPU kunnen draaien. Hun latency en accuracy hangen af van het geselecteerde model, de pagin-resolutie, taal, preprocessing en hardware. Benchmark ze daarom op dezelfde gelabelde pagina’s die je voor de VLM-evaluatie gebruikt.
| Engine | Deployment | Useful baseline for |
|---|---|---|
| Tesseract 5.5 | Local CPU | Clean printed text and established scripts |
| EasyOCR | Local PyTorch on CPU or GPU | Prototypes and scene text |
| PaddleOCR 3.x | Local CPU, GPU, and mobile variants | Multilingual OCR and deployment toolchains |
Tesseract voor schone afdrukken
Tesseract (v5.5.x, Apache 2.0) is een mature, voornamelijk CPU-engine met 100+ language packs. De accuracy op schone afdrukken kan hoog zijn na passende rasterization en preprocessing, maar handwriting, scene text en complexe layouts vereisen afzonderlijke tests. Het belangrijkste voordeel is een kleine, lokale CPU-deployment. Experimentele OpenCL-ondersteuning vormt geen algemeen bewijs voor een performancevoordeel.
EasyOCR
EasyOCR combineert een CRAFT-detector met een CRNN-recognizer. Met volledige PyTorch GPU-acceleration is het een snelle optie voor quick prototyping en scene text.
Het snippet vereist pip install easyocr, PyTorch, de gedownloade model weights van EasyOCR en een lokale receipt.jpg. Het is syntax-checked maar niet uitgevoerd door de Markdown-runner van de repo.
import easyocr
# Three lines for complete OCR
reader = easyocr.Reader(["en"])
result = reader.readtext("receipt.jpg")
# Returns: [(bbox, text, confidence), ...]
PaddleOCR 3
PaddleOCR 3 bundelt onderhouden OCR-, document-parsing- en deployment-pipelines. De huidige quick start gebruikt de predict()-API en expliciete orientation-instellingen. Pin het paddleocr-package en de geselecteerde pipeline, omdat 2.x-examples met .ocr(..., cls=True) niet overeenkomen met de 3.x-API.
Het snippet vereist pip install "paddleocr>=3,<4", een compatibele PaddlePaddle-runtime, gedownloade model weights en een lokale receipt.jpg. Het is syntax-checked maar niet uitgevoerd door de Markdown-runner van de repo.
from paddleocr import PaddleOCR
ocr = PaddleOCR(
use_doc_orientation_classify=False,
use_doc_unwarping=False,
use_textline_orientation=False,
)
for result in ocr.predict("receipt.jpg"):
result.print()
result.save_to_json("output")
Gespecialiseerde en algemene VLM-opties
Scheve receipts, scheefstaande productlabels, handschrift en dense layouts zijn de situaties waarin gespecialiseerde of algemene VLMs het testen tegenover traditionele engines waard worden.
De golf van gespecialiseerde OCR
De modellijst in deze sectie is gecontroleerd op 2026-09-06. Het is geen actuele ranking. Gespecialiseerde document-parsing-models die tussen 2024 en 2026 zijn gepubliceerd, zijn onder meer:
- PaddleOCR-VL 1.6: Een two-stage pipeline die eerst layout analysis uitvoert en daarna een 0.9B VLM-component gebruikt op gedetecteerde regions. PaddleOCR rapporteert 109 talen en 96.3 op OmniDocBench v1.6; koppel dit vendor-resultaat aan de genoemde pipeline en benchmarkversie.
- dots.mocr (3B): De rebrand van maart 2026 van dots.ocr-1.5 parseert text en structured graphics, waaronder een SVG-georiënteerde variant. Het oorspronkelijke dots.ocr blijft een afzonderlijk model uit 2025.
- GOT-OCR 2.0: Een unified model met 580M parameters dat plain text en geformatteerde outputs zoals Markdown en LaTeX emit. De officiële repo publiceert geen minimum-VRAM-getal. Meet daarom het piekgeheugen met de gekozen runtime, precision, image size en outputlimiet.
- DeepSeek-OCR2: Het checkpoint dat op de snapshotdatum in de officiële repo is gedocumenteerd, als opvolger van het oorspronkelijke 3B-class DeepSeek-OCR-model dat “contextual optical compression” introduceerde. Behandel throughputcijfers voor beide generaties als hardware- en dataset-specifiek.
- Mistral OCR 4.1 (
mistral-ocr-4-1): De model card dateert de release op 16 juli 2026; de changelog vermeldt general availability op 31 augustus. Het voegt block confidence toe naast paragraph boxes en structural labels. Calibreer confidence tegen field correctness voordat je automatisch accepteert. De OCR 3-identifier van de companion beschrijft historische execution-context en is niet de huidige candidate of prijs. Pin een expliciete versie voor vergelijkingen; eenlatest-alias kan veranderen. - Granite-Docling 258M: Emit DocTags die kunnen worden omgezet naar een gestructureerde
DoclingDocument. Doclings VLM-pipeline moet expliciet worden geselecteerd; een default converter is geen bewijs dat dit model is uitgevoerd. - MinerU en olmOCR: Kandidaten voor respectievelijk structured conversion en document linearization. Inspecteer hun volledige pipelines en de geselecteerde modell licenties. De modelvoorwaarden van MinerU voegen voorwaarden toe aan een Apache 2.0-basis, dus de licentie van de library alleen bepaalt niet de deploymentrechten.
Frontier VLMs
Algemene VLMs zijn een andere optie wanneer de task extraction combineert met visual of semantic reasoning. Deze kandidaten zijn gecontroleerd op 2026-09-06 en worden gebruikt in het gateway-example hieronder. Het is een startende shortlist, geen OCR-ranking:
- Gemini 3.8 Flash (Google): Een algemeen beschikbaar multimodaal model met image input en structured outputs. Gebruik de stable ID wanneer je een nieuwe vergelijking start, in plaats van het oudere Gemini 3 Flash Preview-example.
- Claude Sonnet 5 (Anthropic): Een nieuwere Sonnet-generatie voor een hosted vergelijking. Test transcription fidelity en field extraction op je eigen documenten; verbeteringen in algemene reasoning bewijzen geen OCR-accuracy.
- Qwen3.8-27B (Alibaba): Een open-weight vision-language model dat via een gateway of self-hosted kan worden getest. De omvang van 27B maakt dit een andere deploymentkeuze dan het eerdere Qwen3-VL 8B, dat een nuttige kleinere baseline blijft wanneer memory beperkt is.
Een nieuwere release verdient een plaats in de testset, niet automatisch een promotie naar production. Vergelijk field correctness, abstention, latency en cost per accepted document onder hetzelfde protocol.
Meet latency per tier
Meet page latency met de werkelijke resolution, batch size, hardware of provider region en outputlengte. Neem preprocessing en retries mee in het totaal; een model-only timing kan de kosten van een succesvolle pagina niet bepalen.
Metrics: meten wat ertoe doet
Kies een metric die past bij het outputtype:
- CER en WER voor plain text. Character en Word Error Rate hangen af van normalization-keuzes zoals case, whitespace en punctuation. Leg daarom eerst het vergelijkingsprotocol vast voordat je models vergelijkt.
- Field exact match en Field F1 voor forms en receipts. Exact match is binair voor één field; het percentage is het aandeel geëvalueerde fields dat slaagt. Rapporteer document-level all-fields correctness afzonderlijk. Definieer voor Field F1 de matching van key/value-paren, normalization, duplicate en missing fields en aggregation; een correct bedrag dat aan de verkeerde rij is toegewezen, is een error.
- TEDS voor tables. Tree-Edit-Distance-based Similarity vergelijkt voorspelde en referentie-HTML-trees en detecteert structurele errors en fouten in cell content die CER verbergt.
- Reading-order comparison wanneer de consumer één lineaire sequence nodig heeft. Vergelijk ordered blocks of spans direct, of gebruik een order-aware metric; OmniDocBench evalueert reading order afzonderlijk. Correcte characters en table cells bepalen niet de volgorde van een pagina met meerdere kolommen.
- ANLS voor document VQA. Average Normalized Levenshtein Similarity scoort antwoorden tegen geaccepteerde referenties. De oorspronkelijke ST-VQA-definitie kent
1 − normalized_distancealleen toe wanneer de distance strikt kleiner is dan 0.5; anders is de score nul. De beste score tegen een geaccepteerde referentie wordt genomen en over de questions gemiddeld. DocVQA gebruikt ANLS. Pin de case-, whitespace- en distance-normalization van de evaluator wanneer je een score reproduceert. De companion scoort daarentegen strings van volledige pagina’s en neemt de 0.5-grens mee, waardoor de variant niet overeenkomt met het benchmarkprotocol.
CER/WER tellen substitutions, deletions en insertions gedeeld door respectievelijk reference characters of words. Ze kunnen hoger dan één worden wanneer insertions domineren. Vermeld of aggregation corpus-errors en referentielengtes optelt of documentscores gemiddeld. Bewaar page, block, bounding box, original text en de normalization history, zodat een verkeerd field tot aan de afbeelding kan worden getraceerd.
Voor implementaties: jiwer verwerkt CER/WER out of the box en TEDS-implementaties staan in de OmniDocBench-repo.
VLMs testen met OpenRouter
OpenRouter biedt een OpenAI-compatible gateway naar models van verschillende providers. Model IDs en ondersteunde request-features veranderen, dus controleer ze tegen de actuele catalogus van de gateway voordat je het example uitvoert.
Het snippet vereist pip install openai, een OPENROUTER_API_KEY, network access, een lokale receipt.jpg en model IDs die nog door OpenRouter worden ondersteund. Het is syntax-checked maar niet uitgevoerd door de Markdown-runner van de repo.
import base64
import os
from openai import OpenAI
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.environ["OPENROUTER_API_KEY"],
)
def extract_text(image_path: str, model: str) -> str:
with open(image_path, "rb") as f:
image_b64 = base64.b64encode(f.read()).decode()
response = client.chat.completions.create(
model=model,
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Extract all text from this image, preserving layout as markdown."},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{image_b64}"}},
],
}],
max_tokens=4096,
)
choice = response.choices[0]
if choice.finish_reason != "stop":
raise RuntimeError(f"{model} did not finish: {choice.finish_reason}")
if not choice.message.content:
raise RuntimeError(f"{model} returned no text (finish_reason={choice.finish_reason})")
return choice.message.content
# Compare models by changing one string
models = [
"google/gemini-3.8-flash",
"anthropic/claude-sonnet-5",
"qwen/qwen3.8-27b",
]
for model in models:
print(f"\n--- {model} ---\n{extract_text('receipt.jpg', model)[:200]}...")
De OpenRouter-modelcatalogus vermeldde op 2026-09-06 google/gemini-3.8-flash, anthropic/claude-sonnet-5 en qwen/qwen3.8-27b met image input en structured-output-parameters. Catalog support bewijst niet dat dit exacte request op elk gerouteerd endpoint slaagt; voor deze refresh is geen betaalde inference uitgevoerd.
Gebruik voor structured extraction response_format met een JSON Schema wanneer het geselecteerde model en de gateway dit ondersteunen. Dat kan de response parseable maken, maar valideert de geëxtraheerde values niet tegen de afbeelding. Bij OpenRouter zorgt provider.require_parameters ervoor dat het request faalt wanneer geen enkel gerouteerd endpoint alle gevraagde parameters ondersteunt, in plaats van terug te vallen op een endpoint dat het schema niet kan afdwingen. Het volgende block herhaalt de setup zodat het zelfstandig leesbaar is. Het vereist nog steeds pip install openai, een OPENROUTER_API_KEY, network access, een lokale receipt.jpg en een model dat JSON Schema ondersteunt; de repository-runner voert alleen syntax-checks uit.
import base64
import json
import os
from openai import OpenAI
with open("receipt.jpg", "rb") as f:
image_b64 = base64.b64encode(f.read()).decode()
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.environ["OPENROUTER_API_KEY"],
)
response = client.chat.completions.create(
model="google/gemini-3.8-flash",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Extract only visible receipt fields. Copy amounts as source strings. Use null for absent or unreadable values; do not infer them. Use null for an unreadable item list, and [] only when no items are present."},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{image_b64}"}},
],
}],
max_tokens=4096,
response_format={
"type": "json_schema",
"json_schema": {
"name": "receipt",
"strict": True,
"schema": {
"type": "object",
"properties": {
"vendor": {"type": ["string", "null"]},
"date": {"type": ["string", "null"]},
"items": {
"type": ["array", "null"],
"items": {
"type": "object",
"properties": {
"description": {"type": ["string", "null"]},
"amount": {"type": ["string", "null"]},
},
"required": ["description", "amount"],
"additionalProperties": False,
},
},
"total": {"type": ["string", "null"]},
},
"required": ["vendor", "date", "items", "total"],
"additionalProperties": False,
},
},
},
extra_body={"provider": {"require_parameters": True}},
)
def completed_text(response, label: str) -> str:
choice = response.choices[0]
if choice.finish_reason != "stop":
raise RuntimeError(f"{label} did not finish: {choice.finish_reason}")
if not choice.message.content:
raise RuntimeError(
f"{label} returned no text (finish_reason={choice.finish_reason})"
)
return choice.message.content
receipt = json.loads(completed_text(response, "receipt extraction"))
Bewaar de gekopieerde amount-strings naast de genormaliseerde values. Parse money downstream met decimal of integer minor-unit arithmetic onder een expliciete currency en locale; schema-validity valideert geen betalingstotaal. Routeer null critical fields naar review.
Benchmarkresultaten: wat de getallen daadwerkelijk laten zien
De onderstaande table is één versioned snapshot: OmniDocBench v1.6_full, officiële README op commit 09ba2b606662695b16aafe5f5e36b7ef020e11a8, gepubliceerd op 2026-04-10 en geraadpleegd op 2026-08-09. Alle vier rows komen uit die gepinde table. De table combineert geen waarden uit eerdere paper tables of andere leaderboards.
| Model | Size | Overall ↑ | Text Edit ↓ | Table TEDS ↑ |
|---|---|---|---|---|
| PaddleOCR-VL-1.5 | 0.9B | 94.93 | 0.038 | 91.67 |
| GLM-OCR | 0.9B | 95.22 | 0.044 | 92.83 |
| Gemini 3 Flash | — | 92.62 | 0.066 | 89.29 |
| dots.ocr | 3B | 90.77 | 0.048 | 87.18 |
De conclusie is beperkt tot deze OmniDocBench-versie: modelgrootte alleen voorspelt de document-parsing-score niet. OmniDocBench registreerde later v1.7 en EvalScope-integratie. Wijzigingen in prediction/reference matching kunnen scores veranderen, zelfs bij identieke model-output. Bewaar de historische rows hierboven; vergelijk nieuwe runs alleen onder één gepinde evaluator. De composite bevat text edit distance, table TEDS en formula CDM; reading order vereist een afzonderlijk resultaat.
De companion berekent illustratieve metrics op vijf samples. Corrigeer pipeline identity, recognition references, failure accounting, modelnamen, metric-protocol en kostenveronderstellingen voordat je een row als vergelijkend bewijs interpreteert.
OCR in production deployen
Een tiered architecture kan CPU-preprocessing scheiden van GPU- of API-inference en dure paden reserveren voor documenten die dit nodig hebben.
Opmerking over orchestration: Tools zoals Docling kunnen conversion en batch processing coördineren. Retry policy hoort nog steeds bij de omringende applicatie of service, en routing heeft eigen quality labels en thresholds nodig.
Het tiered fallback pattern
Begin met het goedkoopste pad dat het kwaliteitsdoel haalt en calibreer routing vervolgens op gelabelde pagina’s:
- Controleer embedded text (Tier 0). Inspecteer bij PDF’s de text layer met
PyMuPDFofpdfplumbervoordat je rasteriseert, maar valideer dat de layer volledig en correct geordend is. - Probeer een snel model. Gebruik een traditionele engine voor documentklassen waarvoor deze het target haalt.
- Evalueer calibrated confidence. Combineer model confidence met document class, field criticality en validation rules.
- Escalate naar een sterker model. Routeer onzekere pagina’s naar een gespecialiseerde of algemene VLM.
- Escalate high-risk failures naar een human. Human review is een afzonderlijke tier voor values waarvan de cost of error groter is dan de automation benefit.
Opmerking over confidence: Raw character probabilities zijn niet automatisch gecalibreerd op field correctness. De onderstaande area-weighted function is een baseline voor page-level aggregation, geen universele router. Calibreer deze tegen gelabelde pagina’s en geef critical fields eigen rules, omdat een paginagemiddelde een verkeerde ID of een verkeerd totaal kan verbergen.
def area_weighted_confidence(page):
"""Compute area-weighted confidence from one PaddleOCR 3.x result."""
total_area, weighted_sum = 0, 0
for (x_min, y_min, x_max, y_max), score in zip(
page["rec_boxes"], page["rec_scores"]
):
width = int(x_max) - int(x_min)
height = int(y_max) - int(y_min)
area = width * height
weighted_sum += score * area
total_area += area
return weighted_sum / total_area if total_area > 0 else 0
assert area_weighted_confidence({
"rec_boxes": [[0, 0, 300, 300]], "rec_scores": [0.5]
}) == 0.5
Bewaar voor elk gepland engine/document-paar een resultaat met status success, error of skipped. Failed, empty en truncated outputs blijven in de attempted-document-denominator staan, samen met de gemaakte kosten. Rapporteer completion rate, critical-field errors onder automatische acceptances, review fraction, p50/p95 end-to-end latency en cost per successfully processed document. Hergebruik converterobjecten voor warm timings en registreer initialization afzonderlijk.
Kostenanalyse op schaal
Er is geen universeel break-evenpunt op basis van page volume tussen een API en self-hosting. Bouw de vergelijking op uit dezelfde workload:
| Cost component | API path | Self-hosted path |
|---|---|---|
| Inference | Current page- or token-based price | GPU-hours at measured pages/hour |
| Idle capacity | Usually absorbed by provider | Utilization and capacity slack |
| Engineering | Integration and provider monitoring | Deployment, upgrades, observability, and on-call |
| Data handling | Transfer, retention, and region terms | Storage, network, and compliance controls |
| Quality failures | Retries and human review | Retries and human review |
Gebruik een gedeelde formule: monthly pages × cost per successful page + review cost + fixed operating cost. Een “successful page” moet op beide paden aan dezelfde text-, table- en field-criteria voldoen. Providerprijzen en GPU-rentals veranderen te snel om als duurzame procurement-estimate te worden ingebouwd.
Error handling: het hallucination-probleem
VLM-errors kunnen contextueel plausibel maar feitelijk onjuist zijn. Een receipt-totaal van “$42.50” kan “$45.20” worden: syntactisch geldig, maar onzichtbaar voor een spell-checker.
Synthetic failure example: Een VLM extraheert drie receipt line items en een stated total die onderling overeenkomen, maar één digit wijkt af van de afbeelding. De interne arithmetic slaagt, hoewel de extraction verkeerd is. Daarom heeft validation image-grounded labels of een independent review path nodig, niet alleen consistency checks.
Enkele praktische mitigations:
- Arithmetic reconciliation. Controleer, wanneer het schema deze exposeert,
subtotal + tax + fees + shipping - discountsbinnen de rounding tolerance van de currency tegen het stated total. Routeer ontbrekende components of mismatches naar review. - Regex sanity checks voor dates (geen maand 13), telefoonnummers (correct digit count) en currency formats.
- Cross-model verification. Stuur critical fields door twee verschillende models en flag disagreements.
- Independent OCR cross-check. Voer een tweede extraction path uit op critical figures en flag disagreements. Agreement verhoogt confidence alleen wanneer de twee paths voldoende verschillende failure modes hebben; het is geen bewijs van correctness.
Belangrijkste conclusies
- Stem de modeltier af op een gelabelde documentklasse. Traditionele engines kunnen volstaan voor schone text; gespecialiseerde en algemene VLMs moeten hun extra kosten op moeilijkere pagina’s rechtvaardigen.
- Voeg ongelijke leaderboards niet samen. OmniDocBench-metrics en OCR Arena-voorkeuren beantwoorden verschillende vragen.
- Calibreer routing. Confidence thresholds, documentklassen, field criticality en human-reviewbeleid horen in één evaluation.
- Valideer plausibele output. Schema-conformance en interne arithmetic kunnen niet bewijzen dat een value in de afbeelding voorkomt.
- Prijs succesvolle pagina’s. Neem retries, review, vaste operationele kosten en quality checks mee wanneer je APIs met self-hosting vergelijkt.
Preprocessing en detection blijven belangrijk, maar production OCR vereist nu ook routing, task-specifieke evaluation en bescherming tegen plausibele extraction-errors.
Referenties
- OCR Arena Leaderboard - Crowdsourced head-to-head modelbattles
- The OCR Gauntlet repo - Uitvoerbare notebooks voor het vergelijken van OCR-engines, het inspecteren van Docling-output en het schatten van kosten
- OmniDocBench - End-to-end document-parsing-eval
- dots.ocr - Ongeveer 3B totale parameters, inclusief een language model van 1.7B
- PaddleOCR - Traditionele OCR-toolkit en models
- OpenRouter - Unified access gateway voor A/B-testing van models