乐于分享
好东西不私藏

从4周到45分钟:为4700多份PDF设计文档提取系统

从4周到45分钟:为4700多份PDF设计文档提取系统


引言

有人走进我的办公室,问我能否帮助从 4,700 多份工程图纸 PDF 中提取修订号。他们正在迁移到一个新的资产管理系统,需要每张图纸当前的 REV 值——一个埋藏在每个文档标题栏中的小字段。

另一种方案是让一个工程师团队逐个打开 PDF,定位标题栏,并手动将值输入电子表格。每张图纸按两分钟计算,大约需要 160 个人工小时,相当于一个工程师四周的工作量。按每小时约 50 英镑的全负荷成本计算,这项任务的人工成本超过 £8,000——而除了填充电子表格的一列之外,这项工作不产生任何工程价值。

这不仅仅是一个 AI 问题,而是一个具有真实约束的系统设计问题:预算、准确性要求、混合文件格式,以及一个需要可信结果的团队。AI 只是解决方案的一个组成部分,围绕它所做的工程决策才是系统真正发挥作用的关键。


"简单"PDF 中隐藏的复杂性

工程图纸不是普通的 PDF,主要分为两类:

  • 基于文本的 PDF
    :在 CAD 软件中创建并导出,可以通过编程提取文本
  • 基于图像的 PDF
    :20 世纪 90 年代和 21 世纪初的遗留图纸,从纸质原件扫描而来,整个页面是平坦的光栅图像,没有文本层

我们的语料库约 70-80% 是基于文本的,20-30% 是基于图像的

即使是基于文本的子集也很棘手,REV 值至少以四种格式出现:

  • 带连字符的数字版本,如 1-02-0 或 5-1
  • 单个字母,如 ABC
  • 双字母,如 AA 或 AB
  • 偶尔出现空字段或缺失字段

其他挑战还包括:

  • 部分图纸被旋转了 90° 或 270°
  • 旁边有修订历史表(多行变更日志),这是显而易见的误报陷阱
  • 图纸边框上的网格参考字母很容易被误认为是单字母修订版

为什么完全采用 AI 方案是错误的选择

你可以把每个文档都扔给 GPT-4 Vision 然后一了百了,但这样做意味着:

  • 按每张图像约 $0.01 和每次调用 10 秒计算,总花费约 $47,耗时近 100 分钟 的 API 时间
  • 更重要的是,你将为那些用几行 Python 代码就能在毫秒内提取答案的文档支付昂贵的推理费用

逻辑很简单:如果文档有可提取的文本,且 REV 值遵循可预测的模式,就没有理由涉及 LLM。 将模型留给确定性方法失败的情况。


行之有效的混合架构

该管道采用两阶段混合设计:

每个 PDF → 第1阶段(基于规则的 PyMuPDF 提取)              ↓ 成功 → 直接输出 CSV              ↓ 失败 → 第2阶段(GPT-4 Vision via Azure OpenAI)

第1阶段:PyMuPDF 提取(确定性,零成本)

对于每个 PDF,我们尝试使用 PyMuPDF 进行基于规则的提取。逻辑集中在页面的右下象限(标题栏所在位置),并搜索已知锚点(如 “REV”、“DWG NO”、“SHEET”、“SCALE”)附近的文本。评分函数根据候选文本与这些锚点的接近程度以及对已知 REV 格式的符合程度进行排名。

defextract_native_pymupdf(pdf_path: Path) -> Optional[RevResult]:"""尝试使用 PyMuPDF 进行原生文本提取(含空间过滤)"""try:        best = process_pdf_native(            pdf_path,            brx=DEFAULT_BR_X,      # 右下角 X 阈值            bry=DEFAULT_BR_Y,      # 右下角 Y 阈值            blocklist=DEFAULT_REV_2L_BLOCKLIST,            edge_margin=DEFAULT_EDGE_MARGIN        )if best and best.value:            value = _normalize_output_value(best.value)return RevResult(                file=pdf_path.name,                value=value,                engine=f"pymupdf_{best.engine}",                confidence="high"if best.score > 100else"medium",                notes=best.context_snippet            )returnNoneexcept Exception:returnNone

阻止列表过滤掉常见误报:区域标记、网格参考、页码指示器。将搜索限制在标题栏区域,将误匹配率降至接近零。


第2阶段:GPT-4 Vision(处理第1阶段遗漏的所有情况)

当原生提取返回空结果时(基于图像的 PDF,或文本布局过于复杂),我们将第一页渲染为 PNG,并通过 Azure OpenAI 发送给 GPT-4 Vision。

defpdf_to_base64_image(self, pdf_path: Path, page_idx: int = 0,                         dpi: int = 150) -> Tuple[strintbool]:"""将 PDF 页面转换为 base64 PNG,并智能处理旋转"""    rotation, should_correct = detect_and_validate_rotation(pdf_path)with fitz.open(pdf_path) as doc:        page = doc[page_idx]        pix = page.get_pixmap(matrix=fitz.Matrix(dpi/72, dpi/72), alpha=False)if rotation != 0and should_correct:            img_bytes = correct_rotation(pix, rotation)return base64.b64encode(img_bytes).decode(), rotation, Trueelse:return base64.b64encode(pix.tobytes("png")).decode(), rotation, False

经测试,150 DPI 是最优选择:

  • 更高分辨率会使负载膨胀并降低 API 速度,而不会提升准确性
  • 更低分辨率则会在边缘扫描件上丢失细节

生产环境中出现的问题

只有在运行完整的 4,700 个文档语料库时,才暴露出两类关键问题。

旋转歧义

工程图纸通常以横向布局存储,但编码方向的 PDF 元数据千差万别:

  • 有些文件正确设置了 /Rotate
  • 其他文件物理旋转了内容,但将元数据保留为零

解决方案:如果 PyMuPDF 可以从未校正的页面中提取超过十个文本块,则认为方向可能没问题;否则,在发送给 GPT-4 Vision 之前应用旋转校正。

提示词幻觉

模型有时会抓住提示词示例中的值,而不是读取实际图纸内容(例如,如果每个示例都显示 REV “2-0”,模型就会偏向输出 “2-0”)。

解决方案

  1. 多样化示例以涵盖所有有效格式,并添加明确的反记忆警告
  2. 清晰区分修订历史表(多行变更日志)和当前 REV 字段(标题栏中的单个值)

关键规则——避免以下情况:

✗ 不要从修订历史表中提取(列:REV | 描述 | 日期)  → 我们需要标题栏中的当前 REV(单个值)✗ 不要提取网格参考字母(沿边缘的 A、B、C)✗ 不要提取区域标记("SECTION C-C"、"SECTION B-B")

结果与权衡

用包含 400 个文件的人工验证数据集进行验证,结果如下:

指标
混合方案(PyMuPDF + GPT-4)
仅使用 GPT-4
准确率(n=400)
96%
98%
处理时间(n=4,730)
~45 分钟
~100 分钟
API 成本
~$10-15
~$47
人工审查率
~5%
~1%

2% 的准确率差距,换来了 55 分钟的时间节省和显著的成本控制。对于数据迁移场景而言,96% 的准确率配合 5% 的人工复核率是完全可以接受的。如果用例是法规合规,则应对每个文件都运行 GPT-4。

关于最新模型

我们后来对较新模型(包括 GPT-5+)在同一验证集上进行了基准测试。准确率与 GPT-4.1 相当,约为 98%。对于此提取任务,较新的模型没有提供有意义的性能提升,反而每次调用成本更高、推理速度更慢。 最终我们选择了 GPT-4.1。

当任务是在明确定义的文档区域内进行空间受限的模式匹配时,上限在于提示词和预处理,而不是模型的推理能力。


从脚本到系统

最初的交付物是一个命令行工具:输入一个 PDF 文件夹,输出一个结果 CSV。它在 Microsoft Azure 环境中运行,使用 Azure OpenAI 端点进行 GPT-4 Vision 调用。

初始迁移成功后,我们将管道包装在一个轻量级内部 Web 应用程序中,带有文件上传界面,让非技术用户也能随时运行提取,无需接触终端。该系统随后被组织内多个站点的工程团队采用,每个团队都运行自己的图纸档案库,用于迁移和审计任务。


给从业者的经验教训

1. 从最便宜的可行方法开始

使用 LLM 时,本能反应是将其用于所有事情。要抵制这种冲动。确定性提取以零成本处理了我们语料库的 70-80%。LLM 之所以能增加价值,只是因为我们将其集中在规则失败的情况下。

2. 在全量规模上验证,而不是在精选样本上

旋转歧义、修订历史表混淆、网格参考误报——这些在我们最初的 20 个文件测试集中都没有出现。你的验证集需要代表生产环境中实际会遇到的边缘情况分布。

3. 提示词工程就是软件工程

系统提示词经过多次迭代,包含结构化示例、明确的负面案例和自我验证检查表。将其视为一次性文本而不是精心版本控制的组件,会导致不可预测的输出。

4. 衡量对利益相关者重要的指标

工程师不在乎管道使用的是 PyMuPDF、GPT-4 还是"信鸽"。他们在乎的是:

  • 4,700 张图纸在 45 分钟内处理完毕,而不是四周
  • API 调用成本为 $50-70,而不是 £8,000+ 的工程时间
  • 结果足够准确,可以放心进行下一步

总结

整个管道约有 600 行 Python 代码。它节省了四周的工程时间,API 费用比一顿团队午餐还便宜,并且后来作为生产工具部署到多个站点。

我们测试了最新的模型。它们对于这项工作并没有更好。

有时,最高影响力的 AI 工作并不在于使用最强大的模型,而在于知道模型在系统中的位置,并让它待在那里。


往期推荐

掌握智能体 AI 系统中记忆的 7 个步骤

超越提示工程:5 种检测与缓解 LLM 幻觉的实用技术

从提示词到预测:深入理解 LLM 中的 Prefill、Decode 与 KV Cache

2026年值得关注的7大机器学习趋势