
1. 先泼盆冷水图片和 PDF 才是 RAG 知识库真正的“硬骨头”这一篇是接着上一篇来的。上一篇我们聊了文本类数据的导入和清洗标题叫《RAG 数据导入与解析全攻略一》没看过的朋友可以先去补课。但说实话真正让 RAG 项目从“能跑 Demo”到“能上生产”的往往不是那一堆 Markdown 和 JSON 文本而是散落在各处的图片、扫描件和 PDF——尤其是那种批量导入、版面复杂、还夹着表格和印章的 PDF。为什么这么说因为很多人在搭建 RAG 知识库的时候默认一个前提我能找到文本然后直接切块、embedding、入库。但真实业务里根本不是这么回事。合同是扫描件发票是图片PPT 导出的 PDF 连文字层都没有技术手册的 PDF 排版精美但文字全被塞进文本框里——你拿 PyPDF2 一抽抽出来的全是乱码、错序甚至空字符串。到最后知识库里的内容是残缺的用户一问到具体数据系统给出的答案全靠猜所谓的“检索增强”变成了“检索残缺”。还有个很常见的疑问也是我每次讲 RAG 都会被人追问的RAG 知识库能存图片吗这个问题得分两层。第一层向量数据库确实可以存图片的向量表示比如用 CLIP 这类模型把图片转成向量再存进 Milvus、Qdrant这个技术上完全可行。第二层存进去之后你要考虑检索能拿到什么。如果你只存了图片向量用户提问“这张提货单上的金额是多少”你检索出来的是一张图片本身但大模型并不能直接看图除非你接的是 GPT-4V、Qwen-VL 这类多模态模型或者你提前用 OCR 把图片里的文字抽出来以文本形式入库。这两条路都能走但适合的业务场景完全不同。这一篇的核心就是帮你把这些路径拆开搞清楚什么时候用传统 OCR什么时候上多模态大模型以及市面上那几种 PDF 解析工具到底该怎么挑。先说结论没有万能的解析方案只有适合场景的取舍。下面我一个个展开。2. 先搞清楚你的 PDF 到底是“真文本”还是“假文本”2.1 什么是“带文字层”的 PDF什么是“扫描版 PDF”很多刚接触解析的人会犯一个低级错误——拿到 PDF 就直接用 PyPDF2 提取文本发现提取出来的内容是空的然后一脸懵。其实问题不在代码而在于你根本不清楚这个 PDF 是“带文字层的”还是“纯图像型”的。所谓带文字层的 PDF就是你在用鼠标选中 PDF 里的文字时能一个个字选中能复制粘贴。这种 PDF 最常见的是由 Word、LaTeX、WPS 直接导出或者由 web 页面打印生成也就是热词里经常出现的“web 页面 pdf 打印”。这类 PDF 内部的文本是真实存在的解析的时候直接用文本提取工具即可。而纯图像型 PDF 没有文字层本质上是把一页纸拍成图片或渲染成图片再嵌到 PDF 里。你在阅读器里能看但鼠标选中不了文字CtrlC 复制出来的是空白。这样一份 PDF无论你用 PyMuPDF 还是 PDFPlumber提取到的文本都是空的。这类文件必须走 OCR 或视觉模型理解才能把图片里的内容变成文字。这里给一个小技巧拿到一个 PDF先不要急着写解析代码用最快的方式做个判断——在阅读器里随便选中一段文字如果能选就是文字层 PDF如果选不了就是扫描版。你也可以直接在命令行里用 pdfinfo 查看如果页面信息里显示 “Pages” 和 “Encrypted” 之外没有特殊标记且用 pdftotext 能抽出内容那就是文字层 PDF。这个判断决定了你后续用什么工具省很多无用功。2.2 文字层 PDF 不等于解析无忧排版和文本流才是坑即便你确认 PDF 带文字层解析也不是简单提取。做过 PDF 解析的人都知道最磨人的是两个问题文本错序和排版碎片化。什么叫文本错序拿双栏排版的技术文档举例。印刷排版的时候页面是两栏并排的但 PDF 内部的文本对象是按生产顺序存储的可能先写完第一栏第三行再写第二栏第三行甚至对象顺序跟视觉顺序完全错开。你用 PyPDF2 直接提取得到的内容是一堆两三行一组、东拼西凑的碎片切块时不仅语义断裂检索匹配度也会大打折扣。排版碎片化更常见。很多 PDF 是从 PPT 导出的一个文本框里的标题是一段正文正文是一段图表里的标注又是另一个 text object。直接提取的时候你会发现页面上几十个 text chunk 平铺出来顺序全乱章节标题、正文、页眉页脚、图表说明完全搅在一起。所以我的经验是文字层 PDF 的解析重点不在“能不能提取”而在“提取后如何重建阅读顺序”。这一步做不好后面怎么切块 embedding 都是白搭。2.3 如何处理版面和顺序pdfplumber 的分栏检测兜底针对排版错序的问题我建议优先用 pdfplumber它比 PyPDF2 多提供一些版面信息基础能力至少能拿到每个字符的位置坐标从而做分栏检测和顺序重排。具体思路是对页面里的每个 word 对象提取它的 x0 坐标左边距。如果一页里的文字明显存在两组 x0 聚集区间说明是双栏布局。此时需要把文本按“栏”分组先从上到下提取左栏再提取右栏而不是让工具按原生顺序输出。用 pdfplumber 实现时大致逻辑是import pdfplumber with pdfplumber.open(sample.pdf) as pdf: for page in pdf.pages: words page.extract_words(use_text_flowTrue, keep_blank_charsFalse) # 按 x0 坐标聚类分栏 left_column [w for w in words if w[x0] page.width / 2] right_column [w for w in words if w[x0] page.width / 2] left_lines {} right_lines {} for w in left_column: key round(w[top] / 10) # 按行高近似归行 left_lines.setdefault(key, []).append(w[text]) for w in right_column: key round(w[top] / 10) right_lines.setdefault(key, []).append(w[text]) # 先输出左栏再输出右栏这个方案当然不是万能的但对大多数双栏 PDF 已经够用。楼层的“按行高近似归行”看起来粗糙处理正常排版的文档时效果却很稳定。讲到这里你可能会问如果 PDF 是扫描版连文字层都没有这些网页上说得再热闹的 pdfplumber 全都不管用了怎么办这就进入了 OCR 的地盘。下一节我们专门聊 OCR 选型和实践。3. 传统 OCR 工具选型PaddleOCR、Tesseract、RapidOCR 到底选哪个3.1 OCR 的实质与准确率认知不要追求 100%OCR光学字符识别的基本原理并不神秘——它本质上是把图像里的文字区域检测出来然后对每个区域的字符做分类识别。这种“检测 识别”的两段式流程决定了它的能力边界质量好的文档图片检测得准、识别得准准确率可以到 99% 以上但如果是低分辨率、倾斜、光照不均、带印章、艺术字体OCR 准确率会断崖式下降。我做项目时一直强调一个观念不要追求 OCR 的 100% 准确率你追求的是“关键字段不缺、核心内容可检索、错误率可控”。因为 OCR 错误直接污染 RAG 的知识质量你花大力气去修 2% 的识别错字往往不如在设计阶段就考虑如何规避低质量输入。从热词里能看到有人用 PaddleOCR 识别韩文失败其实这不是 PaddleOCR 的能力问题而是模型选择和使用姿势的问题。PaddleOCR 不只是中文简体它有超过 80 种语言的多语言模型。韩文需要用专门的韩文识别模型或者多语言模型而不是默认选中文模型硬扛。下面这张表是我在项目里反复对比不同 OCR 工具后整理出来的核心结论工具优势劣势推荐场景PaddleOCR中文效果好支持多语言表格识别强化版可用依赖 Paddle 框架部署稍重中文文档、发票、扫描书籍Tesseract开源老牌多语言支持广泛中文精度不如 PaddleOCR版面分析弱英文为主、多语种混合的轻量任务RapidOCR基于 PaddleOCR 模型转换出的 ONNX 版本无需 Paddle 环境功能基本跟随 PaddleOCR 版本需要轻量部署、CPU 推理为主的场景百度 OCR API精度高支持表格、印章识别商用收费有调用量限制对精度要求极致的在线场景腾讯、阿里云 OCR类似百度收费部分场景有专属优化特定行业字段合同、票据3.2 以 PaddleOCR 为例完整落地流程与常见坑PaddleOCR 是目前中文开源 OCR 里效果最稳的一个。它的基本用法很简单from paddleocr import PaddleOCR import json ocr PaddleOCR(use_angle_clsTrue, langch, ocr_versionPP-OCRv5) result ocr.ocr(invoice.jpg, clsTrue) lines [] for line in result: for word_info in line: text word_info[1][0] confidence word_info[1][1] lines.append({text: text, confidence: confidence})用这二十多行代码你就能把一张发票图片里的文字全部提出来并输出每个文本行的坐标和置信度。这里我特别强调几个在生产项目里一定会踩的坑第一use_angle_cls 一定要开。很多手机拍的文档、扫描件有 90 度或 180 度旋转不开方向分类器识别率惨不忍睹。第二识别结果里带坐标信息不要丢掉。坐标信息在后面对接 PDF 解析和版面恢复时非常有用——比如按 top 坐标排序就能还原阅读顺序按 x 坐标能判断属于哪个表格列。第三长图或大图尽量切片处理。PaddleOCR 对整张大图直接推理时内存消耗高质量略降切片后再识别速度反而更快。热词里那个人问“PHP OCR 识别验证码”和“C# OCR PDF”本质上也都是 OCR 流程的问题换成 PaddleOCR、RapidOCR 或百度 API 都可以做只是 PHP 和 C# 要调用 REST API 而已。3.3 轻量替代RapidOCR 的部署价值如果你的服务是 CPU 环境、不想装 PaddlePaddle 这个大依赖或者你用的是 FastAPI 这类轻量后端我建议你用 RapidOCR。它是把 PaddleOCR 的模型转成 ONNX 格式后的独立工程包接口相似度很高from rapidocr_onnxruntime import RapidOCR ocr RapidOCR() result, elapse ocr(scan.png) lines [] if result: for box, text, confidence in result: lines.append({text: text, confidence: confidence})RapidOCR 的体积比 PaddleOCR 小很多推理速度在 CPU 上也有不错的表现。我之前的印象是“精度会打折”但实测新版 RapidOCR 在中文通用场景上与 PaddleOCR 差距很小完全可以作为生产主力。4. 多模态大模型解析把图片和复杂版面交给视觉理解4.1 多模态大模型在 RAG 中的三副面孔OCR 解决的问题是怎么把“图像中的文字”变成“文本”。但 RAG 场景里图片要发挥价值的维度更多至少有三条路可以选第一原始图片直接进知识库查询时用多模态模型做问答。这要求你的 RAG 系统接入 GPT-4V、Qwen-VL、GLM-4V 这类模型要么在对话生成阶段直接传图片给大模型要么在检索阶段用 CLIP 类模型做图文匹配。这个方案非常适合企业画册、设计图、工程图纸这类“图本身才是知识”的内容。第二用多模态模型做“图片翻译成文本”的预处理。也就是先让 Qwen-VL 这类模型看图输出一段详细的结构化描述或文字转录再把这段文本入 RAG。这个方案的好处是数据链路简单后续处理完全走文本管道。第三多模态大模型做“版面结构解析”输出 HTML、Markdown 或 JSON 格式的结构化数据用于 PDF 的复杂版面拆分。这也是目前 RAG 工具链里最流行的方案。4.2 实测多模态大模型解析真实场景的最优解还是“降本组合”我做过一个企业知识库项目里面有几万份扫描版的技术手册和质检单。最开始直接上 PaddleOCR效果还可以但遇到带复杂页眉页脚、多级标题、嵌套表格的手册时OCR 输出的纯文本流直接把层级结构冲散了。后来我换了一个思路先用传统 OCR 廉价地把所有文字捞出来再让多模态大模型针对“OCR 文本流 原图版面”做一次结构化整理。具体做法是构建一个两阶段流水线第一阶段用 RapidOCR 或 PaddleOCR 抽取整页文字得到带坐标的文本块。第二阶段把页面的截图或 OCR 结果送到 Qwen-VL 或 InternVL让其输出 Markdown 格式的页面大纲、标题层级、表格结构。实测下来这种方案的稳定性和性价比远高于“直接让大模型识别整页所有文字”——因为大模型直接读图识别文字不仅慢而且小字密集时频繁漏字OCR 的先验抽取则保证了文字的完整性大模型只做“整理”压力小很多。如果你不想花太多时间调流程也可以用现成的框架比如 Marker 和 MinerU它们内置了这套思路。后面讲到 PDF 工具时会提。4.3 多模态选型参考从 Qwen-VL 到 InternVL 到商业模型多模态大模型这两年发展很快给大家一个选型倾向开源模型里首选 Qwen-VL或 Qwen2-VL中文理解能力强版面解析效果好社区资料多遇到问题容易排查。搭配 vLLM 部署延迟能压到可接受范围。InternVL 系列在图文交错内容上做过专项优化如果你处理的是一堆带截图的教程文档、公众号长文InternVL 的结构化输出能力不比商业模型差。商业模型GPT-4o、Claude适合业务要求极高、单次调用量不大的场景。比如合同关键字段抽取、票据核验这类场景偶尔调用一次准确性优先级最高。我在多模态大模型解析里的核心观点是能用 OCR 解决的就别上大模型能用小模型解决的就别上大模型但涉及语义理解和结构化任务时不要舍不得用多模态模型。OCR 负责“把字认出来”大模型负责“把内容看懂”它们不是竞争关系是接力关系。5. 九种 PDF 解析工具选型适合 RAG 管线的横向对比与终极建议5.1 工具全景表从 PyPDF2 到 MinerU接下来是这篇的重头戏。文档解析工具五花八门但适合 RAG 数据导入的并不多。我按“文本提取 → 规则布局分析 → 视觉模型解析 → 多模态结构抽取”四类能力整理出了一张对比表九种常用工具一目了然工具类型核心能力输出格式适合场景推荐指数PyPDF2 / pypdf纯文本提取简单文本提取合并拆分纯文本应急处理、快速预览★★pdfplumber规则版面分析提取文字与坐标、表格数据文本/表格带文字层的报表、表格 PDF★★★★PyMuPDFfitz高性能提取极快提取文本、图像支持坐标文本/图像大批量处理、文本层 PDF★★★★★pdf2image OCR扫描件转换把 PDF 转图片再走 OCR图片/文本扫描版 PDF 解析★★★★Camelot表格专用基于规则提取 PDF 表格表格/CSV财务、统计表格★★★★Tabula表格专用类似 CamelotUI 友好CSV/JSON简单表格提纯★★★LayoutParser版面分析框架检测版面区块、图表区域文本块/布局复杂版面的研究文档★★★Marker深度学习解析版面分析 OCR 结构重组Markdown/JSON高质量转换的通用 PDF★★★★★MinerU深度学习解析版面解析、公式识别、表格重建Markdown/JSON学术论文、技术手册★★★★★表格看起来信息量大但真正选型时不能只看功能还要看你的管线里“跑一次的成本”和“后续处理链路的复杂度”。下面逐个讲清楚每个工具在实际项目里的表现。5.2 文本提取派PyMuPDF 为什么是大批量文本层 PDF 的首选如果你已经把 PDF 判定为“带文字层”那文本提取派工具里最值得选的是 PyMuPDF。它的最大优点是快快得离谱。实测同样一份 300 页的 PDFPyPDF2 可能要跑十几秒PyMuPDF 往往 1 秒内出结果。这种性能差异在大批量知识导入时非常关键。另一个优点是它不仅能提取文本还能提取图片、批注、元数据而且能保留文字的坐标信息和块级结构。import fitz doc fitz.open(tip.pdf) for page in doc: text page.get_text(text, sortTrue) blocks page.get_text(blocks) for x0, y0, x1, y1, block_text, block_no, block_type in blocks: print(block_text)get_text(text, sortTrue) 里的 sort 参数值得说一下。默认按 PDF 内部对象顺序输出sortTrue 会按阅读顺序粗略排序对大多数单栏文档非常友好。虽然它比不上复杂的版面重建但已经足够应付 80% 的通用场景。PyPDF2 在生态中有点“老前辈”的味道很多老教程还在推荐它。实际用起来它的文本提取能力偏弱复杂排版下会丢字、错序而且已经停止大力维护新项目不建议再用它做主力解析只有快速预览、加密解密、合并拆分之类的小任务可以用。5.3 表格派Camelot 与 pdfplumber 的实战对比表格在 RAG 里是个特殊的存在。普通文本切块对表格来说基本失效——表格是二维关系切成文本块后列名和值会被拆散语义丢失严重。所以解析表格时最好的方法是用专门的表格工具把表格数据转成结构化格式再用“表格还原”或“摘要描述”的方式入库。Camelot 和 pdfplumber 都提供表格提取能力但思路不同。Camelot 基于视觉检测线条来定位表格边框对有线框的表格识别极准输出 DataFrame可以直接转 CSV 或 JSON。pdfplumber 则靠字符坐标和线条判断对无边框表格更友好但速度比 Camelot 慢。import camelot tables camelot.read_pdf(table.pdf, pages1, flavorlattice) for table in tables: df table.df print(df.to_json(orientrecords))我一般这样用如果表格线条明显用 Camelot 的 lattice如果是无边框表格用 pdfplumber 的矩离阈值来定位行列。但要注意这两种工具在扫描版 PDF 上都无能为力必须先把页面 OCR 成带位置信息的文本再分析。5.4 深度学习派Marker 和 MinerU 的体验与差异最后说两个目前在 RAG 圈子里热度上升很快的解析工具Marker 和 MinerU。它们代表了 PDF 解析的新方向——不像老工具那样依赖规则和坐标去猜版面而是用视觉模型直接“看”页面输出 Markdown 或 JSON 结构。Marker 的定位是准确转换各种 PDF 为 Markdown。它对复杂双栏、多级标题、图片说明、代码块的识别非常稳定而且在表格抽取上比 Camelot 更智能——即便表格没有明确的线框它也能根据深度学习模型恢复出单元格结构。MinerU 则更偏学术文档解析对公式识别、参考文献、段落层级做了专项优化。我用它处理过很多论文 PDF输出质量非常高能直接把数学公式转成 Latex这在普通工具里简直是不可想象的。在 RAG 场景里MinerU 的输出结果可以直接以 Markdown 切块嵌入质量远高于纯文本流。用的方式也很简单pip install marker-pdf marker_single input.pdf --output_format markdown或者直接拉 MinerU 的镜像跑批处理。这类工具唯一的缺点是速度慢因为要跑视觉模型对 GPU 有要求。所以实际生产线上我还是坚持“分级处理”——简单 PDF 走 PyMuPDF复杂排版上 Marker扫描件先 OCR 再重组。没有一份统一配置能处理所有情况。5.5 三级管道一个兼顾成本与效果的实战方案讲了这么多工具大家最关心的可能是一个可以把它们串起来的最小可行方案。实际做 RAG 导入时直接无脑用最高级工具是浪费无脑用免费工具是埋坑。我个人推荐的三级管道是这样的第一级先跑一遍 PyMuPDF判断是否有文字层提取粗文本。如果提取到了完整流畅的文本就直接走切块入库。第二级如果 PyMuPDF 提取的文本出现大量错位或空页跳到 pdfplumber 做分栏与顺序重建按需配合 Camelot 抽取表格。第三级如果到了这一步发现 PDF 是扫描版或者版面复杂到离谱比如几十层嵌套的杂志页面再启动 Marker 或 MinerU 做视觉解析或者干脆走“PDF 转图片 OCR 大模型结构化”的组合。这套“多级回退”的方案不仅能把解析成本压到最低也能让不同来源的文档各归其位。RAG 项目的数据源永远是脏、乱、杂的一个解析工具打天下的思路是不现实的。这一点做多了数据工程的人一定深有体会。6. 回扣主题RAG 瓶颈不在模型在“喂进去的东西”如果要说我做这么多解析工作后最大的体会那就是大部分 RAG 项目效果不理想病根根本不是模型选得不好也不是向量库不够快而是知识库里的内容在“进入向量化之前”就已经坏了。错序的文本、残缺的 OCR 结果、被拆得四分五裂的表格这些问题会在后面检索、排序、生成的全链路里被持续放大。所以项目启动时真的值得多花一点时间在解析选型这件事上把它当成一个正式的工程问题来看而不是“先随便抽抽文本跑通流程再说”。我甚至建议团队里专门有一个人对“文档解析工具链”负责他不需要每天都优化模型但要清楚地知道每份新进来的文档应该走哪条解析管道。这项工作听起来琐碎却直接决定了你知识库的上限。针对图片能不能放进 RAG 知识库的问题我的结论再强调一次绝对能但建议优先把图片“翻译”成文本或结构化描述再入库除非你的业务本质上需要看图工程设计、品牌素材、医疗影像。前者的链路简单、可控、检索效果好后者对技术栈和成本的要求高很多。这一篇到这里基本把图文和 PDF 解析的全路径讲完了。下一篇我会继续聊文档解析完成后的“清洗与切块策略”包括怎么处理标题层级、表格怎么切块不散架、长文档的重叠窗口优化这些如果处理不好前面所有解析的心血照样白费。先把上面这套解析流程在自己项目里跑一遍有具体问题可以再来交流。