← All lessons
Lesson 32 RAG and documents 5:23

Parsing PDFs for RAG: from PyPDF to dots.ocr

The first link in the pipeline is the one nobody looks at: text extraction. Why not all PDFs are equal, four tools in order of power (and requirements), and three questions to pick the right one without wasting GPU time.

The video loads only if you ask: no request to YouTube before the click.

The video is in Italian; this page is the written version in English.

A carefully built RAG that answers badly. The first reaction is to blame the language model, the second the embeddings. Almost always the problem sits before both: at the moment the text is extracted from the PDFs. If parsing drops a table or shuffles the columns, nothing downstream can repair it. It is the classic garbage in, garbage out, and it counts double because the error goes into the database and stays there.

Not all PDFs are equal

A PDF can hold text in two ways that have nothing in common.

"Digital" PDF                            "Scanned" PDF
text is encoded as characters            each page is an image
→ just read it                           → an OCR has to "look" at it

Digital PDFs are most modern books, papers and manuals: the text is already inside the file, you can select it with the mouse. Scanned PDFs are photocopies, old books, digitised paperwork: pixels, not letters. Then there are the mixed ones: native text for the body, but tables, formulas and charts pasted in as images. Those are the deceptive ones, because basic tools work on them “fine” and silently lose the part that mattered.

The practical rule that settles half the cases: open the PDF and try to select the text. If you can, the first level is enough.

Level 1: PyPDF and PyMuPDF

These are the foundations. Lightweight libraries, no models, instant: hundreds of pages per second.

from pypdf import PdfReader

reader = PdfReader("book.pdf")
for page in reader.pages:
    text = page.extract_text()

PyMuPDF (fitz) does the same faster and adds extraction of images, links and metadata. Neither does OCR, understands tables or recognises layout: on a digital PDF with linear text they are excellent, on everything else they lose structure without saying so. The knowledge bot built on game-design books uses PyPDF and never needed anything more: 232 chapters, 5,234 chunks, digital PDFs.

Level 2: the specialists, Docling and Marker

When structure matters, you need tools that understand the page rather than read it.

Docling (IBM Research) combines two models: one recognises the layout (headings, paragraphs, tables, figures, footnotes), the other rebuilds tables cell by cell, merged and nested ones included. The number that stands out is table accuracy, 97.9%. It runs on CPU and on a Mac, about four seconds per page, and returns Markdown or JSON ready for chunking.

from docling.document_converter import DocumentConverter

result = DocumentConverter().convert("report.pdf")
markdown = result.document.export_to_markdown()

Marker (Datalab) is a complete OCR pipeline: base text, scanned-page recognition, layout, Markdown. Its strengths are mathematical formulas, converted to LaTeX, and languages: more than ninety. GPU optional, and it also runs on the accelerator of Apple Silicon Macs. If you work with scientific papers, this is the one.

Level 3: dots.ocr, one model for everything

Here the approach changes. Docling and Marker are pipelines: one model for layout, one for OCR, one for tables, chained. dots.ocr is a single vision-language model that looks at the page image and directly produces structured output: text, tables as HTML, formulas as LaTeX, even charts as SVG.

Pipeline:   PDF → layout → OCR → tables → output     (three models)
dots.ocr:   PDF → VLM → output                       (just one)

On benchmarks it is state of the art, and on text and tables it beats some well-known commercial models. The price is hardware: it needs an NVIDIA GPU with at least 8 GB of memory, installation goes through CUDA, and it does not run on a Mac. It is the tool for a server that has to digest difficult scans in bulk, not for a laptop.

How to choose: three questions

QuestionIf the answer is…Then
What kind of PDF do I have?Selectable textPyPDF or PyMuPDF, and you are done
Complex tables, multi-column layoutDocling
Formulas, scientific papersMarker
Hard scans, charts, all of the abovedots.ocr
What hardware do I have?CPU only, or a MacDocling or Marker
NVIDIA GPUdots.ocr becomes an option
What do I really need?Fast, “good enough” extractionThe lowest level that works
Absolute fidelity of tables and formulasThe highest level the hardware can run
Can the text be selected?
├── YES → PyPDF / PyMuPDF
└── NO, or tables and formulas are critical
    ├── NVIDIA GPU available? → dots.ocr
    ├── tables matter most → Docling (CPU/Mac)
    ├── formulas matter most → Marker (CPU/Mac/MPS)
    └── general case without GPU → Docling

The typical mistake: one parser for all

You pick PyPDF because it is fast, try it on two clean PDFs, it works, and you run it on a thousand mixed company documents. The RAG answers badly and nobody understands why: the contract tables are gone, the report headers got mixed into the body, the charts became empty strings. Broken text went into the vector database, and the model quotes it with complete confidence.

The approach that works is a triage: classify documents before extracting them (digital, complex, scanned) and route each one to the parser it deserves. Not all to the most powerful: reprocessing a digital PDF with dots.ocr wastes hours and GPU time and improves nothing.

Where the field is going

2020-2023  modular pipelines: OCR → layout → post-processing
2024       integrated frameworks: Docling, Marker
2025+      unified models: one VLM looks at the page and does it all

The direction is clear: from chains of components to single models that understand the whole page. But it does not make the simple tools obsolete. For a digital PDF, PyPDF remains the smartest choice: no dependencies, no waiting, no model to download. It is worth asking whether the weakest link in your system is precisely the first one.

In short

ConceptIn one line
Why it mattersBadly extracted text enters the database and no model repairs it
The test to run firstIf the PDF’s text can be selected, PyPDF or PyMuPDF is enough
DoclingLayout and tables (97.9%) on CPU and Mac
MarkerFormulas to LaTeX, 90+ languages, Mac too
dots.ocrOne model, top quality, but an NVIDIA GPU is mandatory
How to choosePDF type, hardware, required precision; then a per-document triage

Related lessons

  • What RAG is: letting a model read your documents

    A model does not know your files. RAG lets it consult them at question time: search first, then answer. It is the difference between a closed-book and an open-book exam.

  • Chunking: how documents get split

    The most underrated choice in the whole RAG pipeline. What the system can find depends on how you cut the text: bad chunking wastes the best embedding model and the best LLM.

  • Building a local RAG, from PDF to answer

    The full pipeline on a single machine: extract the text from PDFs, index it, query it. With the places where it actually trips up and how to tell whether it is working.

Watch on YouTube