处理单页 PDF,OCR 就够了。但处理多页 PDF(比如跨页表格、跨页的上下文引用),你需要的是 “视觉长上下文(Visual Long Context)”。
InternVL 2.5 解决这个问题的思路不是硬抗(虽然它支持 128k 上下文),而是通过 “动态分辨率策略” 和 “视频模式hack” 来平衡精度与显存。
1. 核心机制:Image-Token 的预算管理
在 InternVL 2.5 中,处理多页文档有两种策略,分别对应不同的业务场景:
- 策略 A:高精模式 (High-Res Strategy)
- 原理:每页 PDF 都作为一张独立的高分辨率图片输入(
<image>Page1</image> <image>Page2</image>...)。 - Token 消耗:每页约 1000~3000 Tokens。
- 瓶颈:一张 A100 (80G) 最多只能塞进约 8-10 页高精图。
- 适用场景:合同比对、发票审核。必须看清每一个小数点。
- 原理:每页 PDF 都作为一张独立的高分辨率图片输入(
- 策略 B:视频模式 (The Video Hack)
- 原理:这是处理长文档的黑科技。InternVL 2.5 具备强大的视频理解能力。我们可以把 PDF 的每一页看作视频的一帧。
- Token 消耗:模型会自动对帧进行降采样(Sub-sampling)。虽然分辨率降低了,但模型能理解“时间序”(也就是页码序)。
- 优势:你可以一次性塞进 50 页甚至 100 页 PDF,让模型做摘要或宏观分析。
- 适用场景:研报摘要、PPT 逻辑梳理、书籍大纲提取。
2. 架构优势:Pixel Shuffle 与 动态 Patch
为什么 InternVL 比 LLaVA 更适合多页?
- 动态 Patch:它不是死板的 336×336。如果你的一页 PDF 是长条形的,它会自适应切片,不会引入过多的 Padding(无效 Token)。
- M-LLM 架构:InternVL 的基座(InternViT)极其强大(6B 参数),它在视觉编码阶段就压缩了大量信息,传给 LLM 的 Token 密度很高。这意味着同样的 128k 上下文,InternVL 能容纳的信息量远超同类模型。
3. 代码实战:如何一次性喂入 10 页 PDF
使用 lmdeploy 跑多图推理是最稳的。这里演示如何将一个 PDF 拆成图片,然后作为 “多图对话” 喂给 InternVL。
环境准备: 你需要安装 pdf2image 来处理 PDF。
Bash
pip install lmdeploy pdf2image
# 系统需安装 poppler-utils (apt-get install poppler-utils)
Python 推理代码:
Python
from lmdeploy import pipeline, TurbomindEngineConfig
from lmdeploy.vl import load_image
from pdf2image import convert_from_path
import os
# 1. PDF 转图片列表
def pdf_to_images(pdf_path, max_pages=5):
# dpi=200 足够看清大部分文字,太高会撑爆显存
images = convert_from_path(pdf_path, dpi=200)[:max_pages]
saved_paths = []
for i, img in enumerate(images):
path = f"page_{i}.jpg"
img.save(path, "JPEG")
saved_paths.append(path)
return saved_paths
# 2. 初始化引擎
# session_len 必须开大,因为多图会产生巨量 Token
backend_config = TurbomindEngineConfig(
session_len=32000,
cache_max_entry_count=0.4, # 留给 KV Cache 的显存比例
tp=1 # Tensor Parallel (如果你有多卡,可以设为 2 或 4)
)
pipe = pipeline('OpenGVLab/InternVL2-8B', backend_config=backend_config)
# 3. 准备 Prompt 和 图片数据
pdf_file = "annual_report.pdf"
image_paths = pdf_to_images(pdf_file, max_pages=5) # 取前5页
# 加载所有图片
loaded_images = [load_image(p) for p in image_paths]
# 构造多图 Prompt
# 格式: (prompt, [img1, img2, ...])
# 注意:InternVL 会自动识别 list 中的 image 并插入到 prompt 中
prompt = "This is a 5-page financial report. Please summarize the revenue growth and highlight any risks mentioned across these pages."
print(f"正在处理 {len(loaded_images)} 页文档...")
# 4. 推理
response = pipe((prompt, loaded_images))
print("\n=== 分析结果 ===")
print(response.text)
# 清理临时文件
for p in image_paths: os.remove(p)
4. 显存优化:KV Cache 的那点事
在工业落地中,多页文档最大的敌人是 KV Cache。
- 现象:模型加载只占了 16G 显存,但一跑 10 页 PDF,显存瞬间飙到 40G 然后 OOM。
- 原因:每一张高分图切出来的 Token,在 LLM 的 Attention 层都要生成 KV Cache。Image Token 是不会像 Text Token 那样被逐个生成的,它们是一次性灌入的(Prefill 阶段)。
- 解法:
- 限制
max_dynamic_patch:在lmdeploy配置中,限制每张图最多切 4 块(默认可能是 12 或更多)。这会降低分辨率,但能显著减少 Token 数。 - 4-bit KV Cache:LMDeploy 支持 KV Cache 量化。开启后,长文档推理的显存占用能砍半。
- 限制
5. 进阶玩法:Visual RAG (视觉检索增强)
对于几百页的文档,直接喂给 InternVL 是不现实的(也没必要)。
工业界的标准做法是 Visual RAG:
- Embedding:用视觉模型(如 ColPali 或 CLIP)给每一页 PDF 打 Embedding。
- Retrieval:用户问“2023年营收是多少?”,检索出最相关的 Top-3 页 图片。
- Generation:只把这 3 页高清图喂给 InternVL 2.5 进行精读。
总结:
InternVL 2.5 的出现,让 “文档理解” 终于摆脱了 OCR 的中间环节。
- 对于 < 10 页的精密文档(合同、票据),直接用 High-Res 模式 全量喂入。
- 对于 > 10 页的宏观文档(PPT、书籍),使用 RAG + 局部精读 的策略。
别再试图用 Tesseract 去还原复杂的跨页表格了,直接让 InternVL “看着” 表格回答问题,才是 GenAI 时代的正确姿势。