MiniCPM-OCR Jev 技术实践:OCR 识别完了,谁来检查它有没有认错?

举报
yd_54922183 发表于 2026/10/29 09:32:45 2026/10/29
【摘要】 MiniCPM-OCR Jev,一款仅有 2B 参数的 OCR 正确性决策模型。它通过联合分析原始图像和 OCR 候选结果,输出 0~1 的质量评分。本文介绍其核心架构,并通过财务票据自动质检、多 OCR 模型结果择优两个案例,演示如何为文档解析系统增加一道自动化质量检查。

摘要: OCR 模型已经能够识别复杂文档中的文字、表格和公式,但识别结果到底有多可靠,一直是实际应用中的难题。2026 年 10 月,OpenBMB 开源了 MiniCPM-OCR Jev,一款仅有 2B 参数的 OCR 正确性决策模型。它通过联合分析原始图像和 OCR 候选结果,输出 0~1 的质量评分。本文介绍其核心架构,并通过财务票据自动质检、多 OCR 模型结果择优两个案例,演示如何为文档解析系统增加一道自动化质量检查。

一、为什么 OCR 已经很强了,还需要 Jev?

假设我们正在处理一张银行交易凭证。

原始图片写着:

交易金额:¥ 18,680.00

OCR 模型却识别成:

交易金额:¥ 18,880.00

只错了一个数字,但后果可能相当严重。

更麻烦的是,模型往往会非常自信地输出错误结果。尤其使用视觉语言模型(VLM)进行 OCR 时,生成的文字可能非常流畅,看起来没有任何异常。

过去我们可以采用几种方法检查:

  • 使用正则表达式校验金额格式。
  • 对账检查金额是否一致。
  • 调用另一个视觉大模型重新识别。
  • 将部分结果交给人工复核。

但这些方法各有局限。例如,一笔错误金额仍然可能满足所有格式规则。

于是有了一个很自然的想法:

能不能训练一个专门的模型,让它对照原图,判断 OCR 结果到底有没有认错?

MiniCPM-OCR Jev 就是为此设计的。

1.1 Jev 与 MiniCPM-OCR 1.0 的区别

OpenBMB 同时发布了两个不同定位的模型:

模型 参数量 主要任务
MiniCPM-OCR 1.0 1.3B 识别文字、表格、公式及解析文档
MiniCPM-OCR Jev 2B 判断现有 OCR 识别结果是否正确

它们可以串联:

原始文档
   │
   ▼
MiniCPM-OCR 1.0
   │
   ▼
OCR 识别结果
   │
   ▼
MiniCPM-OCR Jev
   │
   ▼
质量评分(0~1)
   │
   ├── 高分 → 自动处理
   │
   └── 低分 → 人工复核

这里的 Jev 也可以检查 PaddleOCR、GLM-OCR 等其他模型的输出,并不要求前置 OCR 必须来自 MiniCPM-OCR。

二、Jev 的核心技术原理

MiniCPM-OCR Jev 基于 Qwen3.5-2B 训练。

它保留了原有视觉编码器和语言模型主体,将语言模型的 lm_head 替换成一个二分类头。

原来生成式模型需要逐个预测文本 Token。

现在则直接判断:

给定这张图片,候选识别结果是否正确?

其工作过程如下:

原始图像区域
      │
      ├────────────────┐
      │                │
OCR 候选文本           │
      │                │
      ▼                │
文本渲染为图片         │
      │                │
      └────────┬───────┘
               ▼
       MiniCPM-OCR Jev
               │
               ▼
         二分类评分头
               │
               ▼
       正确性评分 0~1

这里有个容易忽略的细节:Jev 实际会使用三种输入信息。

  1. 原始文档区域的图像。
  2. OCR 识别出来的候选文本。
  3. 将候选文本重新渲染得到的图像。

为什么还要把文字重新渲染成图片?

因为文本是否正确,有时需要比较视觉结构。

例如数学公式:

[
\frac{a+b}{c}
]

和:

[
\frac{a-b}{c}
]

只有一个符号不同,但数学意义已经改变。

对于表格,模型也可以利用渲染结果比较行列结构。

使用官方封装的服务时,开发者通常只需要提交原始图片、候选文本和区域类型,服务端会自动完成渲染。

2.1 模型性能怎么样?

在官方 JevOCRBench 测试中:

模型 AUROC
JEV-35B-A3B 90.1%
MiniCPM-OCR Jev(2B) 93.6%
Qwen3.5-397B-A17B 93.8%

AUROC 衡量模型区分正确和错误 OCR 结果的能力,越接近 1 越好。

这里非常有意思:一个只有 2B 参数的专用决策模型,在这个任务上的表现已经非常接近大型通用模型。

但 AUROC 93.6% 并不意味着 OCR 结果有 93.6% 的识别准确率,也不意味着自动通过的结果有 93.6% 正确。

这几个指标需要分开理解。

官方项目:

项目采用 Apache 2.0 许可证。


三、环境准备:本地部署 Jev

官方提供 Docker、SDK、vLLM 等部署方式。

为了让后面的案例更容易复现,这里使用官方 Docker 服务。

根据官方文档,原生部署推荐环境为:

  • NVIDIA GPU,至少 12GB 显存。
  • NVIDIA 驱动版本不低于 535。
  • 支持 NVIDIA Container Toolkit 的 Docker 环境。

对于显存较小的设备,可以进一步研究官方提供的 GGUF、AWQ、GPTQ 量化权重,但需单独验证兼容性和推理速度。

3.1 下载项目与权重

git clone https://github.com/OpenBMB/MiniCPM-OCR.git

pip install -U huggingface_hub

hf download openbmb/MiniCPM-OCR-Jev \
    --local-dir ./jev-weights

然后构建 Docker 镜像:

cd MiniCPM-OCR/scripts/minicpm-ocr-jev

docker build \
    -f serve/Dockerfile \
    -t minicpm-ocr-jev:latest .

启动模型服务:

docker run -d \
    --name minicpm-ocr-jev \
    --gpus all \
    -p 127.0.0.1:8030:8030 \
    -v /绝对路径/jev-weights:/weights:ro \
    minicpm-ocr-jev:latest 8030 /weights

需要把 /绝对路径/jev-weights 替换为真实权重目录。

服务启动后,检查健康状态:

curl http://127.0.0.1:8030/healthz

当返回的 status 为 ok 时,就可以调用评分接口。

接下来安装 Python 请求库:

pip install requests

四、实践案例一:财务票据 OCR 自动质检

4.1 业务场景

假设企业每天需要处理数千张银行回单、发票及交易凭证。

OCR 完成后,我们希望对识别出的金额进行质量检查。

理想流程如下:

票据图片
    │
    ▼
OCR 文字识别
    │
    ▼
金额字段及对应图片区域
    │
    ▼
MiniCPM-OCR Jev
    │
    ▼
质量评分
    │
    ├── 高可信 → 进入业务校验
    │
    └── 不确定 → 人工复核

假设我们已经通过 OCR 得到以下结果:

交易金额:18,680.00

同时,保存了这个金额在原始凭证中的图片区域:

amount.png

注意,Jev 更适合检查具体文档区域,而不是把整张复杂票据与其中一个金额字段直接进行比较。

4.2 Python 完整实现

本地 Docker 服务提供:

POST /v1/rm/score

编写代码:

import base64
import requests
from pathlib import Path

API = "http://127.0.0.1:8030"


def encode_image(path):
    """图片转换为原始Base64字符串"""
    return base64.b64encode(
        Path(path).read_bytes()
    ).decode("utf-8")


def check_ocr(image_path, text, category="text"):
    """检查一条OCR识别结果"""

    payload = {
        "input_form": "ternary",
        "items": [
            {
                "case_id": "amount-001",
                "image": encode_image(image_path),
                "ocr_text": text,
                "category": category
            }
        ]
    }

    response = requests.post(
        API + "/v1/rm/score",
        json=payload,
        timeout=60
    )

    response.raise_for_status()

    result = response.json()["results"][0]

    # 只有scored代表模型成功完成判断
    if result["verdict"] != "scored":
        raise RuntimeError(
            f"OCR评分失败:{result['detail']}"
        )

    return result["prob_yes"]


# 检查票据金额
score = check_ocr(
    image_path="amount.png",
    text="交易金额:18,680.00"
)

print(f"OCR质量评分:{score:.4f}")

# 演示阈值,正式使用需验证
if score >= 0.95:
    print("进入自动业务校验")
else:
    print("进入人工复核")

需要特别注意:接口中的 image 是不带 data:image/png;base64, 前缀的 Base64 字符串,这是官方 Docker API 的要求。

4.3 如何理解结果?

假设模型输出:

{
  "case_id": "amount-001",
  "category": "text",
  "verdict": "scored",
  "prob_yes": 0.98,
  "prob_no": 0.02,
  "detail": ""
}

以上为模拟结果。

prob_yes=0.98 表示模型对候选 OCR 结果正确性的评分较高。

但这里还需要处理一个实际问题。

假设 OCR 把 18,680.00 识别成 18,880.00,即使 Jev 检测出了问题,也不会自动把金额修改回来。

它的作用是发现可能存在错误的识别结果,并引导系统重新识别或人工检查。

因此,在金额、身份证号、银行账号等关键字段的处理流程中,Jev 可以发挥很大的作用。


五、实践案例二:两个 OCR 模型结果不同,应该相信谁?

第二个案例更能体现 Jev 的独特价值。

假设我们正在解析一篇数学论文,图片里有这样一个公式:

[
y=\frac{a+b}{c}
]

两个 OCR 模型分别给出了以下结果。

模型 A:

y=\frac{a+b}{c}

模型 B:

y=\frac{a-b}{c}

到底应该采用哪个?

过去可以采用多数投票、多模型交叉验证,或者再调用一个 VLM 判断。

但如果模型只有两个,投票并不能解决分歧。

Jev 可以分别评估两个候选结果与原始图片的一致性,再选择评分更高的版本。

5.1 使用 score_best 接口

官方提供了专门的接口:

POST /v1/rm/score_best

这个接口可以在同一个文档区域中比较多个候选结果。

继续使用前面定义的 encode_image():

import requests

# 假设公式图片保存在equation.png
image = encode_image("equation.png")

# 两个OCR模型的候选结果
candidates = [
    r"y=\frac{a+b}{c}",
    r"y=\frac{a-b}{c}"
]

payload = {
    "input_form": "ternary",
    "image": image,
    "category": "formula",
    "candidates": candidates
}

response = requests.post(
    API + "/v1/rm/score_best",
    json=payload,
    timeout=60
)

response.raise_for_status()

result = response.json()

# 检查哪些候选真正完成了模型评分
valid = [
    i for i, status in enumerate(result["verdicts"])
    if status == "scored"
]

if not valid:
    raise RuntimeError("所有候选均评分失败")

best_index = result["best_index"]

if best_index not in valid:
    raise RuntimeError("最优候选状态异常")

best_score = result["scores"][best_index]

print("候选评分:", result["scores"])
print("最佳结果:", result["best_text"])
print("最佳评分:", best_score)

# 低于阈值时仍然人工复核
if best_score < 0.95:
    print("需要人工复核")

5.2 预期输出

假设模型返回:

{
  "best_index": 0,
  "best_text": "y=\\frac{a+b}{c}",
  "scores": [0.97, 0.12],
  "verdicts": ["scored", "scored"]
}

那么系统就会选择模型 A 的识别结果。

以上分数为示例,并非实测。

这个案例最重要的地方在于:

我们可以将 OCR 识别和 OCR 结果评估拆成两个独立的阶段。

例如:

              原始文档区域
                   │
             ┌─────┴─────┐
             ▼           ▼
          OCR模型A    OCR模型B
             │           │
             ▼           ▼
          候选结果A    候选结果B
             │           │
             └─────┬─────┘
                   ▼
            MiniCPM-OCR Jev
                   │
                   ▼
              评分与择优
                   │
                   ▼
              最终OCR结果

官方还提供 score_best_batch,可以一次对多个文档区域执行候选择优,更适合批量文档处理。

需要注意,两个候选必须对应同一张原始区域图片,且内容边界一致。否则,比较结果的意义会大幅下降。

另外,如果两个 OCR 模型都识别错了,Jev 只能从已有候选中选择相对可信的一个。因此,即使评分最高,也要结合阈值决定是否进入人工复核。


六、实际部署时,哪些问题值得注意?

6.1 评分不是经过校准的正确概率

虽然 Jev 的输出位于 0~1,但模型分数和真实正确率之间的关系,还需要通过业务数据验证。

例如,假设模型给出 0.95 分,我们不能直接推断这类结果在真实业务中就有 95% 的正确率。

更科学的办法是准备一批人工校验过的 OCR 数据,分别统计不同评分阈值下的实际错误率。

6.2 重点关注自动通过率与准确率

实际使用时,可以定义两个指标:

[
自动通过率=\frac{自动通过数量}{全部样本数量}
]

[
自动通过准确率=
\frac{自动通过且正确的数量}{自动通过数量}
]

例如:

评分阈值 自动通过率 自动通过准确率
0.80 90% 97.0%
0.90 80% 98.5%
0.98 60% 99.5%

以上数据仅用于说明阈值与人工审核工作量之间的关系。

在金融、医疗、法律等领域,自动通过准确率可能比自动通过数量更加重要。

6.3 不同文档类型应该分别评估

Jev 支持三种区域类别:

category 用途
text 普通文字
formula 数学公式
table 表格

不同类别的错误形式可能差别很大。

例如:

  • 文字容易出现错字、漏字。
  • 公式容易出现上下标、运算符错误。
  • 表格容易出现行列错位、单元格丢失。

因此,正式部署时,最好分别评估三类数据的识别正确率和模型评分效果。

另外,模型需要渲染候选文本。不同字体、浏览器和渲染环境可能使分数发生轻微变化。如果希望不同部署环境的评分具有可比性,应该尽量统一渲染配置。

还有一个容易踩的坑:一定要检查 verdict。

官方服务在图像编码失败、渲染失败等情况下,也可能返回 0.0 或 -1.0。

这些是失败状态的固定值,不能当成模型认为 OCR 错误的正常评分。


七、总结:Jev 为 OCR 系统增加了一层质量控制

前面我们已经研究过 PaddleOCR-VL、MiniCPM 系列 OCR、Clairic 以及各种决策模型。

MiniCPM-OCR Jev 的出现,让文档 AI 系统又多了一个很实用的组件:

          PDF / 扫描图片
                 │
                 ▼
         文档解析与OCR模型
                 │
                 ▼
           结构化识别结果
                 │
                 ▼
          MiniCPM-OCR Jev
                 │
        ┌────────┴────────┐
        ▼                 ▼
    高可信结果         低可信结果
        │                 │
        ▼                 ▼
    自动业务处理        人工复核
        │
        ▼
  Clairic / LLM / 数据库

本文的两个实践案例分别展示了:

  • OCR 自动质检: 通过评分筛选可能存在识别错误的文本区域。
  • 多模型择优: 比较不同 OCR 模型对同一图像的识别结果,选择更可靠的候选。

从技术发展趋势看,这类专用决策模型很值得关注。

过去,我们总希望把 OCR 模型训练得越来越强,让它自己解决所有识别问题。

现在则出现了另一条路线:让一个模型负责识别,让另一个专用模型负责检查。

尤其对于金融票据、合同、技术文档等对准确性有较高要求的场景,增加一层独立的识别质量评估,可能比单纯增加 OCR 模型参数更有实际价值。

MiniCPM-OCR Jev 给我们的启发是:

AI 系统除了需要知道答案,还需要知道哪些答案值得进一步核实。

当 AI 开始大规模处理真实业务数据时,这种能力往往非常重要。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。