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

ParserPage-accurate citationsSpeed (168-page, 36 MB PDF)RunsNotes
liteparse (default)Yes — real page_num per page2.6 sSelf-hosted (run-llama, PDFium)Fast and page-accurate; OCR off by default (text PDFs).
anydocNo — every chunk is page=10.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.
doclingYes — page-accurate103 s (slow)Self-hostedOCRs scanned pages (EasyOCR) as part of the same pass.
llamaparseYes — page-accurateCloud-dependentLlamaIndex cloud APINeeds 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 ~/.EasyOCR on the Celery worker host.
  • Kill switch: set RAGZ_OCR_ENABLED=false to 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): anydoc for 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.