RAGFlow PDF 文档分片实现详解
RAGFlow 的 PDF 文档分片(chunking)流程是一个多阶段的处理管道, 涵盖了从 PDF 解析、OCR 识别、版面分析、表格结构识别,到最终的文本合并和向量化存储 等多个步骤。 以下是对该流程的详细解读。
PDF 文档的分片(chunking)在 RAGFlow 中是一个多阶段流水线,主要涉及以下三个核心模块:
deepdoc/parser/pdf_parser.pyrag/app/naive.pyrag/nlp/__init__.py
阶段一:解析器选择
rag/app/naive.py 的 chunk() 函数是所有文件格式的统一入口。对于 PDF 文件,会根据配置的 layout_recognizer(如 DeepDOC、MinerU、Docling 等),从 PARSERS 字典中选择对应的解析函数。
默认使用 DeepDOC 解析器,即 by_deepdoc,它会调用 Pdf 类(继承自 PdfParser,即 RAGFlowPdfParser)。
阶段二:PDF 页面转换与 OCR(__images__)
RAGFlowPdfParser.__images__() 方法主要完成:
- 使用
pdfplumber将每页 PDF 渲染成图片(默认zoomin=3,即 216 DPI)。 - 提取每页字符信息(
dedupe_chars)。 - 判断是否为英文文档。
- 对每页图片调用
__ocr()进行 OCR 识别并写入结果。
__ocr()会先检测文本框位置,再将pdfplumber提取字符与 OCR 框进行匹配,最后对无法匹配的区域进行 OCR 文本识别。
阶段三:版面分析(_layouts_rec)
调用 LayoutRecognizer(ONNX 模型)对页面图像进行版面识别,将每个文本框标注为 text、table、figure、title 等类型,并把累计高度附加到 top / bottom 坐标上。
阶段四:表格结构识别(_table_transformer_job)
使用 TableStructureRecognizer 对识别出的表格区域做结构分析(行、列、表头、跨列单元格),并支持自动旋转校正。
阶段五:文本框合并(_text_merge / _naive_vertical_merge)
_text_merge():水平方向上,将同一版面区域内同一行的文本框合并。_naive_vertical_merge():垂直方向上,根据文本末尾标点、行距、位置重叠等特征,判断是否将相邻文本框拼接为一段。
阶段六:提取表格与图片(_extract_table_figure)
将 layout_type 为 table 和 figure 的文本框从 self.boxes 中分离,调用 cropout() 裁剪对应图片区域,并用 TableStructureRecognizer.construct_table() 构建 HTML 格式的表格文本。
阶段七:Pdf.__call__ 组装 sections 和 tables
Pdf.__call__() 会串联前述步骤,最终返回:
sections:每个文本框的(文本, 位置标签)对,位置标签格式为@@页码\tx0\tx1\ttop\tbottom##。tables:表格/图片的(图片, 内容)列表。
阶段八:naive_merge(按 Token 数合并 sections)
naive_merge() 将 sections 按分隔符与最大 Token 数(chunk_token_num,默认 512)合并为 chunks,并支持通过 overlapped_percent 配置相邻 chunk 的重叠比例。
阶段九:tokenize_chunks(最终向量化存储)
tokenize_chunks() 会对每个 chunk 分词(rag_tokenizer)、裁剪位置截图(pdf_parser.crop()),并组装成可写入 Elasticsearch 的文档格式。
表格部分由 tokenize_table() 单独处理。
其他解析器
除 DeepDOC 外,还支持以下 PDF 解析方式:
| 解析器 | 函数 |
|---|---|
| MinerU | by_mineru |
| Docling | by_docling |
| PaddleOCR | by_paddleocr |
| TCADP | by_tcadp |
| 纯文本(PlainParser) | by_plaintext |
PlainParser 直接使用 pypdf 提取文本,不包含 OCR 和版面分析。
VisionParser 则将每页渲染为图片,并由视觉大模型(Vision LLM)直接描述页面内容