
前陣子幫同事處理一份掃描版項目立項書PDF接近一百頁頁面上是清晰可讀的漢字但鼠標劃線就是選不中復制出來全是空白。同事想直接丟給大語言模型LLM做摘要結果模型告訴我“無法從圖片中提取文字”。那一刻我意識到OCR并不是一個可有可無的預處理步驟而是決定LLM任務能否成立的第一道關卡。這個場景并不算少見。越來越多的知識庫、合同、檔案、行業報告仍以掃描件或圖片格式存在。它們不是秘密也不是不存在只是沒法被直接復制、檢索、喂給模型。沒有OCR這些文檔等于“看得見摸不著”有了OCR它們才能進入LLM的上下文成為可計算、可提問、可生成的內容資產。我后來把整套處理邏輯整理成了一個簡單的流水線并給它取了個名字叫“OCR It”從無法復制的文檔中提取文本供你的LLM使用。這篇博客想講的不只是怎么安裝一個OCR工具而是為什么這條流水線的關鍵點不在識別字符而在如何提供一份干凈的、結構完整的、LLM真正消費得了的文本。換句話說OCR不是為了存檔而是為了把文檔從“視覺對象”翻譯成“語言模型的輸入”。1. 為什么“無法復制的文檔”正在成為LLM工作流的隱形瓶頸1.1 從復制到理解文檔里其實有“兩層文本”一個很常見的誤解是只要是PDF里面的文字就應該能復制。實際上PDF里的文字存在兩種完全不同的形態。第一種是“文本型PDF”。文件里本身就包含了字符編碼和字體信息就像Word導出的PDF一樣鼠標可以選詞CtrlC可以復制。這種情況下解析PDF是最簡單的事很多Python庫都能直接抽取文本根本不需要OCR。第二種是“圖像型PDF”。每一頁其實是一張圖片可能是掃描儀生成的也可能是打印后重新拍照的。它看起來有文字但底層只有像素沒有任何字符信息。你想要復制復制出來的當然是空白或亂碼。LLM能理解什么它能理解的是token是文本序列。哪怕現在出現了多模態大模型能直接讀圖片多數商業化工作流里仍然會把文本抽取作為前置步驟。因為文本更輕、更便宜、更容易緩存和處理。所以“無法復制的文檔”對LLM來說幾乎等于不存在的文檔。OCR就是把這層阻斷打開的鑰匙。1.2 掃描件、圖片PDF和拍照件處理難度完全不同很多人覺得OCR就是“拿個工具掃一下”。但實際接觸后會發現不同來源的圖片難度完全不是一個量級。我一般會把需要處理的文檔分成三類文檔類型特征典型處理難度常見策略掃描型PDF掃描儀生成文字較正分辨率較高相對容易直接頁面轉圖片后OCR圖片型PDF由JPG、PNG等圖片直接合成PDF中等必要時先增強圖像再OCR手機拍照件有透視、陰影、反光、傾斜困難需要先矯正、裁剪、增強如果面對的是一批質量參差不齊的拍照件直接調用OCR接口往往會出現很多錯誤。這時候不要急著調整識別參數而要先處理圖像質量。這個原則在后面的工程化部分會反復出現。1.3 LLM對輸入文本的要求不是“能讀”而是“好用”OCR工具輸出的原始文本很多時候并不是LLM真正想吃的格式。比如段落被硬拆成一行一行頁眉頁腳混在正文里多欄新聞稿被讀成左右穿插表格單元格順序混亂識別結果里夾雜大量空格和換行。如果直接把這種文本丟給LLM模型可能也能回答但回答質量會明顯下降。因為LLM非常依賴上下文連貫性一個被切碎的文本會讓模型抓不住主謂賓關系甚至把不同欄目的內容混在一起理解。所以我建議把OCR之后的文本處理當成一個獨立環節。OCR負責“識別”文本處理負責“組織”。只有兩者都做好了LLM才能拿到結構完整、邏輯清晰的輸入。這也是“OCR It”理念里最容易被忽略的部分。2. 一條從文檔到LLM的OCR提取流水線2.1 先判斷文檔類型再選OCR策略拿到一個文檔后不要直接寫代碼先花30秒做判斷。如果文檔是PDF優先檢查它是否有文本層。最簡單的方法是用PDF閱讀器嘗試選擇文字或者用pdftotext命令直接抽取pdftotext sample.pdf sample.txt如果抽取出來的文件是空的或者只有少量頁眉頁腳那么這個PDF多半是圖像型需要進入OCR流程。如果原始材料是圖片比如PNG、JPG、微信截圖就跳過PDF解析直接做圖像預處理。具體來說要檢查分辨率夠不夠文字區域是否小于200像素高有沒有明顯傾斜有沒有陰影、反光、水印干擾頁面是否是多欄排版。2.2 最小可用的本地OCR流程在常見的開源方案里Tesseract仍然是很多人的入門選擇。雖然它面對復雜中文文檔時不一定是最優解但勝在免費、跨平臺、容易上手。下面是一個管道示意Python環境下比較常見import pdf2image import pytesseract from PIL import Image # PDF頁面轉圖像 images pdf2image.convert_from_path(scan.pdf, dpi200) # 逐頁識別 for i, img in enumerate(images): text pytesseract.image_to_string(img, langchi_sim) print(f--- Page {i1} ---) print(text)這段代碼是示意結構實際運行前需要安裝Tesseract引擎和中文語言包同時確認路徑配置正確。在macOS上可以用Homebrew安裝在Ubuntu上可以用apt install tesseract-ocr tesseract-ocr-chi-simWindows上則需要下載安裝包。如果你更愿意用PaddleOCR也可以獲得更好的中文版面效果但依賴安裝會更重一些。初期不必糾結選哪個先用最小流程跑通一頁再根據結果決定是否換引擎。2.3 讓OCR結果可以直接交給LLM識別完文本只是完成了一半。我們要把輸出整理成適合LLM閱讀的結構。一種實用的做法是給每一頁加上頁碼標記并把連續的行合并成段落。比如# Page 1 項目立項書 本項目的目標是構建一套基于OCR的文檔處理流水線 用于將掃描件中的文本提取并交給大語言模型使用。 # Page 2 第一章 背景與意義 ...這樣的結構至少解決了三個問題頁碼保留方便追溯段落合并避免上下文斷裂Markdown層級讓LLM更容易識別結構。如果直接使用云端或本地API還可以把這段整理后的文本作為system或user消息的一部分傳入然后再提具體要求比如“根據以上內容生成摘要”。經過整理的OCR文本模型的理解效果通常比直接喂原始OCR輸出好很多。3. 關鍵選擇本地OCR、云端OCR還是離線模型3.1 三種方案的對比在實際項目中OCR的選型通常不是技術潔癖問題而是成本、隱私和精度的權衡。方案優點缺點適合場景本地開源OCRTesseract、PaddleOCR免費、離線、可控、隱私好中文準確率依賴模型和預處理個人使用、敏感文檔、小批量云端OCR服務各類商業API準確率高、接口簡單、支持復雜版面有費用、有并發限制、數據離開本機大批量、通用文檔、團隊工具多模態LLM直接讀圖可理解版面、語義更強成本高、速度慢、不穩定復雜表格、少樣本、混合場景選擇哪種方案取決于你的“無法復制的文檔”到底是什么形態以及你打算把它用在什么任務上。3.2 為什么我會先選本地OCR做小批量驗證我個人的做法是當項目剛起步手里只有幾十頁樣例時先不要開通任何付費API也不要急著訓練模型。先用本地OCR跑通全流程。這樣做有幾個實際好處沒有網絡請求排查問題更快輸出可以隨時打印出來檢查不用被接口文檔干擾如果本地OCR效果已經足夠好就可以省下后續云服務費用更關鍵的是你可以先建立一套“預處理→識別→清洗→喂模型”的流程框架后續哪怕換成云端API也只是替換其中一環。本地OCR的缺點是準確率可能不如大廠的商業服務。但很多時候先跑通流程比咬住那1%到2%的準確率更重要。流程穩定后再升級單點效果是更現實的路徑。3.3 批量場景下的成本、限流和隱私邊界一旦從單頁驗證進入批量處理問題就會從“效果”轉向“工程”。使用云端OCR時需要確認接口的并發限制單條請求大小限制每月免費額度響應超時數據存儲策略。不能把所有頁面一次性循環調用否則很容易觸發限流。通常要加一個簡單的重試機制比如遇到429或者5xx時等待幾秒再重試。隱私邊界也要提前判斷。合同、病歷、身份證、內部報告這類敏感內容不適合未經脫敏就上傳到云端。這種情況下本地OCR幾乎是唯一合規選擇。即使是本地模型也要注意模型運行環境的安全而不是只看識別準確率。4. 提高可復用性的幾個工程化細節4.1 預處理決定OCR上限的不是模型而是圖像質量很多人把OCR效果差歸罪于模型不夠強但實際觀察下來大部分問題都出在圖像上。一張照片如果傾斜、曝光不均勻、文字模糊無論用多好的OCR引擎效果都會受限。常見且有效的操作包括轉灰度去掉顏色干擾清理背景降低陰影和斑點影響二值化讓文字和背景對比明顯傾斜矯正讓文字行保持水平提高分辨率確保小字能被識別。這些操作不一定每次都需要但遇到拍照件時值得先做一輪實驗。你可以保存處理前后兩張圖把OCR結果分別跑一遍直觀看到差異。4.2 版面分析多欄、表格、頁眉頁腳要先處理中文文檔里最常見的版面問題是多欄。論文、報紙、甚至一些排版復雜的報告都是左右兩欄。直接把整頁圖丟給OCR兩個欄目的文字可能會被交錯讀取。Tesseract里可以通過--psm參數設置頁面分割模式比如--psm 3自動頁面分割但可能處理不好復雜版面--psm 4按單列文本處理--psm 6假設統一文本塊。PaddleOCR則帶有版面分析模型可以檢測標題、段落、表格、圖片等區域。如果你的文檔類型比較固定比如只有合同或只有論文可以針對性地調整版面參數。在實際操作中我建議先用“自動版面檢測”生成一個結構預覽確認欄目邊界和段落順序再決定是否拆分區域單獨識別。這一步看起來很笨但能省下后續大量清洗時間。4.3 輸出清洗把“文本塊”拼成“段落”OCR輸出通常會有大量換行因為引擎是按文本框輸出的。如果你的目標是讓LLM理解整段邏輯就必須把斷開的行重新拼起來。一種簡單的啟發式方法是如果當前行以句號、問號、感嘆號結尾說明是段落結束保留換行如果當前行末尾沒有任何標點且下一行不是標題就把兩行合并過濾掉頁眉、頁腳、頁碼比如只出現一次的內容或純數字行。可以使用正則表達式處理也可以用規則腳本。更高級的做法是訓練一個小模型判斷段落邊界但大多數項目沒有必要。清洗之后一定要輸出一份“清洗后文本”給人工抽檢不要只看前幾頁就認為全部沒問題。4.4 把OCR封裝成可復用的函數為了讓整個流程可復用我建議把OCR從“腳本”升級成“函數”。def extract_text(file_path, page_start1, page_endNone): 從文檔中提取文本返回整理后的Markdown字符串。 這里只展示流程骨架具體參數需根據你的環境調整。 text_blocks [] images load_images(file_path, page_start, page_end) for page_no, img in enumerate(images, startpage_start): try: raw run_ocr(img) cleaned clean_ocr_output(raw) text_blocks.append(f# Page {page_no}\n\n{cleaned}) except Exception as e: text_blocks.append(f# Page {page_no}\n\n[OCR_ERROR] {e}) return \n.join(text_blocks)這樣做的好處是調用方不需要關心OCR細節異常能被捕獲并記錄后續換成云端API時只需要替換run_ocr內部實現頁面級錯誤不會中斷整個批次。這也是“OCR It”從一次性腳本走向工程化工具的關鍵一步。5. 實際落地時最常遇到的四個問題5.1 識別結果出現大量錯字或亂碼排查順序不要亂先看原圖是否清晰。如果文字邊緣模糊先做圖像增強再確認語言包和編碼。中文文檔要用中文語言包輸出編碼建議指定UTF-8檢查字體。如果文檔里是特殊字體可能不匹配訓練數據最后再看OCR引擎配置。比如Tesseract的--oem、--psm是否適合當前版面。如果錯字集中在某些字符上例如“0”和“O”混淆“一”和“-”混淆可以通過后處理規則修復。但要注意不要濫用替換規則否則可能把正確字符改錯。5.2 多欄文檔被當成一欄讀取句子錯亂這是報紙、論文、PPT講義里最容易出現的問題。第一步切換不同PSM模式觀察哪一檔接近正確欄序。第二步使用版面分析模型把左欄、右欄分別切出來再按“左上到右上”的順序拼接。第三步如果文檔結構固定可以在圖像預處理階段按欄切割為后續LLM輸入保留清晰順序。有一個經驗可以分享不要指望一個通用設置解決所有文檔。先固定文檔類型再調整版面參數是更高效的路徑。5.3 表格和公式變成亂行OCR面對表格時通常表現較差。因為表格里的單元格位置信息很重要而純文本序列會丟失這種二維關系。如果表格數量少可以不用OCR轉而使用專門的表格解析工具或者手動錄入關鍵字段。如果表格很多可以考慮把表格區域單獨截取出來交給支持表格識別的服務或多模態模型。要理解的是OCR并不能“理解”表格它只是把文字按位置輸出。真正的表格結構化需要額外的定位和行列推理。公式就更特殊了普通的OCR不擅長處理數學符號。如果文檔核心內容是數學公式你需要考慮公式識別方案比如把公式區域導出為LaTeX。5.4 長文檔超過LLM上下文限制現在主流LLM的上下文窗口在不斷增大但掃描件動輒幾十上百頁依然可能超出限制。常用的策略是“分層摘要”按頁提取OCR文本對每頁文本做一次獨立摘要再把所有頁的摘要拼接成最終輸入如果需要細粒度答案可以在最終回答時附帶“引用頁碼”。這種方法不會丟失太多信息也能讓長文檔被“塞進”上下文。另一個辦法是使用向量數據庫把每頁文本切塊并嵌入讓LLM先檢索相關頁面再回答。但這就是更完整的RAG工程了需要額外搭建。6. 從單次嘗試到長期使用的判斷框架6.1 一個三次迭代的落地方法先跑通、再優化、最后工程化面對OCRLLM項目我的建議永遠是分三步走。第一步跑通。拿3到5頁文檔寫一個最簡單的腳本用默認配置識別把結果打印出來。目標是確認流程沒有斷能輸出文本即可。第二步優化。根據第一步輸出的問題調整圖像預處理、版面參數和文本清洗規則。每次只改一個變量重新評估。最多迭代幾次就能找到適合自己的配置組合。第三步工程化。把腳本封裝成函數通過命令行或API輸入文件路徑輸出整理后的Markdown記錄日志并處理異常。如果文檔量很大再加入任務隊列、并發控制和失敗重試。這三步不要跳步。很多人一上來就想做整個RAG系統結果數據源還沒清洗干凈后面全部白費。6.2 適用邊界與不適合場景“OCR It”并不是萬能的。它適合解決的是“可讀但不可復制”的文檔比如清晰掃描件、截圖、高質量拍照件。它不適合以下幾個場景低分辨率的監控截圖、模糊的傳真件手寫文字密集的文檔大量復雜公式的數學論文需要高精度證據鏈比如法院卷宗、病歷原件。在這些場景里OCR可以作為輔助檢索工具但絕不能作為唯一事實來源。要讓LLM基于OCR結果做嚴肅判斷必須保留人工復核環節。6.3 真正的判斷OCR是為LLM準備“干凈的上下文”回到開頭的場景。那份一百頁的掃描版立項書如果不經過OCRLLM一點忙都幫不上。但經過OCR后能不能直接得到一份完美摘要也不一定。識別過程中的分段錯誤、表格丟失、版面混亂都會影響最終結果。所以我更愿意把OCR看作“文檔進入LLM之前的數據治理層”。它真正要解決的問題不只是把字符取出來而是讓取出來的文本變成可追溯、可切分、可理解的結構化上下文。你越早意識到這一點就越不會迷信某個OCR工具而是會花精力去搭建一條穩定、可維護、能應對真實臟數據的流水線。如果你手里也有一批“看得見、復制不了”的文檔別急著丟給一個在線工具。先選定3頁樣例跑通本地OCR整理成一頁干凈的Markdown再丟給LLM試一次。這一步走通之后后面才談得上批量、自動化和工程化。