跳到主要內容

【2026 最新】MiniCPM-OCR Jev 教學:繁中表格分數怎麼放行?Docker、門檻校準與 RAG 入庫六步

最後更新: ·
MiniCPM-OCR Jev 教學:繁中表格分數與複核門檻

你把掃描表格轉成文字,品名、金額排得整整齊齊,卻把「應付 1,240」抄成「1,248」。如果接到文件問答系統,錯字可能變成之後每次回答的依據。MiniCPM-OCR Jev 教學要解決的,就是怎麼在入庫前,多設一道能追查的品質分流。

這篇寫給第一次接觸 OCR 品質評分的讀者:先用白話理解原理,再準備繁中表格、呼叫本機 API、選擇複核門檻。概念段不需要程式背景;操作段需要已備妥 NVIDIA GPU 的 Linux Docker 環境,以及基本 Python 操作。

本文依 2026 年 10 月 29 日查閱的官方文件與固定程式版本整理。本次主機是 Apple silicon,未執行 Jev GPU 推論;下方是部署與評估方法,紙上數字均另行標示,不把它們寫成模型成績。

先說結論:分數是篩檢尺,放行要有驗收收據

可靠入庫=有效評分+自己的門檻驗證+可回看的原圖。把 Jev 想成收件處的篩檢員:它幫你安排哪些稿件先看,合格標準則由你的文件與錯誤成本決定。

  • 先看 verdict=scored,再讀 prob_yes;技術失敗與低品質候選分開記。
  • 同一張原圖配上正確、錯字、錯金額、錯欄四種候選,檢查這把尺會漏掉什麼。
  • 用校準集選門檻,再到未參與選門檻的保留集驗收;金額等重要欄位仍保留獨立規則。

一、MiniCPM-OCR Jev 教學:先分清五個零件

OCR(光學字元辨識)負責從圖片讀字;Jev 接在辨識之後,對已有結果評分。官方模型指南把評估單位定為一個文字、公式或表格區域,輸入包含原圖、候選文字,以及候選文字重新畫成的圖片。

  • ①「底稿」:文件上的原始區域裁圖。保留頁碼與座標,別讓正確數字來自隔壁欄。
  • ②「抄本」:OCR 輸出的候選內容,連同表格結構一起交給評分器。
  • ③「重印稿」:Renderer(渲染器)把候選內容畫回像素,讓模型比較版面。
  • ④「篩檢尺」:Jev 比較這組輸入,給出 0 到 1 的分數。
  • ⑤「收件規則」:你選的門檻、關鍵欄位檢查與複核流程,決定資料往哪走。

為何要重畫?同樣一段繁中文字,換字型可能改變字形、換行與欄寬。對模型而言,這些像素都是輸入。官方 Dockerfile特別處理 CJK 字型與字型替代;缺少對應字型,可能畫成方框。先把尺固定,才有意義比較分數。

別把 prob_yes=0.95直接翻成「這批繁中表格有 95% 正確率」。官方指南明確要求另查分數區間與實際正確比例是否吻合。機率校準文件也用這種對照解釋 calibration:同一分數區間的預測,要和觀察到的比例相符,才有機率意義。

MiniCPM-OCR Jev 教學:原圖、候選渲染、評分與複核入庫流程
流程示意:評分是其中一段;未通過的區域留在複核路徑,保留原圖。圖/AlphaLab。

二、先固定 Docker 與字型,再評第一張圖

擔心裝好後每台分數不同?先選官方 Docker 路徑。本機部署指南列出的這條 NVIDIA 起點是至少 12 GB VRAM、驅動版本至少 535。這是本篇採用的部署配置,不是所有推論後端的共同最低需求。

先準備 Docker、可用的 NVIDIA 容器 GPU,以及官方模型權重目錄。從官方權重入口取得並記錄 revision 與檔案雜湊;本篇不在一般筆電下載或啟動整套 GPU 服務。已具備條件的人,從新的練習目錄執行:

git clone https://github.com/OpenBMB/MiniCPM-OCR.git
cd MiniCPM-OCR
git checkout b33b474136088dc43a2341e94590c804ec0c16a5
cd scripts/minicpm-ocr-jev
docker build -f serve/Dockerfile -t jev-eval:pinned .
docker run -d --name jev-eval --gpus '"device=0"' \
  -p 127.0.0.1:8030:8030 \
  -v /absolute/path/to/checkpoint:/weights:ro \
  jev-eval:pinned 8030 /weights
curl -f http://127.0.0.1:8030/healthz

把 /absolute/path/to/checkpoint換成你已下載的真實絕對路徑。驗收時打開 health 回應,確認 status為 ok;HTTP 有回應仍可能是在載入。這條指令只把服務埠綁到本機,練習文件先用自行製作的無個資表格。

固定 commit 還不等於日後重建必定得到同一份映像:Dockerfile 仍會從套件來源安裝部分系統依賴。建置成功後,記下 docker image inspect jev-eval:pinned --format '{{.Id}}',保留那一份映像,另存 health JSON、模型 revision、字型清單及 Chromium 版本。換了映像、字型或裁圖設定,就視為新配置重新驗收。

三、繁中表格怎麼配對?四份抄本共用同一張底稿

怕測到的只是「排版漂亮」?先做受控錯誤對照。自製一張橫排表格,含「項目、金額、應付」等繁中字,並在人工稿標清每個儲存格與欄位歸屬。原圖可以是自己用文書軟體匯出的 PNG;同一區域保留列標題,避免裁到只剩數字。

  • 正確稿:文字、數字、欄位與儲存格關係皆吻合。
  • 錯字稿:只改一個繁中字,其餘結構不動。
  • 錯金額稿:把 1,240改成 1,248,只動一位數。
  • 錯欄稿:保留數字,交換兩個欄位的值,測試歸屬錯誤。

每份候選各存一個 UTF-8 檔,表格候選可沿用抽取器產生的 HTML 結構,送 category=table。先目視渲染結果有沒有保留表格;不要為了讓分數變好,把候選修成與正式輸出不同的樣子。官方渲染程式說明它會處理 Markdown、HTML 與 LaTeX。

這四份是找破綻的壓力題,不代表實際錯誤比例。還要收集有權使用的真實 OCR 錯誤,涵蓋字型、掃描、低對比、合併儲存格與不同供稿來源。官方資料準備建議要求保留真實與合成錯誤,並以頁面切分,避免相關區域跨到不同資料集。

實作上先把來源文件分成「開發、校準、保留」三組;同頁四份候選永遠留在同組,同文件多頁也一起分。開發組排錯,校準組挑門檻,保留組最後才打開。按群組切分的工具可協助落實;還要檢查重複掃描與相同版型有沒有洩漏。

四、MiniCPM-OCR Jev 教學:呼叫 API,先讀狀態再讀分數

已把裁圖命名 crop.png、候選存成 candidate.html?下面存成 score_one.py,執行 python3 score_one.py。它使用 Python 標準函式庫,把圖片編成沒有 data: 前綴的 base64,寫出原始回應;格式依Docker API 文件。

import base64, json, math
from pathlib import Path
from urllib.request import Request, urlopen

payload = {
    "input_form": "ternary",
    "items": [{
        "case_id": "doc01-p1-table1-correct",
        "category": "table",
        "image": base64.b64encode(Path("crop.png").read_bytes()).decode(),
        "ocr_text": Path("candidate.html").read_text(encoding="utf-8")
    }]
}
Path("request.json").write_text(json.dumps(payload, ensure_ascii=False))
req = Request("http://127.0.0.1:8030/v1/rm/score",
    data=json.dumps(payload).encode(),
    headers={"Content-Type": "application/json"})
with urlopen(req, timeout=120) as response:
    result = json.load(response)
Path("response.json").write_text(json.dumps(result, ensure_ascii=False, indent=2))
rows = result.get("results", [])
if len(rows) != 1 or rows[0].get("case_id") != payload["items"][0]["case_id"]:
    raise RuntimeError("回應無法和輸入對帳")
row = rows[0]
if row.get("verdict") != "scored":
    raise RuntimeError("本次未得到有效評分,保留回應並送錯誤佇列")
s = row.get("prob_yes")
if type(s) not in (int, float) or not math.isfinite(s) or not 0 <= s <= 1:
    raise RuntimeError("分數格式異常")
print("有效評分:", s)

這段只示範單區域收發;網路逾時、HTTP 錯誤會使程式停止,停止不等於已送入實際複核系統。擴成批次時要加上持久化工作狀態、重試上限與去重,依官方 API 的 case_id逐筆對帳,失敗項另列並保留原始資料。

特別分清三件事:summary.pass_rate是成功完成評分的比例;prob_yes是單筆模型分數;你人工標註後算出的正確率,才是候選在這批任務是否正確。官方回傳的 0.0或 -1.0也可能伴隨失敗狀態,所以判斷順序必須先看 verdict。

若做 best-of-N(同區域多份候選選一份),先逐筆排除失敗,再評估被選結果是否過門檻。文件提醒 score_best在候選全部失敗時會回退到 index 0;只讀 best_text會把這個預設位置誤當有效勝出。選最大分數的整條策略,也要重新在保留集評估。

五、門檻怎麼選?把三種分母寫在紙上

門檻不是先猜 0.9,而是先問「漏放一筆錯金額的代價有多高,能複核多少?」在校準集試不同門檻,每筆用人工稿判定:所有必要儲存格正確才算正確;模糊到人也無法裁定的項目另列待查。

  • 錯誤漏放率:放行的錯誤筆數 ÷ 全部已知錯誤筆數。看壞稿漏進去多少。
  • 放行後錯誤率:放行的錯誤筆數 ÷ 全部自動放行筆數。看進資料庫的稿有多乾淨。
  • 複核比例:需要複核筆數 ÷ 全部輸入筆數。技術失敗與模糊稿也計入工作量,另報各類數量。

紙上算例:假設有 100 個區域,人工判定 20 個有錯。某個門檻放行 70 個,其中 2 個有錯,其餘 30 個送複核。錯誤漏放是 2/20=10%;放行後錯誤是 2/70≈2.86%;複核比例是 30/100=30%。這些是教算式的假設筆數,未替 Jev 填入推論結果。

品質門檻三種分母的紙上算例:2除20、2除70、30除100
同一組假設資料,三個問題要用三個分母;非 Jev 實測。圖/AlphaLab。

要把分數讀成機率,再把 scored 項目依分數區間分組,逐組記平均分數、人工正確比例與筆數。高分區若只有幾筆,先擴樣本,別用一條好看的平均線代替資料。合成四件組刻意增加了錯誤,對應真實流量的放行後錯誤率,要另用接近正式分布的樣本估計。

選定門檻後凍結,再開保留集;報告以上比例、原始筆數、金額錯誤與錯欄分組,以及複核分鐘數。若看過保留集又調門檻,下一輪另備新保留集。零漏放只代表這批未觀察到錯誤,仍要看樣本量與比例的信賴區間;相關區域也別當作完全獨立樣本。

六、接入 RAG:先進暫存區,再進可搜尋的索引

RAG(檢索增強生成)是先找資料,再請模型依資料回答。你可以把索引想成圖書館目錄:抄錯的書卡若先上架,問答再流暢也可能引用錯誤。尚不熟悉執行層的人,可先看Agent Harness 白話解說。

先在 staging(暫存區)保存 document_id、page_id、region_id、bbox、crop_hash、candidate_text、category、parser_revision、renderer_id、model_revision、verdict、prob_yes、threshold_version、review_status。bbox 是裁圖座標,記清像素或相對座標;人工改稿另存新版本、複核人與裁定時間。原圖與文字的存取權限一起控管。

# 接線示意,不是可直接執行的資料庫程式
record = save_to_staging(original_crop, candidate, versions)
if verdict != "scored" or not valid_score:
    queue_error(record)
elif not policy_applies or hard_checks != "pass":
    queue_review(record)
elif score < frozen_threshold:
    queue_review(record)
else:
    mark_accepted(record)
index_only_accepted_records()

上面省略資料庫交易、佇列實作與權限檢查;正式串接要讓「記錄接受」與「索引工作」可對帳,重試同一版本不重複入庫,修正或撤回時刪掉舊索引。評分服務的欄位依前述官方 API 接入;應用程式的接受狀態由你保存。Harness 實作教學可幫你把狀態與停止條件接齊。

hard checks 是可明確計算的規則,例如欄位齊全、金額格式、同幣別下適用的加總。規則失敗或不確定就送複核,高分不抵銷它。這部分可接著看帳單 OCR 的來源與算術驗收;本篇新增的是外部區域評分與渲染校準這一段。

常見坑:尺換了、分母換了,卻沿用舊結論

  • 只換 CJK 字型:保留同一批原圖、候選與模型,對新舊渲染配置重新評分;分開看排序翻轉、門檻跨越與真實錯誤。本文不預測繁中字型會讓分數上升多少。
  • 只看總平均:把錯金額、錯欄、漏列與技術失敗分開報;整體漂亮可能掩蓋重要欄位。
  • 只挑成功請求:把逾時與 render_error 留在總輸入帳上,另外估算重試和人工成本。
  • 把模型選優當修稿:所有候選都錯時,最高分仍可能錯;保留最低接受條件與原圖路徑。

常見問題:八個直接答案

1. Jev 就是另一個 OCR 嗎?

不是同一角色。這篇用它評估已有候選;讀圖產生候選由上游抽取器負責。

2. 0.95 可以當繁中正確率嗎?

先別這樣用。先用自己的標註資料對照分數區間與觀察比例,再決定能否解讀為機率。

3. 官方 AUROC 很高,門檻就選 0.5?

不成立。AUROC 衡量區分正誤的排序能力;接受門檻由你的錯誤成本與資料驗證決定。

4. 繁中一定比簡中分數差嗎?

目前不預設方向。本文查閱的公開資料以中英與區域類型說明,未據此推估繁中金額表格的專屬正確率。請保留字形與錯誤類型分組。

5. 表格當 text 送也行嗎?

要用 table 對應表格。官方指出 category 用錯可能扭曲分數,且未必報錯。

6. Mac 讀者該先做什麼?

先做人工稿、四件候選與分組清單。本篇 Docker 指令選的是 NVIDIA 路徑;其他後端應沿各自官方指南另驗,不把這條指令當通用安裝。

7. 複核後改好的文字可以保留原分數嗎?

要另存版本。原分數屬於原本那組候選與圖;人工修稿與重新評分分開留下紀錄。

8. 第一批全對就能大量自動放行嗎?

先通過獨立保留集與業務門檻,再小批觀察。把新字型、新版型和抽取器升版當成重新驗收的觸發條件。

給新手的三個重點

  • 先固定原圖、候選與渲染環境,再比較分數。
  • 先分清技術成功、錯誤漏放與放行後品質,再選門檻。
  • 先留可追查的暫存紀錄,再把已接受版本送進索引。

接著閱讀

左右滑動查看更多推薦

下一步:先為一張表格留下四份抄本

今天先自製一張繁中表格,存好原圖、正確稿與三種錯稿,把預期裁定寫下來,分數先留白。接通服務後再逐筆填入,親眼看看哪些錯誤穿過你的門檻。回到口訣:可靠入庫=有效評分+自己的門檻驗證+可回看的原圖。想繼續把小練習接成完整系統,可瀏覽AI 專區,或從AlphaLab 課程練習下一個工作流程。

ALPHALAB 社群

有問題?來 Telegram 聊

和 Terry、編輯、其他網友一起討論這篇文章。提問、分享觀點,回覆更即時。

加入 Telegram 討論

📩 訂閱 AlphaLab 電子報

週日 Weekly 週報+週二、週四 Alpha Signal,每週最多三封。

我們不會 spam,隨時可退訂。已訂閱?管理訂閱偏好(會寄登入連結到你的信箱)

主題篩選與退訂說明

寄送日期以台灣時間為準。主題偏好會篩選每期精選,並非每篇新文章的即時通知;當期符合主題的文章不足時會略過寄送。

未勾選任何主題會收到所有主題的精選,並不會停止寄信。

取消勾選 Alpha Signal 可停止週二、週四短報,仍保留週日週報。若要停止所有電子報,請使用信件底部的「取消訂閱」。