摘要:多模态 RAG 的常见痛点是 PDF 里的图片、表格、扫描件检索不到,关键词命中率低,信息不全时 LLM 容易瞎编。JoyAgent 的 mrag 用 MinerU 把 PDF 拆成文本、图片、页面截图分别入库,检索时稠密向量与 BM25 稀疏向量并行召回再 cross-encoder 重排,信息不够就自动改写查询多轮查,直到够用。
一、多模态 RAG 要解决什么
企业里常见的资料是产品手册 PDF、销售报告 Word、架构图图片、各种表格。想问「产品 X 的性能指标是多少」「这张架构图说明了什么」,直接问通用大模型行不通——它没见过内部资料。把资料全塞进 prompt 也不现实,量太大、成本高,而且上下文窗口装不下。
RAG(Retrieval-Augmented Generation,检索增强生成)的做法是:先把资料处理成可检索的形式存起来,提问时先检索相关片段,再把片段连同问题一起交给大模型回答。相当于给大模型外挂了一个「专属资料库」。
为什么要「多模态」
普通 RAG 只能处理文字。但真实资料里有图、有表、有图表。问「分析这张走势图」,纯文字 RAG 抓瞎。多模态 RAG 能理解图片内容,把图也纳入检索和回答。这就是 mrag 名字里「m」(multimodal)的含义——同时处理文本和图像两种模态。
二、整体架构与两条链路
mrag 有两条主要链路:写入(建知识库)和查询(问答)。理解这两条链路就理解了整个模块。
写入流:文档上传 → 异步下载 → 解析(MinerU 输出 markdown + 图片 + 页面预览)→ 图片和页面上传 OSS 替换链接 → 切分 → 三种嵌入(文本/图像/BM25)→ 存 Qdrant + SQLite 元数据。
查询流:提问 → Agentic 多轮循环(生成子查询 → 4 路并发检索 → 总结 → 判断信息够不够)→ 重排过滤 → LLM/VLM 生成 → SSE 流式返回。
下面逐层拆。
三、写入链路第一步:文档解析
3.1 为什么解析这么麻烦
上传 PDF 不能直接用。PDF 里的文字、图片、表格混在一起,大模型没法直接读,得先拆开:文字提取成 markdown(对 LLM 友好),图片单独抽出来(要向量化),每页渲染成预览图(页面级检索用)。document/parser.py干的就是这件事。
3.2 MinerU:PDF 解析的主力
MinerU 是什么
上海 AI Lab 开源的文档解析工具,能把 PDF(尤其是带图表、公式的复杂 PDF)解析成 markdown + 图片。mrag 不在本地跑 MinerU,而是调它的 HTTP API——需要单独部署一个 MinerU 服务,配MINERU_BASE_URL。代码里PdfParser在document/parser.py:948起,_call_mineru_api在 990 行提交任务拿task_id,_wait_for_mineru_result在 1004 行轮询结果。
智能分页调度(大 PDF 优化)
大 PDF 一次扔给 MinerU 容易超时。mrag 的办法:10 页以下直接整文件处理;超过就每 4 页拆一块,逐块调 MinerU,结果带<!-- Chunk N: Pages x-y -->标记拼接,图片存images/chunk_{N}/子目录防冲突。分块处理在document/parser.py:1054的_process_single_pdf_chunk。
配置:SMALL_PDF_PAGE_THRESHOLD=10、PDF_CHUNK_SIZE=4。
3.3 四种格式四种解析器
get_document_parser工厂按扩展名分发:
docx 的标题识别有多细
Word 文档的标题样式(Heading 1-6)会被识别成 markdown 的 H1-H6。中文文档常用的「一、」「(一)」「1.」「(1)」这种手动编号也会被映射成对应层级标题。这样切分时能按标题结构切,上下文保留得好。
统一产物结构(所有解析器输出都长这样):
work_dir/├── {filename}.md # 纯文本 markdown(LLM 能读)├── images/ # 文档内提取的图表(要向量化)└── pages/ # 每页预览图 page_{i}.png(页面检索用)四、写入链路第二步:文本切分
4.1 为什么要切分
一本书 10 万字,不能整本塞给 LLM(超 token 上限),也不能整本变一个向量(太粗,检索不准)。得切成小块(chunk),每块几百字,独立向量化、独立检索。
chunk 是什么
chunk = 文本块。把长文档切成一个个小段落,每段是一个独立检索单元。比如一段 500 字的产品说明就是一个 chunk,有自己的向量和元数据。检索时按 chunk 粒度返回。
切分逻辑在document/splitter.py,入口是get_text_splitter(chunk_type, chunk_size, chunk_overlap)工厂(120 行起),默认从环境变量读:CHUNK_TYPE=markdown/CHUNK_SIZE=500/CHUNK_OVERLAP=100。
4.2 两种切分器
自研切分器的核心是SplitSentence(splitter.py:21)做句子切分,再用双指针贪心(splitter.py:153-207)按chunk_size组句成块。
为什么要有 overlap(重叠)
假设一句话正好在切块边界被切成两半,前半句在前一个 chunk,后半句在后一个 chunk。检索时可能只命中一个,语义不全。
overlap 让相邻块重叠一部分(比如 100 字)。前一个 chunk 的末尾 100 字,也是后一个 chunk 的开头 100 字。即使边界切断语义,重叠部分能兜住。代价是存储冗余,但检索质量好。
markdown 切分为什么要保留标题层级
一个 chunk 检索出来时,光看 chunk 内容不知道它属于哪一节。切分时把「这个 chunk 在 ## 安装 > ### Windows 安装 下」这种层级信息存进元数据,检索时就能告诉 LLM 出处,答案更靠谱。build_context(query_processor.py:83)干的就是这件事。
五、写入链路第三步:多模态嵌入(核心创新)
这一步把文字、图片都变成向量存起来,而且要让「文字 query 能搜到图片」。
5.1 三种嵌入模型
三种嵌入各干什么
文本嵌入(TextEmbedding,
embedding/embedding.py:28):把文字变稠密向量(dense vector,1024 个连续浮点数)。稠密向量的特点是每个维度都有值,能编码语义——搜「手机」能找到「智能手机」,因为两者向量距离近。
图像嵌入(ImageEmbedding,
embedding/embedding.py:59;QwenVL 实现embedding/image_embedding.py:13):把图片变向量,让图片可被语义检索。
BM25 嵌入(
embedding/bm25_embedding.py:4):把文字变稀疏向量(sparse vector,大部分维度是 0,只在命中的关键词维度上有值)。BM25 是经典的关键词检索算法,擅长精确匹配专有名词。它和稠密向量互补:稠密向量懂语义但可能漏关键词,BM25 懂关键词但不懂同义词,一起用召回全。
不是 ColQwen
代码里image_embedding.py:18用的是 dashscope 的qwen2.5-vl-embedding(一图一向量),不是 ColQwen(晚交互模型)。
区别:ColQwen 给一张图生成多个向量(patch 级,把图切成小区域各算一个向量),检索时做「晚交互」逐 patch 打分,更准但更慢。qwen2.5-vl-embedding 一图一向量,简单快。mrag 选了简单方案。
5.2 图文跨模态对齐:最巧妙的设计
核心难题
文字 query 怎么搜到图片?文字向量和图像向量在不同的向量空间里,直接比距离没意义——就像用米和千克比大小。
mrag 的解法不是训练一个图文共享嵌入空间,而是把图像转成文字描述,再走文本嵌入:
OCR 和 Caption 是什么
OCR
(Optical Character Recognition,光学字符识别):识别图里有什么字,比如柱状图上的标签、表格里的数字。机械提取,
utils/ocr_utils.py提供 DeepSeekOCR / VLMOCR 两种实现。Caption
(图像字幕):用 VLM(视觉语言模型)描述图讲什么,比如「这是展示季度销量趋势的柱状图,Q3 最高」。语义理解,
utils/caption_utils.py调 VLM 生成不超过 100 字。
两个都做,OCR 给精确文字,caption 给语义概括,检索时都能命中。冗余但召回全。
为什么这个设计聪明
不依赖共享嵌入空间(那个很难训练)。靠 OCR + Caption 把图像「翻译」成文字,文字再走标准文本嵌入。这样:
- 文字检索能命中「图片内容」(通过 ocr_text/caption 文本)
- 命中后通过 payload 里的
image_id反查到原图 - 降级友好——就算图像嵌入模型很差,靠文字描述也能兜底
代价是依赖 OCR 和 Caption 的质量,且存了多份向量(图像向 + ocr 文本向 + caption 文本向)。
5.3 三种 chunk 处理
DocumentProcessor编排三种处理,对应三种内容(document/processor.py):
文本处理批量 10 个(processor.py:123),图像处理批量 5 个(199 行),都先 resize 再嵌入。
子块增强(可选)
配ENABLE_SUB_CHUNK_ENHANCE后(processor.py:155),文本块再用 100 字小切器二次切,生成更细粒度的 chunk。提升小粒度检索召回,代价是存储翻倍。
LightRAG 图谱补充(可选)
配LIGHTRAG_SERVER_BASE_URL后,全文 POST 到 LightRAG 做 graph RAG 索引。Graph RAG 用知识图谱做关联检索,是向量检索之外的另一种 RAG 范式,这里作为补充。
六、查询链路第一步:Agentic 多轮检索(核心)
这是查询链路的精髓。不是「检索一次就答」,而是像人查资料一样多轮检索、反思、补充,直到信息够用。
6.1 为什么需要「Agentic」
普通 RAG:query → 检索一次 → 拼进 prompt → 回答。简单,但有几个问题:复杂问题一次检索不够(「对比 A 和 B 的优劣」要分别检索 A 和 B);检索结果可能不相关,但没有机制判断;信息缺口没法补。
Agentic RAG 让 LLM 当「检索指挥官」,自主决定检索几次、每次查什么、什么时候信息够了。
6.2 AgenticRAG 核心循环详解
入口是AgenticRAG.run()(query/aigent.py:154),主循环在 182 行while True,硬上限loop > 3(205 行)。
四大 Agentic 特征都齐了
多轮检索循环
:最多 3 轮,信息不够再来一轮
query 改写
:每轮根据上轮结果改写查询
子查询扩展
:把一个问题拆成多个同义/多视角子查询
LLM 自我反思
:POST_CHECK 判断信息缺口并给出改写方向
第 0 步——快速通道(避免无谓检索,aigent.py:157-170):
有图片输入 →
extract_image_content(query_processor.py:62)生成图片 captionsimple_query_check(
query_processor.py:150):问候/常识题(如「你好」「1+1」)直接llm_answer,不检索simple_image_query_check(
query_processor.py:161):图片问答类直接vlm_answer
主循环(while True,硬上限 loop>3):
POST_CHECK 充分性判断(query_processor.py:104的generate_next_instruction):
POST_CHECK 的精髓
这是「反思」机制。LLM 检索完不急着答,先自问「这些信息够回答原问题吗」。够就答,不够就指出还缺什么(rewrite_query 给出下一步检索方向)。这模拟了人查资料的过程——查一次不够,根据已有信息调整搜索词再查。
第 3 步——重排生成(aigent.py:239起):
循环退出后,合并所有检索结果,重排,生成答案:
为什么 page 只取 top1
page 是整页预览图。多页塞给 VLM 会超 token 且互相干扰。只取最相关的 1 页作为附图,让 VLM 结合文本和这页图回答。这是 token 消耗和效果之间的权衡。
七、查询链路第二步:4 路并发检索
检索是 RAG 的心脏。mrag 不只一路检索,而是 4 路并发,覆盖不同召回角度。入口在retrieval/retriever.py:38,用ThreadPoolExecutor(max_workers=4)并发提交。
7.1 四路是什么
| 路 | 检索什么 | 怎么检索 | 阈值 |
|---|---|---|---|
| ① 文本向量 | text 集合 | query 文本向量化 → cosine 搜 | 0.7 |
| ② BM25 | text 集合 | query BM25 稀疏向量化 → 关键词搜 | 无 |
| ③ 文本查图 | image 集合 | query 文本 → 图像向量空间搜 | 0.6 |
| ④ 文本查页面 | page 集合 | query 文本 → 页面向量空间搜 | 0.35 |
学AI大模型的正确顺序,千万不要搞错了
🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!
有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!
就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋
📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇
学习路线:
✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经
以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!
我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~