一、引言
书籍文件往往篇幅巨大、结构复杂,不同章节、目录、致谢等混杂在同一文档中。RAGFlow 在处理 book 类文档时,整合了多种解析器(docx、pdf、txt、html、doc),通过自动识别版面结构、过滤非正文、并结合视觉模型生成图片摘要,实现对长文档的精准切分与高质量抽取。本篇将带你逐步拆解源码,了解 RAGFlow 如何优雅地解析一本“书”。
二、省流版
1.核心逻辑
book 模式 面向长篇书籍类文档(docx/pdf/txt/html/doc),通过对不同文件类型自动选择最优解析策略,融合文本语义分块与视觉摘要,实现高质量内容抽取。其目标是:在保持上下文完整性的同时最大限度地过滤无效内容(如目录、致谢页等),为后续知识检索提供干净、结构化的输入。
2.设计亮点
- 语义级正文过滤:通过正则与上下文规则剔除目录、致谢等非正文部分;
- 文本块连续性优化:pdf 文档通过_naive_vertical_merge 与 _merge_with_same_bullet 修复 OCR 切分断裂、项目符号分裂等问题。
3.手撕版
书籍的解析支持文件格式为 docx|pdf|txt|html|doc 五种格式。
其中官方建议由于一本书篇幅较长,并非所有部分都有用,如果是 PDF 格式,请为每本书设置页码范围,以消除负面影响并节省计算时间。
if re.search(r"\.docx$", filename, re.IGNORECASE):
...
elif re.search(r"\.pdf$", filename, re.IGNORECASE):
...
elif re.search(r"\.txt$", filename, re.IGNORECASE):
...
elif re.search(r"\.(htm|html)$", filename, re.IGNORECASE):
...
elif re.search(r"\.doc$", filename, re.IGNORECASE):
...
docx
1.1 解析器初始化
docx 的解析器是直接引用的 General 模式下的 docx 解析器,主要对 docx 文档中的段落和表格分别进行处理。详细的 docx 解析器技术拆解可参考《General 模式语义切块(docx 篇)》。
doc_parser = naive.Docx()
段落和表格处理后的最终输出格式如下:
sections, tbls = doc_parser(
filename, binary=binary, from_page=from_page, to_page=to_page)
'''
# sections
[
(清洗后的文本, 合并后的图片对象, 样式名),
("这是段落文本", PILImage对象, "Normal"),
("这是图注", PILImage对象, "Caption"),
...
]
# tbls
[
((None, "<table>...</table>"), ""),
((None, "<table>...</table>"), ""),
...
]
'''
1.2 目录表格过滤
过滤 docx 文档中的目录表格。
tbls = _remove_docx_toc_tables(tbls)
通过关键字正则判断是否是目录表格,满足其中一条则认为是目录表格。
_TOC_TABLE_KEYWORDS = re.compile(r"(table of contents|目录|目次)", re.IGNORECASE)
_TOC_DOT_PATTERN = re.compile(r"[\.|·]{3,}\s*\d+")
1.3 非正文内容过滤
过滤解析后文本中的非正文内容,例如:目录,致谢等。
remove_contents_table(sections, eng=is_english(
random_choices([t for t, _ in sections], k=200)))
通过关键字正则判断是否是非正文内容。
re.match(r"(contents|目录|目次|table of contents|致谢|acknowledge)$",
re.sub(r"( | |\u3000)+", "", get(i).split("@@")[0], flags=re.IGNORECASE))
1.4 使用视觉模型识别并总结图片摘要
使用 VLM 对文档中的图片进行摘要总结,并以规定格式输出。详细的 vision_figure_parser_docx_wrapper 技术拆解可参考
tbls=vision_figure_parser_docx_wrapper(sections=sections,tbls=tbls,callback=callback,**kwargs)
将包含图片信息的对象数组转换成 figures_data,如以下格式:
(
(figure_data[1], [figure_data[0]]), # 原始图片信息,图片描述信息
[(0, 0, 0, 0, 0)], # 位置信息
)
1.5 移除正文中的图片内容
sections=[(item[0],item[1] if item[1] is not None else "") for item in sections if not isinstance(item[1], Image.Image)]
docx 处理流程结束后输出,sections(正文文本内容)和 tbls(表格内容,图片内容)。
2.1 布局识别器
与 General 模式下 pdf 文档的处理一样,分为 DeepDOC 和 Plain Text 两种布局识别器。
if parser_config.get("layout_recognize", "DeepDOC") == "Plain Text":
pdf_parser = PlainParser()
else:
pdf_parser = Pdf()
Plain Text 布局识别器实现请参考[下【Plain Text 布局识别器】模块。
2.2 DeepDOC 布局识别器
中相同,Pdf 继承基类 PdfParser。
pdf_parser = Pdf()
class Pdf(PdfParser)
PdfParser 基类的核心功能在《General 模式语义切块(pdf 篇)》中已有详细说明,这里作简要概述:
- __images__:负责将 PDF 页面数字化,生成可结构化的页面图像数据,为后续的布局分析与表格提取奠定基础。
- _layouts_rec:基于页面图像与 OCR 文本框信息,执行每页的版面分析与坐标重建。
- _table_transformer_job:针对识别出的表格区域,提取和解析表格内容,实现表格结构化处理。
- _text_merge:通过规则合并相邻文本块,解决 OCR 输出中文本碎片化的问题。
- _concat_downward:按照阅读顺序(Y 坐标从上到下,X 坐标从左到右)对文本框进行排序,恢复自然的文本流。
- _filter_forpages:检测并过滤非正文页面,如目录页、致谢页等,以提升后续文本分析质量。
- _extract_table_figure:负责表格与图像的提取与输出,支持跨页表格合并及图像截取。
- __filterout_scraps:对碎片化文本进行二次清理与组装,进一步优化 OCR 文本的完整性。
2.2.1 Pdf 类
Pdf 类作为入口点,调用 PdfParser 中提供的功能实现整个复杂的文档处理流程,并记录了各阶段耗时,解析进度等信息,这点与 General 模式下的 Pdf 类职能一致,但具体实现内容存在差异。
class Pdf(PdfParser):
def __call__(self, filename, binary=None, from_page=0,
to_page=100000, zoomin=3, callback=None):
# 静态的 pdf 页面转换为可结构化数据
self.__images__(
filename if not binary else binary,
zoomin,
from_page,
to_page,
callback)
# 对文档每页的布局分析,和坐标重建
self._layouts_rec(zoomin)
# 表格数据内容提取
self._table_transformer_job(zoomin)
# 基于规则合并文本
self._text_merge()
# 提取表格,图片内容输出
tbls = self._extract_table_figure(True, zoomin, True, True)
self._naive_vertical_merge()
# 检测并过滤非正文页面
self._filter_forpages()
self._merge_with_same_bullet()
callback(0.8, "Text extraction ({:.2f}s)".format(timer() - start))
return [(b["text"] + self._line_tag(b, zoomin), b.get("layoutno", ""))
for b in self.boxes], tbls
2.2.1.1 _naive_vertical_merge
其中 _naive_vertical_merge 主要目的是将同一列中垂直方向相邻的文本框进行合并。
先过滤无效文本:
1)跨页数字符号过滤:移除跨页的页码、编号等无关文本
if b["page_number"] < b_["page_number"] and re.match(r"[0-9 •一—-]+$", b["text"]):
bxs.pop(i)
continue
2)空文本过滤
if not b["text"].strip():
bxs.pop(i)
continue
再通过文本框布局识别,确认文本布局是否符合合并规则:
3)布局一致性检查:确保合并的文本框属于同一布局区域
if not b["text"].strip() or b.get("layoutno") != b_.get("layoutno"):
i += 1
continue
4)垂直距离阈值检查:防止合并距离过远的文本框
if b_["top"] - b["bottom"] > mh * 1.5:
i += 1
continue
5)水平重叠度检查:确保文本框在水平方向有足够重叠
overlap = max(0, min(b["x1"], b_["x1"]) - max(b["x0"], b_["x0"]))
if overlap / max(1, min(b["x1"] - b["x0"], b_["x1"] - b_["x0"])) < 0.3:
i += 1
continue
最后通过上述筛选的文本框,对其文本语义连续性分析,决定是否需要合并。
# 支持合并的特征(连接性标点)
concatting_feats = [
b["text"].strip()[-1] in ",;:'\",、‘“;:-",
len(b["text"].strip()) > 1 and b["text"].strip()[-2] in ",;:'\",‘“、;:",
b_["text"].strip() and b_["text"].strip()[0] in "。;?!?”)),,、:",
]
# 反对合并的特征
feats = [
b.get("layoutno", 0) != b_.get("layoutno", 0),
b["text"].strip()[-1] in "。?!?",
self.is_english and b["text"].strip()[-1] in ".!?",
b["page_number"] == b_["page_number"] and b_["top"] - b["bottom"] > self.mean_height[b["page_number"] - 1] * 1.5,
b["page_number"] < b_["page_number"] and abs(b["x0"] - b_["x0"]) > self.mean_width[b["page_number"] - 1] * 4,
]
# 强制分离特征
detach_feats = [b["x1"] < b_["x0"], b["x0"] > b_["x1"]]
if (any(feats) and not any(concatting_feats)) or any(detach_feats):
i += 1
2.2.1.2 _merge_with_same_bullet
将具有相同项目符号的连续文本框合并为一个文本块,保持项目符号列表的结构。
pdf 中可能存在以下项目列表, 一个完整的项目符号列表可能被识别为多个独立的文本框,_merge_with_same_bullet 主要是将同一个项目列表内容进行合并。
# 带有项目符号列表示例
• 项目一:产品介绍
• 项目二:技术规格
• 项目三:价格信息
2.3 使用视觉模型识别并总结图片摘要
与 docx 处理一致,需要使用 VLM 对文档中的图片进行摘要总结,并以规定格式输出。
tbls=vision_figure_parser_pdf_wrapper(tbls=tbls,callback=callback,**kwargs)
- TXT
与 General 模式下获取 txt 文档方案一致,使用 get_text。如果传入的二进制内容,则使用从 rag.nlp 引入的方式自动推断出正确的编码,进行解码;否则直接从文件路径读取文本进行拼接返回。
txt = get_text(filename, binary)
与 docx 文档处理方案一致,获取文本后过滤文本中的非正文内容,例如:目录,致谢等。
remove_contents_table(sections, eng=is_english(
random_choices([t for t, _ in sections], k=200)))
- HTML
与 General 模式下处理 html 文档方案一致,使用 HtmlParser 解析器进行文档解析。详细技术实现可参考
sections = HtmlParser()(filename, binary)
与 docx 文档处理方案一致,获取文本后过滤文本中的非正文内容,例如:目录,致谢等。
remove_contents_table(sections, eng=is_english(
random_choices([t for t, _ in sections], k=200)))
doc_parsed = parser.from_buffer(binary)
与 docx 文档处理方案一致,获取文本后过滤文本中的非正文内容,例如:目录,致谢等。
如何高效转型Al大模型领域?
作为一名在一线互联网行业奋斗多年的老兵,我深知持续学习和进步的重要性,尤其是在复杂且深入的Al大模型开发领域。为什么精准学习如此关键?
- 系统的技术路线图:帮助你从入门到精通,明确所需掌握的知识点。
- 高效有序的学习路径:避免无效学习,节省时间,提升效率。
- 完整的知识体系:建立系统的知识框架,为职业发展打下坚实基础。
AI大模型从业者的核心竞争力
- 持续学习能力:Al技术日新月异,保持学习是关键。
- 跨领域思维:Al大模型需要结合业务场景,具备跨领域思考能力的从业者更受欢迎。
- 解决问题的能力:AI大模型的应用需要解决实际问题,你的编程经验将大放异彩。
以前总有人问我说:老师能不能帮我预测预测将来的风口在哪里?
现在没什么可说了,一定是Al;我们国家已经提出来:算力即国力!
未来已来,大模型在未来必然走向人类的生活中,无论你是前端,后端还是数据分析,都可以在这个领域上来,我还是那句话,在大语言AI模型时代,只要你有想法,你就有结果!只要你愿意去学习,你就能卷动的过别人!
现在,你需要的只是一份清晰的转型计划和一群志同道合的伙伴。作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。

第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费】

揭秘RAGFlow文档切分原理

被折叠的 条评论
为什么被折叠?



