ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RAG数据导入与解析:OCR与多模态大模型的PDF实战

RAG数据导入与解析:OCR与多模态大模型的PDF实战 干过 RAG 项目的人都有同感前期最难的不是模型选型也不是向量检索调参而是数据导入和解析。反过来你就知道了如果你的 PDF 是从网上下载的“文字层很干净”的报告用简单工具就能搞定但一旦遇到扫描件、票据、PPT 导出的 PDF、多语言文档整条链路马上进入“谁都能做一点但谁都不敢保证不丢信息”的尴尬状态。这篇文章是 RAG 数据导入与解析攻略的第二篇重点锁定图文与 PDF。先把“RAG 知识库能不能直接存图片”这个老问题聊透再带你们过一遍 OCR 的实战细节、多模态大模型的用法以及我实测过的九种 PDF 解析工具的选型逻辑。适合正在搭 RAG 知识库、或者想把 PDF 文档处理成高质量文本 chunk 的开发者也适合那些被扫描 PDF 折磨得想骂人的运维和内容负责人。1. 为什么说图文与 PDF 是 RAG 的第一道坎1.1 “RAG 知识库能存图片吗”这个问题要拆开看很多人一上来就问知识库能存图片吗如果单纯从向量数据库的角度回答当然能——你可以把图片送到一个视觉嵌入模型里生成图片向量存进同一个向量库然后用文本或图像查询去召回。CLIP 这类模型就是干这个的多模态向量检索也是成熟方案。但实际落地时你会发现绝大多数 RAG 场景要的是“基于图片里的内容回答问题”不是“把图片原样找出来”。比如一张扫描的合同用户会问“乙方在什么时间付款”这时候直接存图片向量意义不大因为问题涉及的是图片里的文字信息。所以更务实的做法是把图片中的文字、表格、版式结构抽取成文本进入常规文本检索链路。如果业务确实要求按图找图、或召回后给用户展示截图再单独建一个视觉向量库不与文本检索混在一起。我见到很多项目团队一开始兴致勃勃搞“图片文本双路召回”最后发现双路向量空间不一致融合排序很麻烦。这里最朴素的建议是先搞清楚你要的是“内容可检索”还是“图片可检索”前者走 OCR/多模态抽取后者才值得上视觉嵌入。多数知识库场景其实前者就够用了。1.2 PDF 并不是一种格式而是一堆格式的集合PDF 的麻烦在于它的内部构造差异极大。同样是.pdf后缀背后可能是完全不同的数据形态原生数字 PDF有文字层有字体编码可以通过page.get_text()直接抽文本。扫描 PDF每一页都是一张图片没有任何文字层必须走 OCR。混合 PDF一部分页是文字一部分页是图片最常见的就是“扫描件 我加了一页备注”这种文件。版式复杂的 PDF双栏排版、表格线、页眉页脚、悬浮批注这类文档抽出文本容易乱序尤其是有表格的时候。这些差异决定了没有任何一个工具能通吃所有 PDF。我在实际项目中反复踩过这种坑拿 PyMuPDF 把文字抽出来发现顺序按照“页眉→右栏→左栏→页脚”跳来跳去后来才知道双栏 PDF 需要做版面分析。所以我会在后面的章节里把不同工具的使用场景说得具体一点你会发现选工具其实是选“你当前 PDF 的最大摩擦点”。2. OCR 实战从传统识别到多语言关键时刻2.1 传统 OCR 什么时候够用OCR 的本质是把图像里的文字像素转成可编辑文本。它不负责理解语义也不擅长处理“上下文”但它成本低、速度快、稳定尤其适合大量文本简单、版式固定的扫描件。什么时候我会首选传统 OCR典型场景是发票、运单、标准合同、期刊扫描页。这些页面字迹清晰版式相对固定不需要太多上下文推理。另一个优势是本地化部署容易不需要昂贵的多模态硬件支持。但传统 OCR 有明显天花板。比如一张流程图文字都能识别出来但“A 指向 B、B 又分支到 C”的逻辑关系无论如何都无法从纯文字里还原。还有复杂表格OCR 能把单元格内容识别出来但表格的行列归属经常丢导出后变成一串乱文字。这时就需要考虑多模态模型或者专门的表格解析工具。2.2 Tesseract vs PaddleOCR 的实测经验Tesseract 是老牌开源 OCR前后处理简单适合轻量场景。它的 Python 接口一般长这样from PIL import Image import pytesseract text pytesseract.image_to_string( Image.open(page.png), langchi_simeng ) print(text)但注意chi_sim语言包需要单独下载装完 Tesseract 主程序不代表就能识别中文。另外 Tesseract 对清晰英文扫描件的识别效果不错可一旦遇到低分辨率图片、复杂背景或者手写体识别率会明显下滑。PaddleOCR 是另一个路线内置检测加识别的完整流程对中文支持更好。用 PaddleX 的管道式接口写起来也很简单from paddlex import create_pipeline pipeline create_pipeline(OCR) result pipeline.predict(invoice.png) for res in result: texts res[ocr_res][texts] print(texts)我第一次跑通这条链路时很惊喜普通中文发票上的数字和字段基本都能抽出来而且它自带方向分类器竖排文字也能处理。不过 PaddleOCR 的模型文件比较大首次加载会有明显延迟部署在服务器上要注意显存或内存占用。实战里我还会在喂图片前先做预处理灰度化、二值化、去噪点。简单三步对扫描件有奇效很多原本识别失败的模糊文档预处理后正确率能提升一大截。常用做法是用 OpenCV 做个自适应阈值import cv2 img cv2.imread(scan.png, cv2.IMREAD_GRAYSCALE) thresh cv2.adaptiveThreshold( img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, 8 ) cv2.imwrite(scan_clean.png, thresh)2.3 韩文、日文等非中英场景经常翻车网上搜 OCR 相关问题时经常看到有人拿默认配置去识别韩文结果一团乱。比如有人用paddlex默认管道识别含韩文的图片输出的却是中文乱码。这不是引擎不行而是语言配置不对。Tesseract 识别韩文需要指定langkor并且要有kor.traineddata语言包。PaddleOCR 这边的多语言模型则用参数指定语言。如果你不指定默认模型基本都是按中英文训练的遇到韩文字符就会硬生生映射到近似的汉字或字母上。混排文档就更麻烦。中文、英文、数字混排还好中日韩混排时我不会指望单次 OCR 全搞定。我的做法是先做版面分析和段落切分把每个区块单独裁剪出来再按区块语言去识别。这样虽然工程量大但准确率远比“一张大图跑到底”靠谱。别嫌麻烦这恰恰是 RAG 知识库真正落地时最值钱的处理细节。2.4 OCR 和验证码不是一回事经常有人搜 “OCR 识别验证码”甚至有人问我能不能直接把验证码识别模块接进 RAG 流程。我的态度很明确别这么干。验证码本身是反识别的对抗场景需要针对性训练和处理跟知识库里的文档提取完全是两个方向。而且从合规角度讲绕过验证机制本来就不该是 RAG 系统该做的事。如果只是在自己的测试环境里学习 OCR 基础可以拿验证码图片练习图像预处理和字符分割但生产系统里千万别把验证码识别当成通用 OCR 来用。把精力放在票据、扫描件、合同上收益会大得多。3. 多模态大模型把“识别”升级为“理解”3.1 为什么 OCR 之后还需要多模态模型传统 OCR 输出的是文字序列但 RAG 检索和问答需要语义结构。举个很常见的例子一张 PPT 页面里左边是流程图右边是说明文字下面还有一个总结表格。OCR 能识别出所有字符但分不清哪个文字是流程节点、哪个是单元格、哪个是图片里的注释。多模态大模型在这类场景里优势明显。它把整张图片作为视觉输入再结合语言指令去理解布局、内容和逻辑关系。你可以说“把这张图里的流程图转成 Mermaid 语法”也可以说“把表格转成 Markdown”它能返回结构化的结果而不仅仅是扁平文本。我自己最常用的一条链路是PDF 页面转 PNG → 多模态大模型直接输出 Markdown → 再对 Markdown 做分块。这样保留了标题层级、表格结构、列表语义检索时的上下文质量提高非常明显。3.2 本地多模态模型怎么选市面上能跑的多模态模型很多本地部署常用 MiniCPM-V、Qwen-VL 系列等。选择逻辑很简单显存够不够、推理速度可不可以接受、对中文排版和表格的理解行不行。8GB 左右显存可以跑 7B 级别的小模型适合做中文单据、规范文本抽取。24GB 以上显存可以上更大的 VLM处理复杂图表能力更强。没有 GPU建议先用云端 API或者只在少量样本上做标注验证别硬跑本地。还有个容易被忽略的点多模态模型把页面当图片理解时DPI 会直接影响效果。一般建议把 PDF 页转成 150-220 DPI 的 PNG分辨率太低模型看不清小字太高则推理时间暴涨。我通常对含小字表格的页面用 220 DPI纯文字页面 150 DPI 足够。3.3 提示词怎么写得能直接落到 RAG 管道我给多模态模型的提示词已经稳定成一套模板核心是“结构化输出”四个字请把这张图片的内容转成 Markdown 格式输出 1. 标题用 # 表示小节用 ## 2. 表格必须用 Markdown 表格 3. 流程类内容用有序列表表达 4. 图片内的图例、说明文字不要遗漏 5. 如果看不清某个字标注 [无法识别]不要猜测。这个提示词既约束了输出格式又给了“不知道就说不知道”的安全出口。模型返回的内容我会直接当成 Markdown 文档再做分块和向量化。相比传统 OCR 输出的裸文本这种带结构的输出检索效果更好问答时能看清楚标题层级不会把两个小节的文字混在一起。3.4 成本和准确率之间怎么平衡多模态模型比传统 OCR 贵很多推理也慢。所以我在生产管道里做了一套兜底逻辑先用传统 OCR 抽文本如果抽出来之后发现某页文本量极低比如扫描件图片页、或者包含明显图表的页面再把这一页单独交给多模态模型做结构化抽取。这样既控制成本又保证复杂页面的效果。实际操作上这个决策不需要很精确。我是按“每页提取到文本字符数”来兜底的少于 50 个字符说明这一页基本是图像内容直接转多模态多于 500 个字符说明还是以文字为主OCR 结果已经可以接受中间地带看版面是否有表格有表格就优先多模态。这条规则我跑了几个项目效果稳定。4. 九种 PDF 工具选型一张表看清方向4.1 九种工具对比一张表收好我筛选了九个在实际项目里用过的 PDF 相关工具把它们的主打能力和适用场景整理成一张表。这样你在选型时可以直接定位不用每个都试一遍。工具核心能力适用场景输出形式部署复杂度PyMuPDF文本抽取、页面转图片、PDF 合并拆分原生文本 PDF、需要页面渲染纯文本、图片低pdfplumber表格抽取、坐标定位表格密集的报表、账单文本、表格结构低pypdf纯文本抽取、页面操作简单文本 PDF不需要高精度纯文本低PDFMiner底层解析、文本位置信息需要精细坐标与字体信息文本、布局数据中Camelot基于线和区域识别的表格抽取有线表格表格、DataFrame中tabula-py基于 Java 的表格抽取规则表格需要识别边框表格、DataFrame中unstructured文档元素级切分、分区多格式文档统一进 RAGelement 对象中MarkerPDF 转 Markdown需要保留结构、高质量文本Markdown高Mathpix公式、复杂表格转结构化学术论文、公式密集文档Markdown 等高商业这张表不是让你选最强大的而是让你按当前文档类型选最省心的。很多人上来就看unstructured和Marker觉得它们功能全结果部署依赖一堆、速度还很慢最后连原始文本都没跑通。我建议从小而美的工具开始。4.2 PyMuPDF先抽文本再用图片兜底PyMuPDF 是我的首选第一棒因为它既能快速抽文本又能极低门槛地把 PDF 页转成图片。遇到原生 PDF 时它的准确度和速度都让人放心。基本用法如下import fitz doc fitz.open(report.pdf) for page in doc: text page.get_text(text) if page.get_text(words): # 原生文字层直接进入后续处理 pass else: # 没有文字层转图片后交给 OCR pix page.get_pixmap(dpi220) pix.save(fpage_{page.number}.png)page.get_text(words)会返回单词列表如果列表为空基本可以确定这一页是扫描图片需要转图片走 OCR。这个方法极其简单却能判断整个文档的扫描率帮你决定后面要不要接入 OCR 管道。我还会经常用page.get_text(blocks)因为它按文本块返回能保留一定的阅读顺序。注意双栏 PDF 依然可能乱序这时候不要急着硬跑可以观察块坐标按y0坐标重新排序。4.3 pdfplumber 和 Camelot把表格从 PDF 里“捞”出来表格是 RAG 里的重灾区。很多 PDF 用纯文本抽取后表格里的数字和内容会被打散完全看不出行列关系。pdfplumber 这时就派上用场import pdfplumber with pdfplumber.open(table_report.pdf) as pdf: for page in pdf.pages: for table in page.extract_tables(): for row in table: # 每行就是一个列表可以转 DataFrame print(row)pdfplumber 通过解析页面上的线条和文本坐标来还原表格结构对有线框的表格效果尤其好。但遇到无线框表格它会力不从心这时候可以试试 Camelot 的lattice模式或者用多模态模型兜底。Camelot 的典型用法是import camelot tables camelot.read_pdf(report.pdf, pages1-5) df tables[0].df它对“有明显线条”的扫描件有过人之长但在原生文字版式表格上反而没有 pdfplumber 稳。我的建议是这两个工具都配好同页面先用 pdfplumber 试表格行列对不上再换 Camelot谁输出对用谁。4.4 unstructured 和 Marker面向 RAG 的“全套西装”如果你不想自己拼装那么多零件unstructured是个不错的起点。它把 PDF 解析成一系列Element对象比如Title、NarrativeText、Table并直接把表格输出成 HTML 格式正好适合后续分块。它的 API 风格是这样的from unstructured.partition.pdf import partition_pdf elements partition_pdf(docs.pdf, strategyauto)strategyauto表示自动判断页面有没有文字层没有就启动 OCR。它能直接输出带类型标记的 element 列表分块时非常方便。但代价是依赖复杂模型文件多新手安装经常会遇到一堆依赖错误。Marker 则更偏向“把 PDF 变成高质量 Markdown”。它对版面分析、标题层级和表格结构的保留做得非常好适合想把整个文档干净地变成 RAG 输入的团队。代价是模型重、部署条件高对纯文本 PDF 有点杀鸡用牛刀。4.5 我的选型决策套路总结一下我实际用下来的选型路径先抽样 5 页判断扫描率和表格比例。扫描率低、表格少直接用 PyMuPDF 抽文本分块入库。表格多且线框清晰pdfplumber Camelot。扫描率很高、语言单一PaddleOCR 批量识别。扫描率高、版式复杂、有大量逻辑图表多模态大模型抽取 Markdown。对统一格式有要求且团队人力足unstructured 统一承载。这套路径的好处是先快后慢不会一上来就陷入复杂工具的学习成本里。你完全可以根据自己的文档特点只取其中一环不必所有工具都精通。5. 常见问题与排查笔记5.1 识别出的文本顺序混乱怎么办PDF 文字层其实带有坐标信息PyMuPDF 按“块”抽取时如果原文档是双栏顺序很有可能是“左栏上半、右栏上半”交叉输出。这时候我不直接使用get_text(text)而是基于块的坐标自行排序import fitz doc fitz.open(column.pdf) page doc[0] blocks page.get_text(blocks) blocks.sort(keylambda b: (round(b[1] / 50), b[0])) import fitz doc fitz.open(column.pdf) page doc[0] blocks page.get_text(blocks) blocks.sort(keylambda b: (round(b[1] / 50, b[0])))代码第二行用了round(b[1] / 50)把相近高度的行归并再按b[0]即 x 坐标排序。实测下来能把大多数双栏文章恢复成正确的阅读顺序。如果你的文档是有三栏或更复杂的版式干脆转图片交给多模态模型让模型理解版面比人工写排序规则快得多。5.2 识别出来全是乱码 / 空字符原生 PDF 抽取有时会得到乱码常见原因是字体编码问题尤其是方正字体、某些中日韩字体子集。这种情况下别纠缠文字层直接用页面转图片再 OCR反而更可靠。我见过有人在字体映射问题上折腾一整天最后换 OCR 十分钟解决。RAG 是结果导向没必要在 PDF 底层解析上死磕。5.3 扫描 PDF 识别率很低扫描件识别率低的原因大多是分辨率不够、倾斜角度、阴影遮挡、页面底色偏灰。我的处理顺序是转图片时设置 DPI 不低于 300先用 OpenCV 做倾斜校正再做自适应二值化最后才交给 OCR。如果这样还不行多半是原图本身质量差只能尝试多模态大模型。多模态模型在低清晰度图片上的抗干扰能力比传统 OCR 强虽然也不是万能但很多时候能靠上下文猜出正确内容。5.4 表格行列错乱怎么保留结构表格行列错乱的核心是没有利用坐标信息。pdfplumber 可以直接读取单元格坐标你也可以把每个文字块的坐标一起存进元数据后续分块时按坐标重组。另一个更省心的办法是直接输出 HTML 表格unstructured和部分多模态模型都支持这种输出。HTML 表格在检索时反而好处理因为你可以按tr、td标签切分。5.5 韩文、日文混排的文档别指望一个语言模型解决所有语言。我把多语言文档先按“语言区块”切分再分别交给对应语言模型。PaddleOCR 虽然支持多语言但混排时参数设置麻烦。如果页面少直接交给支持多语言的多模态大模型更省事。我在韩文测试里用过的经验是模型输入图片把整段提示词里的语言要求写清楚比如“韩文部分必须原样输出”效果比设置各种参数更直观。5.6 C#、Java、PHP 环境怎么办网上很多人搜 C# OCR、Java OCR、PHP OCR 识别验证码之类的问题。如果你不是 Python 技术栈我的建议也很简单OCR 和 PDF 解析这部分已经高度服务化和平台化不必非要在一个语言里什么都自己做。独立跑一个 Python 解析服务通过 HTTP 接口对外提供C#、Java 直接调用是最稳妥的架构。RAG 管道本质上是数据处理系统处理层的语言不必跟业务系统强绑。6. 我习惯的本地落地流程说这么多最后分享一下我在具体项目里面跑得最顺的落地流程也当作你入手时的默认模板。我的完整管道是五段式入参统一转 PDF。Word、PPT、图片全部转成标准 PDF简化后续处理。每页抽取文字层统计空页与非空页自动判断扫描率。空页走 OCR文本页走 PyMuPDF 抽取表格页走 pdfplumber。对复杂图表页面单独截取交给多模态大模型输出 Markdown。把文本和 Markdown 统一分块、向量化最终进入 RAG 检索。这个流程不用一上来就套重型工具能最大化利用原生 PDF 的文字层只在必要的时候引入 OCR 和多模态成本控制得比较好。关于“图片到底存不存向量库”这个开头的问题我现在的回答是知识库以文本检索为主图片拆成文本信息使用只有确需按图找图才单独建图像向量库。这套组合在多个业务系统里跑得都很稳后续如果文档量继续增大我还会在分块和版面分析上继续做优化但至少目前这套流程解决了我遇到的所有扫描件和复杂版式问题。
返回列表