引言
在 RAG 系统中,文件解析是构建知识库和实现高效信息检索的关键环节。随着系统需要处理的文件类型日益增多(如PDF、Word、Excel、PPT、HTML等),如何高效解析并利用这些异构数据成为核心挑战。
由于每种文件类型的数据结构和内容(如PDF的复杂排版、Excel的表格结构、PPT的多媒体元素)都不一致,在实际的应用场景中,我们需要对不同文件类型实现不同的解析器,解析之后还需要根据不同文件的结构实现对应的文档分块方法。整体来说,这样的系统实现和维护成本都是比较高的,要把每种文件类型的解析都做到比较好是比较繁琐的,但是文件解析如果做的不好,就会不同程度地影响后续 RAG 系统流程,该种方案流程如下:
可能你会问,为什么需要这么多的解析器呢?不能把各种文件直接读取成字节流后丢给 LLM 吗?以当前 LLM 的能力,无论是什么内容都需要得组织成文本,它才能处理。而 PDF、Word、网页等其实都是富文本,里面除了文字,通常还包含公式、图片、表格、统计图,排版方式也各不相同,甚至其中的格式也是很重要的内容,而这也是文件解析的作用,把各种富文本转换成 LLM 好理解的纯文本的过程。
为什么是 Markdown
- 统一数据格式,降低解析复杂度:Markdown 以纯文本形式保留了基本结构(标题、列表、代码块、表格),同时去除了冗余的格式信息(如字体、颜色);所有文件统一转换为 Markdown 后,RAG 系统只需针对一种格式进行后续处理(如分段、分句、实体提取),显著降低代码复杂度。
- 提升信息提取与语义理解能力: Markdown 的标题语法(#、##)可直接映射为文档结构,便于模型快速定位关键信息;Markdown 的表格和代码块标记(如`````)能保留原始数据的排版逻辑,帮助模型理解数据关系;通过-、>等符号标记的列表和引用内容,可辅助模型识别要点和上下文关联。去除原始文件中的样式、脚注、页眉页脚等非核心内容,使文本更聚焦于语义信息。
- 优化存储与检索效率:Markdown 文件体积小,适合大规模知识库的存储和快速加载;基于 Markdown 的结构化文本可直接生成倒排索引,提升检索速度和准确性。
- 增强可维护性与可解释性:开发者可直接通过文本编辑器查看 Markdown 内容,便于调试和验证解析结果;Markdown 文件易于进行版本管理(如Git),支持团队协作和历史追溯。
统一转换成 Markdown 之后,可优化成如下流程:
统一转成 Markdown 之后,只需要将注意力专注在 Markdown 解析和处理上就可以了,这样可以大幅降低整个系统的开发、维护成本。
而将 PDF 转 Markdown、Word 转 Markdown 等有很多成熟的工具可以使用这样就没必要自己写解析器来处理了,比如 MinerU[1] - 上海人工智能实验室开源的项目、MarkItDown - Microsoft AutoGen 团队开源的项目等等,这些项目都是专门用于将各种文件格式转换为 Markdown,可以参考借鉴和使用。
本文完整代码地址[2]
MinerU 使用方法
今天就以 CPU 运行的方式来简单介绍下 MinerU 的使用方法(没有找到类似 Nodejs 的工具,只能使用 Python 来介绍了...),更多内容到 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 的命令创建虚拟空间安装:
复制python3.12 -m venv .venv source .venv/bin/activate pip install -U "magic-pdf[full]" -i https://mirrors.aliyun.com/pypi/simple
(截止到发文时)这里需要注意,Python 的版本需要在 3.10 ~ 3.12 之间,不然 magic-pdf 会被自动降级到 0.6.1。
下载模型文件
模型文件可以从 Hugging Face 或 Model Scope 下载,由于网络原因,国内用户访问 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/用户名"。
您可修改该文件中的部分配置实现功能的开关,如表格识别功能:
复制{ // other config "layout-config":{ "model":"doclayout_yolo" }, "formula-config":{ "mfd_model":"yolo_v8_mfd", "mfr_model":"unimernet_small", "enable":true// 公式识别功能默认是开启的,如果需要关闭请修改此处的值为"false" }, "table-config":{ "model":"rapid_table", "sub_model":"slanet_plus", "enable":true,// 表格识别功能默认是开启的,如果需要关闭请修改此处的值为"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少儿编程教育行业发展趋势报告.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 文档:
原始文档:
可以看到,提取的结果还是比较符合预期的,图片也都正确提取出来了。
结语
今天通过简单介绍 MinerU 的使用方法的同时,来给大家带来一种文件解析优化的思路,希望能对大家有所启发。
引用链接
[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