Pipeline Stage Architecture#
Overview#
Docling's threaded PDF pipeline runs pages through five concurrent stages wired in sequence, followed by two sequential cross-page models and an enrichment pass. The architecture is implemented in StandardPdfPipeline, which extends ConvertPipeline → PaginatedPipeline → BasePipeline .
Every execute call constructs a fresh RunContext with new threads and bounded queues — models are initialized once at construction time and shared read-only across worker threads .
Stage Topology#
Pages flow as ThreadedItem envelopes — each carries a Page, run_id, page_no, ConversionResult, and error state. Stages are wired via ThreadedQueue instances (bounded, blocking, with close() propagating shutdown downstream). Stage wiring is in _create_run_ctx().
| Stage | Class | Batch size | Model |
|---|---|---|---|
| Preprocess | PreprocessThreadedStage | 1 | PagePreprocessingModel — renders page image at images_scale |
| OCR | ThreadedPipelineStage | ocr_batch_size | Pluggable: EasyOCR, Tesseract, RapidOCR, OcrMac, Nemotron, KServe v2 |
| Layout | ThreadedPipelineStage | layout_batch_size | LayoutModel (wraps LayoutPredictor from docling-ibm-models) |
| Table | ThreadedPipelineStage | table_batch_size | TableFormer V1/V2 or Granite Vision |
| Assemble | ThreadedPipelineStage | 1 | PageAssembleModel — converts clusters to typed page elements |
After all pages are drained, _assemble_document() runs sequentially: ReadingOrderModel → HeadingHierarchyModel → _enrich_document() .
The Assemble stage's postprocess hook (_release_page_resources()) frees page image caches and unloads the page backend unless enrichment stages need them. keep_backend is set to True whenever any enrichment flag (do_picture_classification, do_code_enrichment, etc.) is active .
Model Interface Contracts#
BasePageModel — page-level, streaming#
BasePageModel is the contract for all five threaded stage models. Its single abstract method:
__call__(conv_res: ConversionResult, page_batch: Iterable[Page]) → Iterable[Page]
The Page datamodel carries all per-page state between stages:
parsed_page: SegmentedPdfPage | None— text cells from the PDF backend ; accessed aspage.cells(thetextline_cellslist)predictions: PagePredictions— output slots for layout, table structure, VLM responseassembled: AssembledUnit | None— typed elements, filled byPageAssembleModel_backend/_image_cache— freed after Assemble unlesskeep_images/keep_backendis set
The non-threaded PaginatedPipeline._apply_on_pages() also chains build_pipe models using this same contract .
Ordering constraint: OCR runs before Layout. OCR text cells populate
page.cellsand are spatially assigned to layout clusters during postprocessing — this is why the two stages are separate and ordered.
GenericEnrichmentModel[T] / enrichment model hierarchy — document-level#
Enrichment models operate on a fully assembled DoclingDocument (not on Page objects). Three abstract methods are required :
| Method | Signature | Purpose |
|---|---|---|
is_processable | (doc, element) → bool | Filter which NodeItems enter the batch |
prepare_element | (conv_res, element) → Optional[T] | Transform/crop element for inference |
__call__ | (doc, element_batch) → Iterable[NodeItem] | Run inference, annotate elements in-place |
Two concrete base classes specialize prepare_element:
BaseEnrichmentModel— returns the element unchanged ifis_processable. No image involved. Use for text-only enrichment.BaseItemAndImageEnrichmentModel— crops the element's bounding box from the source page image atself.images_scale(with optionalexpansion_factor). Returns anItemAndImageEnrichmentElement(item, image)pair. ForPictureItemwith an embedded image (e.g. Word/HTML), the embedded image is used directly, so the page backend is not required.
The execution loop in BasePipeline._enrich_document() iterates each model in self.enrichment_pipe, uses prepare_element() to filter and prepare candidates, chunks them by model.elements_batch_size, and calls the model. The inner iterator must always be fully exhausted — side effects on NodeItems occur during iteration.
Pipeline Class Hierarchy and Extension Points#
BasePipeline
├── build_pipe: List[Callable] ← page-level models (BasePageModel)
├── enrichment_pipe: List[GenericEnrichmentModel] ← doc-level models
│
└── ConvertPipeline ← adds picture description / classifier / chart extraction
└── PaginatedPipeline ← sequential page-batch loop (non-threaded base)
└── StandardPdfPipeline ← threaded 5-stage topology
└── prepends CodeFormulaVlmModel to enrichment_pipe
Extension point 1 — Swap a threaded stage model: StandardPdfPipeline._init_models() sets self.layout_model, self.ocr_model, etc. Subclass and override to inject a custom model; it must still implement BasePageModel.__call__.
Extension point 2 — Add enrichment models: Subclass StandardPdfPipeline and reassign self.enrichment_pipe in __init__, then wire via PdfFormatOption(pipeline_cls=MyPipeline). For installed packages, register models via setuptools entry-point plugins under the "docling" group (only loaded when allow_external_plugins=True) .
Key Data Types#
| Type | Location | Role |
|---|---|---|
Page | datamodel/base_models.py | Carries all per-page state through threaded stages |
ThreadedItem | standard_pdf_pipeline.py | Envelope wrapping Page for inter-stage queues |
PagePredictions | datamodel/base_models.py | Output slots for each stage (layout, table, VLM, etc.) |
AssembledUnit | datamodel/base_models.py | Per-page assembled typed elements |
ItemAndImageEnrichmentElement | datamodel/base_models.py | (item, image) pair for BaseItemAndImageEnrichmentModel |
Key Source Files#
| File | Purpose |
|---|---|
docling/pipeline/base_pipeline.py | BasePipeline, ConvertPipeline, PaginatedPipeline; _enrich_document() loop |
docling/pipeline/standard_pdf_pipeline.py | Threaded stage topology, _create_run_ctx(), model init, RunContext, ThreadedItem |
docling/models/base_model.py | BasePageModel, GenericEnrichmentModel, BaseEnrichmentModel, BaseItemAndImageEnrichmentModel |
docling/datamodel/base_models.py | Page, PagePredictions, AssembledUnit, ItemAndImageEnrichmentElement |