多模態RAG賽題實戰之策略優化--Datawhale AI夏令營

科大訊飛AI大賽(多模態RAG方向) - Datawhale

項目流程圖

1、升級數據解析方案:從 fitz?到 MinerU

PyMuPDF(fitz)是基于規則的方式提取pdf里面的數據;MinerU是基于深度學習模型通過把PDF內的頁面看成是圖片進行各種檢測,識別的方式提取。

(1)識別表格 :將表格轉化為結構化的Markdown或JSON格式。

(2)提取圖片 :對文檔中的圖片進行識別。

(3)圖片描述 :(可選)調用多模態模型為提取出的圖片生成文字說明。

這會為后續的RAG流程提供包含表格和圖片信息的、更豐富且更精確的上下文,是解決多模態問題的關鍵舉措。

  • 基礎方案所使用的 fitz 工具僅能提取文本,會遺漏表格、圖片等關鍵信息。

  • MinerU 的優勢:對PDF進行深度的版面分析,除了能更精準地提取文本塊外,還具備以下功能:

  • 因此轉而使用 mineru_pipeline_all.py 腳本,具體操作如下:
?# 建議在GPU環境下運行,執行完大約需要1.5h
python mineru_pipeline_all.py

報錯:系統網絡無法訪問外網 huggingface.co,導致 Mineru 無法下載所需的 PDF 處理模型。

解決方法:在 mineru_pipeline_all.py 文件開頭添加環境變量設置:

os.environ['MINERU_MODEL_SOURCE'] = "modelscope"

這將使 Mineru 從 ModelScope(阿里云模型庫)下載模型,避免因網絡問題無法訪問 Hugging Face,下載到的是OpenDataLab的MinerU2.0-2505-0.9B模型。

mineru_pipeline_all.py 文件中關鍵的有兩個函數依次執行:

1、parse_all_pdfs 函數——分析 PDF 的版面布局,識別出里面的文本、標題、表格和圖片,然后把這些識別出的所有內容元素,連同它們的類型、位置、層級等信息,都存進一個名為 _content_list.json 的文件里。

2、process_all_pdfs_to_page_json 函數——讀取 _content_list.json ,先按頁碼把內容分好組,然后逐個處理每一頁里的內容項,里面內嵌了一個item_to_markdown 函數,這個函數是一個轉換器,它根據內容項的類型( text、table、image)來決定如何轉換成MarkDown格式,而且代碼會檢查圖片本身有沒有自帶的文字描述( caption ),如果沒有,并且我們允許進行視覺分析( enable_image_caption=True ),它就會調用一個多模態大模型(代碼里指定的是 Qwen/Qwen2.5-VL-32B-Instruct來給這張圖片生成一段描述。

MinerU的輸出:會是三種類型——text、table、image的集合(相比于fitz則完全是text,對圖表也是提取text,完全丟失了圖的表意)

    {"type": "text","text": "分析師: 彭波  \nE-mail: pengbo@yongxingsec.com  \nSAC編號: S1760524100001  \n分析師: 陳燦  \nE-mail: chencan2@yongxingsec.com  \nSAC編號: S1760525010002  \n相關報告:  \n《伏美替尼持續放量,適應癥拓展仍  \n有空間》2025 年 05 月 06 日","page_idx": 0},{"type": "table","img_path": "images/e615166fd385400608ed9069eb20088bb78ce2c5de7fad66da7072570597386f.jpg","table_caption": [],"table_footnote": [],"table_body": "<table><tr><td colspan=\"2\">基本數據</td></tr><tr><td>07月04日收盤價(元)</td><td>94.61</td></tr><tr><td>12mthA股價格區間(元)</td><td>39.82-99.99</td></tr><tr><td>總股本(百萬股)</td><td>450.00</td></tr><tr><td>無限售A股/總股本</td><td>100.00%</td></tr><tr><td>流通市值 (億元)</td><td>425.75</td></tr></table>","page_idx": 0},{"type": "image","img_path": "images/cefb4046fc651be250334d71e02a2c9289c2dc5420d575183f79eb329cdb68d5.jpg","image_caption": ["最近一年股票與滬深 300比較","資料來源:Wind,甬興證券研究所"],"image_footnote": [],"page_idx": 0},

table:

image:原圖和提取的圖

但是目前mineru只是提取出來了圖片,還需要對圖片進行進一步的融合,只是簡單加入圖片的描述信息還有有比較大的局限性的。

2、升級分塊策略

目前的分塊策略:

按頁來分塊(每一頁都是一個知識塊,可以直接用于后續的向量化和索引),每一個pdf文件按頁來排序,每一頁的內容包含text、table、image,上一個pdf最后一頁結束之后,便是下一個pdf的第一頁,以此類推直到最后一個pdf的最后一頁。

上述分塊方式存在缺點:按“頁”分塊過于粗暴,一個完整的表格或邏輯段落可能被硬生生切開,或者說當本來應檢索的信息分布于前后兩頁之中時,便破壞了信息的上下文完整性。

優化分塊策略:

有了 MinerU 精細化的解析結果,我們可以對圖片進行進一步的內容解釋,添加圖片的描述信息。

后續涉及對圖像描述信息的融合處理。

3、引入重排模型

在終端下載BAAI的bge-reranker-v2-m3重排模型:

# 先下載 lfs
git lfs install
git clone https://www.modelscope.cn/BAAI/bge-reranker-v2-m3.git

加載重排模型:

# 初始化 FlagReranker(加載一次就行)
local_model_path = "./bge-reranker-v2-m3"  # 替換為你的下載模型路徑
self.reranker = FlagReranker(local_model_path,use_fp16=True # 沒 GPU 用 "cpu"
)

召回+重排實現代碼:取的是先召回后重排得到的Top-k個chunks,代替原來的直接取的Top-k個chunks。

        # 1?? 向量粗召回 15 個q_emb = self.embedding_model.embed_text(question)retrieved_chunks = self.vector_store.search(q_emb, top_k=15)if not retrieved_chunks:return {"question": question,"answer": "","filename": "","page": "","retrieval_chunks": []}# 2?? 用 FlagReranker 精排pairs = [[question, chunk['content']] for chunk in retrieved_chunks]scores = self.reranker.compute_score(pairs)  # 返回每個pair的相關性分數# 綁定分數for i, sc in enumerate(scores):retrieved_chunks[i]['score'] = sc# 按分數排序,取 top_kreranked_chunks = sorted(retrieved_chunks, key=lambda x: x['score'], reverse=True)[:top_k]# 3?? 拼接上下文context = "\n".join([f"[文件名]{c['metadata']['file_name']} [頁碼]{c['metadata']['page']}\n{c['content']}"for c in reranked_chunks])# 4?? 構造 Promptprompt = (f"你是一名專業的金融分析助手,請根據以下檢索到的內容回答用戶問題。\n"f"請嚴格按照如下JSON格式輸出:\n"f'{{"answer": "你的簡潔回答", "filename": "來源文件名", "page": "來源頁碼"}}'"\n"f"檢索內容:\n{context}\n\n問題:{question}\n"f"請確保輸出內容為合法JSON字符串,不要輸出多余內容。")# 5?? 調用大模型client = OpenAI(api_key=qwen_api_key, base_url=qwen_base_url)completion = client.chat.completions.create(model=qwen_model,messages=[{"role": "system", "content": "你是一名專業的金融分析助手。"},{"role": "user", "content": prompt}],temperature=0.2,max_tokens=1024)

4、升級索引策略?

多路召回與融合:

除了原先的基于向量的語義檢索——使用 embedding 模型來查找意思相近的chunk之外,另外再引入一種基于關鍵詞的檢索方法——BM25 算法,它擅長匹配問題中出現的具體詞語,即要將chunk中的content內容的每一個單詞/字給分出來,再去做匹配。

step1:下載BM25算法庫和中文分詞器

uv pip install rank_bm25, jieba

step2:在SimpleVectorStore類中新增 BM25 算法關鍵詞檢索函數,利用中文分詞器(jieba)去對中文句子進行分詞

class SimpleVectorStore:def __init__(self):self.embeddings = []self.chunks = []# --- 新增 ---self.bm25 = None  # BM25 模型self.tokenized_chunks = []  # 預先分好詞的文本def add_chunks(self, chunks: List[Dict[str, Any]], embeddings: List[List[float]]):self.chunks.extend(chunks)self.embeddings.extend(embeddings)# --- 新增:構建 BM25 ---# 使用 jieba 精確分詞self.tokenized_chunks = [list(jieba.cut_for_search(c['content']))  # 搜索引擎模式,速度快for c in self.chunks]self.bm25 = BM25Okapi(self.tokenized_chunks)def search(self, query_embedding: List[float], top_k: int = 3) -> List[Dict[str, Any]]:from numpy import dotfrom numpy.linalg import normimport numpy as npif not self.embeddings:return []emb_matrix = np.array(self.embeddings)query_emb = np.array(query_embedding)sims = emb_matrix @ query_emb / (norm(emb_matrix, axis=1) * norm(query_emb) + 1e-8)idxs = sims.argsort()[::-1][:top_k]return [self.chunks[i] for i in idxs]# --- 新增:bm25檢索 ---def search_bm25(self, query: str, top_k: int = 3) -> List[Dict[str, Any]]:if not self.bm25:return []# 同樣用 jieba 分詞tokens = list(jieba.cut_for_search(query))scores = self.bm25.get_scores(tokens)idxs = scores.argsort()[::-1][:top_k]return [self.chunks[i] for i in idxs]

step3:在 SimpleRAG 類中新增混合檢索接口

class SimpleRAG:def __init__(self, chunk_json_path: str, model_path: str = None, batch_size: int = 32):self.loader = PageChunkLoader(chunk_json_path)self.embedding_model = EmbeddingModel(batch_size=batch_size)self.vector_store = SimpleVectorStore()self.memory = ConversationBufferMemory(return_messages=True)def search_hybrid(self, question: str, top_k_vec: int = 10, top_k_bm25: int = 10) -> List[Dict[str, Any]]:"""混合檢索:向量 + BM25,各取 top_k,合并去重后返回"""# 向量檢索q_emb = self.embedding_model.embed_text(question)vec_results = self.vector_store.search(q_emb, top_k=top_k_vec)# BM25 檢索bm25_results = self.vector_store.search_bm25(question, top_k=top_k_bm25)# 合并去重(保持順序)seen = set()merged = []for chunk in vec_results + bm25_results:cid = (chunk['metadata']['file_name'], chunk['metadata']['page'], chunk['content'])if cid not in seen:seen.add(cid)merged.append(chunk)return merged

step4:函數應用,修改原來search方法為混合檢索

# chunks = self.vector_store.search(q_emb, top_k)
# 2. 混合檢索
chunks = self.search_hybrid(rewritten_question)


5、反思重寫:

我們甚至可以考慮讓RAG系統擁有自我修正的能力。

具體來說,就是讓系統在檢索一次之后,能自己判斷一下找到的上下文夠不夠回答問題。

如果不夠,它可以自己生成一個新的、更具體的查詢語句,再次進行檢索,把兩次的結果合在一起再生成答案。

這會讓整個問答過程更動態一些。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95403.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95403.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95403.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

09--解密棧與隊列:數據結構核心原理

1. 棧 1.1. 棧的簡介 棧 是一種 特殊的線性表&#xff0c;具有數據 先進后出 特點。 注意&#xff1a; stack本身 不支持迭代器操作 主要原因是因為stack不支持數據的隨機訪問&#xff0c;必須保證數據先進后出的特點。stack在CPP庫中實現為一種 容器適配器 所謂容器適配器&a…

打造專屬 React 腳手架:從 0 到 1 開發 CLI 工具

前言: 在前端開發中&#xff0c;重復搭建項目環境是個低效的事兒。要是團隊技術棧固定&#xff08;比如 React AntD Zustand TS &#xff09;&#xff0c;每次從零開始配路由、狀態管理、UI 組件&#xff0c;既耗時又容易出錯。這時候&#xff0c;自定義 CLI 腳手架 就派上…

Python day43

浙大疏錦行 Python day43 import torch import numpy as np import pandas as pd import torchvision import torchvision.transforms as transforms import torch.nn as nn import torch.optim as optim import torch.nn.functional as F from torch.utils.data import Da…

python基于Hadoop的超市數據分析系統

前端開發框架:vue.js 數據庫 mysql 版本不限 后端語言框架支持&#xff1a; 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 數據庫工具&#xff1a;Navicat/SQLyog等都可以 摘要&…

如何用 COLMAP 制作 Blender 格式的數據集

如何用 COLMAP 制作 Blender 格式的數據集并劃分出 transforms_train.json、transforms_val.json 和 transforms_test.json。 一、什么是 Blender 格式數據集? Blender 格式數據集是 Nerf 和 Nerfstudio 常用的輸入格式,其核心是包含了相機內外參的 JSON 文件,一般命名為:…

[GESP202309 六級] 2023年9月GESP C++六級上機題題解,附帶講解視頻!

本文為GESP 2023年9月 六級的上機題目詳細題解和講解視頻&#xff0c;覺得有幫助或者寫的不錯可以點個贊。 題目一講解視頻 GESP2023年9月六級上機題一題目二講解視頻 題目一:小羊買飲料 B3873 [GESP202309 六級] 小楊買飲料 - 洛谷 題目大意: 現在超市一共有n種飲料&#…

linux 操作ppt

目錄 方法1&#xff1a;用 libreoffice 打開PPT文件 播放腳本&#xff1a; 方法2&#xff1a;用 python-pptx 創建和編輯PPT 方法3&#xff1a;其他方法 在Linux中&#xff0c;可以使用Python通過python-pptx庫來創建和編輯PPT文件&#xff0c;但直接播放PPT文件需要借助其…

元數據管理與數據治理平臺:Apache Atlas 基本搜索 Basic Search

文中內容僅限技術學習與代碼實踐參考&#xff0c;市場存在不確定性&#xff0c;技術分析需謹慎驗證&#xff0c;不構成任何投資建議。 Apache Atlas 框架是一套可擴展的核心基礎治理服務&#xff0c;使企業能夠有效、高效地滿足 Hadoop 中的合規性要求&#xff0c;并支持與整個…

LangChain4J-(1)-Hello World

一、LangChain4J是什么&#xff1f; LangChain4J 是一個專為 Java 生態系統設計的開源框架&#xff0c;用于簡化與大語言模型&#xff08;LLM&#xff0c;如 OpenAI 的 GPT 系列、Google 的 Gemini、Anthropic 的 Claude 等&#xff09;的集成和交互。它借鑒了 Python 生態中 L…

HTTPS應用層協議-中間攻擊人

HTTPS應用層協議-中間攻擊人 ? Man-in-the-MiddleAttack&#xff0c;簡稱“MITM 攻擊” 確實&#xff0c;在方案 2/3/4 中&#xff0c;客戶端獲取到公鑰 S 之后&#xff0c;對客戶端形成的對稱秘鑰 X 用服務端給客戶端的公鑰 S 進行加密&#xff0c;中間人即使竊取到了數據&am…

利用 Makefile 高效啟動 VIVADO 軟件:深入解析與實踐

利用 Makefile 高效啟動 VIVADO 軟件&#xff1a;深入解析與實踐 系列文章目錄 1、VMware Workstation Pro安裝指南&#xff1a;詳細步驟與配置選項說明 2、VMware 下 Ubuntu 操作系統下載與安裝指南 3.基于 Ubuntu 的 Linux 系統中 Vivado 2020.1 下載安裝教程 文章目錄利用 …

[前端算法]排序算法

默認情況下&#xff0c;sort() 會將元素轉換為字符串&#xff0c;然后按照 Unicode 編碼的順序進行排序&#xff1a; const fruits [apple, banana, cherry, date]; fruits.sort(); console.log(fruits); // 輸出: ["apple", "banana", "cherry"…

C#標簽批量打印程序開發

C#標簽批量打印程序開發&#xff08;集成Bartender解決方案&#xff09;一、系統架構設計 1. 核心模塊劃分 public class LabelPrintingSystem {private IDataLoader _dataLoader; // 數據加載器private ITemplateEngine _templateEngine; // 模板引擎private IPrintControl…

ECC的原理、背景、工作機制和數學基礎

ECC的原理、背景、工作機制和數學基礎摘要&#xff1a;本文首先詳細介紹ECC&#xff08;Error-Correcting Code&#xff0c;糾錯碼&#xff09;的原理&#xff0c;包括背景、工作機制和數學基礎。然后&#xff0c;解釋ECC在SRAM&#xff08;Static Random-Access Memory&#x…

計算機網絡2-2:物理層下面的傳輸媒體

目錄 導引型傳輸媒體 同軸電纜 雙絞線 光纖 電力線 非導引型傳輸媒體 無線電波 微波 紅外線 可見光 無線電頻譜管理機構 導引型傳輸媒體 同軸電纜 雙絞線 光纖 光在光纖中傳播的基本原理 電力線 非導引型傳輸媒體 無線電波 微波 紅外線 可見光 LiFi(可見光通信) …

Dify 從入門到精通(第 32/100 篇):Dify 的日志分析與監控

Dify 從入門到精通&#xff08;第 32/100 篇&#xff09;&#xff1a;Dify 的日志分析與監控 Dify 入門到精通系列文章目錄 第一篇《Dify 究竟是什么&#xff1f;真能開啟低代碼 AI 應用開發的未來&#xff1f;》介紹了 Dify 的定位與優勢第二篇《Dify 的核心組件&#xff1a…

【IntelliJ IDEA】修改堆內存

idea卡頓&#xff0c;鼠標漂移修改idea文件打開 idea 安裝路徑&#xff0c;【bin】目錄下【idea64.exe.vmoptions】文件修改【-Xms】最小內存【-Xmx】最大內存-Xms2048m -Xmx9216midea更改內存設置工具欄幫助更改內存設置設置堆大小上限為 文件 設置的最大內存保存并重啟Leslie…

Docker與Docker Compose:容器世界的“單兵作戰”與“軍團指揮官”

在容器化技術的浪潮中&#xff0c;Docker和Docker Compose如同“雙子星”&#xff0c;一個專注于單兵作戰&#xff0c;一個擅長軍團指揮。它們看似相似&#xff0c;卻各司其職。對于開發者來說&#xff0c;理解它們的區別不僅能讓代碼部署事半功倍&#xff0c;更能避免踩坑。本…

進階向:Python編寫自動化郵件發送程序

Python編寫自動化郵件發送程序&#xff1a;從零開始詳解在數字化時代&#xff0c;自動化郵件發送功能已成為企業和個人提升工作效率的重要工具。據統計&#xff0c;全球每天發送的商業郵件超過30億封&#xff0c;其中約40%是通過自動化系統發送的。這種功能被廣泛應用于多種場景…

ChatGpt 5系列文章1——編碼與智能體

人工智能技術正在以驚人的速度發展&#xff0c;重新定義著開發人員的工作方式。2025年8月&#xff0c;OpenAI正式發布了面向開發人員的GPT-5 一、GPT-5的編碼能力突破 GPT-5在關鍵編碼基準測試中創造了行業新紀錄(SOTA)&#xff0c;在SWE-bench Verified測試中得分74.9%&…