Document parsers for RAG pipelines: Docling, MinerU, and Unstructured

Document Parsers for Production RAG

Rank 01 · MIT
Docling
IBM Research · ~55K stars
Rank 02 · Apache 2.0*
MinerU
OpenDataLab · ~32K stars
Rank 03 · Apache 2.0
Unstructured
Unstructured-IO · Mature OSS
Docling — why it ranks #1 for production RAG
MIT license CPU viable RAG-native output Air-gap friendly PDF · DOCX · PPTX · XLSX · HTML · images
CPU speed
3.1 s/pg
GPU speed (L4)
0.49 s/pg
Min VRAM
~2 GB
Strengths
  • MIT license — zero IP risk in SaaS
  • DoclingDocument JSON preserves full hierarchy
  • HybridChunker for RAG-aware splitting
  • TableFormer — best OSS table structure model
  • Native LangChain / LlamaIndex / Haystack connectors
  • Runs on CPU, GPU, MPS (Apple Silicon)
Limitations
  • Not absolute SOTA on layout mAP (MinerU beats it)
  • Dense financial tables lose to LlamaParse (API)
  • Formula handling weaker than MinerU's UniMERNet
  • Multilingual OCR depends on chosen backend
Docling — pipeline stages
Layout detect
RT-DETR (DocLayNet 81K)
72 dpi rasterised
Table structure
TableFormer (1M+ tables)
spans, merged cells, borders
OCR
EasyOCR / Tesseract / RapidOCR / macOS Vision
pluggable backend
Formula
Equation detector → LaTeX
weaker than MinerU
Inference
onnxruntime (CUDA / MPS / CPU)
~2 GB VRAM
Output
DoclingDocument → Markdown / JSON / HTML / DocTags
hierarchy preserved
Use case 1 — Enterprise RAG ingest (legal / annual reports)
Parse a PDF with full hierarchy, extract tables as HTML, chunk semantically, push to vector store.
from docling.document_converter import DocumentConverter
from docling.chunking import HybridChunker
from langchain_docling import DoclingLoader
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

# 1. Parse — hierarchy, tables, reading order preserved
converter = DocumentConverter()
result = converter.convert("annual_report_2024.pdf")
doc = result.document

# 2. Inspect — DoclingDocument gives you structure for free
for table in doc.tables:
    print(table.export_to_html())  # TableFormer HTML

# 3. Semantic chunking — respects section boundaries
chunker = HybridChunker(tokenizer="BAAI/bge-small-en-v1.5", max_tokens=512)
chunks = list(chunker.chunk(doc))

# 4. Push to ChromaDB
texts = [c.text for c in chunks]
metas = [{"source": c.meta.origin.filename, "page": c.meta.page_no} for c in chunks]
Chroma.from_texts(texts, OpenAIEmbeddings(), metadatas=metas)
Expected output (doc.export_to_markdown() excerpt)
## Revenue by Segment (FY 2024)

| Segment | Q1 | Q2 | Q3 | Q4 | Total |
|---------|----|----|----|----|-------|
| APAC | 1.2B | 1.4B | 1.5B | 1.7B | **5.8B** |

> Section 3.2 — Risk Factors
> Exchange-rate fluctuations in emerging…
Use case 2 — Air-gapped batch pipeline (LlamaIndex)
from llama_index.readers.docling import DoclingReader
from llama_index.node_parser.docling import DoclingNodeParser
from llama_index.core import VectorStoreIndex
import glob

reader = DoclingReader()  # no API key, fully local
docs = reader.load_data(glob.glob("contracts/*.pdf"))
parser = DoclingNodeParser()  # preserves IndexNode hierarchy
nodes = parser.get_nodes_from_documents(docs)
index = VectorStoreIndex.from_nodes(nodes)
response = index.as_query_engine().query(
    "What are the termination clauses across all contracts?"
)
Side-by-side — all three tools
Dimension Docling MinerU Unstructured
LicenseMITApache 2.0 (v2.x)Apache 2.0
CPU-only viableYes (3.1 s/pg)Yes but slowerYes (4.2 s/pg)
GPU speed0.49 s/pg (L4)0.21 s/pg (L4)No benefit
Layout accuracyStrong (DocLayNet)Best-in-class (OmniDocBench)Solid
Table extractionTableFormer (strong)Best OSSGood / column shifts
Formula → LaTeXExists, weakerUniMERNet (best)Not native
Multilingual OCRBackend-dependent109 langs (PaddleOCR)Tesseract / PaddleOCR
Format breadth8 formatsPDF + Office + images25+ formats
Hallucination controlModular (low risk)VLM path has some riskSCORE best (0.027)
RAG hierarchyBest (DoclingDocument)GoodTyped elements
IntegrationFirst-partyFirst-partyFirst-party
Production costLowMedium (CUDA)Medium (many options)
Pick your parser — decision guide
Air-gap / regulated env / no GPU — need MIT license?
Docling
Scientific papers, formulas, math-heavy content?
MinerU
Multilingual corpus: CJK, Indic, Cyrillic, 109+ languages?
MinerU
Enterprise knowledge base: PDFs + emails + DOCX + Slack?
Unstructured
Best document hierarchy / sections for RAG chunking?
Docling
Lowest hallucination risk on text extraction?
Unstructured
GPU available, need fastest throughput (GPU)?
MinerU
Financial / ESG dense tables, on-prem only?
MinerU
Need S3 / SharePoint / Confluence connectors out of box?
Unstructured
LlamaIndex-first stack, broad format RAG?
Docling
Layered strategy (text fast-path + AI fallback)?
PyMuPDF → Docling → MinerU
Production-hardened pattern (from the report):
Run PyMuPDF as a fast text-layer check. If chars extracted < 10K → trigger Docling or MinerU. For numeric tables → cross-validate with Camelot. For VLM-parsed content → post-validate numbers against rule-based extraction.