RAG 切 PDF:全文入库还是抽字段?一个反直觉的结论
做 RAG 时最先要做的决定不是选向量库,是决定 PDF 切完之后存什么。全文入库和结构化提取是两条完全不同的路,医疗场景的数据把这个问题讲得很清楚。
做 RAG 项目的时候,大部分人的注意力都在选型上:Milvus 还是 Chroma,用哪个 Embedding 模型,Top-K 设多少。
这些都是后面的事。最先要做的决定其实是:PDF 解析完之后,你到底往库里存什么。
这个问题有两条完全不同的路,选错了后面全要推倒重来。
两条路
全文切割入库:PDF → 提取文本 → 按策略切成 chunk → 向量化 → 入库。你保留的是文档的完整内容,检索的时候靠语义相似度去命中。
结构化提取入库:不存全文,用 LLM 把关键字段抽出来,以 JSON 形式入库。比如一份影像报告,抽出来的可能是评分、肿瘤大小、位置、淋巴结状态这四个字段。
大多数教程只讲第一条路,因为它通用。但第二条路在某些场景下是对的唯一答案。
全文切割的几种策略
如果走全文这条路,切割策略直接决定检索质量。常见的有四种:
- 固定大小:按固定 token 数切,带 overlap。快,但会把一句话拦腰截断
- 语义切割:按句子或段落边界切,相似内容合并。精度高,实现麻烦
- 递归切割:先粗分,超长的块再细分。适合长文档
- 按结构切割:顺着标题、章节的层级切。适合论文、白皮书这种本身有结构的文档
实践里用得最多的是递归切割,因为它是这几者里性价比最高的:
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=512,
chunk_overlap=50,
separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""]
)
chunks = text_splitter.split_text(pdf_text)
注意 chunk_overlap。新手经常设成 0,结果一个关键信息刚好跨在两个 chunk 的边界上,两个 chunk 各有半句,检索的时候哪个都命中不了。50 到 100 的重叠是常见的取值范围。
还有一个容易被忽略的点:separators 里要不要放中文标点。上面这个配置里放了 。!?;,,这是处理中文文档必须做的——默认的英文分隔符对中文段落基本不起作用,最后你会得到一整段 5000 字的 chunk。
结构化提取长什么样
结构化这条路的关键是 prompt。以影像报告为例:
从以下影像报告文本中提取:
1. BT-RADS 评分
2. 肿瘤大小
3. 位置描述
4. 淋巴结状态
报告文本:{report_text}
返回 JSON 格式。
输出就是一个干净的结构体。医生问”最近 EGFR 突变阳性的患者有多少”这种问题时,只有这条路能答——全文切割入库根本没法做统计类查询。
一组反直觉的数据
这是我这篇最想记下来的东西。
有研究拿 7294 份影像报告和 2154 份病理报告做了对比,结果和我预期的方向相反:
| 报告类型 | RAG 的效果 | 原因 |
|---|---|---|
| 影像报告(短) | 反而略降 | 报告本身就很短,检索引入了噪声 |
| 病理报告(长、复杂) | 提升 48% | 需要从长文本里精准定位相关信息 |
短报告上 RAG 反而拖后腿,这件事值得停下来想一下。
我们默认”RAG 一定比直接塞上下文好”,其实前提是文档长到上下文放不下、或者放得下但噪声太多。当文档本身很短、直接全塞进上下文毫无压力的时候,RAG 的检索环节引入的每一个不相关 chunk 都是负资产。
所以判断要不要上 RAG,先看你的文档长度分布,而不是看别人都在做 RAG。
医疗场景的特殊之处
医疗是这个问题上张力最大的领域,因为它同时要两样互相冲突的东西:完整保留上下文和精准提取关键信息。
患者问”这个药有什么副作用”,需要的是开放式的、带上下文的回答,全文切割合适。医生问”最近三个月 EGFR 突变阳性的患者有多少”,需要的是精确的字段统计,只有结构化提取能做。
我目前的结论是这两条路不是二选一,而是都要,按查询类型路由。判断逻辑可以很简单:查询里带统计意图(多少、比例、均值)的走结构化,带语义意图(为什么、怎么办、有什么副作用)的走向量检索。
这个判断本身也可以交给 LLM 做,代价是多一次调用。
我踩过的坑
表格被切烂了。 PDF 里的表格用常规文本提取出来会变成一串没有结构的文字,再切成 chunk 之后基本不可用。后来是先做表格识别、把表格单独转成 markdown 或者结构化数据,剩下的正文再走切割流程。
页眉页脚混进正文。 医疗报告每页都有医院名、页码、打印时间。这些东西不清理,会污染 embedding,而且因为每一页都有,它们在向量空间里的存在感反而很强。清理规则看起来很土,但不做不行。
扫描件。 有一部分 PDF 是扫描的,直接提取出来是空的或者乱码。要先判断是不是文本层缺失,是的话走 OCR。OCR 的错误会一路传下去,所以 OCR 质量要单独抽检。
小结
把决策过程压缩成三个问题:
- 用户会问统计类问题吗?会 → 必须有结构化提取这条路
- 文档普遍很短吗?是 → 先试试不检索直接塞上下文,别默认上 RAG
- PDF 里有表格和扫描件吗?有 → 解析层的工作量会超过你预期,单独排期
选型(向量库、Embedding 模型)当然也重要,但相对于”存什么”这个决定,它们都算细节。
关注我