RAG系列:解析優(yōu)化 - 不同文件類型統(tǒng)一轉(zhuǎn)換成Markdown
引言
在 RAG 系統(tǒng)中,文件解析是構(gòu)建知識庫和實現(xiàn)高效信息檢索的關(guān)鍵環(huán)節(jié)。隨著系統(tǒng)需要處理的文件類型日益增多(如PDF、Word、Excel、PPT、HTML等),如何高效解析并利用這些異構(gòu)數(shù)據(jù)成為核心挑戰(zhàn)。
由于每種文件類型的數(shù)據(jù)結(jié)構(gòu)和內(nèi)容(如PDF的復(fù)雜排版、Excel的表格結(jié)構(gòu)、PPT的多媒體元素)都不一致,在實際的應(yīng)用場景中,我們需要對不同文件類型實現(xiàn)不同的解析器,解析之后還需要根據(jù)不同文件的結(jié)構(gòu)實現(xiàn)對應(yīng)的文檔分塊方法。整體來說,這樣的系統(tǒng)實現(xiàn)和維護成本都是比較高的,要把每種文件類型的解析都做到比較好是比較繁瑣的,但是文件解析如果做的不好,就會不同程度地影響后續(xù) RAG 系統(tǒng)流程,該種方案流程如下:
可能你會問,為什么需要這么多的解析器呢?不能把各種文件直接讀取成字節(jié)流后丟給 LLM 嗎?以當(dāng)前 LLM 的能力,無論是什么內(nèi)容都需要得組織成文本,它才能處理。而 PDF、Word、網(wǎng)頁等其實都是富文本,里面除了文字,通常還包含公式、圖片、表格、統(tǒng)計圖,排版方式也各不相同,甚至其中的格式也是很重要的內(nèi)容,而這也是文件解析的作用,把各種富文本轉(zhuǎn)換成 LLM 好理解的純文本的過程。
為什么是 Markdown
- 統(tǒng)一數(shù)據(jù)格式,降低解析復(fù)雜度:Markdown 以純文本形式保留了基本結(jié)構(gòu)(標題、列表、代碼塊、表格),同時去除了冗余的格式信息(如字體、顏色);所有文件統(tǒng)一轉(zhuǎn)換為 Markdown 后,RAG 系統(tǒng)只需針對一種格式進行后續(xù)處理(如分段、分句、實體提?。?,顯著降低代碼復(fù)雜度。
- 提升信息提取與語義理解能力: Markdown 的標題語法(
#
、##
)可直接映射為文檔結(jié)構(gòu),便于模型快速定位關(guān)鍵信息;Markdown 的表格和代碼塊標記(如`````)能保留原始數(shù)據(jù)的排版邏輯,幫助模型理解數(shù)據(jù)關(guān)系;通過-
、>
等符號標記的列表和引用內(nèi)容,可輔助模型識別要點和上下文關(guān)聯(lián)。去除原始文件中的樣式、腳注、頁眉頁腳等非核心內(nèi)容,使文本更聚焦于語義信息。 - 優(yōu)化存儲與檢索效率:Markdown 文件體積小,適合大規(guī)模知識庫的存儲和快速加載;基于 Markdown 的結(jié)構(gòu)化文本可直接生成倒排索引,提升檢索速度和準確性。
- 增強可維護性與可解釋性:開發(fā)者可直接通過文本編輯器查看 Markdown 內(nèi)容,便于調(diào)試和驗證解析結(jié)果;Markdown 文件易于進行版本管理(如Git),支持團隊協(xié)作和歷史追溯。
統(tǒng)一轉(zhuǎn)換成 Markdown 之后,可優(yōu)化成如下流程:
統(tǒng)一轉(zhuǎn)成 Markdown 之后,只需要將注意力專注在 Markdown 解析和處理上就可以了,這樣可以大幅降低整個系統(tǒng)的開發(fā)、維護成本。
而將 PDF 轉(zhuǎn) Markdown、Word 轉(zhuǎn) Markdown 等有很多成熟的工具可以使用這樣就沒必要自己寫解析器來處理了,比如 MinerU[1] - 上海人工智能實驗室開源的項目、MarkItDown - Microsoft AutoGen 團隊開源的項目等等,這些項目都是專門用于將各種文件格式轉(zhuǎn)換為 Markdown,可以參考借鑒和使用。
本文完整代碼地址[2]
MinerU 使用方法
今天就以 CPU 運行的方式來簡單介紹下 MinerU 的使用方法(沒有找到類似 Nodejs 的工具,只能使用 Python 來介紹了...),更多內(nèi)容到 Github 上使用cpu快速體驗[3]查看。
安裝 magic-pdf
conda create -n .venv 'pythnotallow=3.12' -y
conda activate .venv
pip install -U "magic-pdf[full]" -i https://mirrors.aliyun.com/pypi/simple
以上是官方示例。如果你沒有安裝 conda(不建議使用 uv,有兼容性問題),可以直接使用 Python 的命令創(chuàng)建虛擬空間安裝:
python3.12 -m venv .venv
source .venv/bin/activate
pip install -U "magic-pdf[full]" -i https://mirrors.aliyun.com/pypi/simple
(截止到發(fā)文時)這里需要注意,Python 的版本需要在 3.10 ~ 3.12 之間,不然 magic-pdf 會被自動降級到 0.6.1。
下載模型文件
模型文件可以從 Hugging Face 或 Model Scope 下載,由于網(wǎng)絡(luò)原因,國內(nèi)用戶訪問 HF 可能會失敗,請使用 ModelScope。
pip install modelscope
wget https://gcore.jsdelivr.net/gh/opendatalab/MinerU@master/scripts/download_models.py -O download_models.py
python download_models.py
修改配置文件【可選】
完成第二個步驟后,腳本會自動生成用戶目錄下的 magic-pdf.json 文件,并自動配置默認模型路徑。 您可在【用戶目錄】下找到 magic-pdf.json 文件。
windows的用戶目錄為 "C:\Users\用戶名",
linux用戶目錄為 "/home/用戶名",
macOS用戶目錄為 "/Users/用戶名"。
您可修改該文件中的部分配置實現(xiàn)功能的開關(guān),如表格識別功能:
{
// other config
"layout-config":{
"model":"doclayout_yolo"
},
"formula-config":{
"mfd_model":"yolo_v8_mfd",
"mfr_model":"unimernet_small",
"enable":true// 公式識別功能默認是開啟的,如果需要關(guān)閉請修改此處的值為"false"
},
"table-config":{
"model":"rapid_table",
"sub_model":"slanet_plus",
"enable":true,// 表格識別功能默認是開啟的,如果需要關(guān)閉請修改此處的值為"false"
"max_time":400
}
}
代碼示例
import os
from magic_pdf.data.data_reader_writer import FileBasedDataWriter, FileBasedDataReader
from magic_pdf.data.dataset import PymuDocDataset
from magic_pdf.model.doc_analyze_by_custom_model import doc_analyze
from magic_pdf.config.enums import SupportedPdfParseMethod
defmain():
# args
pdf_file_name = "2024少兒編程教育行業(yè)發(fā)展趨勢報告.pdf"# replace with the real pdf path
name_without_suff = pdf_file_name.split(".")[0]
# prepare env
local_image_dir, local_md_dir = "output/images", "output"
image_dir = str(os.path.basename(local_image_dir))
os.makedirs(local_image_dir, exist_ok=True)
image_writer, md_writer = FileBasedDataWriter(local_image_dir), FileBasedDataWriter(
local_md_dir
)
# read bytes
reader1 = FileBasedDataReader("")
pdf_bytes = reader1.read(pdf_file_name) # read the pdf content
# proc
# Create Dataset Instance
ds = PymuDocDataset(pdf_bytes)
# inference
if ds.classify() == SupportedPdfParseMethod.OCR:
infer_result = ds.apply(doc_analyze, ocr=True)
# pipeline
pipe_result = infer_result.pipe_ocr_mode(image_writer)
else:
infer_result = ds.apply(doc_analyze, ocr=False)
# pipeline
pipe_result = infer_result.pipe_txt_mode(image_writer)
# draw model result on each page
infer_result.draw_model(os.path.join(
local_md_dir, f"{name_without_suff}_model.pdf"))
# get model inference result
model_inference_result = infer_result.get_infer_res()
# draw layout result on each page
pipe_result.draw_layout(os.path.join(
local_md_dir, f"{name_without_suff}_layout.pdf"))
# draw spans result on each page
pipe_result.draw_span(os.path.join(
local_md_dir, f"{name_without_suff}_spans.pdf"))
# get markdown content
md_content = pipe_result.get_markdown(image_dir)
# dump markdown
pipe_result.dump_md(md_writer, f"{name_without_suff}.md", image_dir)
# get content list content
content_list_content = pipe_result.get_content_list(image_dir)
# dump content list
pipe_result.dump_content_list(
md_writer, f"{name_without_suff}_content_list.json", image_dir)
# get middle json
middle_json_content = pipe_result.get_middle_json()
# dump middle json
pipe_result.dump_middle_json(md_writer, f'{name_without_suff}_middle.json')
if __name__ == "__main__":
main()
運行之后,會在本地生成提取到的圖片、中間過程文件以及最終生成的 Markdown 文件。
生成的 Markdown 文檔:
原始文檔:
可以看到,提取的結(jié)果還是比較符合預(yù)期的,圖片也都正確提取出來了。
結(jié)語
今天通過簡單介紹 MinerU 的使用方法的同時,來給大家?guī)硪环N文件解析優(yōu)化的思路,希望能對大家有所啟發(fā)。
引用鏈接
[1]
MinerU: https://github.com/opendatalab/MinerU
[2]
本文完整代碼地址: https://github.com/laixiangran/ai-learn-python/blob/main/app/file2Markdown.py
[3]
使用cpu快速體驗: https://github.com/opendatalab/MinerU/blob/master/README_zh-CN.md#%E4%BD%BF%E7%94%A8cpu%E5%BF%AB%E9%80%9F%E4%BD%93%E9%AA%8C