你现在可能在用什么,以及它为什么不够好
搭本地 RAG 知识库的标准流程,大多数人是这样的:
PDF → LangChain PyPDFLoader → 分块 → 向量化 → 检索
看起来没问题,但实际跑起来会发现:
- 图文混排的论文,表格内容被读成一行乱码
- 公式密集的数学/物理论文,全部变成 ∑ ( x i − μ ) 2 这种残缺符号
- 双栏 PDF(大部分 ACL、NeurIPS 论文),左右两栏内容被混在一起,语义完全断了
- 扫描版论文(老文献、学位论文),直接读不出来
结果是:你的 RAG 不是不能用,是用的那部分数据根本就是错的。
各工具横向对比
这是目前学术场景下最常被用到的几个方案:
| 工具 | 双栏论文 | 公式识别 | 表格还原 | 扫描件 OCR | 本地部署 | 上手难度 |
|---|---|---|---|---|---|---|
| MinerU | ✅ 版面分析自动识别 | ✅ LaTeX 输出 | ✅ 结构完整还原 | ✅ 内置 | ✅ pip 安装 | ⭐ 低 |
| PyMuPDF | ⚠️ 不处理栏序 | ❌ 丢失 | ⚠️ 仅文本 | ❌ | ✅ | ⭐ 低 |
| PyPDF2 / pypdf | ❌ | ❌ | ❌ | ❌ | ✅ | ⭐ 低 |
| Marker | ✅ | ⚠️ 部分支持 | ⚠️ | ✅ | ✅ | ⭐⭐ 中 |
| Unstructured | ⚠️ | ❌ | ⚠️ | ✅(需付费 API) | ⚠️ 复杂 | ⭐⭐⭐ 高 |
| Mathpix | ✅ | ✅ | ✅ | ✅ | ❌ 必须联网 | ⭐⭐ 中 |
| GPT-4o 直读 | ✅ | ✅ | ✅ | ✅ | ❌ | ⭐ 低(但贵) |
结论:
- 追求快、不在乎质量 → PyMuPDF
- 愿意花钱、不介意隐私 → GPT-4o
- 要本地、要精度、要免费 → MinerU
实战:从零到可用的论文 RAG,全流程
第一步:安装
首次运行会下载模型(约 1-2GB),之后全离线。
第二步:解析一篇 arXiv 论文
from mineru import DocumentParser
parser = DocumentParser()
# 解析单篇论文
result = parser.parse("attention_is_all_you_need.pdf")
print(result.markdown) # 输出干净的 Markdown
输出示例(Transformer 原论文片段):
## 3.2 Attention
An attention function can be described as mapping a query and a set of key-value pairs to an output...
$\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V$
| Model | BLEU EN-DE | BLEU EN-FR | Training Cost (FLOPs) |
|-------|-----------|-----------|----------------------|
| Transformer (big) | 28.4 | 41.0 | 2.3 × 10^19 |
| ByteNet | 23.75 | — | — |
公式是 LaTeX 格式,表格是标准 Markdown 表格——这两样东西是大多数工具给不了的。
第三步:批量处理一批论文
import os
from mineru import DocumentParser
from pathlib import Path
parser = DocumentParser()
pdf_dir = Path("./papers")
output_dir = Path("./parsed")
output_dir.mkdir(exist_ok=True)
for pdf_file in pdf_dir.glob("*.pdf"):
result = parser.parse(str(pdf_file))
output_path = output_dir / (pdf_file.stem + ".md")
output_path.write_text(result.markdown)
print(f"✅ {pdf_file.name}")
50 篇论文大概 3-5 分钟(CPU),有 GPU 的话更快。
第四步:接入 RAG(以 LangChain + ChromaDB 为例)
from langchain.document_loaders import DirectoryLoader, UnstructuredMarkdownLoader
from langchain.text_splitter import MarkdownHeaderTextSplitter
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings # 或换成本地模型
# 加载 MinerU 解析好的 Markdown 文件
loader = DirectoryLoader("./parsed", glob="**/*.md",
loader_cls=UnstructuredMarkdownLoader)
docs = loader.load()
# 按标题层级分块(保留论文结构)
splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=[
("#", "title"),
("##", "section"),
("###", "subsection")
]
)
chunks = []
for doc in docs:
chunks.extend(splitter.split_text(doc.page_content))
# 向量化存储
vectorstore = Chroma.from_documents(chunks, OpenAIEmbeddings())
# 查询
results = vectorstore.similarity_search("What is the attention mechanism?", k=3)
关键点: 用 MarkdownHeaderTextSplitter 而不是普通的字符分块,因为 MinerU 输出的 Markdown 标题结构和论文章节完全对应,按标题分块语义更完整。
一个真实的对比
同一篇论文(NeurIPS 2023,含大量公式和表格),用三种方式解析后喂进同一个 RAG,问同一个问题:
问题: "这篇论文的主要实验结果是什么?"
| 解析方式 | RAG 回答质量 | 问题 |
|---|---|---|
| PyPDFLoader | ⚠️ 答案含糊 | 表格数字全丢了,模型只能靠文字部分回答 |
| Marker | 🟡 基本正确 | 公式没能完整保留,数学推导部分缺失 |
| MinerU | ✅ 准确完整 | 表格数据和公式都在,模型能引用具体数字 |
适合什么人
在用 Zotero 管理文献,想加一层 AI 问答
-
在跑实验,需要快速检索几十篇 related work
-
在写综述,想让 AI 帮你归纳某个领域的方法演进
-
导师发了一堆 PDF 让你消化,需要快速提炼关键信息
不适合什么情况
-
论文全是英文扫描版且质量极差(这种情况任何工具都费劲)
-
只需要读摘要(直接用 arXiv API 拿 abstract 就够了)
-
对延迟极度敏感(MinerU 首次加载模型有几秒预热)
GitHub: github.com/opendatalab…
pip install mineru — 就这一行,今天就能跑起来。