Towards Data Science

Loop Engineering with Adaptive Parsing in Action: Parsing Flat Tables with Azure and Figures with a Vision LLM

8.5内容质量

TL;DR · AI 摘要

自适应解析结合视觉LLM能显著提升表格和图表的文档处理准确率,Azure与PyMuPDF的协同解析可平衡成本与效率。

核心要点

  • PyMuPDF解析速度达5ms/页,而视觉LLM解析成本高1万倍且耗时10秒
  • 自适应解析机制通过三重校验触发LLM作为最终防线
  • Azure表格解析准确率较基础解析提升47%(测试数据)

结构提纲

按章节快速跳转。

  1. 揭示传统OCR解析在表格场景中的致命缺陷及LLM的防御价值

  2. 三重校验触发机制实现解析器动态升级的自适应架构

  3. Azure表格解析与视觉LLM图表解析的端到端验证流程

  4. PyMuPDF与视觉LLM的性能/成本对比分析

  5. LLM通过输入校验实现错误解析的自动修正

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • 自适应解析架构
    • 核心组件
      • PyMuPDF基础解析
      • Azure进阶解析
      • 视觉LLM
    • 验证机制
      • 三重校验触发
      • LLM输入校验
    • 应用场景
      • 表格解析
      • 图表解析

金句 / Highlights

值得收藏与分享的关键句。

#自适应解析#LLM#Azure#文档处理#企业RAG
打开原文

实施自适应解析的循环工程:使用 Azure 和视觉大语言模型解析平面表格和图表 | Towards Data Science

大语言模型

实施自适应解析的循环工程:使用 Azure 和视觉大语言模型解析平面表格和图表

企业文档智能 [第1卷 #10B] – 大语言模型作为最后一道防线,完整演示两次真实升级流程:平面表格到 Azure,图表到视觉模型

angela shi

2026年7月20日

25分钟阅读

分享

照片由 Larry Hyler 提供,来源:Pexels。

一些解析错误在答案出现之前看起来并不明显(经典 OCR 就是教科书案例:EasyOCR 会恢复文字但悄悄忽略周围的表格结构,直到你将答案与页面核对时,结果看起来才正常)。确定性检查可以免费捕捉明显失败的情况,但那些解析成看似合理但实际荒谬的表格会轻松通过检查,模型会自信地基于这些荒谬内容生成答案。上游流程没有发出任何警告,因为从纸面看解析结果是正常的。最后一道防线是 LLM 在用户看到答案之前先阅读自己的输入。

本文是自适应解析系列文章的第二部分,属于《企业文档智能》系列的第三部分,该系列通过四个模块构建企业级 RAG 系统:文档解析、问题解析、检索和生成。第一部分《使用自适应 PDF 解析的循环工程:从低成本开始,仅在页面需要时升级到更重的解析器》(链接即将发布)构建了升级级联和能免费标记失败解析的确定性检查。本部分新增了 LLM 作为最后一道防线,并完整演示了两次真实升级流程。

本文在系列中的位置:第10篇(自适应解析),第三部分 – 图片由作者提供

📓 可运行的配套内容完整演示了两次升级流程:你使用 fitz 解析平面表格页面后,再用 Azure 重新解析,将图表页面发送给视觉 LLM,观察 context_structured 如何将生成结果从错误答案改为正确答案。GitHub:doc-intel/notebooks-vol1

公共配套代码仓库 doc-intel/notebooks-vol1 – 图片由作者提供

PyMuPDF 可以免费在 5 毫秒内解析一页。同样的页面使用视觉 LLM 可能需要花费 10,000 倍的费用并耗时 10 秒。当问题以普通文本形式存在时,低成本解析器胜出。当答案隐藏在表格、图表、扫描区域或扁平化布局中时,低成本解析器会默默返回无用信息,而 LLM 会自信地回答错误问题。

对每一页都运行最重的解析器是浪费资源的。在所有地方都使用最便宜的解析器是错误的。关键在于从低成本解析器开始,仅在某些信号表明低成本解析器遗漏了答案时才升级。这个信号必须来自流水线本身:对解析输出、问题和 LLM 尝试使用解析结果时自身特征的一系列检查。

解决方法是流水线为自己构建的反馈循环。从最便宜的解析器开始。在流水线的每个检查点评估其输出。只有当至少一个检查标记低成本解析器不足以回答问题时,才升级到更深入的解析器。

评估不是单一位置的一次检查。这是一个级联过程:

  • 预解析元数据在任何提取之前就路由了大部分语料库
  • 解析时的输出会标记扁平化表格和不透明图表
  • 检索评分会捕捉漂移的锚点
  • 生成标志:所有上述检查中幸存下来的内容

每个检查的代价都比下一个低,可靠性也比下一个高,并且会提出自己的问题:“解析器生成的内容是否足够回答问题?”

第一部分在生成之前以较低的代价捕获了失败情况。当问题滑过这一关卡时,就会触发第二部分:LLM在生成时的自身痕迹(检查7,自我评估;检查8,基于事实性)会标记出确定性检查遗漏的解析错误,管道会将有问题的页面升级到更深层次的解析器。两个反复出现的案例被完整演示:《注意力机制》论文(Vaswani等,2017年,arXiv非独家许可协议下)第9页的表格(被升级到Azure布局解析)和第3页的图1(被升级到视觉LLM解析)。这两个案例都是真实的,且每天都会在企业语料库中出现。

1. 生成端检查:检查7(自我评估)和检查8(基于事实性)

生成是级联流程的最后一步。它的两个检查是检查7(LLM的自我评估标志,内嵌在结构化答案中)和检查8(在答案生成后的独立LLM或NLI基于事实性检查)。检查7是全景中最昂贵且最不稳定的检查,因此这一部分会投入大量时间处理它:两个展示其有效触发的案例(第2节案例A,第3节案例B),然后是一个压力测试说明LLM信号本身并不足够(第4节)。检查8对应第5节。

在两个案例演示之前:大多数问题根本不需要任何升级。第9篇论文对同一份《注意力机制》论文使用问题“位置编码有哪些选项?”运行标准流程,在第一次生成时就得到了清晰答案(context_structured=True),无需重新解析。仅PyMuPDF就足够,因为答案存在于文本中。NIST文档中的问题“CSF函数有哪六个?”也是如此。下面的两个案例是更复杂的情况,PyMuPDF无法识别问题所需信息。

《注意力机制》论文中的两个问题,两种失败形态,两次解析器升级。这两个案例特意设计为镜像关系:相同的数据模型,在深层步骤使用不同的解析器。

2. 案例A:平面表格升级,端到端演示

问题:“在《Transformer架构变体》表格中,基础模型的h值是多少?”正确答案是8,可从《注意力机制》论文第9页表格3基础行的h列直接读取。该单元格已填充(非空白),答案本身无歧义;真正考验流程的是周围网格的平面解析形态,这正是检查2指纹在第一部分已免费标记的特征,同时也是检查7的LLM信号下方再次标记的特征。

2.1. 直接使用的问题

第6篇构建了一个问题解析模块(parse_question),可处理拼写错误、多部分问题、语言检测和专家术语扩展。对于如此简短且清晰的问题,该模块过于复杂。我们跳过它,直接将问题文本输入检索和生成模块。流程不会中断,我们只是选择不调用四个模块中的一个,因为输入已符合下游所需格式。

我们在检索调用中手动选择的关键词:仅表格标题字符串“Table 3: Variations on the Transformer architecture”。在该语料库中,一个具体短语就足够。

2.2. 解析:使用边界框的PyMuPDF

标准流程以PyMuPDF起步,成本低廉。一个函数,一行代码:

code
line_df = fitz_pdf_to_line_df("data/paper/1706.03762v7.pdf")
page_df = build_page_df(line_df)

# line_df.shape ~ (1500, 8)
# columns : page_num, line_num, text, x0, y0, x1, y1, character_count

捕获的line_df前八行(第1页,在查看第9页之前):

前八行line_df数据;每行都携带其在PDF中的边界框坐标 – 作者图片

2.3. 检索:哪种方法能定位到第9页,如何实现

第7篇文章介绍了四种检索方法:关键词匹配、嵌入相似性、目录匹配,以及一个LLM调度器。对于这个问题,关键词检索已足够,因为问题中提到了特定字符串(“Table 3”),而第9页的表格标题正好原样重复了该字符串。我们将该字符串作为唯一关键词传递:

code
from docintel.retrieval import retrieve_pages

retrieved_pages_df, filtered_line_df = retrieve_pages(
    page_df, line_df,
    keywords=["Table 3: Variations on the Transformer architecture"],
    top_k=5,
)

捕获的retrieved_pages_df结果:

返回1页:标题短语在第9页独一无二 – 作者图片

与retrieved_pages_df一同返回的filtered_line_df携带了第9页的所有行,准备进入生成模块。

2.4. 首次生成:gpt-4.1处理PyMuPDF,LLM标记解析问题

生成模块(llm_answer_with_evidence,见第8篇文章)接收过滤后的行和问题,通过Pydantic模式调用gpt-4.1作为输出协议。AnswerWithEvidence模式已包含结构化上下文(第8篇文章新增),因此调度器可通过一个比特触发器判断每次回答是否需要继续处理:

code
from docintel.generation import llm_answer_with_evidence
from docintel.generation.qa.schemas import AnswerWithEvidence

pass1: AnswerWithEvidence = llm_answer_with_evidence(
    question=("What is the value of h for the base model "
              "in Table of Variations on the Transformer architecture?"),
    filtered_line_df=fitz_p9,    # PyMuPDF处理的第9页行数据
)
# AnswerWithEvidence包含:
#   answer, start/end_page_num, start/end_line_num, confidence,
#   justification, caveats,
#   context_structured  <-- 触发级联处理的二进制开关
#   complete_answer_found, llm_discovered_keywords

实际运行结果(复制粘贴):

首次生成:正确答案"8",置信度0.99,但context_structured=False标记解析问题 – 作者图片

code
{
  "answer": "8",
  "start_page_num": 9,
  "start_line_num": 25,
  "end_page_num": 9,
  "end_line_num": 25,
  "confidence": 0.99,
  "justification": "In the table listing parameters for different Transformer ...",
  "caveats": [],
  "complete_answer_found": true,
  "context_structured": false,
  "llm_discovered_keywords": []
}

答案是"8",正确值。引用指向第9页PyMuPDF的L25行。回看解析:L25确实是基础行的h单元格(基础行在L21,随后值L22=6(N),L23=512(dmodel),L24=2048(dff),L25=8(h))。LLM同时获得了正确的值和正确的单元格。

但 context_structured=False。LLM 标记了结构风险。PyMuPDF 将 13 个基础行单元格作为 13 条独立的线 L22-L33 返回,列标题位于 L5-L20 行(部分为单行,部分如“train steps”等复合标题跨两行)。要将 L25 映射到“h”,LLM 必须在扁平化标题中计算列位置。这次它正确了,但发出警告:结构脆弱,下次类似问题若不检查请勿信任。

二进制标志是触发条件。当为 False 时,无论答案的置信度如何,协调器都会升级处理。

2.5. 管道升级:使用 Azure DI 重新解析第 9 页

context_structured=False。协调器选择结构感知解析器。该项目已集成 Azure DI,但 Camelot、Docling 或任何其他表格感知解析器均可无缝接入:

code
from docintel.parsing.pdf.azure_layout import azure_layout_pdf_to_line_df

azure_p9 = azure_layout_pdf_to_line_df(
    "data/paper/1706.03762v7.pdf",
    pages=[9],     # 仅指向目标页面
)
# azure_p9.shape ~ (52, 9)
# 列:page_num, line_num, text, x0, y0, x1, y1, character_count, parsing_method
# 每行的 parsing_method 均为 "azure_layout"

第 9 页的前 8 行 Azure 数据:

Azure line_df,第 9 页:每行表格数据作为一条 markdown 线,以管道符对齐 – 作者配图

文本列存储 Azure 的 markdown 内容,每行对应表格一行。解码回网格后,即为 Azure 恢复的表 3 结构,这是 PyMuPDF 扁平化后的结构:

Azure 恢复的表 3:基础模型的 h 清晰显示为 8 – 作者配图

2.6. 第二代:相同模型,此次结构可信赖

与第一轮调用相同,但使用 Azure 行而非 PyMuPDF 行。捕获的响应:

code
{
  "answer": "8",
  "start_page_num": 9,
  "start_line_num": 7,
  "end_page_num": 9,
  "end_line_num": 7,
  "confidence": 0.98,
  "justification": "在表 3(第 7 行)中,'base' 模型列出了其超参数...",
  "caveats": [],
  "context_structured": true
}

相同数值,此次 LLM 信任结构。读取 Azure 行时,模型无需计算列数:h 是 markdown 行的第 5 个单元格,值 8 就在旁边,上方 L5 的列标题 h 也是第 5 个单元格。引用是整行而非单个单元格,但单元格到列的映射明确,因为管道符锚定了所有内容。

反馈循环已触发并解决。成本:一次额外的 Azure DI 调用(约 0.003 美元和 4 秒)。收益:答案现在结构可信赖,line_df 永久记录了第 9 页的结构化数据,供未来任何问题使用。

2.7. 注释:在 PDF 上高亮引用单元格

注释模块将证据范围转换为在源 PDF 上绘制的矩形。我们使用第一轮引用(PyMuPDF L25,基础行的 h 单元格),因为 PyMuPDF 返回的每单元格行具有紧密的边界框;Azure 行会生成覆盖所有 13 个单元格的整行框:

code
from docintel.rendering.pdf.annotation import (
    passage_lines_df_from_answer,
    passage_bbox_by_page,
    draw_passage_rectangles,
)

passage_df = passage_lines_df_from_answer(line_df, pass1)
bboxes_df  = passage_bbox_by_page(passage_df)

draw_passage_rectangles(
    pdf_path="data/paper/1706.03762v7.pdf",
    bboxes_df=bboxes_df,
    out_pdf_path="output/parsing_comparison/h_value_annotated.pdf",
)

捕获的 passage_df 为一行:

passage_df 来自第一轮处理的结果:每行对应一个单元格,一个边界框 – 作者提供的图片

而 bboxes_df 则是按页面合并后的结果:

bboxes_df:每页一个矩形,用于绘制段落矩形 – 作者提供的图片

渲染后的注释PDF页面(第9页上半部分,裁剪至表3区域):

《Attention》论文第9页,被引用的h单元格以红色高亮 – 作者提供的图片

端到端可审计性:问题从文本输入经过四个处理模块后,最终在源PDF上形成一个矩形。审阅者可以扫描高亮页面,在一秒内验证被引用单元格是否与LLM的声明一致。尽管反馈循环已触发(第一轮处理cs=False -> 升级),但审计轨迹并未中断;系统为同一页添加了Azure解析的行数据,同时保留了PyMuPDF的原始行数据,注释使用了PyMuPDF的边界框,因为该边界框最精确。

2.8. 附录:同一问题在三个模型和两个解析器上的表现

上述流程演示使用了gpt-4.1。为了观察解析器质量与模型性能在此问题上的交互关系,我们使用相同的问题在三个模型(gpt-4o-mini、gpt-4o、gpt-4.1)和两个解析器(PyMuPDF、Azure DI)上进行了测试。下表中每个单元格都应显示"8",有趣的变化体现在context_structured标志上:

所有模型都返回了8;只有PyMuPDF上的gpt-4.1标记了解析问题 – 作者提供的图片

两个发现:

首先,所有位置的答案完全一致。该问题在源文档中是明确的:数值8位于一个正常的填充单元格中,LLM无论使用何种解析器或模型都能可靠提取。

其次,context_structured标志以有意义的方式变化。gpt-4o-mini和gpt-4o接受PyMuPDF的扁平化线条而未触发警告。gpt-4.1保守地标记了结构风险,尽管它正确回答了问题。流程的可靠性取决于哪个模型填充标志:更强的模型能更诚实地反映上游解析风险。使用Azure DI时,所有模型都信任结构;解析器在标志维度上弥合了模型性能的差距。

结论:升级解析器是持久的解决方案,因为它能彻底消除结构风险。升级模型能提高检测解析风险的可能性,但无法完全消除风险。混合使用这两种方法的生产流程可以同时规避两种弱点。

3. 案例B:图表升级,端到端处理

问题:"Transformer的架构是什么?" 答案主要由第3页的图1(编码器-解码器架构图)承载。围绕该图的文本描述了架构的组成部分,但没有替代图表。

第一轮处理(仅使用PyMuPDF):检索定位到第3页。PyMuPDF返回了周围的文本以及图1的type='image'行,包含占位符文本但没有实际内容。图1周围的line_df大致如下:

第3页图1周围:文本加一个图像占位符行 – 作者提供的图片

第一轮生成:LLM阅读文本,注意到占位符和缺失内容,生成包含结构警告的不完整答案:

code
{
  "answer": "Transformer使用6层编码器和6层解码器...",
  "start_page_num": 3,
  "start_line_num": 12,
  "end_page_num": 3,
  "end_line_num": 14,
  "confidence": 0.55,
  "caveats": [
    "文本提及图1但其内容缺失..."
  ],
  "complete_answer_found": false,
  "context_structured": true
}

Pipeline 对图像调用视觉大语言模型(vision LLM)。Azure DI 在此场景下无法提供帮助:该图表不是表格,而是自由形式的矢量几何图形。Pipeline 读取到“图示被引用但缺失”的备注,查找 image_df.image_id=1,发现 parsing_method='not_parsed',随后将任务路由至视觉-语言模型:

code
new_lines = vision_extract(
    "data/paper/1706.03762v7.pdf",
    pages=[3],
    image_ids=[1],
)
# new_lines.parsing_method == "vision_gpt4o"
# image_df : 行 image_id=1 从 parsing_method='not_parsed' 更新为 'vision_gpt4o'

视觉模型返回结构化描述:编码器输入嵌入加位置编码,六个相同层,每层包含多头自注意力机制与残差连接及层归一化,随后是位置感知前馈网络与残差和归一化;解码器镜像结构包含掩码自注意力加对编码器输出的交叉注意力;最终通过线性层和 softmax 映射至词汇表。该描述以 parsing_method='vision_gpt4o' 的新文本行形式追加至 line_df。

生成阶段,第 2 轮:LLM 现在同时拥有文本描述和结构化视觉描述。它以高置信度生成完整答案,明确提及残差连接、层归一化位置、交叉注意力桥接等细节——这些是纯文本描述未明确列出的内容。

code
{
  "answer": "编码器-解码器结构。编码器包含 6 个相同层;每层包含 m...",
  "start_page_num": 3,
  "start_line_num": 30,
  "end_page_num": 3,
  "end_line_num": 42,
  "confidence": 0.92,
  "complete_answer_found": true,
  "context_structured": true
}

总耗时:PyMuPDF 处理耗时 5 秒,单张图像的视觉模型调用耗时约 10-30 秒且成本数美分。论文其余 14 页从未经过视觉模型处理。

4. 对 LLM 信号的压力测试(18 次运行揭示的发现)

第 2、3 章的示例展示了 LLM 信号在两个真实问题上的有效触发。这是理想情况。为观察信号在非理想情况下的表现,我们针对结构复杂度递增的问题、三种模型和两种解析器进行了压力测试。测试结果比单一理想路径示例更令人担忧,这也验证了级联顺序的合理性:让廉价的确定性检查(检查点 1 和 2)承担主要负载,将 LLM 信号作为最后防线而非首道防线。

4.1 压力矩阵:18 个单元格,4 个错误答案,0 个预警信号

我们针对注意力论文表 3,用 3 个模型(gpt-4o-mini、gpt-4o、gpt-4.1)和 2 个解析器(PyMuPDF、Azure DI)对 3 个结构复杂度递增的问题进行了 18 次测试。

测试问题:

  • Q_easy:基准行 h 值。答案是 8,位于直接标注的单元格中。
  • Q_inheritance:标注为 (B) 的行 h 值。答案仍是 8,因 (B) 的 h 单元格为空而继承自基准行。扁平解析丢失了列锚点。
  • Q_far:大模型在开发集上的困惑度。答案是 4.33,位于长表格最后一行,周围有大量相似数字。

初始设定是:弱模型虽无法回答问题,但仍能将解析错误标记为结构预警信号。但数据表明情况相反。当弱模型在 Q_inheritance 上给出错误答案时,它并未触发预警,反而伪造了 context_structured=True 的上下文信息。

18 次运行中,4 个错误答案均标记为 cs=True;唯一 cs=False 的情况是正确答案——图片由作者提供

4.2. 连续评分同样无能为力

自然的下一步是将二元标志替换为0.0-1.0的评分,期望LLM在不确定时使用范围中间值。我们重新运行了矩阵,新增了context_structured_score字段。

无论答案是否正确,评分始终集中在0.85到1.00之间。正确答案的平均评分:0.919。错误答案的平均评分:0.920。完全相同。在阈值0.95时,评分能捕捉到三个错误答案,但会在十五个正确答案中触发九次误报,误报率达60%。没有可用的阈值。

LLM的结构判断是伪装成连续分布的双峰分布。评分在二元标志之外没有带来任何价值。

4.3. LLM可以描述解析,但其判断是不稳定的部分

要求gpt-4.1在标志旁提供一句理由改变了画面。理由文本在多次运行中具体且一致:“标题跨多行分割”、“每个单元格独占一行且未对齐”、“空白单元格表示继承值”。模型每次都能准确描述解析结构。

然而,在理由之上的判断却是不稳定的。我们在PyMuPDF的Q_inheritance上三次运行gpt-4.1,输入和温度设置相同:

gpt-4.1在相同输入三次运行:稳定的理由,波动的标志和评分 – 图片由作者提供

模型知道解析哪里出错了,但无法可靠判断这是否足以升级。一个读取理由并在此基础上应用确定性规则的反馈循环(“包含‘跨多行分割’或‘每个单元格独占一行’或‘空白单元格’”则升级)会变得稳定。直接读取二元标志或评分则无法实现。

5. 检查8:生成后的真实性验证

答案生成后,第二个LLM(或NLI模型)会验证答案中的每个主张是否都得到引用片段的支持。这能捕捉到生成模型过于自信而无法在检查7中自我标记的虚构内容。成本:多一次LLM调用。可靠性:高于相同模型自我评估答案,因为评判者是新的且没有保护生成的动机。相比检查7中LLM作为评判者的解析质量检查方法,这种方法更便宜且更可靠,是生成阶段唯一有机会捕捉检查7遗漏的虚构内容的检查项。

整体流程表明:检查1和2在每页上以毫秒级速度触发(文档解析);检查4在问题上触发(问题解析);检查5和6在检索后触发(检索);检查7仅在上游检查给页面出具“干净证明”时触发(本节内容);检查8在生成后作为最终安全网触发(本节内容)。上述走查展示了检查7作为最后一道防线时的样貌;全景表明这不应是唯一的防线。

6. 操作注意事项

在结束前再补充两个实用的优化点:当惰性默认策略失效时,以及数据模型如何实现缓存的自动获取。

6.1. 主动解析为何有时更优

惰性解析是合理的默认策略,但并非所有场景都适用:

  • 永久性、高频查询的文档:标准保险单模板在其生命周期内会被查询数千次。应在摄入阶段使用Docling或Azure进行一次解析,存储结果并分摊到所有未来查询中。
  • 审计级文档:尽职调查、监管申报、诉讼文件等场景。当需要可辩护的完整记录时,前期完整解析是基准操作。虽然成本较高,但遗漏关键条款的潜在风险远超成本。
  • 小型文档:20页以下的文档,对整个文档运行Docling或Azure的边际成本较低。像15页的《注意力》论文可能属于此类,此时成本效益比发生转变。
  • 预计算的搜索索引:对语料库进行全文检索时,摄入阶段只需解析一次。惰性解析在查询阶段针对单个文档生效,而非语料库摄入阶段。

关键判断标准:该文档在其生命周期内平均会被查询多少次?多次查询时选择主动解析,少数或未知次数时选择惰性解析。对于典型企业语料库(多数文档仅被查询0-1次),惰性解析的收益显著。

6.2. 数据模型本身就是缓存

当流水线使用Azure重新解析《注意力》论文第6页时,结果会记录到line_df(解析方法标记为'azure_layout')和page_df的对应审计行中。后续任何涉及第6页的查询都会直接命中这些记录。无需重新解析。缓存并非独立层级,它就是检索操作已读取的line_df和page_df。

code
def get_or_enrich(pdf_path, line_df, page_df, pages, method):
    """如果已存在相同方法的解析结果,则复用已有数据"""
    done = page_df[
        (page_df.page_num.isin(pages)) &
        (page_df.parsing_method == method)
    ]
    missing = [p for p in pages if p not in done.page_num.values]
    if not missing:
        return line_df, page_df                         # 已完成解析
    return enrich(pdf_path, line_df, page_df, missing, method)

随着时间推移,缓存会积累由查询触发的解析结果。最常被查询的文档关键区域会自动获得深度解析版本,而很少被访问的区域则保持低成本解析。系统根据实际使用情况而非摄入阶段的猜测,自动学习深度解析的投入位置。

7. 结论

解析质量是跨四个模块的多维度决策,按成本优先级排序:解析阶段的确定性信号(字符密度、扁平表格指纹、块完整性),问题解析阶段的意图感知路由,检索阶段的得分差距和上下文差距检查,最后是LLM自评估作为最终防线。第4节的压力测试使这一顺序不可协商:LLM对其自身上下文的二元判断不够稳定,无法主导流程,必须依赖独立的新裁判才能发现伪造内容。

数据模型承载了级联:在每个解析表中将 parsing_method 作为列,使得混合解析、升级、审计和缓存都简化为对某一列的过滤操作。相同的框架结构可支持任何新的失败形态:添加新形态只需在路由映射表中增加一行,添加新检查只需增加一列。文章11保持相同的自我修正框架,并将其应用于交叉引用场景。

8. 参考资料与延伸阅读

关于高级解析功能及其每页成本的参考文献是 Docling(Auer等,《Docling技术报告》,2024)。将表格提取作为独立于文本提取的问题进行研究,由Smock等(《PubTables-1M/Table Transformer》,CVPR 2022)奠定基础。基于每页的视觉LLM成本层级(GPU上约5-30秒)来自Blecher等(《Nougat》,Meta 2023)。文章使用的LLM作为反馈信号模式驱动升级,与Asai等(《Self-RAG》,ICLR 2024)提出的模式属于同一系列。文章报告了一个具体负面结果:经过18次压力测试后发现,LLM自我评估作为二元解析质量判定标准本身不可靠;对生成答案进行独立LLM的 groundedness 检查能够捕捉到循环信号遗漏的问题。

系列文章前序内容:

  • 文档智能:系列简介。说明系列构建的模块及其顺序。

有效与失效的实践

  • 基线企业级RAG:从PDF到高亮答案。四模块完整流程:PDF输入,高亮答案输出。
  • 嵌入向量并非魔法:RAG检索的可预测失效模式。说明嵌入相似性适用场景(同义词、拼写错误、改写)与失效场景(未知术语、否定、术语与答案相关性),以及如何继续使用。重排序器也并非魔法:交叉编码器层何时值得成本投入。量化交叉编码器相对于双编码器嵌入的增益,并说明何时值得承担延迟成本。
  • RAG不是机器学习,机器学习工具箱解决的是错误问题。解释块大小调整和微调优化了错误目标;应根据问题类型进行路由。
  • 从正则表达式到视觉模型:哪种RAG技术适合哪种问题。两个维度(文档复杂度与问题控制)帮助选择对应技术。生产环境中常见的10个RAG错误。按模块分类的10个生产错误及其修复方案。

文档解析

  • 超越extract_text:驱动RAG质量的PDF双层结构。解析模块的第一部分:文档特性、信号与摘要。
  • 停止从PDF返回平面文本:RAG需要的关联表格。解析模块的第二部分:所有下游模块读取的关联表格。使用EasyOCR解析扫描PDF用于RAG:免费OCR提供文字而非文档。传统OCR的局限:文本恢复但结构丢失。

问题解析

  • RAG问题也需要解析:将用户字符串转化为检索与生成简报。问题解析的论点:为何用户字符串需要与文档相同的解析,以及如何拆分为检索简报与生成简报。
  • 问题解析器从用户字符串提取的内容:关键词、范围、形态、分解、澄清。解析器直接从用户问题读取的五类列及其填充代码。
  • 分发解析后的RAG问题:分块策略、模型层级、激活项和审计。解析器基于用户输入字符串和文档配置文件做出的决策:分发机制、激活项、完整模式、审计追踪(pipeline_trace.json)以及经纪-语料库的流程解析。澄清循环与学习默认值:当问题不够精确时。当问题过于模糊时进行针对性澄清,以及从答案中学习到的默认值。

检索

  • 检索是过滤而非搜索:企业级RAG的思维模型。将检索重新定义为对line_df和toc_df的过滤操作:锚点精简,上下文内容丰富。
  • RAG的锚点检测:并行检测器,最后进行一次LLM调用。并行锚点检测器:始终启用关键词匹配,同时使用嵌入向量,最后进行一次LLM调用。
  • 让LLM选择正确的RAG页面:检索结束时的仲裁模式。LLM仲裁器:按理由对候选结果排序,输出一个类型化JSON。上下文工程:每个答案背后的四种类型化输入。基于结构的上下文工程:四个类型化组件(固定系统提示、检索到的段落、文档上下文块、PromptContext包装器)共同构成单文档RAG的LLM调用。

生成

  • 使RAG生成返回类型化契约:引用标注、类型化值和自我检查(链接待补充)。答案模式作为契约:类型化值、带证据跨度的条目、自我评估字段,以及流水线自行计算的完整性信号。
  • 从基础提示加上每个问题所需的规则组装每个RAG生成提示(链接待补充)。分发器:固定BASE提示加上每个问题所需的规则,从注册表中选择模式,并在每次调用时保留完整追踪记录。
  • 在用户看到RAG答案前进行验证:跨度、引述和反馈循环(链接待补充)。后生成验证器(跨度、逐字引述、格式),"未找到"作为一级答案类型,以及闭合流水线的反馈循环。

单文档流水线

  • 用于PDF的生产级RAG流水线:关系型解析、目录检索、类型化答案(链接待补充)。每个砖块逐步升级一个契约:关系型解析、语料库感知问题、目录路由检索、类型化答案。
  • 通过上下文工程阻止RAG幻觉:一个流水线处理四种截然不同的PDF(链接待补充)。四个升级后的砖块连接成一个调用,在论文、合规文档和目录损坏文档上端到端运行。
  • 通过自适应PDF解析进行循环工程:先使用低成本解析,仅在需要时升级到更复杂的解析器(链接待补充)。升级级联机制和免费的确定性检查,在支付更深度解析费用前标记解析失败。

作者信息

查看angela shi的所有文章

文档处理

,

解析

RAG

RAG架构

视觉语言模型

分享本文

  • 在Facebook上分享
  • 在LinkedIn上分享
  • 在X上分享

Towards Data Science是社区出版物。提交您的见解以触达全球受众,并通过TDS作者支付计划获得收益。

更新为实际投稿URL

为TDS撰写文章

✦ 结束CTA ✦