1. 多模态 RAG 到底在解决什么问题1.1 从纯文本 RAG 的天花板说起做过 RAG 项目的人大概都有这种体会纯文本检索这条路在遇到真实业务文档时经常撞墙。合同、招标文件、产品手册、学术论文、财务报表这些文档里真正有价值的信息往往不是一段干净的纯文本而是藏在表格、流程图、印章、手写批注、复杂排版里的。你拿一个 PDF 直接抽文本抽出来的东西可能顺序全乱表格变成一堆散落的数字图片里的关键信息直接丢失。我早期做知识库的时候就踩过这个坑。客户给了一批产品规格书PDF 里有一半是参数表格我用常规的文本抽取方案跑完检索出来的答案驴唇不对马嘴因为表格的行列关系在纯文本里完全塌掉了。后来才意识到这不是检索算法的问题是文档解析和表征方式从根上就不对。多模态 RAG 要解决的核心问题就是这个让检索系统不仅能读字还能看图、懂版式、理解结构。它把文档里的文本、图像、表格、版面布局统一纳入检索和生成流程而不是粗暴地把一切压平成字符串。1.2 多模态 RAG 的能力边界具体来说多模态 RAG 相比传统方案多出来这么几块能力视觉检索用户可以用一张图去检索相关文档或者系统直接对文档里的图表建立向量索引查询时命中图片内容。结构化解析把 PDF、扫描件解析成带页码、章节、段落层级的结构化文本保留阅读顺序和层级关系。跨模态对齐用 CLIP 这类多模态模型把图像和文本映射到同一语义空间实现以文搜图和以图搜文。版面理解识别标题、正文、页眉页脚、表格区域、图片区域避免把页眉当成正文检索出来。适合谁来参考如果你正在做企业知识库、合同审查、招投标文件分析、学术文献管理、票据识别这类场景并且发现纯文本方案效果上不去那多模态 RAG 就是你要走的路。零基础也能看懂但落地时需要一定的工程能力。1.3 一个典型的失败案例我拿一个真实场景说明为什么必须上多模态。某次处理一批招标文件纯文本 RAG 检索投标保证金金额结果返回的是另一份文件里的数字因为所有文件的页眉都写着项目名称抽取时页眉和正文混在一起向量空间里这些文档高度相似检索直接串了。后来改成结构化解析把页眉页脚剥离按章节切块再对关键表格单独建索引命中率从不到 40% 提到了 85% 以上。这个提升不是靠换更大的模型而是靠解析质量。这也是我写这一系列解读时反复强调的一点RAG 的瓶颈八成在检索前的数据处理不在生成模型本身。2. 文档解析多模态 RAG 的地基2.1 为什么解析质量决定 RAG 上限很多人做 RAG 的路径是拿个框架把 PDF 丢进去切块embedding存向量库完事。跑 demo 效果还行一上真实数据就崩。问题几乎都出在解析环节。文档解析要输出的不是一堆文字而是带结构的信息。理想情况下一份合同解析完应该长这样有页码标记有章节层级第一章、1.1、1.1.1有段落边界有表格结构行列对应关系有图片位置和图片内容描述。只有这样后续切块才能按语义边界切而不是按固定字数硬切。我见过太多项目用固定 500 字切块结果一个条款被切成两半检索时两半都命中但都不完整生成出来的答案缺胳膊少腿。这不是模型的问题是切块策略的问题而切块策略又依赖解析质量。2.2 主流文档解析方案对比市面上文档解析工具不少我按实际用下来的感受做个对比方案类型优势局限适用场景PyMuPDF本地库快、轻量、纯文本抽取稳表格和版面理解弱文字型 PDF 快速抽取pdfplumber本地库表格抽取能力强速度慢、复杂版面吃力表格为主的文档Marker本地模型版面理解好、支持公式表格依赖模型、资源占用高学术论文、技术文档Tesseract OCR本地 OCR免费、离线、多语言复杂版面差、需预处理扫描件、简单票据Umi-OCR本地工具开箱即用、支持竖排批量集成需二次开发本地快速识别云端 OCR API云服务精度高、字段抽取强有成本、数据出域票据、合同字段提取选型逻辑很简单文字型 PDF 优先用解析库扫描件必须上 OCR复杂版面优先用带版面理解的模型。Marker 这类工具之所以在 RAG 圈子里火就是因为它能输出 Markdown 格式的结构化文本表格转成 Markdown 表格公式转成 LaTeX直接就能喂给后续流程。2.3 结构化解析要保留哪些信息我总结了一份文档解析的最小信息集缺了任何一项后续检索都会受影响页码用于溯源用户问这个条款在哪一页你得答得出来。章节层级标题级别决定切块边界一级标题下的内容不该和二级标题混切。段落边界段落是最小语义单元跨段落切块会破坏语义。表格结构行列关系必须保留否则数字全乱。图片位置与描述图片要么 OCR 出文字要么用多模态模型生成描述。阅读顺序多栏排版、竖排文本的顺序必须正确否则语义颠倒。提示解析阶段多花的时间会在检索阶段成倍省回来。别为了快牺牲解析质量。2.4 竖排与复杂阅读顺序的处理中文文档里有个容易被忽略的坑竖排文本。古籍、部分港台文档、某些设计稿是竖排的常规 OCR 按横排顺序识别出来的字序完全是乱的。Umi-OCR 这类工具提供了竖排/纵向阅读顺序开关处理这类文档时一定要打开。多栏排版的学术论文也是重灾区。两栏排版如果按从左到右、从上到下的顺序抽会把左栏第一行和右栏第一行拼在一起语义直接错乱。Marker 这类带版面分析的模型能识别栏边界按栏内顺序输出这就是它比纯 OCR 强的地方。3. 视觉检索让图片也能被搜到3.1 CLIP 与跨模态对齐原理视觉检索的核心是跨模态对齐。CLIP 这类模型的做法是用两个编码器一个编码图像一个编码文本通过对比学习让匹配的图文对在向量空间里靠近不匹配的远离。训练完之后一张图和一段描述它的文字向量距离会很近。这意味着你可以用文字去搜图片也可以用图片去搜文字。在 RAG 场景里这个能力非常关键用户问那个流程图里第三步是什么系统得能定位到流程图这张图而不是只搜文本。我实测下来CLIP 类模型对整体语义的匹配不错但对细节比如图里某个小字就力不从心了。所以实践中通常是双路并行一路用 CLIP 做粗粒度图文匹配一路用 OCR 把图里的文字抽出来做细粒度文本检索两路结果融合。3.2 图像向量化的实操要点把文档里的图片纳入检索流程大致是这样图片抽取从 PDF 里把图片对象抽出来同时记录它在文档中的位置页码、上下文。图片预处理统一尺寸、去噪、必要时增强对比度。图像编码用 CLIP 或类似模型编码成向量。文本补充对图片做 OCR把文字也编码成文本向量和图像向量一起存。元数据绑定把图片向量和它的来源文档、页码、上下文文本绑定。这里有个细节图片不要单独存要和上下文绑定。一张孤立的图表检索出来用户也不知道它在说什么。把图表前后的说明文字一起存进去检索命中时能给出完整语境。3.3 视觉检索的召回策略视觉检索的召回我一般用三路融合文本路查询文本直接和文档文本块向量匹配。图像路查询文本和图像向量匹配CLIP 跨模态。OCR 路查询文本和图片内 OCR 文字匹配。三路各自召回 Top-K然后用 RRF倒数排名融合或加权融合排序。实测下来三路融合比单路召回的 hit rate 能高出 20 到 30 个百分点。这个提升在图表密集的文档里尤其明显。注意融合权重需要按业务调。图表多的文档图像路权重要高纯文字文档文本路为主。3.4 多模态特征文件的组织方式多模态 RAG 的存储层我建议按文档-块-模态三层组织文档层文档 ID、标题、来源、解析时间、版本。块层块 ID、所属文档、页码、章节路径、块类型文本/表格/图片。模态层每个块的向量文本向量、图像向量、OCR 向量分开存。这样组织的好处是检索时可以按块类型过滤比如只在表格里搜或者只在图片里搜灵活度很高。用支持多向量字段的向量库比如 Milvus、Qdrant能直接实现用单向量库就得自己维护映射关系。4. 多模态 RAG 的完整落地流程4.1 环境准备与工具链搭建先说环境。本地跑多模态 RAG硬件上建议至少 16GB 显存跑 CLIP 和 OCR 模型才不憋屈。纯 CPU 也能跑但速度会让你怀疑人生。工具链我一般这么配# 文档解析 pip install pymupdf pdfplumber marker-pdf # OCR # Tesseract 需系统安装再装 Python 封装 pip install pytesseract # 或直接用 Umi-OCR 的 HTTP 接口 # 多模态模型 pip install transformers torch pillow # CLIP 类模型 pip install open_clip_torch # 向量库 pip install qdrant-client # 或 milvus、chromadb # 编排 pip install langchain langchain-communityTesseract 安装包在 Windows 上要单独下装完记得把安装路径加进环境变量否则 pytesseract 找不到。这个坑我踩过报错信息还不明显折腾半天。4.2 文档解析与结构化输出解析这一步我写个简化版的流程说明。假设输入是一份 PDFimport fitz # PyMuPDF def parse_pdf(path): doc fitz.open(path) blocks [] for page_num, page in enumerate(doc): # 抽取文本块带位置信息 for block in page.get_text(dict)[blocks]: if block[type] 0: # 文本块 text .join( span[text] for line in block[lines] for span in line[spans] ) blocks.append({ page: page_num 1, type: text, text: text, bbox: block[bbox], }) elif block[type] 1: # 图片块 blocks.append({ page: page_num 1, type: image, bbox: block[bbox], }) return blocks这只是最基础的抽取。真实场景里你还需要用字体大小和加粗判断标题层级用位置信息判断页眉页脚并剔除用表格检测模型识别表格区域并结构化对图片块做 OCR 和 CLIP 编码Marker 这类工具把这些都封装好了直接输出 Markdown省事很多。但如果你的文档格式特殊还是得自己写解析逻辑。4.3 切块策略与语义边界切块是多模态 RAG 里最容易被低估的环节。我的经验是按结构切不按字数切优先在章节边界、段落边界切实在没有结构信息才按字数。块大小动态调整表格整块保留不要切长段落可以按句子边界切。重叠窗口相邻块之间留 10% 到 20% 重叠避免边界信息丢失。元数据随块走页码、章节路径、块类型每个块都要带上。一个实用的切块参数目标块大小 300 到 500 token重叠 50 到 100 token。这个范围在大多数场景下表现稳定。表格和图片块单独处理不参与字数切分。4.4 向量化与索引构建向量化阶段文本块用文本 embedding 模型比如 BGE、M3E 这类中文友好的图片块用 CLIPOCR 文字用文本模型。三路向量分别存。from qdrant_client import QdrantClient from qdrant_client.models import PointStruct, VectorParams, Distance client QdrantClient(:memory:) client.create_collection( collection_namemultimodal_rag, vectors_config{ text: VectorParams(size768, distanceDistance.COSINE), image: VectorParams(size512, distanceDistance.COSINE), ocr: VectorParams(size768, distanceDistance.COSINE), }, )命名向量named vectors是多模态存储的关键Qdrant 和 Milvus 都支持。这样一次查询可以指定搜哪个模态也可以多模态并行搜再融合。4.5 检索与生成链路串联检索阶段查询进来先做意图判断是文本查询还是图像查询。文本查询走文本路 OCR 路图像查询走图像路 文本路用图像描述做文本检索。三路召回后用 RRF 融合取 Top-N 送给生成模型。生成阶段把命中的块按原始文档顺序重排拼成上下文连同用户问题一起送给 LLM。这里有个技巧上下文里标注来源比如[来源合同A 第3页 第2章]生成时模型能引用用户也能溯源。5. 常见问题与排查技巧实录5.1 检索命中率低的排查思路命中率低是最常见的问题。我的排查顺序是先看解析质量抽出来的文本是不是乱的表格是不是塌了页眉页脚混进去了没再看切块块边界是不是切断了语义块大小是不是太极端再看 embedding模型是不是不适合中文维度是不是太低最后看检索策略单路还是多路融合权重合理吗大多数情况下问题在前两步。我遇到过最离谱的一次是 PDF 解析出来全是乱码因为文档用了特殊字体编码PyMuPDF 抽出来是乱码换 OCR 才解决。5.2 OCR 识别的典型坑OCR 的坑我列几个高频的问题原因解决识别率低图像分辨率不够先放大到 300 DPI 再识别竖排乱序未开启竖排模式用 Umi-OCR 的竖排开关表格错乱OCR 不理解表格结构先用表格检测再分格识别中英混排错语言模型未切换指定多语言或自动检测印章干扰红色印章被当文字预处理时按颜色过滤票据识别还有个特殊问题固定模板票据字段位置固定用通用 OCR 反而慢且不准。这种情况直接按坐标裁切字段区域单独识别精度和速度都更好。5.3 多模态融合的权重调优三路融合的权重不是拍脑袋定的。我的做法是准备一批标注好的查询-答案对网格搜索权重组合看哪个组合的 hit rate 最高。通常文本路权重 0.5图像路 0.3OCR 路 0.2 是个不错的起点但具体要看文档类型。图表密集的文档图像路可以提到 0.4纯文字文档文本路可以到 0.7。这个调优过程不复杂但很值往往能带来 10 个点以上的提升。5.4 性能与成本的平衡多模态 RAG 比纯文本 RAG 重得多。CLIP 编码、OCR、多路检索每一步都吃资源。我的优化经验离线预处理解析、编码、索引构建全部离线做线上只做查询编码和检索。缓存高频查询的 embedding 缓存起来避免重复编码。分级检索先用轻量模型粗筛再用重模型精排。按需 OCR不是所有图片都要 OCR先判断图片里有没有文字。提示线上服务的延迟八成花在查询编码和检索上生成反而快。优化要抓重点。6. 我在多模态 RAG 实践中的几点体会做这一系列解读和实操下来最大的感受是多模态 RAG 的难点不在模型在数据管道。模型都是现成的CLIP、OCR、embedding 模型拿来就能用。真正花时间的是把一份乱七八糟的 PDF变成干净、结构化、可检索的数据。这个环节没有捷径只能一个场景一个场景地磨。另一个体会是别追求一步到位。我见过有人一上来就想做全模态统一检索结果每个环节都半吊子。更务实的做法是先把文本解析和检索做扎实再逐步加入表格、图片、OCR。每加一个模态单独评估它的增益有增益就留没增益就砍。最后分享一个小技巧建一个坏案例库。每次检索失败把查询和文档存下来定期分析。你会发现失败案例高度集中在某几类文档或某几种查询上针对性优化这几类比盲目调参有效得多。我靠这个方法把一个项目的 hit rate 从 60% 磨到了 90% 以上靠的不是换模型是持续地看坏案例、改解析、调切块。多模态 RAG 这条路还很长文档解析、视觉检索、跨模态对齐每个方向都有大量细节可以挖。这一篇先到这里后续我会继续拆解具体的论文和工程实现把踩过的坑一个个填上。