A Shortcut to High-Quality PDF Extraction
12 min read
—

Shanay Mehta
MTS @ DevRev

Anirudh Jayakishan
Ex-MTS Intern @ DevRev
Category
A lot of the PDFs that flow through an enterprise are straightforward: a report exported from Google Docs, a contract generated by a CRM, a spec sheet saved from Word. The text is right there in the file, fully addressable, ready to be read out in microseconds. Yet production OCR systems routinely spend GPU time running a vision model over these pages, “reading” an image of text that was never an image to begin with. It is the equivalent of taking a photograph of a book and then asking someone to transcribe it, when the book is already open in front of you.
At DevRev, we deployed a production document extraction pipeline based on GLM-OCR, a vision-language model for document understanding. This post describes the hybrid document-extraction pipeline we developed and use. Its smart routing directs each page to native text extraction or GLM-OCR, avoiding GPU work for pages that do not need it and reducing median latency by 240× for roughly 27% of our traffic.
The baseline pipeline
Before describing our optimization, it is important to understand the baseline system that we are improving upon.
The GLM-OCR pipeline has two stages. First, a layout detector — PP-DocLayoutV3 running on CPU — processes each page and identifies regions: text blocks, titles, tables, formulas, images, and other structural elements, returning their bounding boxes and type labels. Second, each detected region is cropped and sent to GLM-OCR, a vision-language model served on a GPU, which reads the cropped image and produces structured text (markdown for text regions, formatted tables for table regions, LaTeX for formulas, and so on.).

This baseline is accurate across the full spectrum of PDFs — it handles born-digital text, scans, tables, and formulas uniformly because the VLM sees each region as an image and interprets it visually. However, it is also uniformly expensive: every region on every page, regardless of difficulty, requires a GPU inference call. Each call carries the cost of queuing (which under load can add significant wait time) and autoregressive decoding (the model generates the region’s text token by token, so processing time scales with output length). In practice, a single request — including queue wait and decoding — can take anywhere from seconds to as long as ten minutes under heavy load. For born-digital PDF pages — where the content is already fully embedded in the file and could be extracted in milliseconds — we are paying this cost to “read” an image of something that was never an image to begin with.
The inefficiency we identified
We are spending GPU time to "read" text that was never an image in the first place. On born-digital pages, the characters and their coordinates already live in the file — yet the baseline still routes them through an expensive vision model. This is the inefficiency in the baseline pipeline that we set out to address.
The hybrid architecture
We augmented the baseline with a fast path: native text extraction using PyMuPDF (fitz). When a PDF page is born-digital, the characters and their coordinates are already in the file — PyMuPDF reads them out directly. There is no model inference, no GPU, and the latency is dominated by PDF parsing. It is essentially free.
The resulting hybrid architecture has three components:
- Layout detector (PP-DocLayoutV3, CPU) — detects regions on every page and returns their bounding boxes and type labels. This runs unconditionally, because we need the region structure both to drive the VLM with targeted crops and to determine whether a page is eligible for the fast path.
- Fast path (PyMuPDF, CPU) — extracts text natively from the PDF structure for eligible pages. Zero GPU cost.
- VLM path (GLM-OCR, GPU) — performs visual reading on cropped region images for all pages that are not eligible for native extraction.
The key question is: how do we determine which pages are eligible for the fast path without compromising accuracy?

The hybrid pipeline: layout detection runs on every page, then each page is routed to either the native fast path or the VLM based on page-level eligibility checks.
The routing decision
First attempt: routing per region
If you were designing this yourself, this is almost certainly where you'd start — and it's exactly where we started too. The layout detector already identifies every region and labels its type, so the obvious move is to route each region independently: send text regions to the fast path, and tables, formulas, and images to the VLM. It feels like it has to be the right answer. It maximizes savings by construction — on a page that is mostly text with a single table, only the table region pays for the VLM while everything else is resolved natively for free. Clean, granular, and obviously optimal.
Except it isn't. This approach did not produce acceptable results.
The problem is that layout-detector bounding boxes are approximate. They can overlap or clip neighbouring content — a box drawn around one paragraph may capture a line or two from the paragraph above or below, and nested boxes (such as a title inside a larger text block) can share the same words. The VLM is robust to this: it processes the cropped image and is capable of ignoring stray content at the edges, reading only what is semantically relevant. Native text extraction has no such capability. When PyMuPDF extracts text within an imperfect bounding box, it returns exactly the characters whose coordinates fall inside that box — including clipped fragments from neighbouring regions, and excluding words whose coordinates fall just outside the boundary. The result is duplicated lines, dropped words, and incorrect reading order at region boundaries.
The core asymmetry: the VLM is robust to noisy region boundaries; native extraction is not. Per-region routing therefore forces native extraction to rely on the layout detector’s approximate bounding boxes, which are not always reliable: a slightly incorrect crop can duplicate text, drop words, or disrupt reading order.

Per-region routing fails because detector boxes are approximate. The VLM tolerates noisy crops; native extraction takes bounding-box coordinates literally and produces corrupted output at region boundaries.
The solution: routing per page
We moved the routing decision up to the page level. We use the fast path on the entire page only when a page is unambiguously safe for native extraction. A page qualifies only when it passes all four checks:
- Every detected region on the page is a text region. Tables and formulas require structured markdown formatting (e.g. pipe-delimited tables, LaTeX) that native extraction libraries like PyMuPDF cannot produce — they can only return raw text, not reconstruct the structure. If the layout detector identifies any table, formula, or image region, the entire page is routed to the VLM.
- The page has a substantial embedded text layer (text characters ≥ 8). The page must contain at least 8 extractable characters in its text layer. This floor filters out pages that technically have a text layer but contain too little content to be meaningfully extracted natively (e.g. a page with only a page number or a single header).
- The text layer is genuinely visible, not an OCR overlay (visible-text ratio ≥ 0.7). PDFs have a text rendering mode, which controls how text is displayed. Scanned PDFs are sometimes processed by OCR tools which add a text layer to make the PDF searchable. These are often lower accuracy OCR engines and extracting this text would negatively impact the quality of our output. However, these tools add the text in render mode 3 or 7, whereas embedded text in born digital PDFs is in render mode 0. We compute the fraction of text spans drawn in a visible render mode (mode 0) versus an invisible one (mode 3 or 7). If at least 70% of the text is visible, we treat it as a genuine born-digital page. Below that threshold, the text layer is likely an OCR overlay on a scan, and we route to the VLM instead.
- Unassigned words check. After native extraction, we assign each extracted word to a layout-detected region by its center point. If any word cannot be assigned to a region, it indicates a mismatch between the text layer and the detected layout — the page may not be as clean as the other checks suggest. In this case, the page falls back to the VLM.

The page-level eligibility gate. A page falls through to the VLM at any failed check; only pages that pass all conditions are resolved natively.
Everything that fails the gate flows to the VLM unchanged. The fast path is a pure optimization layered on top of a correct VLM baseline: in the worst case it contributes nothing, and the system is no worse off than an all-VLM pipeline.
Why page-level is the right granularity
Per-region routing would yield greater theoretical savings, but the detector’s bounding boxes are too noisy to feed a method that interprets its input literally. The page is the smallest unit at which we can both (a) make a reliable statement about content type and (b) assign words to regions using global page context rather than trusting individual bounding boxes. The tradeoff is that a mixed page (e.g. one with 80% plain text and one table) goes entirely to the VLM even though most of its content could be extracted natively. We accepted this in exchange for guaranteed output correctness.
Results & impact
Across a representative corpus of 101,134 pages ingested by users in our system, the routing gate directs approximately 27% of pages (27,295) to the native fast path and the remaining 73% (73,839) to the VLM.

The fast path is approximately 240× faster on average and requires zero GPU resources. For the 27% of pages it handles, there is no GPU inference time, no queue pressure, and no batching latency. This directly increases throughput for the remaining 73% of pages that require VLM processing, since GPU capacity is not consumed by pages that could be resolved natively.
Accuracy
Across our evaluation, all accuracy metrics remained within 2–3% of the all-OCR baseline. Pages are only routed natively after conservative safety checks, and every failed check falls back to the OCR baseline.
Where this helps — and where it does not
This is a workload-dependent optimization, not a universal OCR shortcut. Its value is determined by the share of pages that are safe for native extraction under the eligibility gate.
It is especially effective for document collections with many born-digital, text-only pages: for example, reports, contracts, specifications, and exported business documents whose text is embedded in the PDF. It is much less useful for image-heavy documents, scanned pages, forms, pages with tables or formulas, and visually complex layouts. Those pages correctly remain on the OCR path, so the fast-path rate can be close to zero for an extraction-quality benchmark or a highly structured customer corpus.
Our aggregate production routing rate is roughly 27% of pages. That aggregate hides substantial customer-level variation: some customer imports contain a high proportion of clean, born-digital text pages and see 70–80% of pages take the fast path; for others, the rate is closer to 5–10%.
Model-agnostic routing
The routing approach is not specific to GLM-OCR. It combines native PDF extraction with a fallback OCR model, so the same principle applies when the fallback is replaced with another OCR or vision-language model. The speedup comes from avoiding model inference on pages whose PDF text layer is demonstrably safe to use; model quality still matters for every page that falls back.
Accuracy-first routing
Our implementation makes two deliberately conservative decisions:
- Page-level routing. We route at page level rather than region level because native extraction interprets detector boxes literally, while OCR models tolerate imperfect crops.
- Text-only eligibility. Tables, formulas, images, and any page that fails the conservative checks stay on the OCR path.
Together, these choices prioritize output quality and are consistent with only a 2–3% accuracy gap from the all-OCR baseline. However, they are not universal requirements. A team must decide what level of degradation is acceptable for its own workload.
For example, a less conservative page-level policy can allow pages containing tables or formulas to use the fast path instead of sending the entire page to OCR. Many PDFs are otherwise simple but contain a single table or formula, which is enough to route the whole page to OCR under our current policy. Allowing those pages onto the fast path could materially increase coverage, provided that imperfect Markdown table reconstruction or formula formatting is acceptable for the downstream use case.
Next steps and closing thoughts
The most immediate direction from here is mixed-page routing: currently, a page with even one non-text region (e.g. a single table on an otherwise all-text page) is routed entirely to the VLM. As layout detectors improve and produce tighter bounding boxes, it may become feasible to selectively apply native extraction to the text regions of a mixed page while routing only the complex regions to the VLM. We wrote this post because, when we set out to build this, we looked for prior work on hybrid extraction in production and found very little. The general recommendation exists — use a fast path for bulk extraction and fall back to a model for the rest — but we could not find a detailed account of how to implement that routing correctly, what fails when you try the obvious approach, or what the operational surprises look like once it is running at scale. This is our attempt to fill that gap.
References
- GLM-OCR — vision-language model for document OCR.
- PP-DocLayoutV3 (PaddleOCR) — document layout detection model.
- PyMuPDF (fitz) — Python bindings for the MuPDF library; native PDF text extraction.
1/2
DEVREV
See Computer work for you
Your AI teammate that finds answers, takes action, and gets work done across every tool.
Computer+ Apps
Our customers
Resources
Initiatives
