首页 > 随笔 > 从 PDF 到可检索:文档解析与分块实战

从 PDF 到可检索:文档解析与分块实战

简书 2026-09-01 01:37 1 阅读 查看原文

「从零到 AI 应用工程师」专栏 · 第 10 篇


RAG 的第一公里不是向量,是干净的文本
PDF 抽出来乱码、表格碎成渣、手册切成互不相关的半句话——后面 Embedding 再强也是「垃圾进、垃圾出」。

今天两件事:解析(ingest)和分块(chunk)。


一、今天要做出什么

输入:一份 Markdown 或 PDF 样例手册。
输出:若干切片,每条至少带:

{ "text": "……切片正文……", "meta": { "doc_id": "文档指纹", "page": 3, "file_type": "pdf", "source": "示例故障码手册.pdf" } } 

验收标准很朴素:能打印出 chunk 数量,抽几条人眼能读懂,页码/来源还在。


二、解析:先变成「页/篇」级文本

Markdown

相对简单:读 UTF-8 → 清洗多余空白 → 往往整篇先当一块,页码下游再标 -1

PDF

按页抽字(常用 pypdf 一类库):

from pypdf import PdfReader def parse_pdf(path: str) -> list[dict]: reader = PdfReader(path) chunks = [] for i, page in enumerate(reader.pages, start=1): text = (page.extract_text() or "").strip() if not text: continue chunks.append({ "text": text, "meta": {"page": i, "file_type": "pdf", "source": path}, }) return chunks 

清洗建议:

  • 去掉页眉页脚水印行(如「第 N 页 | 某某手册」);
  • 折叠过量空行;
  • 入库前脱敏手机号、SN 等(公开演示必备)。

doc_id 可用路径 MD5,保证同一文件多切片可追溯、可按文档删除。


三、分块:为什么不能整本塞进模型

策略 问题
整本进 Prompt 超长、贵、噪声大
切太碎(几十字) 语义残缺,检索飘
切太肥(上千字) 命中后上下文冗余,易带跑偏

工程上常用 递归字符切分:按段落 → 句号 → 逗号 → 空格依次降级切开,并保留 overlap(重叠),减少「答案正好砍在刀口上」。

中文友好分隔符示例:

\n\n → \n → 。 → , → 空格 

一组可作起点的参数(需用评估集再调):

参数 建议起点 含义
chunk_size 500 字左右 单片目标长度
chunk_overlap 100 字左右 相邻重叠
# 伪代码:RecursiveCharacterTextSplitter 一类工具 slices = splitter.split( pages, # 解析结果 chunk_size=500, chunk_overlap=100, ) # 每条继承/补齐 doc_id、page、source 

四、元数据不是可选项

向量库若只存向量、不存原文和 meta,你会失去:

  1. 给大模型看的原文
  2. 页码 / 文件名溯源;
  3. doc_id 过滤或整文档删除;
  4. 按业务类别过滤(手册 / 故障码 / 工单)。

记住:text + meta 一起进下游;向量只是检索钥匙。


五、常见坑

  1. 扫描版 PDF 无文字层 → 抽出来空白,需要 OCR(本专栏先用可选中文字的 PDF)。
  2. 表格被抽成乱序 → 关键表可转 Markdown 或单独策略。
  3. 只按固定字数硬切 → 句子从中断开,检索命中率差。
  4. 忘记 overlap → 跨段知识点经常丢。
  5. 清洗过度 → 把故障码、阈值电压也洗掉了。

六、带走这三条

  1. 解析质量决定上限;向量救不了乱码和空页。
  2. 分块要有重叠、分隔符要适应中文。
  3. meta(doc_id/page/source)与正文同生共死。

下一篇:Embedding 与向量库——切片如何变成可计算的距离,以及 FAISS / pgvector 怎么选。

这是专栏第 10 篇。两到三天一更,向量检索见。