
如果前几章解决的是"用什么能力""怎么组织能力",那这一章要回答的,是一个更现实的问题:
当不同路径都给了你结果,你到底该怎么用?
这一步,通常被轻描淡写地称为"融合"。但在真实工程里,融合往往是整个系统里最难写、也最容易写炸的部分。
先说清楚一个现实:多数系统里,其实没有融合
在进入"怎么融合"之前,有一件事必须先说清楚。
如果你真的去读一些开源 PDF 解析项目的实现,而不是只看文档,会发现一个很普遍的现象:
很多系统里,其实并不存在经过设计的融合策略。
更常见的情况是:
- 每个区域,默认只有一条解析路径
- 这条路径如果失败:
- 要么直接忽略该区域
- 要么返回空结果
- 要么整页 / 整文档失败
从工程结构上看,这并不是融合,而是对失败的被动处理。
这并不意味着这些项目"做得不好",而是它们的设计目标,本身就不是"在多种信息来源之间做选择"。
被动兜底 ≠ 融合
这也是一个非常容易混淆的点。
在一些系统中,你可能会看到类似现象:
- OCR 和文本解析模块都存在
- 表格模块失败时,正文还能继续跑
- 某些异常被吞掉,流程不中断
但这些行为更多是在保证:
系统别崩。
而不是在回答:
哪一份结果更可信?能不能把它们一起用?
真正的融合,至少要做三件事:
- 明确不同信息来源的角色
- 允许结果不一致
- 在不一致时,有决策逻辑
如果只是"失败了换一条路试试",那更准确的说法是兜底,而不是融合。
融合为什么几乎一定发生在"区域级"
一旦你开始认真考虑融合,就会发现一个结论几乎是必然的:
页面级的融合决策,太粗糙了。
现实中的 PDF 页面,往往是混合态的:
- 正文是文本
- 表格是图片
- 图像是扫描的
- 页眉页脚又可能是可提取文本
如果你在页面级就做"选哪条路线"的决策,那在决策发生的那一刻,信息损失就已经不可逆了。这也是为什么,只要系统开始"认真做融合",粒度几乎一定会下沉到区域级。
区域级融合(拆区域后逐块决策)
页面级切换(整页二选一)
否
是
信息损失:混合页被迫走单一路线
输入:PDF Page
判断:扫描件?
路线A:内容流解析\n(整页)
路线B:OCR/视觉解析\n(整页)
输出:整页结果
输入:PDF Page
布局/区域检测\n(得到多个区域)
按区域类型分流\n(Text/Table/Figure/...)
区域级融合决策\n内容流优先 + 一致性校验 + OCR兜底
汇集区域结果
阅读顺序重建
输出:整页结果
图:页面级切换 vs 区域级融合对比示意图
一个更现实的前提:不同区域,失败模式完全不同
真正把融合落到工程里,很快就会发现:
不存在一套对所有区域都适用的融合逻辑。
文本区域、表格区域、图像区域等,它们的失败方式完全不一样,于是,融合策略几乎一定是按区域类型分治的。
文本区域:优先内容流,但必须做"视觉可信性校验"
在文本区域上,一个相对稳妥、也比较通用的策略是:
先使用内容流,再判断是否值得相信。
但这里的"相信",不是无条件的。
在我的实现里,内容流提取出来的文本,至少要经过两类检查:
- 文本质量检查
- 是否出现大量乱码
- 是否存在异常字符分布
- 视觉一致性检查
- 内容流给出的 bbox
- 是否与该文本区域的视觉边界大致匹配
- 是否明显溢出、错位或断裂
一旦这些检查中出现明显异常,就会认为:
内容流在这个区域上,在视觉上是不可信的。
此时才会触发 OCR 作为兜底策略。
需要强调的是,这里的 OCR 并不是"更高级",而是在当前区域条件下,更稳定、更可靠。
是
否
否
是
输入:文本区域\n(来自布局检测)
内容流提取文本\n(pdf text extraction)
文本质量检查\n是否大量乱码/异常字符?
判定:内容流不可信
视觉一致性检查\nbbox 是否与区域边界匹配?
采用内容流文本\n(作为最终结果)
OCR 文本识别\n(兜底策略)
输出:文本区域结果
图:文本区域融合决策流程图
表格区域:多路径尝试,本身就是常态
表格区域,是融合策略中最复杂、也是失败最频繁的一类。
在实践中,我的一个基本认知是:
表格解析失败是常态,而不是异常情况。
因此,在我的实现中,表格区域并不存在"唯一正确路径",而是被明确建模为一条可配置的插件链。
一个典型的尝试顺序可能是:
- lattice + 内容流 组装表格
- 对规则、有框表格效果很好
- 确定性强,可解释
- 多模态模型解析表格内容
- 对复杂、无框表格更友好
- 但失败模式也很多:
- 死循环
- 内容过大被截断
- 输出格式不符合预期
- lattice 的 stream 算法兜底
- 不追求完美结构
- 但尽量保证信息不丢
在实现上,这些失败并不会被当作"异常",
而是被视为插件级的正常返回状态。
是
否
是
否
是
否
表格区域 Table Region\n(来自布局 / 区域检测)
按业务配置选择插件链
尝试:Lattice 表格线框检测\n(确定性 / 依赖样式)
尝试:结合内容流组装单元格文本
结果可用?\n(结构完整 / 对齐合理)
输出:结构化表格\n(可溯源)
降级:多模态模型解析表格内容
结果可用?
最终兜底:Lattice Stream 算法\n(弱结构 / 保内容)
是否提取到主要内容?
输出:弱结构表格\n(尽量不丢信息)
输出:标记失败\n(保留区域元信息 / 截图)
注:插件失败应作为"正常返回状态"处理\n不应中断整页解析
图:表格区域插件链与降级路径示意图
其他各种区域,也可以配置不同的插件链,实现性能和效果的平衡。这里不再缀述。
一个必须说明的事实:插件链是个人选择,而非行业常态
这里需要非常明确地说一句:
这种"插件链 + 降级策略"的融合方式,更多是我个人的工程选择。
在我看到的多数开源项目中:
- 每个区域类型,通常只对应一种实现
- 失败时:
- 要么忽略该区域
- 要么直接返回失败
- 很少会为同一类区域,设计多条可切换的解析路径
原因也很现实:
- 插件链显著增加复杂度
- 调试成本高
- 测试难度大
- 很容易引入不可预期行为
也正因为如此,这种设计更常见于业务驱动、质量要求较高的系统,而不是算法型或研究型项目。
8. 插件链真正解决的,不是"更准",而是"可预期"
从工程角度看,插件链的价值,并不在于:
"一定能把表格解析对。"
而在于:
当某一种能力失败时,系统知道下一步该做什么。
这使得系统的行为:
- 更可预期
- 更容易配置
- 更容易针对不同业务调整
也让"融合"从一种模糊的概念,变成了一组可以被描述、被修改、被约束的工程决策。
小结:融合不是终点,而是通向多模态之前的"现实形态"
到这一章为止,其实可以把话说得更直白一些。
区域级融合、插件链、降级策略,并不是因为它们优雅,而是因为在当前阶段,它们仍然是工程上最可控的选择。
当你真正做过融合,就会意识到一件事:
- 系统已经在试图"理解文档"
- 但理解是被拆散的
- 语义、结构、版面被分配给了不同能力
- 最后再由工程把它们拼回来
这本身就暴露了一个事实:
我们正在用工程手段,弥补模型在"整体理解"上的不足。
而这件事,从来都不可能是终局解法。
融合之所以复杂,不是因为设计得不够好,而是因为它承担了太多原本应该由模型完成的工作。也正因为如此,当端到端多模态模型出现时,它们天然就会被寄予一种期待:
- 能不能一次性看懂整页?
- 能不能同时理解结构和语义?
- 能不能不再依赖这么多规则与兜底?
下一章,我们就来正面聊这个问题。不是"多模态有多强",而是一个更现实的判断:
端到端多模态模型,为什么在今天,仍然还接不住 PDF 解析这件事。