【Task2】【Datawhale AI夏令营】多模态RAG

发布于:2025-08-10 ⋅ 阅读:(17) ⋅ 点赞:(0)

科大讯飞AI大赛(多模态RAG方向)

夏令营:让AI读懂财报PDF(多模态RAG)

第一次提交截图,顺利运行:
第一次尝试

下面是教程:

copy from

💡
欢迎回到Datawhale AI夏令营第三期,多模态RAG 方向的学习~

我们将聚焦在「多模态RAG图文问答挑战赛」的赛事项目实践。

作为此次项目实践的第二个Task,我们将—— 理解项目目标、从业务理解到技术实现!!

我们只有 理解业务逻辑,才能做出 真正有价值、解决问题的方案!

本次赛题的核心目标是打造一个能看懂图片、读懂文字、并将两者关联起来思考的AI助手,构建一个先进的智能问答系统,以应对真实世界中复杂的、图文混排的信息环境。

让 AI模型能够阅读并理解包含大量图标、图像和文字的pdf文档 ,基于信息回答用户问题。

能找到答案的同时还需要标注出答案的出处,比如源自于哪一个文件的哪一页。

参加本次比赛,你将接触并实践AI领域前沿热门的技术之一: 多模态检索增强生成 (Multimodal RAG)!其中需要涉及到——

多模态信息处理 (Multimodal Information Processing)、向量化与检索技术 (Embeddings & Retrieval)

跨模态检索与关联 (Cross-Modal Retrieval)、大语言模型(LLM)的应用与推理 (LLM Application & Reasoning)

💡
相关知识点及参考资料(点击右侧◀展开查看)

一、此次项目是一个复杂的生成类任务
在开始 设计方案 之前,我们需要 全面理解赛题的背景和要求,

对问题进行清晰的定义,并分析数据的特征,理解解题的要点和难点。

这将有助于我们 选择合适的模型和方法 来解决问题。

任务背景:目前多模态信息(财报PDF)的AI利用率较低

我们正处在一个信息爆炸的时代,但这些信息并非以整洁的纯文本形式存在。它们被封装在各种各样的载体中:公司的年度财报、市场研究报告、产品手册、学术论文以及无数的网页。这些载体的共同特点是 图文混排 ——文字、图表、照片、流程图等元素交织在一起,共同承载着完整的信息。

传统的AI技术,如搜索引擎或基于文本的问答系统,在处理这类复杂文档时显得力不从心。它们能很好地理解文字,但对于图表中蕴含的趋势、数据和关系却是“视而不见”的。这就造成了一个巨大的信息鸿沟:AI无法回答那些需要结合视觉内容才能解决的问题,例如“根据这张条形图,哪个产品的市场份额最高?”或“请解释一下这张流程图的工作原理”。

近年来,大语言模型(LLM)的崛起为自然语言理解带来了革命。然而,它们也面临两大挑战:

知识局限性 :LLM的知识是预训练好的,对于私有的、最新的或特定领域的文档(比如本次比赛的财报)一无所知,并且可能产生幻觉。

模态单一性 :大多数LLM本身只能处理文本,无法直接“看到”和理解图像。

检索增强生成(RAG) 技术的出现,通过从外部知识库中检索信息来喂给LLM,有效地解决了第一个挑战。而本次比赛的核心—— 多模态检索增强生成(Multimodal RAG) ,则是应对这两大挑战的前沿方案。它赋予了AI系统一双“眼睛”,让他不仅能阅读文字,还能看懂图片,并将两者结合起来进行思考和回答。

此次 多模态RAG任务 有四大核心要素
开始之前,我们先理解一下核心任务是什么。

💡
此次赛题的核心不仅仅是简单的问答,而是基于给定的pdf知识库的、可溯源的多模态 问答。

它定义了我们系统的四个基本支柱,也是我们构建解决方案时必须时刻牢记的四个约束:

💡
数据源:一堆图文混排的PDF,这是我们唯一的数据。

💡
可溯源:必须明确指出答案的出处。

💡
多模态:问题可能需要理解文本,也可能需要理解图表(图像)。

💡
问答:根据检索的信息生成一个回答。

二、那么任务要求究竟是怎么样的、以及有哪些重难点呢?

2.1 我们需要通过财报PDF,输出对应的多模态答案
此次的任务 输入-输出 究竟是什么?最后需要提交什么样格式的结果?

输入 (Input):我们需要处理什么?
比赛官方为我们提供了三样核心材料,它们是我们构建系统所需用到的全部信息:

财报数据库.zip

一个包含了多个PDF文件的压缩包。这些PDF是真实世界的公司财报,内容上是典型的 图文混排 格式,包含了大量段落、数据表格以及各种图表(如条形图、饼图、折线图等)。这是我们系统的 唯一信息来源 。所有问题的答案都必须从这些PDF文档中寻找,并且不能依赖任何外部知识。

train.json

一个JSON格式的文件,为我们提供了一系列“问题-答案”的范例。这是我们用来开发、训练和验证我们系统模型的主要依据。我们可以通过它来调试我们的算法,看看对于给定的问题,我们的系统能否找到正确的答案和出处。

数据格式示例

:文件内容是一个JSON列表,其中每个元素代表一个问答对,结构如下:

[
{
“question”: “根据图表显示,产品A的销售额在哪个季度开始下降?”,
“answer”: “产品A的销售额在第三季度开始出现下降。”,
“filename”: “2023年度第三季度财报.pdf”,
“page”: 5
},
{
“question”: “…”,
“answer”: “…”,
“filename”: “…”,
“page”: “…”
}
]

test.json

另一个JSON格式的文件,包含了比赛最终用来评测我们系统性能的所有问题。

这是我们需要完成的任务。文件里 只包含 question 字段 ,而我们需要预测的 answer , filename , 和 page 都是缺失的。

[
{
“filename”: “xx.pdf”,
“page”: 1,
“question”: “广联达在苏中建设集团南宁龙湖春江天越项目中,具体运用了哪些BIM技术,并取得了哪些成果?”,
“answer”: “广联达在苏中建设集团南宁龙湖春江天越项目中,具体运用了哪些BIM技术,并取得了哪些成果?”
},
{
“filename”: “xx.pdf”,
“page”: 1,
“question”: “广联达公司如何通过数字项目管理平台提升施工企业的数字化转型能力?”,
“answer”: “广联达公司如何通过数字项目管理平台提升施工企业的数字化转型能力?”
},
……
]

输出 (Output):我们需要提交什么?
我们的最终任务是为 test.json 中的每一个问题,预测出三个信息: 答案 ( answer ) 、 来源文件名 ( filename ) 和 来源页码 ( page ) 。

提交文件格式

官方要求我们将所有预测结果整理成一个 JSON 文件 进行提交。官方提供了 sample_submit.json 作为格式参考。

这个文件应该包含以下一个列表(列名以 sample_submit.json 为准):

question:问题。

answer :你预测的答案文本。

filename :你预测的答案所在PDF文件的全名。

page :你预测的答案所在的页码。

提交文件示例 ( submit. json) :

[
{
“filename”: “xx.pdf”,
“page”: 1,
“question”: “广联达在苏中建设集团南宁龙湖春江天越项目中,具体运用了哪些BIM技术,并取得了哪些成果?”,
“answer”: “广联达在苏中建设集团南宁龙湖春江天越项目中,具体运用了哪些BIM技术,并取得了哪些成果?”
},
……
]

总结一下 :整个任务流程就是,

读取 test.json 里的一个问题,

驱动你的系统去 财报数据库 中查找信息,

然后生成答案和出处,

最后将这几项信息作为一行写入到最终的 submit.json 文件中。

对 test.json 中的所有问题重复此过程,即可得到最终的提交文件.

其中的train.json文件主要是用来在训练非生成式模型环节中使用的,比如训练embedding模型,或者是微调LLM。

我们Task1和Task2为大家介绍的baseline方案,更侧重于让大家能够快速体验跑通流程,所以只会涉及到如何构建以及跑通问答知识库的环节。

2.2 分析一下赛题数据、探索如何处理
参与算法赛事,一定要仔细理解赛事的 输入-输出 究竟是什么,尤其是提交的格式

因为我们的侧重点在于PDF文件的处理,数据分析的部分我们主要是需要看看他们的PDF大概是什么样子的。

图片
打开 财报数据库.zip 里面的其中一个pdf文件 , 我们可以发现PDF内部的PDF是图文混排的内容,有图片也有文本,其中图片有可能是柱形图,也可能是折线图等等。

所以我们需要思考如何提取PDF里面的数据,主要可以考虑两个工具——

pymupdf:基于规则的方式提取pdf里面的数据,

mineru:基于深度学习模型通过把PDF内的页面看成是图片进行各种检测,识别的方式提取。

其中考虑到学习者可能没有那么高的硬件成本资源条件,所以 Task1 选择的是基于pymupdf的方式给大家作为示例,基于mineru的方式会在后续为大家介绍。

下面是一个使用 PyMuPDF(fitz)提取 PDF 内容的基础代码示例。它可以提取每一页的文本内容:

import fitz # PyMuPDF

def extract_pdf_text(pdf_path):
doc = fitz.open(pdf_path)
all_text = []
for page_num in range(doc.page_count):
page = doc.load_page(page_num)
text = page.get_text()
all_text.append(text)
doc.close()
return all_text

if name == “main”:
pdf_file = “your_file.pdf” # 替换为你的 PDF 文件路径
texts = extract_pdf_text(pdf_file)
for i, page_text in enumerate(texts):
print(f"— Page {i+1} —")
print(page_text)

你只需将 your_file.pdf 替换为你的 PDF 文件路径即可。代码会打印每一页的文本内容。

2.3 赛题主要有四大难点

在上述数据分析与探索的流程中,以下几点是决定方案性能上限的关键,也是主要的难点所在。

难点一:多模态信息的有效融合

一个问题的答案可能同时依赖于一段文字描述和一个数据图表。例如,文字提到“各产品线表现见下图”,而具体数据则完全在图表中。

挑战 :如何让系统理解这种跨模态的指代和依赖关系?如果仅将文本和图像的描述(caption)作为独立的知识块进行检索,可能会丢失它们之间的强关联。检索模块需要足够智能,能够根据一个文本问题,同时召回相关的文本和图像信息。

难点二:检索的准确性与召回率平衡

检索是整个系统的基础,如果检索出的上下文信息就不包含答案,那么后续的LLM再强大也无法凭空生成正确结果(这被称为“大海捞针,针不在海里”)。

挑战 :

语义模糊性 :用户提问的方式可能与文档中的措辞差异很大,这对嵌入模型的语义理解能力提出了高要求。

信息干扰 :如果检索返回的Top-K个结果中,只有1个是相关的,其他K-1个都是噪音,这会严重干扰LLM的判断,可能导致它基于错误信息作答。如何优化检索策略(如使用重排Re-ranking技术)以提高返回结果的信噪比,是一个核心问题。

难点三:答案生成的可控性与溯源精确性

LLM在生成答案时,有时会过度“自由发挥”,产生一些幻觉(Hallucination),即编造上下文中不存在的信息。同时,它也可能错误地引用来源。

挑战 :

忠实度 :如何通过设计Prompt,强力约束LLM,使其回答 严格基于 提供的上下文,减少信息捏造。

溯源 :如何让LLM准确地从多个上下文中,定位到真正提供答案关键信息的那个来源(文件名和页码),并正确地在最终输出中引用。这需要精心设计上下文的格式和给LLM的指令。

难点四:针对性评估指标的优化

最终的评分由三部分构成:文件名匹配度(0.25分)、页面匹配度(0.25分)和答案内容相似度(0.5分)。

挑战 :这意味着,一个完美的答案文本如果来源错误,得分会很低。反之,一个内容不太完美的答案如果来源准确,也能拿到可观的分数。因此,系统优化不能只关注答案文本的质量,必须将 溯源的准确性 放在同等重要的位置。在方案迭代中,需要建立能够模拟这套评分体系的本地验证集,以准确评估每次改动对最终得分的综合影响。

2.4 这里有一份参考的解题思考过程
理解了赛事的具体要求后,大家可以先尝试自己思考解题方案,

下面是教程写作者的思考过程,供大家学习参考——

第一步:从“终点”反推“起点”——快速明确核心任务

快速浏览背景,然后直奔“赛题任务” :这让我迅速了解到,核心是做一个 多模态问答 系统。

查看“提交示例”与“评审规则” :这是整个思考过程中最关键的一步。单纯看任务描述,概念还比较模糊。但当我看到提交格式要求我们为每一个 question ,都精准地提供 answer 、 filename 和 page 时,任务的本质瞬间清晰了——这并非一个开放式的聊天机器人,而是一个 目标明确、要求可溯源的信息抽取与生成任务 。

💡
这个发现,让我立刻明确了数据处理的目标。为了生成这样的提交结果,我的系统内部就必须构建并维护一个大概包含以下元素的核心数据结构:

{ “content”: “内容文本或描述”, “metadata”: { “filename”: “来源文件名.pdf”, “page”: 页码 } }

这个结构是后续所有工作的基础。

同时, content 字段需要被转换成机器能够理解和搜索的形式,为了方便后续召回, 向量化(Embedding)字段选择的是content 。

其他部分的元数据是为了辅助我们后续进行回答的时候能够 知道当前chunk属于什么位置。

第二步:技术方案的权衡与选择

任务明确后,我开始思考如何实现,尤其是如何处理核心的多模态问题。

多模态方案选择 : 我考虑了三种主流的多模态实现路径:

基于图片描述 :对所有图片生成文本描述,将这些描述与原文的文本块统一处理。这能将多模态问题简化为纯文本问题,最适合快速构建Baseline。

多模态分别嵌入 :对文本和图片分别进行向量化,检索时结合文本和图片的相似度。这更精确,但实现也更复杂,而且召回图片与召回文本存在不相关情况,也需要比较多的处理。

多模态大模型端到端处理 :将检索到的文本和原始图片一起交给多模态大模型(如Qwen-VL)进行端到端理解和生成。这是最前沿的方案,但也最消耗资源,因为一般的多模态模型推理能力要稍微差一些。

💡
为了优先保证能跑通一个完整的流程,我选择了 第一种方案:基于图片描述 。它的优点是实现简单、逻辑清晰,能让我快速验证整个RAG(检索增强生成)链路。

具体工具栈调研 :

PDF解析 :这个环节我们选择的mineru,但是task1里面为了降低大家的学习门槛,使用的是pymupdf作为平替方案。

Embedding实现 :我最初考虑使用 sentence-transformer 库。但在进一步查阅资料时,我发现了 Xinference ,它能将模型部署为服务,并通过兼容OpenAI的API来调用。我立即决定采用这种方式,因为 服务化能让我的Embedding模块与主应用逻辑解耦,更利于调试和未来的扩展。

第三步:构建Baseline执行流程

结合上述思考,我的Baseline执行流程变得非常清晰:

预处理(离线完成) :

使用pymupdf批量解析所有PDF文档,得到结构化的JSON数据。

将原始的文本块,以及图片的描述文本,附带上它们的元数据( filename , page ),构造成我们第一步设计的核心数据结构。

调用 Xinference 部署的Embedding模型服务,将所有内容的文本部分转换为向量。

将最终的 { “id”:“……”,“content”: “…”, “vector”: […], “metadata”: … } 存入向量数据库,完成知识库构建。

在线推理 :

接收测试集的json文件中的一个 question 。

调用 Xinference 服务,将 question 向量化。

在向量数据库中进行相似度搜索,召回Top-K个最相关的内容块。

将召回的内容块及其元数据,与 question 一同填入设计好的Prompt模板中。

将完整的Prompt交给一个大语言模型(LLM),生成最终的答案和来源信息。

遇到的卡点及解决建议

在实际操作中,最主要的瓶颈在于 时间消耗 :

pymupdf解析 :处理整个财报数据库会稍微消耗一些时间,特别是如果使用基于深度学习的方式提取内容,比如mineru,不过我们本次baseline使用pymupdf速度会有比较大的提升。

批量Embedding :将接近5000的内容块进行向量化,也会消耗不少时间,如果是基于CPU运行的话大概会慢十倍,使用A6000这样的GPU也需要消耗大概1分钟的时间。

核心痛点 :如果在处理过程中代码出现一个小错误,比如数据格式没对齐,就需要从头再来,这将浪费大量时间。

解决与建议 : 不要在一个脚本里完成所有事 。强烈建议使用 Jupyter Notebook 进行开发调试,并将流程拆分:

第一阶段:解析 。在一个Notebook中,专门负责调用pymupdf,将所有PDF解析为JSON并 保存到本地 。这个阶段成功运行一次后,就不再需要重复执行。

第二阶段:预处理与Embedding 。在另一个Notebook中,读取第一步生成的JSON文件,进行图片描述生成、数据清洗,并调用Embedding模型。将最终包含向量的知识库 保存为持久化文件 。

第三阶段:检索与生成 。在第三个Notebook中,加载第二步保存好的知识库,专注于调试检索逻辑和Prompt工程。

通过这种 分步执行、缓存中间结果 的方式,可以极大地提高调试效率,每次修改只需运行对应的、耗时较短的模块。

三、来仔细了解一下Baseline方案是如何实现解题的!
接下来、请尝试吃透 Baseline的处理逻辑和方案思路吧!

建议从方案的核心函数入手!

在动手写任何代码之前,面对这样一个复杂的赛题,清晰的思路远比匆忙的实现更重要。不妨先停下来,问自己几个问题:

核心矛盾是什么? 是追求第一天就拿到SOTA(State-of-the-Art)的高性能,还是优先构建一个能完整跑通、麻雀虽小五脏俱全的系统?对于Baseline而言,目标应该是后者。一个能稳定输出结果的简单系统,是后续一切优化的基础。我们应该如何设计最简路径?

如何绕开最难的坎? 多模态是这个赛题的核心难点。让机器看懂图片,最直接的方式是让模型直接处理图片像素。但这会引入复杂的多模态模型调用和信息融合问题。有没有更简单、能快速融入现有RAG(以文本为中心)流程的办法?我们能不能先把图片“翻译”成文字?

LLM需要什么样的信息? 检索模块是LLM的眼睛和耳朵。我们是应该只把和问题最相似的那一小块知识喂给LLM,还是应该提供更丰富的周边信息?例如,找到一个关键段落后,是否应该把它的上下文(前后段落、所属章节标题)也一并提供,来帮助LLM更好地理解?

带着这些思考,我们来解读这个Baseline方案的设计。你会发现,这个方案的每一个决策,都是在对这些问题进行回答。

Baseline文件概况
Baseline仓库主要包含如下内容:

文件名

作用简介

fitz_parse_pdf.py

一键式数据处理主脚本,自动完成 PDF 解析、内容结构化、分块合并

rag_from_page_chunks.py

RAG 检索与问答主脚本,支持向量检索与大模型生成式问答

get_text_embedding.py

文本向量化,支持批量处理

extract_json_array.py

从大模型输出中提取 JSON 结构,保证结果可解析

all_pdf_page_chunks.json

所有 PDF 分页内容的合并结果,供 RAG 检索

.env

环境变量配置文件,存放 API 密钥、模型等参数

caches/

预留目录(可选)

datas/

原始 PDF 文件及测试集存放目录

data_base_json_content/

PDF 解析后的内容列表(中间结果)

data_base_json_page_content/

分页后的内容(中间结果)

output/

其他输出文件目录

其中datas的目录结构如下:

datas/
├── 多模态RAG图文问答挑战赛训练集.json
├── 多模态RAG图文问答挑战赛测试集.json
├── 多模态RAG图文问答挑战赛提交示例.json
└── 财报数据库/
├── 伊利股份相关研究报告/
│ ├── 伊利股份-公司研究报告-平台化的乳企龙头引领行业高质量转型-25071638页.pdf
│ ├── 伊利股份内蒙古伊利实业集团股份有限公司2024年年度报告.pdf
│ └── … (其他伊利股份研究报告)
├── 广联达公司研究报告/
│ ├── 广联达-公司深度报告-数字建筑全生命周期解决方案领军者-24041638页.pdf
│ ├── 广联达-云计算稀缺龙头迎收入利润率双升-21080125页.pdf
│ └── … (其他广联达研究报告)
├── 千味央厨公司研究报告/
│ ├── 千味央厨-公司深度报告-深耕B端蓝海扬帆-21090629页.pdf
│ ├── 千味央厨-公司研究报告-大小B双轮驱动餐饮市场大有可为-23061240页.pdf
│ └── … (其他千味央厨研究报告)
└── 其他上市公司研究/
├── 中恒电气-公司研究报告-HVDC方案领头羊AI浪潮下迎新机-25071124页.pdf
├── 亚翔集成-公司研究报告-迎接海外业务重估-25071324页.pdf
├── 传音控股-公司研究报告-非洲手机领军者多元化布局品类扩张生态链延伸打开成长空间-25071636页.pdf
└── … (其他公司研究报告)

重要提示:使用本项目前,请确保 datas/ 目录中包含所需的数据文件。如果没有数据,可以从以下地址下载:

https://challenge.xfyun.cn/topic/info?type=Multimodal-RAG-QA&option=stsj&ch=dwsf2517

下载后请将数据文件复制到 datas/ 目录中。

完整运行过代码之后的目录大概是这样的:

图片

Baseline方案思路
你知道、我们是如何想到和选取这样的baseline方案的吗?

baseline主要有两个处理阶段:

阶段一:离线预处理 (构建知识库)

这个阶段的目标是将原始的PDF知识库,制作成一个可供快速检索的向量数据库。

文档解析 ( Parse ) :

输入 : 财报数据库.zip 里的所有PDF文件。

工具 :fitz

输出 :为每个PDF生成一个结构化的JSON文件。这个过程是全自动的,我们只需要调用脚本运行的命令即可。

知识库构建 ( Index ) :

输入:增强后的JSON内容。

工具:Xinference(用于部署Embedding模型)

逻辑:

加载所有内容块(chunk)。

提取需要检索的文本(如原始text或image_description)。

调用Xinference或者硅基流动上的Embedding模型服务,将文本转为向量。

将文本、向量及元数据(filename, page_idx)存入内存向量库(SimpleVectorStore)。

输出:一个包含所有知识的、可快速检索的内存向量库。

阶段二:在线推理 (生成答案)

这个阶段是用户提问时,系统实时响应的过程。

问题向量化 ( Query ) :

输入 : test.json 中的一个 question 。

逻辑 :调用与构建知识库时完全相同的Embedding模型服务,将问题文本转换为查询向量。

信息检索 ( Retrieve ) :

输入 :查询向量。

逻辑 :在内存向量库(SimpleVectorStore)中执行相似度搜索,找出最相似的Top-K知识块。

答案生成 ( Generate ) :

输入 :用户的原始问题 + 上一步检索到的Top-K个知识块(包含文本和元数据)。

逻辑 :

构建Prompt:将输入信息填入预设Prompt模板,指示LLM角色、上下文和输出格式。

调用LLM:将Prompt发送给LLM(如Xinference中的Qwen)。

解析与格式化:从LLM返回结果中提取答案主体、文件名和页码,整理成最终格式。

输出 :一条完整的、符合提交要求的预测结果。

我们现有的Baseline方案的优点与不足主要有以下几点:

优点

逻辑清晰 :“图像文本化”策略巧妙地将复杂问题降维,整个流程符合经典的RAG范式,易于理解和实现。

端到端完整 :覆盖了从数据处理到最终提交的每一个环节,是一个可以立即上手运行的完整方案。

模块化设计 :每个部分(解析、嵌入、检索、生成)相对独立,可以方便地替换其中任一模块(比如换一个更好的Embedding模型或LLM)进行实验和优化。

不足

信息损失 :没有提取图片里面的内容。

上下文割裂 :将文档按照页面切分成独立的块进行检索,可能会破坏原文中段落与段落、段落与图表之间的上下文关联。检索出的知识块可能是孤立的,缺乏上下文。

检索策略单一 :仅基于语义相似度的检索,对于一些包含特定关键词或需要大范围信息整合的问题,可能不是最优解。

Baseline核心逻辑

Baseline的整体流程图如下:

图片

阶段一:离线预处理 (构建知识库) - fitz_pipeline_all.py
💡
(点击右侧◀展开查看 fitz_pipeline_all.py 的实现代码)

这个脚本是整个数据流水线的核心,用来提取pdf里面的数据成纯文本的内容, process_pdfs_to_chunks() :

作用 : 汇总所有PDF的按页内容,整合成一个统一的知识库文件。

数据结构 : 每个页面被构造成一个 “chunk”(知识块),包含ID、内容和元数据。

{
“id”: “广联达2022年年度报告_page_34”,
“content”: “# 第三节 管理层讨论与分析…”, // 该页的Markdown内容
“metadata”: {
“page”: “34”,
“file_name”: “广联达2022年年度报告.pdf”
}
}

项目根目录下的 all_pdf_page_chunks.json ,这是我们RAG系统的最终知识库。

阶段二:在线推理 (生成答案) - rag_from_page_chunks.py
这个脚本负责实现RAG的检索和生成两大核心功能,主要通过 SimpleRAG 类完成。

💡
(点击右侧◀展开查看 SimpleRAG 类的实现代码)

SimpleRAG.setup() :

作用 : RAG系统的初始化。

步骤 :

加载 all_pdf_page_chunks.json 里的所有知识块。

调用 EmbeddingModel (其核心是 get_text_embedding.py ),将每个知识块的 content 文本批量转换为向量。

将知识块和它们对应的向量存入 SimpleVectorStore (一个简单的内存向量数据库) 中。

SimpleRAG.generate_answer() :

作用 : 针对一个问题,执行完整的“检索-生成”流程。

步骤 :

查询向量化 : 将输入的问题 question 同样转换为向量。

信息检索 : 在 SimpleVectorStore 中进行相似度搜索,找出与问题向量最相似的 Top-K 个知识块。

构建Prompt : 这是最关键的环节之一。脚本将用户的原始问题和检索到的Top-K个知识块(包含内容和元数据)一同填入一个Prompt模板中。这个模板会明确指示LLM:

扮演一个专业角色(金融分析助手)。

必须依据提供的上下文(检索到的知识块)来回答。

必须严格按照指定的JSON格式输出 {“answer”: “…”, “filename”: “…”, “page”: “…”} 。

调用LLM生成 : 将构建好的Prompt发送给大语言模型(如Qwen)。

解析与格式化 : 调用 extract_json_array.py 工具,从LLM返回的可能混杂着其他文本的输出中,稳定地提取出JSON对象,并整理成最终的答案格式。

四、思考一下:如何上分?
我们还能继续从哪些角度更好地理解赛题要求和问题建模?

能从哪些角度来尝试快速调整和上分?

这个Baseline为你提供了一个简单的起点,但远非终点。你可以从以下角度思考,快速调整和提升分数:

分块策略 (Chunking Strategy) :

目前是按“页”分块,这样做简单但粗糙。是否可以尝试更细粒度的分块,比如按段落、甚至固定长度的句子分块?这会如何影响检索的精度和召回率?

如何处理跨越多个块的表格或段落?是否可以引入重叠(Overlap)分块的策略?

检索优化 (Retrieval Optimization) :

当前的Top-K检索策略很简单。如果检索回来的5个块中,只有1个是真正相关的,其他4个都是噪音,这会严重干扰LLM。如何提高检索结果的信噪比?

可以引入重排(Re-ranking)模型吗?即在初步检索(召回)出20个候选块后,用一个更强的模型对这20个块进行重新排序,选出最相关的5个。

Prompt工程 (Prompt Engineering) :

rag_from_page_chunks.py 中的Prompt是整个生成环节的灵魂。你能设计出更好的Prompt吗?

比如,如何更清晰地指示LLM在多个来源中选择最精确的那一个?如何让它在信息不足时回答“根据现有信息无法回答”,而不是产生幻觉?

多模态融合 (Multimodal Fusion) :

“图片->文字描述”的方案有信息损失。有没有办法做得更好?

可以尝试 多路召回 吗?即文本问题同时去检索文本库和图片库(使用CLIP等多模态向量模型),将检索到的文本和图片信息都提供给一个多模态大模型(如Qwen-VL),让它自己去融合信息并作答。

升级数据解析方案:从 fitz 到 MinerU :

这是至关重要的进阶环节。基础方案所使用的 fitz_pipeline_all.py 仅能提取文本,会遗漏表格、图片等关键信息。

转而使用 mineru_pipeline_all.py 脚本,具体操作如下:

建议在GPU环境下运行

python mineru_pipeline_all.py

为什么这么做( MinerU 的优势): MinerU 可以对PDF进行深度的版面分析,除了能更精准地提取文本块外,还具备以下功能:

识别表格 :将表格转化为结构化的Markdown或JSON格式。

提取图片 :对文档中的图片进行识别。

图片描述 :(可选)调用多模态模型为提取出的图片生成文字说明。

效果 :这会为后续的RAG流程提供包含表格和图片信息的、更丰富且更精确的上下文,是解决多模态问题的关键举措。

五、下一个内容、我们将学习更多上分思路!
你花了多少时间完成本篇内容呢?有哪些收获呢?可以在评论区分享分享~

然后、开始 Task3:调整方案、进阶上分! 的学习吧!

附录:知识点概述

RAG (Retrieval-Augmented Generation) : 检索增强生成。它是一种将外部知识库的检索能力与大语言模型的生成能力相结合的技术框架。其核心思想是,当LLM需要回答问题时,不直接让它凭空回答,而是先从一个庞大的知识库(如我们处理好的PDF内容)中检索出最相关的几段信息,然后将这些信息连同问题一起交给LLM,让它“参考”这些材料来生成答案。这极大地提高了答案的准确性、时效性,并解决了LLM的“幻觉”问题。

向量嵌入 (Vector Embeddings) : 这是让计算机理解文本语义的桥梁。Embedding模型(如本方案中的BGE-M3)可以将一段文本(一个词、一句话、一个段落)映射到一个高维的数学向量(比如一个包含1024个数字的列表)。在向量空间中,语义上相近的文本,其对应的向量在空间位置上也更接近。

向量数据库 (Vector Database) : 一个专门用于存储和高效查询海量向量的数据库。当我们把所有知识块都转换成向量后,就需要一个地方来存放它们。当一个新问题到来时,我们将其也转换为向量,然后去向量数据库中进行“相似度搜索”,快速找到与之最“近”的那些知识向量,从而实现语义检索。本Baseline为了简化,用一个内存列表( SimpleVectorStore )模拟了向量数据库的功能。

参考资料
PDF文档解析

MinerU : 功能强大的文档解析工具,能将PDF精准地转换为结构化的Markdown或JSON。

官方网站

GitHub仓库

PyMuPDF : 一个高性能的Python PDF处理库。

官方文档

模型部署与服务化

Xinference : 一个强大的开源推理框架,能将各种大模型(包括文本、嵌入和多模态模型)部署为服务,并提供兼容OpenAI的API接口。

GitHub仓库

文本/多模态向量化模型

FlagEmbedding (BGE模型) : 领先的中文文本向量化模型库。

GitHub仓库

CLIP (Hugging Face实现) : 经典且强大的图文多模态向量化模型。

Hugging Face模型文档

通义千问Qwen-VL (多模态) : 阿里巴巴开源的性能强大的多模态对话语言模型。

GitHub仓库

向量数据库与检索

ChromaDB : 一个简单易用的开源向量数据库。

官方文档

FAISS : 由Facebook AI Research开发的高性能向量检索引擎。

GitHub仓库

入门指南

RAG开发框架

LlamaIndex : 一个主流的、用于构建和开发RAG应用的集成化框架。

五分钟入门教程

OCR

PaddleOCR : 强大的中文OCR工具库。

GitHub仓库


网站公告

今日签到

点亮在社区的每一天
去签到