Parsers & OCR
Every uploaded document is converted to structured Markdown-like blocks
(headings, tables, text) before it's chunked and embedded. Which engine does
that conversion is a single superadmin choice — document_parser, set
in Admin → Settings — that applies to every new ingestion across the
whole install.
Citations are only as good as the parser
A citation's page number is only as accurate as the parser that produced
it. Parsers without real page boundaries stamp page=1 on every chunk, so
every citation from that document says page 1 regardless of where the text
actually came from.
The parser matrix
| Parser | Page-accurate citations | Speed (168-page, 36 MB PDF) | Runs | Notes |
|---|---|---|---|---|
| liteparse (default) | Yes — real page_num per page | 2.6 s | Self-hosted (run-llama, PDFium) | Fast and page-accurate; OCR off by default (text PDFs). |
| anydoc | No — every chunk is page=1 | 0.92 s (fastest) | Self-hosted (pure-Rust) | Best throughput, but citations lose page numbers. Falls back to Docling OCR automatically if a PDF fails to convert. |
| docling | Yes — page-accurate | 103 s (slow) | Self-hosted | OCRs scanned pages (EasyOCR) as part of the same pass. |
| llamaparse | Yes — page-accurate | Cloud-dependent | LlamaIndex cloud API | Needs an API key (Admin → Settings); document bytes leave your infrastructure. |
liteparse is roughly 40× faster than docling at equal page accuracy, and only about 3× slower than the page-blind anydoc — which is why it's the default for new installs.
Switching the parser
Admin → Settings → Document Parser — pick liteparse, anydoc,
docling, or llamaparse (the latter also needs a LlamaParse API key set in
the same page). The change takes effect immediately for the next ingestion —
no restart required.
Existing documents need a re-parse
Page numbers are baked into a document's chunks at parse time, not at embed time. Switching the parser only changes how new uploads are processed — documents already ingested keep whatever page accuracy their original parser produced. To bring existing documents up to the new parser's accuracy, they must be re-parsed (delete the document's vector points and re-run ingestion from the stored source file), not just re-embedded.
OCR for scanned PDFs
Scanned or image-only PDFs — pages with fewer than
RAGZ_OCR_MIN_CHARS_PER_PAGE (default 200) characters of extractable text
— automatically fall back to Docling's OCR path (EasyOCR), regardless of
which parser is selected for text PDFs. anydoc in particular routes
unconvertible PDFs straight to this fallback.
- First OCR use downloads roughly 90 MB of EasyOCR models to
~/.EasyOCRon the Celery worker host. - Kill switch: set
RAGZ_OCR_ENABLED=falseto disable OCR entirely — a scanned PDF then ingests with whatever (little) text the parser can extract directly, rather than triggering a model download and OCR pass. - OCR sensitivity is tunable via
RAGZ_OCR_MIN_CHARS_PER_PAGE— raise it to catch more marginal pages, lower it to trust direct text extraction more.
Choosing a parser
- Default install, mixed document types:
liteparse— page-accurate citations at a small speed cost. - Bulk ingestion where page numbers don't matter (e.g. FAQ snippets,
short docs):
anydocfor maximum throughput. - Heavy scanned-document corpora:
docling, since OCR is folded into the same pass either way. - No local compute for parsing, and cloud egress is acceptable:
llamaparse.