跪拜 Guibai
← All articles
Agent

Building a Production RAG Knowledge Base: DeepDOC Parsing, Hybrid Retrieval, and Pixel-Level Source Tracing

By 去伪存真 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Most RAG systems choke on scanned PDFs, long-tail domain terms, and unverifiable answers. This architecture shows a practical path to production: page-level visual parsing with memory bounds, two-granularity tokenization for specialized vocabulary, and citation anchors that survive all the way to the front end.

Summary

This post breaks down the full architecture of an enterprise RAG knowledge base built for mineral exploration and engineering standards Q&A. The write path is driven by a Canvas DSL orchestration engine over NATS JetStream queues, splitting ingestion into six serial stages: queueing, metadata read, parsing, chunking, optional LLM extraction, and tokenization/vectorization. The authors highlight a common bottleneck: with default single-worker concurrency, tasks often wait 7 minutes in queue for 3 minutes of execution, so tuning worker count matters more than micro-optimizing single nodes.

The parser routes Office documents through lightweight AST extraction, but PDFs get the heavy treatment via a Go port of DeepDOC. Each page goes through a 216 DPI render, OCR detect, DLA layout analysis with 10 semantic labels, TSR table recognition, and a zero-output zoom retry. A key design choice is forking between text-layer PDFs and scanned pages: normal PDFs reuse embedded characters by merging them into detected line boxes, while scanned pages run full OCR recognition in batches of 16. Memory explosions from large fold-out geological maps are prevented by a triple defense: retry only on zero output, a 48M pixel budget pre-check, and a hard clamp inside the renderer.

After parsing, the chunker applies four modes (general, QA, table, manual) with table header inheritance and hierarchical breadcrumbs. The tokenizer produces both coarse and fine-grained full-text tokens plus dense vectors, and supports optional LLM-generated keywords and reverse HyDE questions. Storage can be Elasticsearch or Infinity. On the read path, hybrid retrieval combines sparse keyword matching with dense kNN (default topK 1024), followed by a service-layer rescore (0.7 term weight, 0.3 vector weight) and optional Rerank on the top 64 candidates. The final response includes pixel-level bounding box coordinates that let users click a citation and jump directly to the highlighted table or figure in the original PDF.

Takeaways
— Ingestion uses a 6-stage pipeline (queue, metadata, parser, chunker, extractor, tokenizer) driven by a Canvas DSL over NATS JetStream; default single-worker concurrency causes long queue waits, so scaling workers is the first optimization.
— PDF parsing is a Go port of DeepDOC with per-page pipeline: 216 DPI render, OCR detect, DLA layout analysis with 10 semantic labels, TSR table recognition, and zoom retry only when a page produces zero boxes.
— Normal PDFs reuse embedded characters by merging them into OCR-detected line boxes; scanned pages run full OCR recognition in batches of 16. This fork keeps normal PDFs fast while still handling scans.
— A triple memory defense prevents OOM on large geological maps: retry only on zero output, a 48M pixel budget pre-check before rendering, and a renderer-internal clamp that caps any bitmap at 48M pixels.
— Chunking supports four modes: general (sliding window with natural delimiters, 512 token soft cap), QA (binds Q&A pairs), table (keeps headers attached to row chunks), and manual (chapter-based with breadcrumb prefixes).
— The optional LLM extractor generates auto-keywords, auto-questions (reverse HyDE), and summaries/tags, but costs an LLM call per chunk and becomes the second-largest time sink.
— Indexing writes both coarse-grained (content_ltks) and fine-grained (content_sm_ltks) full-text tokens to handle compound geological terms, plus dense vectors with a per-chunk cache for resumable ingestion.
— Retrieval is hybrid: sparse keyword match plus dense kNN (topK 1024), fused in-engine, then rescored with 0.7 term weight and 0.3 vector weight; optional Rerank on top 64 candidates, with a 0.2 similarity threshold.
— Source tracing uses page-level bounding box arrays from DeepDOC, enabling pixel-level highlight rectangles on the original PDF when a citation is clicked.
— Storage is pluggable between Elasticsearch and Infinity, with Infinity offering native fused dense/sparse/full-text queries at lower memory usage.
Conclusions

The deepest engineering effort in this system goes into PDF parsing, not vector retrieval. The authors treat layout analysis and table recognition as the real bottlenecks for enterprise documents, and that focus is what makes the whole chain usable.

Using two-granularity tokenization for full-text search is a pragmatic alternative to relying solely on embeddings. It directly addresses the long-tail domain term problem without requiring a specialized embedding model.

The explicit memory budget of 48M pixels per rendered page is a concrete, sensible safeguard that most RAG systems skip. It prevents a single pathological scan from taking down the entire ingestion worker.

The 0.7/0.3 term/vector weight default shows a preference for precision over recall; combined with a Rerank stage and threshold filtering, it suggests real production queries need to avoid hallucinating wrong drill hole numbers.

The port of DeepDOC from Python to Go indicates that performance and memory control drove a rewrite rather than a wrapper. This is a pattern likely to repeat as visual parsing models mature.

The optional VLM plugin is positioned as a bolt-on for semantic understanding of figures, not a core component. That keeps the main pipeline cost predictable while opening a path to future richer indexing.

Concepts & terms
DeepDOC
A visual document parsing pipeline that renders pages to images and uses object detection, OCR, layout analysis (DLA), and table structure recognition (TSR) to extract text, tables, and images with page coordinates. Originally Python, here ported to Go and run on CPU via ONNX Runtime.
DLA
Document Layout Analysis: a model that assigns semantic roles (title, text, figure, table, equation, caption, reference) to regions on a rendered page. It distinguishes layout understanding from plain OCR.
TSR
Table Structure Recognition: a model that identifies rows, columns, headers, and merged cells in a table image, converting it into a structured grid that can be filled with OCR text.
Reverse HyDE
In this system, the LLM generates plausible user questions that a chunk could answer, then those questions are vectorized along with the original text. This converts "question searching statement" into "question searching question", improving recall for conversational queries.
Canvas DSL
A domain-specific orchestration engine for defining ingestion pipelines as directed acyclic graphs of nodes. It provides state management, retry, and node reuse (e.g., cached vectors) for resumable execution.
Dual-mode index
Indexing strategy that writes both full-text token strings (coarse and fine granularity) and dense vector embeddings for each chunk, enabling hybrid retrieval that combines keyword matching with semantic similarity.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗