Unlimited OCR 2 使用手册 2026-10-27 发布 · 材料截至 2026-10-28

Handbook · 给工程师和产品

Unlimited OCR 2 上手指南 三分钟知道它是什么,半小时把它跑起来,一张能贴在评审会上的「该不该用」判定表。

市面上的 OCR 大多回答「这一页写了什么」。它回答的是另一件事:这一本讲了什么,以及它怎么排的——跨页断开的表格、跨页续写的段落、整本书的标题层级,都在一次请求里给你。代价是它比你想的更难跑通,而且单页精度并不占优。这份文档只讲清楚三件事:它是什么、怎么把它跑起来、以及什么时候你不该用它。

发布 2026-10-27(百度) 规模 3B 总参 / 约 0.5B 激活 代码许可 MIT 一手材料 README · 技术报告 · config.json · utils/README

一句话

整篇进,整篇出

一叠页图 → 一份带版面结构的文档,不是逐页拼起来的

单窗口容量

≈ 480 页

131,072 位置上限 ÷ 每页 273 视觉 token(推算)

百页 KV 峰值

1.77 GB

分窗解码后;不分窗是 47 GB(官方实测)

最短验证

1 天

Transformers 直跑 + 抽 6 处跨页结构人工核对

01它是什么

先把它从「又一个 OCR」里择出来:它不是把识别率做得更高的 OCR,而是把「一份文档」当成一次推理单位来处理的文档解析模型。

一句话定义

输入是按页序排好的一组页面图像(或由 PDF 转成的页图),输出是整篇文档的版面块序列:每个块带类型(标题/正文/表格/公式/图注)、标题层级、归一化位置框,以及跨页的延续标记。它返回的不是一段干净正文,而是一棵能还原成 Markdown 的结构。

先记住这一点,能省你半天

它不直接输出 Markdown。模型吐的是 <PAGE><BLOCK>title<LEVEL1>[x1,y1,x2,y2]<FORK>… 这种私有块语法,必须再跑官方脚本 utils/process_unlimitedOCR2.py 才能变成人看的 Markdown。所有「跑出来是乱码」的第一现场,八成是跳过了这一步。

三个数字记住它的工作原理

表 1 · 三个数字各自回答一个问题。前两个来自 config.json,可自行复算;第三个是官方实测。
数字含义它回答了什么
273每页压成多少个视觉 token为什么百页能塞进 128K 上下文
640每个解码步最多看多少个 token
4×32 本地 + 16×32 远端
为什么页数涨,单步算力不涨
1.77 GB百页文档的 KV 峰值显存为什么单卡能跑千页,而不是必须堆机器

这三件事由两个不同机制负责,官方叙述里常被并排讲,容易误当成一个机制:640 是稀疏注意力(SR-SWA)管算力,1.77 GB 是分窗解码管显存。二者独立可拆。深度技术分析见另一份报告,这里不展开。

它的输出长什么样

下面这段是真实格式(取自官方 utils/README.md),一页一个 <PAGE>,块与块之间靠 <BLOCK> 分隔,块头与内容用 <FORK> 断开:

模型原始输出(未后处理)

<PAGE><BLOCK>title<LEVEL1>[120,88,880,142]<FORK>第三章 资产减值
<BLOCK>text[120,160,880,268]<FORK>本公司于每一资产负债表日对长期资产判断是否存在减值迹象……
<BLOCK>cross_table[120,300,880,610]<FORK><table><tr><td>项目</td><td>期末余额</td></tr>……
<PAGE><BLOCK>append_table[120,90,880,420]<FORK><table><tr><td>项目</td><td>期末余额</td></tr>……

跑一次 process_unlimitedOCR2.py 之后:

后处理输出(Markdown)

# 第三章 资产减值

本公司于每一资产负债表日对长期资产判断是否存在减值迹象……

<!-- 两个 cross_table / append_table 片段已合并,重复的表头行已自动去重 -->
<table><tr><td>项目</td><td>期末余额</td></tr>……</table>

注意最后一段:表格在 Markdown 里仍然是 HTML,跨页片段被拼成一张表并干掉了重复表头。这正是它相对「逐页识别再拼接」的核心价值——合并逻辑是模型在原生长上下文里做出的,不是你在后处理里猜的。

后处理只做到「评测对齐」,不等于「生产可用」

那个脚本的默认行为是为了对齐 MarathonDocBench 的标注格式,不是为你的业务。四件事它会「做错」:① 页眉/页脚/页码默认保留进正文;② 公式不做 $$ 包裹,和正文混在一起;③ 标题树被强制压成单根,多篇章合集会丢层级;④ 图片只给一个 pageN_x1_y1_x2_y2.jpg 的占位引用,不会替你切图。这四处都要你自己补。

和你熟悉的三条路的分工

它不是「更强的 OCR」,是一条不同的取舍线。放在一起看最清楚:

表 2 · 四条路线的能力边界。「单页精度」一列参照 OmniDocBench v1.6 公开分数。
做法强项弱项什么时候选它
传统 OCR
PaddleOCR / Tesseract
字级准确、坐标齐全、快且便宜版面结构弱;跨页完全没有概念只要文字和坐标,不要结构
页面切块 + 云 OCR API运维为零、按页计价每页独立,跨页表格必然断;结构化靠模板票据、单据、模板固定的单页场景
通用多模态大模型能理解语义,可问答式抽取百页级会崩:要么超上下文,要么分数断崖少页 + 需要「理解」而非「还原」
Unlimited OCR 2整篇一次;跨页表格/段落/标题树天然连续单页精度不如 1B 级专用模型;要自建、要后处理整本要变成一份结构化文档

把它放进血统里看得更明白:DeepSeek-OCR 证明了「用视觉 token 压缩页面」这条路可行,Unlimited OCR(一代)把文本侧的长上下文问题解决了一半、卡在 40 页,二代把视觉侧也拆掉,才有了「页数不再是硬上限」。所以二代相对一代的唯一实质提升就是长文档——单页几乎没动(OmniDocBench 93.92 → 94.02)。

五个名词,知道结论就够

名词一句话解释你需要关心它吗
SR-SWA
稀疏参考滑窗
每步只看近处 128 个 token + 远端 16 个「相关块」(512),合计 640只在调优时关心:它决定「20 页以下没用」这条阈值
分窗解码
page window
文档切成重叠的页窗顺序处理,边界页的 KV 复用,窗外 KV 释放必须关心:页面窗口大小直接换「显存 ↔ 跨页质量」
base 模式每页压成一张全局视图,约 273 token必须关心:多页整篇的默认,也是能塞进百页的前提
gundam 模式单页动态切块,精度更高、token 更多必须关心:单页跑默认用这个;多页文档用它会撑爆上下文
<PAGE>页分隔符,同时是页码对齐的唯一锚点必须关心:请求里必须原样保留,否则整篇页码错位

02怎么跑

整条链路有四段,每段都会静默失败。先看清楚失败点在哪,再动手。

① 页图化 PDF / 扫描件 → PNG PyMuPDF · 300 dpi ② 模型推理 SGLang · 分窗 整篇一次请求 ③ 块串 → MD process_unlimited OCR2.py ④ 入库 / 切块 按标题树切、生成 chunk、入向量库 这一段最常见的塌方 dpi < 300 旋转页未校正 双栏顺序错乱 显存 OOM 复读循环 输出被截断 页码整体错位 跨页表格没合上 公式是裸文本 标题树被压平 页眉页脚混入 图片只有占位 这四段失败都是静默的:不抛异常,不报错,只是结果悄悄变差。所以验收必须看内容,不能看“跑通了”。
图 1 · 端到端四段流水线。第 ② 段是唯一“官方帮你调好了”的一段,第 ③④ 段才是工程量真正所在。

三条路线,先选一条

不要一上来就部署 SGLang。先按你要验证的问题选路线——80% 的人只需要路线 A 就能做完决策。

表 3 · 三条上手路线。耗时指“从零到看见第一份结果”。
路线适合谁耗时能回答什么不能回答什么
在线 Demo
hf.co/spaces/baidu/Unlimited-OCR-2
产品、想先看效果的人1 分钟输出风格、版面还原度肉眼判断你的文档能不能跑、跑多快
A · Transformers做技术验证的工程师15–40 分钟长文档质量、跨页合并效果、显存下限并发吞吐
B · SGLang要上服务、要批处理的人1–3 小时吞吐、并发、长时间稳定性(都要自己搭)

路线 A · Transformers 直跑

官方在 Python 3.10 / torch==2.13.0 / transformers==4.52.1 / A800-80GB 上验证过。依赖装法照抄:

pip install torch==2.13.0 torchvision pillow transformers==4.52.1 huggingface-hub==0.36.0 \
  tokenizers==0.21.4 addict==2.4.0 einops==0.8.2 easydict==1.13

加载一次,然后直接调两个方法:

import torch
from transformers import AutoModel, AutoTokenizer

model_name = "baidu/Unlimited-OCR-2"
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModel.from_pretrained(model_name, trust_remote_code=True, use_safetensors=True,
                                  torch_dtype=torch.bfloat16).eval().cuda()

# 多页:一次请求吃完整篇,跨页上下文才在
pages = [f"your_doc/page_{i}.jpg" for i in range(1, 8)]
text, num_tokens = model.infer_multi(tokenizer, image_files=pages,
                                     output_path="output/multi", save_results=True)

# 单页:默认走 gundam(动态切块),精度更高
text = model.infer(tokenizer, image_file="your_doc/page_1.jpg",
                   output_path="output/single", save_results=True)
接口内部做了什么你要知道的一件事
infer_multi自动拼 <PAGE><image> × N + "Multi page parsing.",每页一张全局视图(base)输出里每个输入页对应一个 <PAGE>,顺序与入参一致——这是你后续做页码映射的依据
infer单页,默认动态切块(gundam)同一张图,gundam 比 base 准,但 token 数高得多

两个必须正视的风险

① trust_remote_code=True 意味着加载即执行仓库里的自定义代码(modeling_unlimitedocr.py)。生产环境别直接 from_pretrained,先把这两个文件过一遍。
② 官方只在 A800-80GB 上验证。24GB / 40GB 卡能不能跑属于未验证区——权重本身约 6GB,能吃下,但页图预处理与分窗调度下的峰值取决于页数和并发,别拿“权重装得下”当结论。

路线 B · SGLang 服务化

SGLang 那条路有个隐藏门槛:必须用仓库自带的定制 wheel(sglang-0.5.20.dev10+g8d62f5fb9c),和你现有的环境大概率版本冲突。所以第一步永远是独立虚拟环境:

uv venv --python 3.10
source .venv/bin/activate

uv pip install wheel/sglang-0.5.20.dev10+g8d62f5fb9c-py3-none-any.whl
uv pip install pymupdf==1.27.2.2
uv pip install fastokens==0.3.2

然后用一组环境变量把显存按住——这一段是“不设就 OOM”的部分,不是调优:

# 分窗调度:1 = 开,0 = 整文档塞一个窗口(千页级必炸)
export SGLANG_UOCR_EANABLE_DOC_LIMIT=1
export SGLANG_UOCR_DOC_GUNDAM_PAGE_WINDOW=10   # gundam 每窗页数
export SGLANG_UOCR_DOC_BASE_PAGE_WINDOW=10     # base 每窗页数
export SGLANG_UOCR_MAX_PAGE_TOKENS=20000        # 每页输出上限

# SAM 注意力偏置的分块上限:默认 512 会一次要 ~462 MiB 连续显存并可能 OOM
export SGLANG_OPT_UOCR_SAM_REL_POS_BIAS_MB=64
# 大 crop 张量走 /dev/shm,绕开 tokenizer → scheduler 的 pickle
export SGLANG_UOCR_SHM_WRAP_MODEL_DATA=1
export SGLANG_UOCR_SHM_WRAP_MIN_MB=1
export SGLANG_VLM_CACHE_SIZE_MB=0
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True

启动服务(关键参数已按官方建议调到保守值,尖括号内是场景相关):

python -m sglang.launch_server \
    --model-path baidu/Unlimited-OCR-2 \
    --served-model-name Unlimited-OCR-2 \
    --chat-template unlimited-ocr \
    --tokenizer-backend fastokens \
    --tokenizer-worker-num 8 \
    --mem-fraction-static 0.7 \
    --max-running-requests 64 \
    --max-prefill-tokens 2048 \
    --enable-custom-logit-processor \
    --enable-streaming-session \
    --allow-auto-truncate \
    --disable-radix-cache \
    --mm-preprocess-cache-size-mb 0 \
    --cuda-graph-backend-decode full --cuda-graph-max-bs-decode 64 \
    --cuda-graph-backend-prefill full \
    --cuda-graph-max-bs-prefill 16384 \
    --cuda-graph-bs-prefill 1024 2048 \
    --cuda-graph-config '{"prefill": {"backend": "full", "full_prefill_max_req": 64}}' \
    --host 0.0.0.0 --port 10000

四个容易抄错的地方

① 环境变量官方拼写就是 EANABLE(不是 ENABLE),照抄,别顺手改;
② --cuda-graph-bs-prefill 的最大桶必须等于 --max-prefill-tokens:偏小会回退 eager 变慢,偏大纯粹浪费 capture 显存;
③ --mem-fraction-static 0.75 在 32+ 并发下余量不够,官方明确建议 0.7;
④ full_prefill_max_req 默认 8,不改的话 16/32 并发会静默回退到 eager。这条最阴——服务能跑,但慢了你还以为是模型的问题。

请求怎么拼

服务起好后是 OpenAI 兼容接口。下面这段是从官方示例精简出的最小可用客户端,带三处必须写对的地方:

import base64, json, os, tempfile
import fitz, requests
from sglang.srt.sampling.custom_logit_processor import DeepseekOCRNoRepeatNGramLogitProcessor

server_url = "http://127.0.0.1:10000"
NGRAM = DeepseekOCRNoRepeatNGramLogitProcessor.to_str()
session = requests.Session()
session.trust_env = False          # ① 绕开系统代理,否则本机 127.0.0.1 也会被代理吞掉

def pdf_to_images(pdf_path, dpi=300):
    doc = fitz.open(pdf_path)
    tmp = tempfile.mkdtemp(prefix="pdf_ocr_")
    mat = fitz.Matrix(dpi / 72, dpi / 72)
    out = []
    for i, page in enumerate(doc):
        p = os.path.join(tmp, f"page_{i + 1:04d}.png")
        page.get_pixmap(matrix=mat).save(p)
        out.append(p)
    return out

def build_content(paths):
    prompt = "<PAGE><image>" * len(paths) + "Multi page parsing."   # ② 页数必须与图数严格相等
    parts = []
    for p in paths:
        b64 = base64.b64encode(open(p, "rb").read()).decode()
        parts.append({"type": "image_url",
                      "image_url": {"url": f"data:image/png;base64,{b64}"}})
    return parts + [{"type": "text", "text": prompt}]

def generate(paths, crop_mode=True, tokens_per_page=8000):
    payload = {
        "model": "Unlimited-OCR-2",
        "messages": [{"role": "user", "content": build_content(paths)}],
        "max_tokens": tokens_per_page * len(paths),   # ③ 全篇总预算,不是每页
        "temperature": 0,
        "skip_special_tokens": False,              # 关掉就丢 <PAGE>,页码全错
        "images_config": {"crop_mode": crop_mode},   # True=gundam  False=base
        "custom_logit_processor": NGRAM,
        "custom_params": {
            "ngram_size": 35,
            "window_size": 1024 if len(paths) > 1 else 128,  # 防复读
            "page_token_id": 128827,
            "eos_token_id": 1,
            "max_page_tokens": 20000,
        },
        "stream": True,
    }
    r = session.post(f"{server_url}/v1/chat/completions", json=payload,
                     timeout=6000, stream=True)
    r.raise_for_status()
    chunks = []
    for line in r.iter_lines(decode_unicode=True):
        if not line or not line.startswith("data:"):
            continue
        data = line[5:].strip()
        if data == "[DONE]":
            break
        ev = json.loads(data)
        for c in (ev.get("choices") or []):
            chunks.append((c.get("delta") or {}).get("content") or "")
    return "".join(chunks)

raw = generate(pdf_to_images("your_doc.pdf", dpi=300))

crop_mode 怎么选,这一条决定成败

多页整篇 → False(base):每页约 273 token,百页才塞得进单窗口,这是官方 infer_multi 的默认。
单页或十几页 → True(gundam):动态切块,精度明显更高,但每页 token 数会涨好几倍。
想把百页文档强行用 gundam 跑,正确做法是同时开分窗(DOC_GUNDAM_PAGE_WINDOW),代价是跨窗的表格合并质量下降。“又长又精”在这套机制里是有物理上限的,别信一键调优。

你的客户端 SGLang 服务 POST /v1/chat/completions(stream=true,N 张页图 + <PAGE>×N) 第 1 窗 prefill(base 默认 10 页/窗) 之后每窗复用上一窗尾页的 KV SSE 逐段吐字符流(每页约上千 token,所以要 stream) 窗外页的视觉 KV 已释放 —— 这就是“显存不随页数增长”的落点 data: [DONE]
图 2 · 一次请求的时序。三个工程后果:必须 stream(整篇输出远超普通 HTTP 超时)、timeout 要按分钟到小时给(官方示例 6000 秒)、页码靠 <PAGE> 流式回传,不能等最后一次性解析。

后处理:把它变成能用的 Markdown

两种用法,批量跑还是嵌进代码:

# 批量:把一个目录下的原始输出(.txt/.md)全转成 Markdown
python utils/process_unlimitedOCR2.py --infer-dir raw --out-dir pred
# 嵌进流水线
from process_unlimitedOCR2 import convert
markdown = convert(raw_output)

它认得的块类型一共这些,看懂这张表你就知道能从输出里拿到什么:

表 4 · 块类型已按用途分组。cross_ / append_ 前缀可加在任意类型前,表示“跨页延续”。
分组类型转成 Markdown 后
结构title 带 <LEVELn># × n 级标题
结构text / ref_text / aside_text / algorithm正文,直接拼接
结构equation裸文本,不会自动包 $$
表格table / cross_table / append_table保留 HTML;跨页片段自动合并并去掉重复表头
图image / figure / chart / seal![](pageN_x1_y1_x2_y2.jpg) 占位,不切图
图image_caption / image_footnote图注 / 图下注,跟图一起输出
页边header / footer / page_number / page_footnote默认保留进正文,要自己清

坐标是归一化值,不是像素

块头里的 [x1,y1,x2,y2] 全部落在 0–1000 的归一化坐标系里(脚本里 _scale() 会钳到 0–1000)。要回原图像素,乘上页宽高再除 1000。直接当像素用会得到一堆越界框,这是接前端坐标系统时最常见的错。

参数速查:每一个都写清楚“动了会怎样”

表 5 · 只列真正会影响结果的参数。其余保持默认。
参数建议动了会怎样
--mem-fraction-static0.7调到 0.75 在 32+ 并发下余量不足;调太低则 KV 空间不够、并发上不去
--max-prefill-tokens2048临时张量约 [tokens, context/32],4096 时这块峰值翻倍
--cuda-graph-bs-prefill 最大桶= max-prefill-tokens偏小 → 回退 eager(慢);偏大 → 白占 capture 显存
full_prefill_max_req64默认 8,16/32 并发静默回退 eager
SGLANG_UOCR_EANABLE_DOC_LIMIT1设 0 = 整文档单窗口:≤480 页更快,千页级必 OOM
..._BASE_PAGE_WINDOW / ..._GUNDAM_PAGE_WINDOW10调小省显存但伤跨页合并(跨窗延续的块丢上下文);调大反之
SGLANG_UOCR_MAX_PAGE_TOKENS20000每页输出守卫,防单页失控;太小会截断密排页
SGLANG_OPT_UOCR_SAM_REL_POS_BIAS_MB64默认 512 会一次要 ~462 MiB 连续显存,启动即 OOM 的元凶
images_config.crop_mode多页 False
单页 True
True=gundam 切块更准、token 更多;False=base 每页 1 视图
max_tokens页数 × 8000 起全篇总预算;按页算错会让你在第 30 页被整体截断
ngram_size / window_size35 / 1024(多页)不挂这个 logit processor 会复读;单页窗口 128 就够
skip_special_tokens必须 False设 True 会吃掉 <PAGE>,整篇页码错位且后处理无法恢复
dpi(PDF→图)300低于 300 直接影响识别质量,尤其小字号与表格线

排错:症状 → 原因 → 处置

表 6 · 按“你看到什么”查,不要按“我猜哪里错了”查。
症状最可能的原因处置
服务刚起就 OOMSAM 偏置默认 512 的一次性大分配SGLANG_OPT_UOCR_SAM_REL_POS_BIAS_MB=64
跑到中途 OOM没开分窗,或窗口太大DOC_LIMIT=1,窗口降到 10 甚至 6
输出反复念同一段没挂 no-repeat-ngram processor,或窗口过小补 custom_logit_processor;多页把 window 提到 1024
输出在某页戛然而止max_tokens 或 MAX_PAGE_TOKENS 撑到上限按“页数 × 8000”重算总预算
整篇内容整体偏移一页skip_special_tokens=true 把 <PAGE> 吃了改回 False,重跑(不可事后修复)
跨页表格被拆成两张窗口太小,或每页用了 base 却靠后处理硬拼窗口调到 10–15;确认请求里是整篇一次而不是逐页并发
跑通了但全是乱码块语法跳过了后处理跑 process_unlimitedOCR2.py
正文里混进页码和页眉脚本默认不删页边块后处理后按 type 过滤,或改 DROP_LABELS
所有请求都 500 / 超时客户端走了系统代理,或 timeout 太短session.trust_env = False;timeout 给到 6000 秒
客户端 import 失败客户端也要装同一个 sglang 包在客户端环境里装定制 wheel
单页精度不如预期用了 base(每页一视图)单页改 gundam:crop_mode=true
中文小字误识多页图 dpi 不够PDF→图改 300 dpi,并确认没有缩放

验收清单:一天走完,别省第 3 步

  • 1 · 拿你自己最长的一份文档跑通务必 > 100 页。单页一次、多页一次,都要出结果。通过标准:结构肉眼可读,不是“没报错”。
  • 2 · 抽 6 处跨页结构逐字核对3 处跨页表格(表头去重、列对齐)+ 3 处跨页段落(有没有被截断/重复)。这是它唯一不可替代的能力,不过关就别往下走。
  • 3 · 做「块边界 vs 块内部」的分层对比官方材料没做这一项。按页位置抽边界页与内部页各 10 页,算编辑距离;差距 < 2 个百分点可接受,明显偏大说明窗口要调大。这一步决定你敢不敢上生产。
  • 4 · 压一次并发,记录 TPS 与峰值显存B=16 下与官方 1,315 TPS / 1.77GB KV 同量级即可;差一个数量级说明参数没调对,不是模型不行。
  • 5 · 跑一遍你的真实后处理页眉页脚、公式包裹、标题树、图片切图——四件事各验一遍。这一步最容易被跳过,也最容易在上线后暴露。

03什么时候用

一句话:页数够多、且文档的结构价值大于文字价值时用它。这两条缺一条,它就不如你现有的方案。

先过三个问题,再谈部署

① 单份文档通常 ≥ 20 页? 20 页以下,稀疏化省不出东西,反而多一层路由开销 不必用它 单页专用模型更准更省:0.8B 级已有更高分 否 是 ② 有跨页表格、跨页段落,或需要整篇标题树? 这是它唯一不可替代的地方;只是“字多”不构成理由 用逐页流水线更划算 单页更准、可并行、便宜;跨页合并自己写 否 是 ③ 单份 ≤ 480 页,且单卡显存 ≥ 40GB? 480 页 ≈ 13.1 万视觉 token,正好一整个位置上限 整文档单窗口,最省心 Transformers 直跑,或 SGLang 关掉分窗 是 否 必须开分窗调度(窗口 10 页起) 代价:跨窗的表格与段落会掉上下文,务必做边界页分层校验
图 3 · 三步判定。第 ② 步是真正的分水岭——只要你的批处理里没有跨页结构,就不该用它。“20 页”阈值来自注意力范围推算(推算),“480 页”来自 131,072 ÷ 273(推算)。

六个它确实值钱的场景

① 年报 / 招股说明书 / 募集说明书整本结构化100–400 页 · 表格密集
为什么适合
资产负债表、现金流量表常年跨页,页眉重复、表头在下一页重印。逐页方案必须写合并逻辑,它原生就给合并结果。
怎么配
多页整篇一次请求,crop_mode=False(base),≤480 页不用开分窗。
预期
跨页表格拼成一张 HTML 表,重复表头自动去掉;标题树能直接给出“第 N 节 → 第 N.M 小节”。
主要坑
页脚的公司名与页码会进正文;表格转 DataFrame 要用 pandas.read_html() 吃那段 HTML,别自己写解析。
② 扫描书籍 / 地方志 / 档案长卷数字化300–3,600 页
为什么适合
这才是它名字里的“unlimited”。官方演示直接跑完了《哈利·波特》全七部与三体全集——注意这是单次演示,不是基准测试结果。
怎么配
必开 DOC_LIMIT=1,窗口 10 页;上千页的卷子建议按“卷/册”切成独立请求,别赌一个请求跑到底。
预期
正文与标题层级连续,跨页断开的句子能接上。
主要坑
书页的页眉页脚几乎全是噪声,必须清;竖排/繁体/异体字没有公开评测数据,属于未知区,先小样本试。
③ 学术论文集 / 标准规范 / 法规汇编跨页公式与图表编号
为什么适合
公式被页边切断、图表编号跨页续排、章节层级深(到四级标题)——这三件事逐页方案都做不好。
怎么配
页数不多(20–80)时可试 crop_mode=True 加分窗,公式识别会更好;纯速度优先就 base。
预期
公式以 LaTeX 文本给出,编号与引用关系保留在正文流里。
主要坑
后处理不会把 equation 包成 $$…$$,你得自己按块类型补;标题树被强制单根,多篇论文合成一本时要重排层级。
④ 招投标文件 / 诉讼卷宗扫描件 + 表格 + 附件
为什么适合
一份卷宗几十到几百页,资质表、报价表跨页是常态,且要保留“第几页第几张表”的可追溯性。
怎么配
base + 整篇;把 <PAGE> 位置映射回原 PDF 页码,作为引用锚点。
预期
结构与页码可对齐,能做“原文第 37 页”级别的溯源。
主要坑
手写批注、盖章遮挡、复印件底噪都是弱项——训练数据以印刷文档为主,没有手写评测数据。有手写就老实上“专用手写模型 + 人工复核”。
⑤ 财报批量入库(表格 → 结构化数据)重复性批处理
为什么适合
输出里表格是标准 HTML,跨页片段已合并。pandas.read_html() 直接吃,比任何自研表格解析都省事。
怎么配
SGLang + 并发;max_tokens 按“页数 × 8000”给足,避免长报表被截断。
预期
一张跨 3 页的资产负债表 → 一个 DataFrame,行不丢、表头不重。
主要坑
合并单元格(rowspan/colspan)在 HTML 里是合法的,但 read_html 默认不展开;要自己 forward-fill。
⑥ 长文档 RAG 的前置处理切块质量决定召回
为什么适合
RAG 切块最怕“表格被拦腰切开”“标题与正文分家”。它给的是带层级的结构,可以按标题树切而不是按字数切。
怎么配
整篇 → Markdown → 按 heading 切段,表格整块不切,图片用 bbox 回原图裁。
预期
chunk 自带章节路径(如“第三章 / 3.2 减值测试 / 表 3-1”),召回后能给出处。
主要坑
后处理默认保留页眉页脚,会污染 embedding;一定要先过滤再用。

五个明确别用的场景

表 7 · 这些场景用了不会“差一点”,而是又贵又差。
场景为什么不该用用什么
单页票据、发票、证件、截图OmniDocBench 94.02,落后 0.8B 的 OvisOCR2(96.47)与 1.2B 的 TeleOCR(96.91),还更贵更慢专用小模型 / 云 OCR API
实时高并发小图(每秒几十张)3B MoE,每页要生成上千 token,单页延迟在秒级;稀疏化在短输入上不省反贵轻量检测+识别流水线
需要字符级坐标或置信度的场景它给的是块级 bbox(0–1000 归一化),没有逐字框,也没有置信度分数传统 OCR 引擎
有文本层的电子版 PDF文本已经在文件里,OCR 只会引入误差,还要为它烧 GPUpdfplumber / PyMuPDF 直接抽
手写为主、或需要语义问答抽取训练数据以印刷文档为主,手写无公开评测;它是解析模型,不是拿来聊天的手写专用模型 / 通用 VLM + 抽取提示词

成本粗算:先算清“每千页”再谈采购

官方给的吞吐是 1,315 TPS @ B=16(A800-80GB)。按每页约 1,000 个输出 token 反推,单卡理论上限约 4,700 页/小时;扣掉 PDF→图(300 dpi 单页约 0.2–0.4 秒 CPU)、prefill、排队与重试,实际按 40–60% 折算更稳。下面全部是算术推算,不是实测。

表 8 · 单卡(A800-80GB 级)耗时,推算值。文档越“图多表多”,每页输出 token 越高,耗时按比例涨。
规模页数单卡预计耗时折算
临时处理一份年报3008–15 分钟不值得一提,随便一张卡
小批量归档5,0002–3.5 卡时单卡跑一夜够用
月度批量(图书馆/律所量级)50,00020–35 卡时2–4 卡并行,一天内完成

把它换成钱只有一个公式:每千页成本 ≈ (1000 ÷ 单卡小时页数) × 你的卡时单价。按 2,500 页/卡时算,每千页约 0.4 卡时——卡时单价你自己代入,因为租用与自建、包月与按量的差别比模型本身的差别还大。

和按页计价的云 OCR 怎么比

云 OCR 按页收费、零运维,量小时(每月几千页)几乎总是更便宜;自建的优势要到月处理量上万页、且文档长到云 API 按页累计成本吃不住时才显现。另一条常被忽略的成本是后处理与人工抽检——那部分不随模型变,但会占掉项目一半的工期。

04边界与风险

这一节不是唱衰,是把“上线后才会发现”的事提前摆到桌面上。

表 9 · 六条需要你在方案里写明的风险。
风险具体是什么怎么应对
自建基准的可信度“百页级领先 43 分”来自百度自建的 MarathonDocBench,标注由强逐页解析器初始化,训练伪标签也来自 MinerU2.5-Pro / PaddleOCR-VL——同一批“老师”既出题又判卷只看 MPDocBench(第三方,84.59)做横向对比;自己的文档必须自测
缺一条最该比的基线对比里没有“通用模型 + 分段流水线”,也就是没有回答“我用逐段调用能不能更便宜地达到同样效果”内部试点时自己补上这条基线,很可能是它最有力的竞争者
单页精度不占优94.02 排第三,落后 1B 级模型 2.5–2.9 分;相对一代只 +0.1混合路由:短文档走小模型,长文档才路由给它
跨页连续性未分层验证官方只给了整篇的 T-TextEdit(0.123),没有“块边界 vs 块内部”的对比,无法判断 1 页重叠够不够这就是验收清单第 3 步,必须自己做
trust_remote_code加载权重即执行仓库内自定义建模代码,供应链风险实打实把 modeling_unlimitedocr.py 等文件纳入代码审计;生产用固定 commit 的内网镜像
许可只覆盖代码仓库 LICENSE 是 MIT(商用友好),但模型权重的许可条款需以模型卡为准;本次整理时 HF 模型卡不可达,未完成核验法务按 HF / ModelScope 模型卡原文确认后再商用

一句总结给决策者

它的价值不在“识别更准”,而在“第一次让整本文档变成一个可查询的结构”。如果你的业务里存在“跨页的表格或段落”,并且这件事今天靠人工补,那它值得一次试点;如果你的业务是单页、实时、要高并发,它不是更贵的正确答案,而是错误答案。

05速查附录

入口与一手材料

表 10 · 地址均取自官方 README 与仓库页面(2026-10-28 摘录)。
用途地址
代码仓库(含 infer.py、utils/)github.com/baidu/Unlimited-OCR
在线试玩(最快看效果)huggingface.co/spaces/baidu/Unlimited-OCR-2
权重(HF)huggingface.co/baidu/Unlimited-OCR-2
权重(国内镜像)modelscope.cn/models/PaddlePaddle/Unlimited-OCR-2
不想自建:云 APIcloud.baidu.com/doc/OCR/s/fmr1p39gb
技术报告arxiv.org/abs/2606.23050
自建基准数据集huggingface.co/datasets/baidu/MarathonDocBench

关键常量(写死在代码里,别猜)

常量值出处 / 用途
page_token_id128827config.json → 传给 ngram processor 的 <PAGE> id
image_token_id128815config.json → 视觉占位符
eos_token_id1解码终止判断
per_page_image_tokens273算容量、算成本的基准数
max_position_embeddings131072单窗口页数上限 ≈ 131072 ÷ 273 ≈ 480
sparse_block_size / sparse_local_block / sparse_topk_blocks32 / 4 / 16合起来决定每步 640 = (4+16) × 32
sliding_window_size128本地窗口
层数 / 专家 / 每 token 激活12 / 64+2 / 6MoE 结构,决定激活参数约 0.5B
视觉编码器deeplip_b_lCLIP-L/14 + SAM-ViT-B 双塔,1024×1024 输入

最小可行代码骨架

# 1. PDF → 页图(300 dpi)           fitz.Matrix(300/72, 300/72)
# 2. 页图 → 原始块串                  POST /v1/chat/completions,stream=True
# 3. 块串 → Markdown                  convert(raw) 或 process_unlimitedOCR2.py
# 4. 你的业务                         按 # 标题切块 / pd.read_html 取表 / bbox 裁图

from process_unlimitedOCR2 import convert
md = convert(raw)                      # 别忘了这一步,否则拿到的是块语法
open("doc.md", "w").write(md)

一句话记忆卡

带走这四句就够

它是把“一整本”当一次推理的文档解析模型,卖点是跨页结构,不是识别率。
怎么跑:页图 → 整篇一次请求 → 跑 process_unlimitedOCR2.py → 才得到 Markdown。
什么时候用:≥20 页,且有跨页表格/段落/整篇标题树。
什么时候别用:单页、实时、要高并发、或 PDF 本来就有文本层。

本文所有命令、参数名、常量取自官方 README、utils/README.md、config.json 与技术报告(Unlimited-OCR-2.pdf,15 页),未做推测性改写。标注 推算 的数值为按官方常量计算的推导值,非官方实测。

配套的技术深度分析(SR-SWA 机制、它与分窗解码的归因边界、评测可信度拆解)见同目录 baidu-unlimited-ocr2-report.html。整理日期 2026-10-28。