
在實(shí)際的 LLM 應(yīng)用開發(fā)里最容易被低估的一步不是 Prompt 怎么寫而是文檔里的文本怎么進(jìn)到模型里。很多業(yè)務(wù)場景提供的資料都是掃描件、截圖、圖片型 PDF這類內(nèi)容看起來有信息但無法直接復(fù)制更沒法直接丟給 LLM。OCROptical Character Recognition光學(xué)字符識(shí)別就是用來做這件事的把圖片和掃描文檔中的文字“摳”出來轉(zhuǎn)成可編輯、可檢索、可繼續(xù)交給模型處理的文本。下面圍繞 “OCR It” 的思路從零搭建一條 OCR 文本抽取管線。完成這條管線后你可以把一張掃描 PDF 變成一段干凈文本再直接發(fā)給任意 LLM API 做摘要、問答或知識(shí)庫入庫。1. 先理解 LLM 為什么需要一條 OCR 預(yù)處理管線1.1 模型不認(rèn)識(shí)圖片文本層是 LLM 的輸入前提LLM 的基本輸入單位是 token也就是一串離散的字符或子詞。無論調(diào)用 OpenAI、Qwen、DeepSeek 還是本地模型接口層傳送的基本上都是字符串。你要是把一張 JPG 塞進(jìn) Chat 接口絕大多數(shù)純文本模型根本不知道這一串二進(jìn)制意味著什么。掃描件里的文字不是字符而是像素。像素和字符之間隔著 OCR 這一步。OCR 的作用就是把圖像里的字形區(qū)域識(shí)別出來還原成對(duì)應(yīng)的 Unicode 字符串。對(duì) LLM 來說這一步不是“可選優(yōu)化”而是“能不能用起來的門檻”。這里還要注意一個(gè)容易混淆的點(diǎn)多模態(tài)模型雖然能看圖但并不意味著所有場景都應(yīng)該直接傳圖。很多業(yè)務(wù)系統(tǒng)只把 OCR 結(jié)果持久化后續(xù)檢索、統(tǒng)計(jì)、摘要都基于文本做。如果每次處理都傳圖片成本、延遲、上下文長度都會(huì)迅速膨脹。更重要的是OCR 一旦完成文本就變成了普通數(shù)據(jù)可以復(fù)用、清洗、分段、進(jìn)向量庫這是圖片輸入不具備的優(yōu)勢(shì)。1.2 哪些文檔算“不可復(fù)制文檔”“不可復(fù)制”不一定是權(quán)限問題更多時(shí)候是技術(shù)問題。常見情況包括掃描 PDF紙質(zhì)合同、書籍、檔案掃描后形成的 PDF內(nèi)容本質(zhì)是整頁圖片。手機(jī)拍攝的照片發(fā)票、名片、黑板、屏幕上的文字受到光照、透視、遮擋影響。截圖網(wǎng)頁、聊天記錄、軟件界面很多內(nèi)容不在 HTML 文本層里。圖片型網(wǎng)頁微信公眾號(hào)文章、圖片廣告文字被切成圖片放在頁面上。低像素圖片郵件里粘貼的掃描件、打印后再次拍照的文檔字跡模糊。這些文檔的共同點(diǎn)是沒有可選擇的文本層。你要讓他們進(jìn)入 LLM 應(yīng)用第一步永遠(yuǎn)是 OCR而不是直接讓模型“猜”。1.3 本地 OCR 與云端 OCR 不是二選一OCR 引擎可以分成兩類本地離線引擎和云端 API。本地引擎常見的是 Tesseract、PaddleOCR、EasyOCR云端有百度 OCR、騰訊 OCR、阿里 OCR、Azure Document Intelligence、Google Cloud Vision 等。它們解決的問題一樣但取舍完全不同。對(duì)比項(xiàng)本地 OCR云端 OCR部署位置應(yīng)用服務(wù)器或邊緣設(shè)備廠商服務(wù)端數(shù)據(jù)出境無需上傳外部服務(wù)需要發(fā)送圖片或 PDF離線可用可以不行模型更新自己升級(jí)依賴廠商維護(hù)中文效果PaddleOCR 較好Tesseract 需要額外調(diào)優(yōu)通常開箱即用成本主要是機(jī)器資源按調(diào)用量計(jì)費(fèi)開發(fā)復(fù)雜度需要處理依賴和模型文件需要申請(qǐng)密鑰和配額實(shí)際項(xiàng)目中不必一開始就選定一個(gè)。建議先用 Tesseract 跑通流程因?yàn)榘惭b簡單、無廠商綁定如果中文識(shí)別率達(dá)不到要求再用 PaddleOCR 做替代如果數(shù)據(jù)合規(guī)允許、預(yù)算充足而且面對(duì)的是復(fù)雜版式發(fā)票或表格可以接云端 OCR 做兜底。重要的是先讓整條鏈路通起來而不是在第一周就糾結(jié)“哪個(gè)準(zhǔn)確率最高”。1.4 “OCR It” 的核心流程整條管線的流程可以分成五段輸入圖片或 PDF 文件。轉(zhuǎn)換PDF 轉(zhuǎn)成位圖保證 OCR 引擎能處理。識(shí)別OCR 引擎輸出帶置信度的文本。清洗去掉多余換行、亂碼、頁眉頁腳整理成可讀文本。投遞把文本交給 LLM API或?qū)懭胛臋n庫、向量庫。后面的章節(jié)會(huì)按照這個(gè)順序?qū)崿F(xiàn)一個(gè)最小可運(yùn)行腳本然后逐步加入?yún)?shù)調(diào)優(yōu)、錯(cuò)誤排查和工程化建議。2. 環(huán)境準(zhǔn)備先把 OCR 引擎跑起來2.1 Tesseract 安裝Windows 和 Linux 不要搞錯(cuò)安裝包Tesseract 是一個(gè)經(jīng)典的 OCR 引擎由 HP 實(shí)驗(yàn)室發(fā)起、Google 維護(hù)。它支持多種語言可以命令行調(diào)用也有 pytesseract 這樣的 Python 封裝。這里先以 Tesseract 為例因?yàn)樗鼘?duì)硬件要求低文檔多適合做第一版。在 Linux 上安裝命令非常簡單sudo apt update sudo apt install tesseract-ocr如果要用中文還必須安裝中文語言包sudo apt install tesseract-ocr-chi-sim在 Windows 上需要下載 64 位安裝包。安裝時(shí)注意安裝路徑例如C:\Program Files\Tesseract-OCR\tesseract.exe。安裝完成后把安裝目錄加入 PATH 環(huán)境變量否則 Python 封裝的 pytesseract 會(huì)找不到可執(zhí)行文件。macOS 上可以用 Homebrew 安裝brew install tesseract tesseract-lang安裝結(jié)束后驗(yàn)證是否成功tesseract --version tesseract --list-langs--list-langs會(huì)列出當(dāng)前可用的語言包。如果沒有chi_sim說明中文語言包沒裝成功。這時(shí)候去手動(dòng)下載chi_sim.traineddata放到 Tesseract 安裝目錄下的tessdata文件夾中然后重新執(zhí)行tesseract --list-langs檢查。2.2 Python 依賴pytesseract 和 Pillow 是兩回事Tesseract 本身是命令行工具pytesseract 只是幫你封裝了子進(jìn)程調(diào)用真正的識(shí)別能力在 Tesseract 里。使用 Python 時(shí)還需要 Pillow 來讀取圖片因?yàn)?pytesseract 的大部分 API 接受的是一張 PIL Image 對(duì)象而不是直接的圖片路徑字符串。創(chuàng)建虛擬環(huán)境后安裝依賴pip install pytesseract pillow pypdf pdf2image其中pytesseract調(diào)用 Tesseract 命令。Pillow圖片讀取和基礎(chǔ)預(yù)處理。pypdf讀取 PDF 元數(shù)據(jù)在某些場景下使用。pdf2image把 PDF 頁面渲染成 PIL Image依賴系統(tǒng)里的 poppler。Windows 下還要在腳本開頭告訴 pytesseract 去哪個(gè)位置找 tesseract.exeimport pytesseract pytesseract.pytesseract.tesseract_cmd rC:\Program Files\Tesseract-OCR\tesseract.exe如果這一步漏了運(yùn)行時(shí)會(huì)報(bào)類似tesseract is not installed or its not in your PATH的錯(cuò)誤。這個(gè)報(bào)錯(cuò)很常見先檢查命令路徑再檢查 PATH不要在安裝依賴上反復(fù)浪費(fèi)時(shí)間。2.3 增加 PaddleOCR 作為中文增強(qiáng)備選Tesseract 的中文識(shí)別對(duì)字體和清晰度比較敏感。如果你要處理的中文掃描件很多建議直接把 PaddleOCR 作為第二方案。PaddleOCR 是百度開源的 OCR 工具安裝方式與 Tesseract 不同。先安裝預(yù)測(cè)基礎(chǔ)庫和 PaddleOCRpip install paddlepaddle paddleocr如果機(jī)器有 NVIDIA GPU需要根據(jù) CUDA 版本安裝對(duì)應(yīng)的 paddlepaddle-gpu。生產(chǎn)環(huán)境里 GPU 版本和 CUDA 版本不匹配是常見坑安裝前先看官方安裝說明不要盲目裝最新版。PaddleOCR 第一次運(yùn)行時(shí)會(huì)把默認(rèn)模型下載到本地~/.paddleocr目錄。第一次使用才會(huì)下載所以不要以為安裝慢是卡住了。在離線環(huán)境部署時(shí)需要手動(dòng)把模型文件拷貝到目標(biāo)機(jī)器。簡單識(shí)別示例from paddleocr import PaddleOCR ocr PaddleOCR(use_angle_clsTrue, langch, show_logFalse) result ocr.ocr(sample.png, clsTrue) for page in result: for item in page: box, (text, score) item print(text, score)這里use_angle_clsTrue表示啟用方向分類器對(duì)旋轉(zhuǎn)圖片效果更穩(wěn)定langch表示使用中文模型。result的結(jié)構(gòu)是每頁的識(shí)別結(jié)果每一項(xiàng)包含文本框坐標(biāo)、文本內(nèi)容和置信度。2.4 驗(yàn)證環(huán)境用一張樣例圖片跑通第一個(gè)識(shí)別不要一上來就處理幾十頁 PDF。先用一張只有少量文字的圖片驗(yàn)證環(huán)境。你可以用系統(tǒng)截圖工具截取一段純文本保存為sample.png然后執(zhí)行下面的命令tesseract sample.png stdout -l chi_simeng如果控制臺(tái)輸出了與圖片內(nèi)容一致或接近的文本說明 Tesseract 安裝成功。如果輸出為空先檢查圖片分辨率是否太低、文字是否太小再考慮語言包問題。Pytesseract 版驗(yàn)證from PIL import Image import pytesseract image Image.open(sample.png) text pytesseract.image_to_string(image, langchi_simeng) print(text)這一步的目標(biāo)是讓 OCR 引擎先動(dòng)起來。如果連一張簡單的截圖都識(shí)別不出來后面處理掃描件時(shí)大概率會(huì)遇到同樣的問題所以要先把第一個(gè)檢查點(diǎn)跑通。3. 實(shí)現(xiàn)一個(gè)可用的文本抽取腳本3.1 最小圖片識(shí)別幾行代碼抽出一段文本圖片識(shí)別是整個(gè) OCR 管線的基礎(chǔ)。一個(gè)最小可運(yùn)行的函數(shù)只需要三步打開圖片、調(diào)用 pytesseract、返回字符串。import pytesseract from PIL import Image def ocr_image(image_path: str, lang: str chi_simeng) - str: image Image.open(image_path) text pytesseract.image_to_string(image, langlang) return text.strip() if __name__ __main__: print(ocr_image(sample.png))langchi_simeng表示同時(shí)啟用簡體中文和英文語言包。語言包之間用加號(hào)連接Tesseract 會(huì)合并多個(gè)語言的識(shí)別結(jié)果。如果你只處理英文可以改成langeng速度會(huì)更快。這里要注意image_to_string的返回結(jié)果可能帶有大量換行和空格這是 OCR 輸出的正常表現(xiàn)不要急著寫正則清理。后續(xù)清洗階段會(huì)統(tǒng)一處理。3.2 從掃描 PDF 抽文本多頁處理掃描 PDF 的頁面本質(zhì)是圖片Tesseract 不認(rèn)識(shí) PDF。所以要先通過pdf2image把每一頁渲染成 PIL Image再逐頁識(shí)別。from pdf2image import convert_from_path import pytesseract def ocr_pdf(pdf_path: str, dpi: int 300, lang: str chi_simeng): images convert_from_path(pdf_path, dpidpi) pages [] for page_num, image in enumerate(images, start1): text pytesseract.image_to_string(image, langlang) pages.append({page: page_num, text: text.strip()}) return pagesdpi300是常用經(jīng)驗(yàn)值。分辨率太低小字號(hào)文字容易識(shí)別錯(cuò)誤分辨率太高轉(zhuǎn)換時(shí)間和內(nèi)存占用會(huì)成倍增加。如果是清晰電子打印件200 DPI 足夠如果是印刷體小字300 DPI 更穩(wěn)妥。convert_from_path依賴 poppler。Linux 下安裝 poppler-utilssudo apt install poppler-utilsWindows 下建議不要手動(dòng)編譯直接下載 poppler 的 Windows 預(yù)編譯包然后把bin目錄加入 PATH。如果缺少 poppler運(yùn)行時(shí)會(huì)報(bào)pdf2image.exceptions.PDFInfoNotInstalledError直接根據(jù)報(bào)錯(cuò)提示處理即可。3.3 輸出 Markdown 或 JSON方便 LLM 和 RAG 使用OCR 腳本只輸出一個(gè)字符串還不夠?qū)嵱谩D阋尳Y(jié)果能進(jìn)入后續(xù) LLM 流程最好保存成結(jié)構(gòu)化格式。保存成 Markdown適合人類閱讀和文檔入庫def save_markdown(pages, output_path): with open(output_path, w, encodingutf-8) as f: for page in pages: f.write(f!-- page {page[page]} --\n) f.write(page[text] \n\n)保存成 JSON適合程序讀取和后續(xù)自動(dòng)化處理import json def save_json(pages, output_path): with open(output_path, w, encodingutf-8) as f: json.dump(pages, f, ensure_asciiFalse, indent2)選擇哪種格式取決于下游。如果你只是把文檔發(fā)給 LLM 做摘要Markdown 就夠如果你要依賴頁號(hào)做定位、做引用溯源JSON 更合適。還可以在 JSON 里加入每頁的字符數(shù)、識(shí)別時(shí)間、置信度方便后面做質(zhì)量評(píng)估。3.4 關(guān)鍵參數(shù)調(diào)優(yōu)不要照抄默認(rèn)值Tesseract 和 PaddleOCR 都提供一批影響結(jié)果的參數(shù)。新手最容易犯的錯(cuò)是不管三七二十一把所有圖片和 PDF 都丟進(jìn)同一個(gè)默認(rèn)配置里。參數(shù)或配置影響使用建議dpiPDF 渲染清晰度200 到 300低清晰度文檔用 300lang識(shí)別語言集合中英文混合用chi_simeng--psm 3自動(dòng)頁面分割大多數(shù)普通文檔用 3--psm 6把整頁當(dāng)作統(tǒng)一文本塊適合簡單單欄頁面--psm 7單行文本適合驗(yàn)證和行識(shí)別不適合整頁use_angle_cls是否啟用方向分類圖片方向不確定時(shí)啟用dpi與 PDF 頁數(shù)越高越吃內(nèi)存頁數(shù)多時(shí)分批處理--psm是 Tesseract 的 Page Segmentation Mode。--psm 3是全自動(dòng)頁面分割適合大多數(shù)情況。遇到某個(gè) PDF 是單欄純文字時(shí)--psm 6往往更穩(wěn)定。遇到只有一行標(biāo)題的截圖--psm 7反而更準(zhǔn)確。不要盲目用一個(gè)參數(shù)跑所有文檔先取 2 到 3 個(gè)樣本試。PaddleOCR 方面如果圖片方向多變保持use_angle_clsTrue如果圖片比較規(guī)整關(guān)閉方向分類可以略微提升速度。高分辨率圖片可以先做等比例縮放避免模型把大圖內(nèi)部的小塊文字割裂。4. 把 OCR 文本安全地交給 LLM4.1 清洗文本為什么不能省OCR 輸出往往有大量問題同一個(gè)段落被拆成多行、句尾出現(xiàn)亂碼、表格邊框被識(shí)別成豎線、頁眉頁腳混入正文。直接把這些原始文本發(fā)給 LLM模型會(huì)浪費(fèi)很多上下文去理解混亂的排版還會(huì)導(dǎo)致摘要不準(zhǔn)確。清洗的基本原則是“少破壞、多修復(fù)”。下面這個(gè)函數(shù)處理常見的換行和空格問題import re def clean_ocr_text(text: str) - str: if not text: return text # 把 Windows 和舊 Mac 的換行統(tǒng)一成 \n text text.replace(\r\n, \n).replace(\r, \n) # 把單行內(nèi)多余空格壓縮但保留換行 text re.sub(r[ \t], , text) # 把連續(xù)兩個(gè)以上的換行壓縮成一個(gè) text re.sub(r\n{3,}, \n\n, text) # 去掉頁眉頁腳常見的孤立頁碼 text re.sub(r^\s*\d\s*$, , text, flagsre.MULTILINE) return text.strip()這個(gè)函數(shù)不會(huì)試圖修復(fù)錯(cuò)別字也不會(huì)強(qiáng)行合并段落。對(duì) LLM 來說保留段落結(jié)構(gòu)往往比壓縮成一大段更有用。4.2 用 OpenAI 兼容接口發(fā)送本地文本清洗后的文本就是普通字符串可以直接傳給任何 LLM API。現(xiàn)在很多模型服務(wù)商都提供 OpenAI 兼容接口所以可以用同一個(gè) SDK 調(diào)用不同模型。import os from openai import OpenAI client OpenAI( api_keyos.getenv(LLM_API_KEY), base_urlos.getenv(LLM_BASE_URL), ) def summarize_ocr_text(text: str, max_length: int 4000) - str: truncated text[:max_length] resp client.chat.completions.create( modelos.getenv(LLM_MODEL, gpt-4o-mini), messages[ {role: system, content: 你是一個(gè)文檔整理助手。請(qǐng)根據(jù)OCR文本內(nèi)容輸出結(jié)構(gòu)化摘要包括主題、關(guān)鍵信息和待辦事項(xiàng)。}, {role: user, content: truncated}, ] ) return resp.choices[0].message.content不要把 API Key 硬編碼在腳本里。使用環(huán)境變量LLM_API_KEY、LLM_BASE_URL、LLM_MODEL管理避免代碼入庫時(shí)泄露密鑰。max_length4000只是示例實(shí)際值要根據(jù)模型的上下文長度和你的業(yè)務(wù)需求調(diào)整。如果文本太長直接截?cái)鄷?huì)丟失信息所以需要分段或使用下面的切分策略。4.3 文檔太長時(shí)按語義切分掃描件經(jīng)常有十幾頁甚至幾十頁。直接把全文塞進(jìn)一次模型調(diào)用既不經(jīng)濟(jì)也容易觸發(fā)上下文限制。常見的做法是按固定字符數(shù)切分并讓相鄰片段有重疊避免在句子中間切斷。def split_text(text: str, chunk_size: int 1500, overlap: int 100): text text.strip() if len(text) chunk_size: return [text] chunks [] start 0 while start len(text): end start chunk_size chunk text[start:end] chunks.append(chunk) if end len(text): break start end - overlap return chunksoverlap100的意思是每次跳過時(shí)保留前一段的尾部讓被切斷的句子至少有部分上下文延續(xù)。更復(fù)雜的方式是按段落切分優(yōu)先在\n\n處斷開再按最大長度合并。對(duì)絕大多數(shù)文檔場景固定長度加重疊已經(jīng)夠用。如果未來要接向量數(shù)據(jù)庫可以進(jìn)一步用 LangChain 或 LlamaIndex 的文本分割器。它們會(huì)嘗試保留語義邊界但原理與上面的代碼一致長度限制加重疊窗口。5. 常見問題與排查路徑5.1 識(shí)別結(jié)果為空或亂碼這是 OCR 使用中最常見的問題。現(xiàn)象是Tesseract 命令執(zhí)行成功但沒有輸出任何文本或輸出一串看不懂的符號(hào)。先按下面的表格排查問題現(xiàn)象常見原因檢查方式處理建議結(jié)果為空語言包缺失tesseract --list-langs安裝對(duì)應(yīng)語言包結(jié)果為空?qǐng)D片分辨率過低放大圖片看文字是否可見提升到 300 DPI 或放大兩倍結(jié)果為空--psm不匹配測(cè)試--psm 6、--psm 3單欄文檔用 6全是亂碼圖片被壓縮嚴(yán)重檢查圖片格式、原始質(zhì)量換原圖或用 PaddleOCR輸出數(shù)字符號(hào)表格、公式區(qū)域被當(dāng)成文本分析版面結(jié)構(gòu)版面分析或區(qū)域裁剪檢查時(shí)先用命令行跑一次tesseract test.png stdout -l chi_simeng --psm 6如果命令行能識(shí)別說明是 Python 封裝或路徑問題如果命令行也識(shí)別不了問題出在圖片、語言包或參數(shù)上。這個(gè)順序能快速縮小范圍。5.2 中文識(shí)別率低中文掃描件的識(shí)別率低于英文屬于正常現(xiàn)象但可以通過幾個(gè)手段改善。首先確認(rèn)是否安裝了中文語言包并且確認(rèn)語言參數(shù)不是eng而是chi_simeng。其次把 DPI 調(diào)到 300 以上因?yàn)橹形墓P畫密集小字號(hào)更容易被誤識(shí)別。第三使用 PaddleOCR 作為替代引擎它在中文場景下通常比 Tesseract 穩(wěn)定。如果文檔有旋轉(zhuǎn)、傾斜或拍照角度先做圖像旋轉(zhuǎn)校正。PaddleOCR 的use_angle_clsTrue會(huì)處理方向問題Tesseract 則需要你在調(diào)用前用 OpenCV 手動(dòng)旋轉(zhuǎn)圖像。5.3 PDF 轉(zhuǎn)圖片失敗或內(nèi)存不足運(yùn)行ocr_pdf時(shí)如果報(bào)PDFInfoNotInstalledError說明 poppler 沒有安裝。Linux 安裝poppler-utilsWindows 下載預(yù)編譯 poppler 并把bin加入 PATH。如果處理幾十頁 PDF 時(shí)內(nèi)存溢出通常是 DPI 開太高或一次性加載所有頁面。解決方案是一次只轉(zhuǎn)換一頁images convert_from_path(pdf_path, dpi200, first_page1, last_page1)再配合循環(huán)處理最后釋放 image 對(duì)象。順序是先降低 DPI再分批處理最后考慮增加機(jī)器內(nèi)存。不要一開始就盲目把 DPI 調(diào)到 600印刷件 300 DPI 已經(jīng)足夠。5.4 邊緣設(shè)備和國產(chǎn)平臺(tái)怎么落地?zé)嵩~里有人搜索“百度 OCR 怎么在 RK3588 運(yùn)行”這對(duì)應(yīng)一個(gè)真實(shí)需求在嵌入式或邊緣設(shè)備上跑 OCR。RK3588 是瑞芯微的 ARM 平臺(tái)常見于智能終端和邊緣盒子。在這種平臺(tái)落地 OCR 需要注意三點(diǎn)確認(rèn)架構(gòu)。RK3588 通常是 ARM64安裝 Python 包時(shí)要選擇匹配 arm64 的 wheel不要直接拿 x86_64 的安裝包硬裝。優(yōu)先選輕量模型。Tesseract 直接編譯可以用但字體依賴較重。PaddleOCR 的 CPU 版本可以在 ARM 上運(yùn)行但首次加載模型和推理速度會(huì)比 x86 機(jī)器慢。云端 OCR 離線 SDK 需要單獨(dú)申請(qǐng)授權(quán)接入前先確認(rèn)是否支持目標(biāo)平臺(tái)和內(nèi)核版本。不要在沒確認(rèn)系統(tǒng)架構(gòu)和依賴兼容性之前就盲目pip install。很多邊緣設(shè)備只有精簡的 Linux 系統(tǒng)缺少libreoffice、poppler、字體庫需要逐項(xiàng)補(bǔ)全。6. 工程化和最佳實(shí)踐6.1 本地 OCR 與云 OCR 的最終選型建議做選型時(shí)不要只看識(shí)別率還要看數(shù)據(jù)隱私、調(diào)用頻率、成本模型和團(tuán)隊(duì)維護(hù)能力。下面的決策清單可以幫你在項(xiàng)目啟動(dòng)階段快速判斷如果文檔包含個(gè)人隱私或公司機(jī)密優(yōu)先本地 OCR。如果調(diào)用量小、文檔種類復(fù)雜、版式不穩(wěn)定云端 OCR 更劃算。如果團(tuán)隊(duì)已經(jīng)有 GPU 推理服務(wù)PaddleOCR 是更可控的選擇。如果只是臨時(shí)腳本Tesseract 足夠不用引入重型依賴。如果同時(shí)需要表格結(jié)構(gòu)識(shí)別、發(fā)票字段抽取建議直接評(píng)估云廠商的文檔理解 API而不是用通用 OCR 自己造輪子。6.2 識(shí)別質(zhì)量如何評(píng)估不要只看一兩張圖片很多項(xiàng)目“看起來識(shí)別得挺好”是因?yàn)橹粶y(cè)試了樣板圖片。真實(shí)文檔里有噪聲、印章、手寫批注、表格線條、水印識(shí)別率會(huì)明顯下降。要建立質(zhì)量評(píng)估流程需要準(zhǔn)備一組有代表性的驗(yàn)證樣本然后人工提取原文和 OCR 結(jié)果逐字對(duì)比。常用評(píng)估指標(biāo)包括指標(biāo)含義計(jì)算方式字符準(zhǔn)確率正確預(yù)測(cè)字符占參考文本的比例正確字符數(shù) / 參考字符數(shù)行準(zhǔn)確率完全正確的行占比正確行數(shù) / 參考行數(shù)文本可讀性人類能否看懂主要段落人工打分或小范圍抽樣OCR 數(shù)據(jù)標(biāo)注在這里非常重要。沒有標(biāo)注樣本你就無法量化評(píng)估模型效果也無法在模型升級(jí)后做回歸對(duì)比??梢韵热斯?biāo)注 50 到 100 頁典型文檔作為持續(xù)評(píng)估的基礎(chǔ)集。6.3 OCR 預(yù)處理發(fā)布檢查清單在把 OCR 管線接入生產(chǎn)環(huán)境之前建議對(duì)照下面的清單逐項(xiàng)檢查檢查項(xiàng)具體內(nèi)容是否完成輸入格式支持圖片和 PDF限制單文件大小和頁數(shù)語言包確認(rèn)中文、英文語言包已安裝版本鎖定鎖定 Tesseract/PaddleOCR 和依賴版本異常處理文件不存在、PDF損壞、圖片解碼失敗有明確報(bào)錯(cuò)輸出結(jié)構(gòu)能輸出可讀文本和 JSON 結(jié)構(gòu)化結(jié)果日志記錄每個(gè)文件的處理耗時(shí)、識(shí)別字符數(shù)、失敗原因密鑰管理LLM API Key 放在環(huán)境變量或密鑰服務(wù)中數(shù)據(jù)合規(guī)敏感資料不會(huì)自動(dòng)上傳到外部服務(wù)監(jiān)控計(jì)算每日識(shí)別成功率、平均耗時(shí)、失敗率這些檢查項(xiàng)不是第一次上線就要全部完美實(shí)現(xiàn)但至少要明確哪些還沒做、誰負(fù)責(zé)補(bǔ)齊。OCR 管線一旦進(jìn)入生產(chǎn)識(shí)別失敗不應(yīng)該是“識(shí)別不了”而應(yīng)該是“有日志、有告警、有兜底”。6.4 從 OCR 出發(fā)可以繼續(xù)擴(kuò)展的方向完成“OCR It”這條基礎(chǔ)管線后擴(kuò)展方向很多。最自然的是接入 RAG 知識(shí)庫OCR 文本經(jīng)過切分、向量化用戶提問時(shí)檢索相關(guān)片段再交給 LLM 生成答案。這樣掃描件也能成為可搜索的“數(shù)字資產(chǎn)”。其次是版面分析和結(jié)構(gòu)化抽取。普通 OCR 只輸出文字不區(qū)分標(biāo)題、表格、圖片區(qū)域。如果你需要處理發(fā)票、合同、簡歷可以引入版面檢測(cè)模型或表格識(shí)別工具。還有公式識(shí)別。論文和試卷里的公式通過普通 OCR 會(huì)變成無意義字符串需要專門的公式識(shí)別引擎才能轉(zhuǎn)成 LaTeX。可以根據(jù)實(shí)際需求選擇。最后是模型迭代。你會(huì)發(fā)現(xiàn)識(shí)別效果不是一勞永逸的。當(dāng)新文檔類型出現(xiàn)時(shí)應(yīng)該回到標(biāo)注集補(bǔ)充樣本、調(diào)參、評(píng)估再?zèng)Q定是否繼續(xù)使用原模型。如果要給新手一個(gè)練習(xí)建議我認(rèn)為是不要一開始就想把所有文檔類型都支持先選一類典型文檔用“OCR It”的思路跑通“圖片 - 文本 - LLM 摘要”的閉環(huán)然后慢慢增加表格、版面、多頁處理。OCR 的質(zhì)量決定 LLM 輸入的質(zhì)量這一步花的時(shí)間一定值得。