Layout-aware parsing with PyMuPDF4LLM

Every vectorless pipeline starts the same way: turn the PDF into a structured representation that exposes headings and page boundaries. Most PDF libraries give you a flat stream of text. PyMuPDF4LLM gives you markdown with heading levels preserved, which is exactly what we need to build a tree.

terminal
bash
# Clone the workshop
git clone https://github.com/learnwithparam/vectorless-rag
cd vectorless-rag

# One command to set up and run
make dev

# Or step by step
make setup
make run

The Makefile handles uv, dependency installation, env file creation, and the first run against the Bigtable paper.

tree.py
python
import pymupdf4llm

# Method one: get full markdown for structure detection
full_md = pymupdf4llm.to_markdown(str(pdf_path))

# Method two: get page-indexed chunks for accurate pagination
page_chunks = pymupdf4llm.to_markdown(
    str(pdf_path),
    page_chunks=True,
    write_images=False,
    embed_images=False,
)

# Build a page-to-text index we can lookup later
page_contents = {i + 1: chunk["text"] for i, chunk in enumerate(page_chunks)}
total_pages = len(page_chunks)

We call PyMuPDF4LLM twice. The first call gives us a single markdown string where headings become hash-prefixed lines. The second returns per-page chunks that let us match content back to a specific page number.

Why two parsing calls? The full markdown is what we scan for headings to build the tree hierarchy. The per-page chunks are what we use to assign accurate page ranges to each node. Without the second call, our citations would be rough estimates based on line position.

Quiz: Quiz

Loading practice…