一次 VLM 调用替代两次:GAIK Vision Extractor 把文档提取成本砍了一半
一次 VLM 调用替代两次:GAIK Vision Extractor 把文档提取成本砍了一半
企业文档结构化提取,今天还在用「先解析、再提取」的两步法。拆成两次 LLM 调用,先让模型把 PDF 转成 Markdown,再让另一个模型从 Markdown 里提取字段。
这个模式有个结构性问题:第一个模型决定「怎么表示文档」的时候,不知道第二个模型「需要什么」。
如果 Parser 把合并单元格拍平了、跨页表格截断了、侧边注释丢掉了,Extractor 只能从有损的中间表示里「猜」答案。更糟的是,它会输出一段看起来完全正确的 JSON——你很难发现数据已经错了。
芬兰 FAIR 项目的 Umair Ali Khan 在 5 月发表了一篇工程实践文章,给出了一个更优雅的方案:Vision Extractor,把解析和提取合并为单次 VLM 调用。
核心思路:Parser 的中间表示,移进模型推理内部
传统两步法的本质问题是:Parser 的输出是 Extractor 的唯一信息来源。模型拿到的是 Markdown,不是原图。一个跨页表格被截成两段,Extractor 无法「回头查看」第二页的原始图像。
Vision Extractor 的做法很简单——不在 Prompt 里要求模型输出中间表示,而是要求它在内部完成版面分析,然后直接输出结构化数据。
1SYSTEM_PROMPT = """
2...
3Before extracting, internally analyze the document by identifying
4each layout element as if wrapping it in a <div> tag with:
5- data-bbox="[x1, y1, x2, y2]"
6- data-label="<category>"
7
8Use this analysis to inform your extraction,
9but output only the structured data.
10..."""
Parser 的中间表示不再是输出 token,而是变成了模型推理过程中的一个环节。模型带着提取任务阅读文档,同时理解版面,同时输出指定字段。
效果:调用次数从 2 次降到 1 次,中间 token 直接省掉,延迟降低,信息损失降低。
Schema 自动生成:从自然语言到 Pydantic 模型
用户的提取需求通常是用自然语言描述的,比如:
"提取采购订单号、日期、供应商名称和所有行项目。"
Vision Extractor 内置了一个 Schema Generator,能从自然语言自动推导输出结构,并生成 Pydantic 模型。
它把输出结构分为三类:
- Flat(单层):每个字段只出现一次。比如酒店订单,一个预订号、一个入住日期
- Nested list(嵌套列表):输出是一张表格,每行有相同的字段
- Parent with nested list(主表+子表):顶层字段一次,行项目重复出现
第一版生成的 schema 可以持久化为 schema.py + requirements.json,后续相同类型的提取任务直接复用。
这套设计在工程层面很实用——业务用户不需要写 Python 类型定义,写自然语言需求就好。
字段级置信度:不只是整体打分
多数文档提取方案只给出「整体置信度」,Vision Extractor 给的是每个字段的置信度分数和推理过程。
评分规则:
| 置信度 | 含义 | 示例 |
|---|---|---|
| 0.95–1.00 | 确定 | 值明确无歧义出现在文档中 |
| 0.80–0.94 | 高 | 需少量解释(日期格式转换、缩写展开) |
| 0.60–0.79 | 中 | 需跨段推理或推断 |
| 0.40–0.59 | 低 | 证据弱或存在冲突 |
| 0.01–0.39 | 极低 | 仅凭猜测,必须人工审核 |
输出示例:
1{
2 "drawing_number": {
3 "value": "A-201",
4 "confidence_score": 0.99,
5 "confidence_reason": "Drawing number is explicitly stated as the sheet identifier."
6 },
7 "slab_thickness": {
8 "value": "4\"",
9 "confidence_score": 0.97,
10 "confidence_reason": "Slab section notes explicitly label the concrete slab as 4 inches thick."
11 }
12}
这个设计让 Human-in-the-loop 变得实际:审核者不需要重读整份文档,只看低置信度字段及其推理即可。
实际成本:单次调用约 $0.007 到 $0.022
文中给出了三组实测数据,全部使用 gpt-5.4-mini、reasoning_effort=low:
| 场景 | 文件数 | LLM 耗时 | Token 总量 | 费用 |
|---|---|---|---|---|
| 建筑蓝图提取(18 个字段) | 1 | 7.8s | 4,550 | $0.0065 |
| 采购订单提取(跨 2 页) | 1 | 18.3s | 10,736 | $0.022 |
| PO + 3 份 BOM 跨文档关联 | 4 | 7.7s | 10,064 | $0.012 |
最关键的数字是:小模型 + 低推理成本已经能覆盖大部分文档提取任务。不是所有场景都需要 GPT-5.5 级别的模型。
对复杂版面的文档,作者建议从小模型加低推理配置开始,如果需要更高精度再切换到大模型或提高 reasoning_effort。
跨文档关联:一次调用内完成
一个更复杂的场景:采购订单(PO)+ 多份物料清单(BOM)。
PO 里有物料编号,每份 BOM 有对应的技术规格。传统做法需要多次提取、手动关联。Vision Extractor 能在一次调用里完成:
- 提取 PO 的头部信息(订单日期、买家、地址)
- 提取每行项目的物料编号和数量
- 用物料编号去匹配对应的 BOM
- 从 BOM 中提取技术规格
- 组装成最终输出
四个 PDF 文件,一次调用,7.7 秒,$0.012。
开源与可用性
Vision Extractor 是芬兰 GAIK(Generative AI-enhanced Knowledge Management) 项目的一部分,MIT 协议开源。
1pip install "gaik[vision-extract]"使用示例:
1from gaik.software_components.vision_extractor import VisionExtractor
2
3extractor = VisionExtractor(
4 model_provider="openai",
5 model="gpt-5.4-mini",
6 reasoning_effort="low",
7 include_verification=True,
8)
9
10result = extractor.extract(
11 file_paths=["po.pdf"],
12 user_requirements="Extract purchase order number, date, vendor name, and all line items.",
13)
支持 OpenAI、Azure OpenAI、Google Vertex AI 三家 Provider。完整代码在 GAIK-project/gaik-toolkit。
适用边界
Vision Extractor 不是万能的。作者明确指出了不推荐的场景:
- 简单布局的纯文本文档:标准两步法(Docling/PyMuPDF + 轻量提取)更高效
- 超过 30 页的文档:VLM 上下文窗口限制
- 高确定性表单:专用 OCR 模型的确定性更好、成本更低
对于中等复杂度、多页、跨文档的场景,它是当前开源方案里最务实的选择之一。
小结
Vision Extractor 的核心贡献不在于发明新架构,而在于把一个已经被验证的想法——单次 VLM 调用替代多阶段 Pipeline——做成了可复用的工程组件。它的三个设计值得借鉴:
- Prompt 技巧:让模型在「内部」完成版面分析,不输出中间表示,降低 token 消耗和累积错误
- Schema 自动生成:从自然语言需求自动推导输出结构,减少工程落地成本
- 字段级置信度:每个字段带置信度分数和推理,让 Human-in-the-loop 从理念变成可操作的设计
文档提取这个领域,2026 年的趋势已经很明显:VLM 能力在快速提升,传统的 OCR + 布局分析 + LLM 提取的三阶段 Pipeline 正在向单次 VLM 调用靠拢。Vision Extractor 告诉我们,这个方向的工程落地门槛已经很低了——七分钱,就能从一份复杂文档里精确提取出你需要的所有字段。