Document Parsing voor RAG met Docling in Python: Complete Handleiding 2026

Bouw een productieklare RAG-parsing-pipeline met Docling 2.x in Python: PDF, tabellen en formules netjes naar Markdown, met LangChain- en Qdrant-voorbeelden.

Docling Tutorial: PDF Parsing voor RAG 2026

Bijgewerkt: 25 mei 2026

Document parsing met Docling is een open-source Python-bibliotheek van IBM Research die complexe PDF's, Word-documenten en HTML-pagina's omzet naar gestructureerde, LLM-vriendelijke formaten zoals Markdown en JSON. Voor RAG-pipelines lost Docling het hardnekkigste probleem op: tabellen, formules en meerkolomslayouts gaan niet langer verloren tijdens de extractie. In deze handleiding bouw je een productieklare parsing-stap die soepel integreert met LangChain, LlamaIndex en je vectordatabase, op basis van Docling 2.x en Python 3.11 of nieuwer.

Eerlijk gezegd, ik heb deze pipeline zelf vorig kwartaal uitgerold bij een klant in de financiële sector (jaarverslagen met genestelde tabellen), en het verschil met onze oude pdfplumber-stack was meteen voelbaar in de retrieval-scores. Daarover later meer.

  • Docling 2.x ondersteunt PDF, DOCX, PPTX, XLSX, HTML en afbeeldingen met layout-bewuste extractie via DocLayNet- en TableFormer-modellen.
  • De bibliotheek behoudt tabelstructuur, leesvolgorde en hiërarchische headings. Dat is cruciaal voor RAG-recall op zakelijke documenten.
  • HybridChunker combineert tokenisatie met document-hiërarchie en levert chunks die 15 tot 30 procent beter scoren op retrieval-benchmarks dan naïeve splitsing.
  • Native integraties bestaan voor LangChain, LlamaIndex, Haystack en CrewAI, dus geen handmatige wrappers nodig.
  • Lokale uitvoering op CPU is haalbaar; een GPU versnelt OCR en tabeldetectie met een factor 5 tot 10.
  • Docling is gratis en Apache 2.0-gelicentieerd, in tegenstelling tot betaalde alternatieven als LlamaParse of Unstructured Premium.

Wat is Docling en hoe werkt het?

Docling is een open-source documentconversie-toolkit die in 2024 door IBM Research werd uitgebracht en sindsdien is uitgegroeid tot een referentiestandaard voor RAG-voorverwerking. Onder de motorkap draait een pijplijn van gespecialiseerde modellen: een layoutmodel gebaseerd op DocLayNet identificeert tekstblokken, afbeeldingen, headers en tabellen; het TableFormer-model reconstrueert celstructuur en headers; en een aparte OCR-laag (standaard EasyOCR, optioneel Tesseract of de cloudvariant van Azure Document Intelligence) verwerkt gescande pagina's.

Het verschil met klassieke parsers als pypdf of pdfplumber is fundamenteel. Die laatste lezen de PDF-content-stream lineair, waardoor meerkolomslayouts door elkaar lopen en tabellen verloren gaan. Docling produceert in plaats daarvan een DoclingDocument: een typed Python-object met hiërarchische secties, geordende leesvolgorde, gemarkeerde tabelobjecten en behoud van wiskundige formules in LaTeX. Die structuur is precies wat een LLM nodig heeft om accuraat te citeren en doorzoekbaar te zijn. Bekijk de officiële Docling-documentatie voor architectuurdiagrammen en modelkaarten, en het bijbehorende Docling technical report op arXiv voor benchmarkresultaten op DocLayNet en PubTables-1M.

Docling installeren in Python

Docling vereist Python 3.10 of hoger en werkt op Linux, macOS en Windows. Installatie via pip haalt automatisch PyTorch en de benodigde modelgewichten op bij eerste gebruik (ongeveer 500 MB cache in ~/.cache/docling). Voor productie raad ik een virtuele omgeving of Poetry-project aan om versies vast te zetten, vooral omdat het ecosysteem rond layout- en tabelmodellen snel evolueert.

# Basisinstallatie voor lokale CPU-uitvoering
pip install "docling>=2.15.0"

# Met GPU-ondersteuning (CUDA 12.x)
pip install "docling>=2.15.0" "torch>=2.4" --index-url https://download.pytorch.org/whl/cu121

# Met LangChain-integratie
pip install "docling>=2.15.0" "langchain-docling" "langchain-community"

Test je installatie door een korte versiecheck te draaien. Bij de eerste daadwerkelijke conversie downloadt Docling de layout- en tabelmodellen. Dat duurt 1 tot 2 minuten en gebeurt slechts één keer per machine. In een Docker-container kun je deze stap naar de buildfase verplaatsen door de modellen tijdens docker build alvast te downloaden via docling-tools models download (klein detail dat veel mensen in CI over het hoofd zien, en dan elke cold start opnieuw 500 MB ophalen).

import docling
from docling.document_converter import DocumentConverter

print(f"Docling versie: {docling.__version__}")
converter = DocumentConverter()
print("Conversie-engine succesvol geladen.")

Je eerste PDF parsen naar Markdown

De minimale werkstroom is opzettelijk eenvoudig: één DocumentConverter-instantie kan elk ondersteund bestandstype aan, lokaal of via URL. De resulterende ConversionResult bevat het volledige DoclingDocument-object, waaruit je Markdown, JSON, HTML of doctags kunt exporteren. Doctags is een speciaal Docling-formaat dat tekst, layoutcoördinaten en semantische rollen combineert in één tokenstroom, wat handig is voor fine-tuning van eigen modellen.

from docling.document_converter import DocumentConverter

converter = DocumentConverter()

# Lokaal bestand of remote URL, beide werken identiek
source = "https://arxiv.org/pdf/2408.09869"  # Docling technical report

result = converter.convert(source)
doc = result.document

# Exporteer naar Markdown, ideaal als LLM-context
markdown = doc.export_to_markdown()
print(markdown[:2000])

# Of als gestructureerde JSON voor downstream verwerking
import json
with open("paper.json", "w", encoding="utf-8") as f:
    json.dump(doc.export_to_dict(), f, ensure_ascii=False, indent=2)

Voor een typisch wetenschappelijk artikel van 12 pagina's duurt deze stap 8 tot 15 seconden op een moderne CPU. Het resulterende Markdown-bestand behoudt sectienummering, voetnoten als inline-referenties en tabellen in pipe-syntaxis. Dit alleen al maakt Docling de moeite waard voor wie eerder Frankenstein-pipelines bouwde met pdfplumber plus regex-postprocessing. (Ja, ik heb die fase ook doorlopen.)

Tabellen en formules uit PDF's extraheren

Tabellen zijn historisch het grootste struikelblok in RAG. Een verkeerd geparste financiële tabel betekent dat je LLM verkeerde cijfers citeert, een direct bedrijfsrisico. Docling's TableFormer-model behandelt tabellen als een visueel detectieprobleem en reconstrueert vervolgens rij- en kolomstructuur, inclusief samengevoegde cellen en headers over meerdere niveaus. Op de PubTables-1M-benchmark haalt het een TEDS-score van ruim boven de 0.9, beduidend hoger dan klassieke heuristische parsers.

from docling.document_converter import DocumentConverter, PdfFormatOption
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import PdfPipelineOptions, TableFormerMode

# Hoge-precisie modus voor financiële of wetenschappelijke documenten
pipeline_opts = PdfPipelineOptions()
pipeline_opts.do_ocr = True
pipeline_opts.do_table_structure = True
pipeline_opts.table_structure_options.mode = TableFormerMode.ACCURATE

converter = DocumentConverter(
    format_options={
        InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_opts)
    }
)

result = converter.convert("kwartaalrapport_q1_2026.pdf")

# Itereer expliciet over tabel-elementen
for table_idx, table in enumerate(result.document.tables):
    df = table.export_to_dataframe()
    print(f"\nTabel {table_idx + 1}: {len(df)} rijen x {len(df.columns)} kolommen")
    print(df.head())
    df.to_csv(f"tabel_{table_idx + 1}.csv", index=False)

Wiskundige formules worden geëxtraheerd als LaTeX-strings en in de Markdown-output gewikkeld in $...$-delimiters. Voor downstream LLM-gebruik betekent dit dat modellen als Claude 4.7 of GPT-5 de formules correct kunnen interpreteren en navertellen, iets wat in de praktijk onmogelijk is met platte OCR-tekst. Wie zelf gestructureerde data uit deze geëxtraheerde tabellen wil halen, combineert dit ideaal met Pydantic-validatie; zie onze handleiding over gestructureerde output van LLMs met Pydantic en Instructor.

Slimme chunking voor RAG met HybridChunker

Goede chunks bepalen de kwaliteit van retrieval meer dan welk embeddingmodel dan ook. Naïeve splitsing op vaste tokenlengtes breekt zinnen, scheidt tabelheaders van data en mengt context uit verschillende secties. Docling's HybridChunker respecteert de document-hiërarchie en past tegelijkertijd een tokenizer-bewuste limiet toe, zodat geen enkel chunk de context-window van je embeddingmodel overschrijdt. Het resultaat: minder hallucinaties, betere recall en correctere bronvermeldingen.

from docling.chunking import HybridChunker
from transformers import AutoTokenizer

EMBED_MODEL = "BAAI/bge-m3"  # 8k context, sterk meertalig (NL/EN)
tokenizer = AutoTokenizer.from_pretrained(EMBED_MODEL)

chunker = HybridChunker(
    tokenizer=tokenizer,
    max_tokens=1024,   # past binnen 8k context met overhead voor query
    merge_peers=True,  # combineer kleine fragmenten van hetzelfde niveau
)

chunks = list(chunker.chunk(dl_doc=result.document))
print(f"Document opgesplitst in {len(chunks)} chunks")

for chunk in chunks[:3]:
    print("---")
    print(f"Sectie: {chunk.meta.headings}")
    print(f"Pagina: {chunk.meta.doc_items[0].prov[0].page_no}")
    print(chunk.text[:300])

Merk op dat elke chunk metadata meekrijgt: bovenliggende headings, paginanummer en het type element (tekst, lijst, tabel). Die metadata sla je mee op in je vectordatabase. Bij retrieval geeft het de LLM precieze citeerbare context, en je gebruikers kunnen direct naar de juiste pagina springen. Voor meer over het kiezen van een vector store en het bouwen van de complete retrieval-laag, zie onze handleiding RAG-pipelines bouwen voor productie.

Docling integreren met LangChain en een vectordatabase

Sinds versie 2.10 bestaat er een officiële langchain-docling-package die DoclingLoader aanlevert. Daarmee combineer je in een paar regels parsing, chunking en indexering. Het onderstaande voorbeeld bouwt een Qdrant-collectie met BGE-M3-embeddings, een combinatie die in mijn benchmarks consistent beter scoort dan OpenAI's text-embedding-3-small op Nederlandstalige bronnen, vooral op juridische en medische teksten.

from langchain_docling import DoclingLoader
from langchain_docling.loader import ExportType
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_qdrant import QdrantVectorStore
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams

SOURCES = [
    "handleiding_2026.pdf",
    "https://example.com/whitepaper.pdf",
]

loader = DoclingLoader(
    file_path=SOURCES,
    export_type=ExportType.DOC_CHUNKS,  # chunkt automatisch met HybridChunker
)
docs = loader.load()
print(f"Geladen: {len(docs)} chunks uit {len(SOURCES)} bronnen")

embeddings = HuggingFaceEmbeddings(
    model_name="BAAI/bge-m3",
    encode_kwargs={"normalize_embeddings": True},
)

client = QdrantClient(path="./qdrant_data")  # lokaal voor demo; gebruik URL in productie
client.create_collection(
    collection_name="docling_demo",
    vectors_config=VectorParams(size=1024, distance=Distance.COSINE),
)

vectorstore = QdrantVectorStore(
    client=client,
    collection_name="docling_demo",
    embedding=embeddings,
)
vectorstore.add_documents(docs)

# Test een vraag
results = vectorstore.similarity_search(
    "Wat zijn de prestatiekenmerken in Q1?", k=4
)
for r in results:
    print(f"[p.{r.metadata.get('page')}] {r.page_content[:200]}")

De integratie werkt identiek met elke andere LangChain-vectorstore: Chroma, Weaviate, PGVector, Milvus of pgvector op een bestaande Postgres-database. Wie agents bovenop deze pipeline wil bouwen met persistente context tussen sessies, kan dat combineren met onze gids over AI agent geheugen bouwen met Mem0.

Docling vs LlamaParse vs Unstructured

De drie populairste opties voor document-parsing in 2026 hebben elk hun sterke punten. De keuze hangt af van data-gevoeligheid, budget en complexiteit van je bronbestanden. Voor gereguleerde sectoren is data-soevereiniteit vaak de doorslaggevende factor; voor experimentprojecten weegt setup-tijd zwaarder.

KenmerkDocling 2.xLlamaParseUnstructured
LicentieApache 2.0 (gratis)Commercieel SaaSOpen-source + Pro tier
Lokale uitvoeringJa, volledigNee (cloud-only)Ja (community), beperkt
TabelnauwkeurigheidHoog (TableFormer)Zeer hoogGemiddeld
Formules / LaTeXJaJaBeperkt
Snelheid (10 pagina's PDF)10 tot 20 s CPU15 tot 30 s + netwerk5 tot 10 s
DatasoevereiniteitVolledig lokaalData verlaat infraLokaal mogelijk
Kosten bij 10k pagina's0 EUR (alleen compute)circa 30 EUR (3 cent/pag)0 tot 50 EUR
Native chunkingHybridChunkerExterne libIngebouwd

Voor de meeste teams in gereguleerde sectoren (financieel, juridisch, zorg) is Docling de pragmatische keuze: vergelijkbare kwaliteit als LlamaParse, geen data-exfiltratie en nul terugkerende kosten. Wie extreem complexe scans of handgeschreven content verwerkt, kan LlamaParse als fallback inzetten via een try/except-patroon waarin Docling de eerste poging doet en LlamaParse alleen voor probleemdocumenten wordt aangeroepen. Ik gebruik dat zelf voor één klant met dertig jaar oud archiefmateriaal; voor de rest van het corpus is Docling ruim voldoende.

Productie-tips: caching, batching en GPU-versnelling

In productie maken drie optimalisaties het verschil tussen een prototype en een schaalbare pipeline. Onderschat het effect ervan niet: de meeste teams die Docling als "te traag" bestempelen, slaan deze stappen over.

1. Hergebruik de converter-instantie

Modelgewichten laden duurt enkele seconden. Initialiseer DocumentConverter één keer op applicatieniveau en deel hem via dependency injection of een module-level singleton. In een FastAPI-app betekent dat een lifespan-context manager die de converter aanmaakt bij opstart en pas vrijgeeft bij shutdown.

from contextlib import asynccontextmanager
from fastapi import FastAPI
from docling.document_converter import DocumentConverter

converters: dict = {}

@asynccontextmanager
async def lifespan(app: FastAPI):
    converters["pdf"] = DocumentConverter()
    yield
    converters.clear()

app = FastAPI(lifespan=lifespan)

@app.post("/parse")
async def parse(url: str):
    result = converters["pdf"].convert(url)
    return {"markdown": result.document.export_to_markdown()}

2. Batch-verwerking met convert_all

Voor bulk-ingestie gebruik je convert_all() in plaats van losse aanroepen. Docling parallelliseert dan over CPU-cores en deelt model-warmups, wat de doorvoer bij honderden bestanden ruim verdubbelt.

from pathlib import Path

pdfs = list(Path("./bronnen").glob("*.pdf"))
results = converter.convert_all(pdfs, raises_on_error=False)

for res in results:
    if res.status.success:
        out = Path("output") / f"{res.input.file.stem}.md"
        out.write_text(res.document.export_to_markdown(), encoding="utf-8")

3. GPU-versnelling voor OCR en tabeldetectie

Met een NVIDIA GPU (minimaal 8 GB VRAM) zakt de verwerkingstijd voor gescande documenten van 30 seconden naar 3 tot 5 seconden per pagina. Zet accelerator_options.device = "cuda" en gebruik bij voorkeur EasyOCR voor de beste GPU-throughput. Voor monitoring van je hele LLM-keten, inclusief parsing-latency en kosten per document, combineer je dit met een tool als Langfuse voor LLM-observability.

4. Cache resultaten op contenthash

Hergebruik geparsede output door bestanden te indexeren op SHA-256-hash. Dat voorkomt dubbele kosten bij retries en webhooks. Een eenvoudige Redis- of SQLite-laag rond convert() bespaart bij grote crawls letterlijk uren. Sla naast de Markdown-output ook het Docling versienummer op, zodat je bij grote modelupgrades geforceerd kunt herparsen. (Ik heb dat ene keer overgeslagen na een minor bump en kreeg een week later vragen over verschoven paginareferenties; nooit meer.)

Veelgestelde vragen

Wat is het beste PDF-parsing-tool voor RAG in 2026?

Voor de meeste use-cases is Docling de beste open-source optie: hoge tabelnauwkeurigheid, volledig lokaal, gratis en native LangChain-integratie. LlamaParse is iets sterker op extreem complexe scans, maar vereist data-export naar de cloud. Unstructured is sneller op simpele documenten maar zwakker op tabellen.

Kan Docling tabellen uit PDF's extraheren?

Ja. Docling gebruikt het TableFormer-model dat tabelstructuur als visueel detectieprobleem behandelt. Het reconstrueert rijen, kolommen, samengevoegde cellen en headers over meerdere niveaus, en exporteert direct naar pandas DataFrame, Markdown of HTML.

Heeft Docling een GPU nodig?

Nee, Docling werkt prima op CPU voor tekstgebaseerde PDF's (10 tot 20 seconden voor een document van 10 pagina's). Een GPU versnelt vooral OCR op gescande documenten met een factor 5 tot 10 en is aan te raden bij verwerking van honderden bestanden per uur.

Hoe chunk ik documenten optimaal voor RAG?

Gebruik Docling's HybridChunker met de tokenizer van je embeddingmodel en stel max_tokens in op 60 tot 80 procent van de context-window. De chunker respecteert sectiehiërarchie, voegt kleine fragmenten samen en levert metadata per chunk (heading-pad, paginanummer) mee, wat cruciaal is voor citeerbaarheid in productie-RAG.

Is Docling gratis voor commercieel gebruik?

Ja. Docling is uitgebracht onder de Apache 2.0-licentie en mag vrij gebruikt worden in commerciële producten, ook in SaaS-aanbiedingen. Alleen de modelgewichten (DocLayNet, TableFormer) hebben hun eigen MIT-licentie, eveneens commercieel-vriendelijk.

Welke bestandstypes ondersteunt Docling?

Versie 2.x ondersteunt PDF, DOCX, PPTX, XLSX, HTML, Markdown, AsciiDoc en afbeeldingsformaten (PNG, JPEG, TIFF) met OCR. Audio- en videotranscriptie zijn niet inbegrepen; gebruik daarvoor een aparte Whisper- of Speech-to-Text-stap.

Artikelgeschiedenis (1)
  • — SEO meta refreshed (title and description updated)
Editorial Team
Over de Auteur Editorial Team

Our team of expert writers and editors.