先说结论——Unlimited-OCR 是我目前用过单页效果最强的文档解析工具,没有之一。 但如果你听信某些教程,去试它所谓的“多页批处理”接口,那大概率会在第 3 页就看着显存飙红、程序崩掉。正确且唯一有效的姿势,就是写个 for 循环,一页一页地喂,让它每页都“失忆”一次。 我就是用这种“笨方法”,在 5060 Ti 16G 上成功啃完了 600 多页排版爆炸的技术书,输出 Markdown 质量吊打 PaddleOCR 十条街。

下面把我的血泪经验全摊开,包括为什么必须逐页循环、怎么把 600 页跑稳、以及合并脚本怎么写,顺便吐槽一下那些“伪多页”的坑。
这条是我用爆显存换来的教训,必须写在最前面:
PaddleOCR 这么干过,崩了;Unlimited-OCR 我也试过,加了 “请修正错别字”,单页推理从 5 秒变 30 秒,显存从 10G 飙到 15.8G,第三页直接 OOM。所以我的 prompt 永远焊死成官方原版:
prompt='<image>document parsing.' # 多一个单词都不要!
错别字、逻辑问题,那是人眼和 LLM 的事,别在 OCR 这一步瞎操心。
PaddleOCR 快是快,但面对多栏、表格、公式,它吐出来的就是一坨“线性文字”——左栏读到一半跳右栏,表格变成空格分隔的灾难,公式全成乱码。我花在“修复结构”上的时间,比跑 OCR 本身还多。
而 Unlimited-OCR 是端到端的 VLM,直接输出带 Markdown 结构的文本:
#、##、###)$...$)单页效果简直是艺术品。但问题来了——怎么把艺术品安全地拼成 600 页的“连环画”?
我在网上看到有人吹 Unlimited-OCR 可以直接传 PDF 路径,内部自动处理多页。于是我也试了试,结果:
后来翻源码才明白,官方那个“多页”其实就是把 PDF 转成图片列表,然后 for 循环调用同一个模型——但它没有做任何显存管理和输出聚合,效果还不如我们自己写循环。所以我的结论是:
既然官方靠不住,那就自己动手。我的完整流水线如下:
import fitz# PyMuPDFpdf = fitz.open("book.pdf")for page_num in range(len(pdf)):page = pdf[page_num]pix = page.get_pixmap(dpi=200)pix.save(f"page_{page_num+1:03d}.png")
for page_num in range(1, total_pages+1):img_path = f"page_{page_num:03d}.png"model.infer(tokenizer,prompt='<image>document parsing.', # 焊死!image_file=img_path,output_path=f"./output/page_{page_num:03d}",base_size=1024,image_size=640,crop_mode=False,# 书本排版整齐,关掉更省显存max_length=32768,no_repeat_ngram_size=35,ngram_window=128,save_results=True,)# 每页跑完清一下缓存,防止碎片堆积torch.cuda.empty_cache()
关键点:
.md 文件,文件名带页码。crop_mode 我关掉了,因为书本排版规整,切块反而容易出边界幻觉,而且费显存。光输出一堆碎片文件没用,必须合并成一本完整的 Markdown。我的合并脚本做了这几件事:
.md 文件。# 都从 1 开始,所以要全局统计,把 # 1. 变成 # 1.,第二页的 # 1. 自动变成 # 2.,子标题同理。|--- 且下一页开头是 |---,说明表格被切断,合并成一个大表格。)。整套脚本跑完,600 页直接变成一个 5MB 的 book.md,导入 Obsidian 后大纲清晰,搜索公式、跳转章节丝般顺滑。
for 循环。document parsing,别想着让 OCR 做总结。有人说“逐页循环太 low,不够智能”,但我想说——在 GPU 资源有限的情况下,稳定、可控、高质量,比花里胡哨的“原生多页”重要一万倍。 我用这套流水线处理了 600 页,成果是一份可以直接出版级的 Markdown 文档,而某些“高级批处理”可能连 50 页都跑不下来。
所以,如果你也想用 Unlimited-OCR 处理多页文档,别犹豫,直接上循环。代码我都给你备好了,拿去抄就行。
本章代码(含 PDF 转图、逐页 OCR、合并脚本)已上传至 Gitee