ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

OCR预处理:让LLM读取扫描件的关键一步

OCR预处理:让LLM读取扫描件的关键一步 前阵子帮同事处理一份扫描版项目立项书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试一次。这一步走通之后后面才谈得上批量、自动化和工程化。
返回列表