Parser-Chunk Contract#
The Parser-Chunk Contract is the inter-component data handoff between the Parser pipeline stage and downstream consumers (chunkers and the Compiler). It is enforced by two Pydantic models and the output_format routing signal.
Pipeline Position#
The standard ingestion chain in rag/flow/ is:
File → Parser → TokenChunker / TitleChunker → Compiler → Indexer
The Parser writes its result into a set of named output slots. The next stage reads those slots via the TokenChunkerFromUpstream schema. A mismatch between what the Parser writes and what output_format declares causes silent zero-chunk failures — the chunker reads the wrong (empty) field and returns {"chunks": []} with no error.
The output_format Signal#
Every parser method calls self.set_output("output_format", ...) first, then writes exactly one of the four format-specific output slots :
output_format value | Output slot written | Content type |
|---|---|---|
"json" | json | list[dict] — structured blocks with text, doc_type_kwd, optional image/positions |
"markdown" | markdown | str — flat markdown text |
"text" | text | str — plain text |
"html" | html | str — HTML string |
"chunks" | chunks | list[dict] — pre-chunked output (Compiler stage) |
The _image() method unconditionally hardcodes output_format = "json" regardless of DSL config — a deliberate fix for a prior bug where format mismatch produced zero chunks .
Schema Definitions#
Parser output → Chunker input: TokenChunkerFromUpstream#
Defined in rag/flow/chunker/schema.py :
| Field | Alias | Type | Purpose |
|---|---|---|---|
output_format | — | Literal["json","markdown","text","html","chunks"] | None | Routes to the correct result field |
json_result | json | list[dict] | None | Structured parser output (PDF, tables, images) |
markdown_result | markdown | str | None | Markdown flat text |
text_result | text | str | None | Plain text |
html_result | html | str | None | HTML content |
chunks | — | list[dict] | None | Pre-chunked output from a previous stage |
file | — | dict | None | File metadata (blob/path, outlines) |
name | — | str | File name (required) |
The model uses populate_by_name=True, extra="forbid" , so upstreams can write json, markdown, etc. as keys directly, and unknown keys raise an error.
Parser upstream input: ParserFromUpstream#
Defined in rag/flow/parser/schema.py . Contains only name (required), file (optional dict), and two boolean flags abstract and author. It does not carry output_format — that is set by the Parser during processing.
How Chunkers Consume the Contract#
TokenChunker._invoke() pattern :
- String formats (
markdown,text,html): readsgetattr(from_upstream, f"{output_format}_result")and processes the string payload. jsonformat: readsfrom_upstream.json_resultas alist[dict]. Each dict carries adoc_type_kwdfield ("text","table","image") that determines how the chunk is handled .chunksformat: readsfrom_upstream.chunksdirectly — used by theCompilerstage .
The json format: block dict structure#
When output_format="json", parsers emit a list[dict]. The canonical fields on each dict are:
| Field | Type | Notes |
|---|---|---|
text | str | Content text (required) |
doc_type_kwd | str | "text", "table", or "image" |
image | PIL Image or None | Present for image/figure blocks |
positions | list | PDF bounding boxes: [page_num, x0, x1, top, bottom] |
layout_type | str | e.g. "text", "title", "table", "figure" |
PDF parsers normalize all blocks through a shared bbox-normalization loop before writing output . After normalization, normalize_pdf_items_metadata() is called before the json slot is written .
Parser-Specific Section Tuple (pre-normalization)#
The low-level parsers (MinerU, DeepDoc, Docling, etc.) work in a distinct intermediate representation before the Parser flow component converts it into the contract above. They return section tuples from parse_pdf():
pipeline/manualparse_method:(text: str, layout_type: str, position_tag: str)— a 3-tuplepaperparse_method:(text_with_tag: str, layout_type: str)— 2-tuple
position_tag is a string of the form @@{page}-{page}\t{x0}\t{x1}\t{top}\t{bottom}## . The Parser._pdf() method iterates these tuples, builds bbox dicts, and converts them into the final contract format .
MinerU maps its native content_list.json content types (text, table, image, equation, code, list) to section tuples via _transfer_to_sections(), discarding header, footer, page_number, and discarded blocks.
Allowed output_format Values per File Type#
Enforced by ParserParam.check() :
| File type | Allowed formats |
|---|---|
json, markdown | |
| Spreadsheet | json, markdown, html |
| DOC / DOCX | json, markdown |
| Slides | json only |
| Image | json only (hardcoded) |
| Markdown, Text&Code, HTML, EPUB | json, text |
json, text | |
| Audio / Video | text (single string transcript) |
Key Files#
| File | Role |
|---|---|
rag/flow/parser/parser.py | Parser component; normalizes all parser backends into the contract |
rag/flow/chunker/schema.py | TokenChunkerFromUpstream Pydantic model |
rag/flow/parser/schema.py | ParserFromUpstream Pydantic model |
deepdoc/parser/mineru_parser.py | MinerU section-tuple producer |
rag/flow/compiler/compiler.py | Compiler; reads chunks from chunker output |
rag/flow/parser/pdf_chunk_metadata.py | normalize_pdf_items_metadata() — finalizes bbox dict fields before JSON output |