文档解析与 Chunking:从固定切分到语义切割

T2-2模块 2 · RAG 工程化面试权重 更新于 2026-08
前置T2-1
关联题目Q2-03Q2-04Q2-05

这篇学完你能回答什么

  • 「chunk 切多大?重叠设多少?依据是什么?」
  • 「固定长度切分会出什么问题?语义切分是怎么做的、值不值得?」
  • 「表格、扫描件、代码这类脏文档怎么进 RAG?」

从一个真实故障讲起

你的员工手册问答系统上线,用户问「试用期多久转正」,系统答不出来。你翻原文,白纸黑字写着:

员工试用期为三个月,考核合格后予以转正。转正后享受完整福利待遇……

排查发现:这句话被切在了两个 chunk 的边界上——「员工试用期为」在第 7 块结尾,「三个月,考核合格后……」在第 8 块开头。两块单独看都不成话,向量化之后都不像答案,检索自然捞不到。

这就是 Chunking 的核心矛盾。切太大:一块里混了七八个主题,向量被稀释成「大概是讲人事的」,检索精度下降,还浪费上下文预算。切太小:语义不完整,代词失去指代(「它」是谁?),模型拿到碎片照样答错。

分块质量是 RAG 效果的天花板之一——后面的 embedding 再强、rerank 再准,都救不回一个被切碎的答案。

一句话被切两半,检索就再也捞不到
员工手册白纸黑字写着「试用期为三个月」,系统却答不出来

  1. 用户提问

    「试用期多久转正」

  2. 原文白纸黑字写着

    「员工试用期为三个月,考核合格后予以转正」

  3. 切在了 chunk 边界断点

    「员工试用期为」在第 7 块尾,后半句在第 8 块头

  4. 两块都不像答案

    向量化之后都捞不到,系统答不出来

切太大一块混七八个主题向量稀释成「大概讲人事的」
切太小语义不完整代词失去指代,拿碎片答错
边界踩中答案两块单独看都不成话,也都不像答案
分块质量是 RAG 效果的天花板之一 —— embedding 再强、rerank 再准,都救不回一个被切碎的答案。而最快的排查动作不是调参,是随机抽 20 个 chunk 人眼读一遍。

上游:先把文档解析干净

面试里很多人直接从「切块」开讲,跳过了解析——这恰恰是生产中最脏最花时间的一环。

文档类型 难点 常用手段
原生 PDF 多栏排版、页眉页脚、跨页段落 pdfplumber / PyMuPDF;先做版面分析再抽文字
扫描件 PDF / 图片 根本没有文字层 OCR;或直接交给多模态模型识别
Word / PPT 样式噪音多 python-docx / python-pptx,保留标题层级
表格 一行行抽出来语义全丢 转 Markdown 表格或整表加一句自然语言摘要
网页 导航栏、广告污染 正文抽取(trafilatura 等)
代码 按行切会切断函数 按 AST 的函数/类边界切

两条实用经验:

  • 保住标题层级。把「一级标题 > 二级标题」作为元数据挂在每个 chunk 上,检索时既能过滤又能在 prompt 里给模型交代上下文——这是投入产出比最高的一招。
  • 表格单独处理。表格拍扁成文本几乎必丢语义。常见做法是整张表存为一个 chunk(Markdown 格式),额外用模型生成一句「本表描述 X 产品各型号的功率参数」作为检索用的摘要向量。

原理拆解:五种切分策略

先用最便宜的切法,贵的等评测说话
固定 / 递归 / 结构 / 语义 / 父子 —— 越往右越贴语义,也越贵

  1. 固定长度切分按字符或 token 数硬切,如每 512 一块
  2. 递归字符切分按优先级尝试分隔符,逐级递归
  3. 结构感知切分按标题、函数与类、报告章节切
  4. 语义切分逐句算 embedding,相似度断崖处下刀
  5. 父子 / 小到大小块去检索,大块去回答
实现越简单,索引越便宜边界越贴语义,代价越高
实现成本硬切,一行代码要多算一层 embedding
语义完整最容易切断句子边界贴着话题转换点
什么时候上只适合原型验证评测显示分块是瓶颈才上

递归字符切分是无脑起步的最优解(LangChain 的 RecursiveCharacterTextSplitter 就是它):先用段落分隔符 \n\n 切,切完还超长就用 \n,再超长用句号,逐级递归到都落进目标大小。它同时兼顾了「尊重自然边界」和「控制长度」。

父子切分一招治两头:用小块(比如 200 token)做向量索引保精度,命中后不给小块,而是回溯它所属的父块(比如整个小节)送进 prompt 保上下文 —— 这是进阶回答里的加分项。

别一上来就用最贵的方案。递归切分做基线,评测显示分块确实是瓶颈时再决定上语义还是父子;而一旦用了结构感知或父子切分,overlap 的必要性也会明显下降。

1. 固定长度切分(Fixed-size)

按字符数或 token 数硬切,比如每 512 token 一块。实现最简单,也最容易切断句子——只适合原型验证,不适合生产

2. 递归字符切分(Recursive)—— 工程默认起点

这是目前最常用的基础策略(LangChain 的 RecursiveCharacterTextSplitter 就是它)。思路是按优先级尝试分隔符:先用段落分隔符 \n\n 切,切完还超长就用 \n,再超长用句号,逐级递归,直到都落在目标大小内。

它兼顾了「尊重自然边界」和「控制长度」,是无脑起步的最优解。

3. 结构感知切分(Structure-aware)

按文档自身结构切:Markdown 按 #/## 标题、代码按函数与类、PDF 报告按章节。规范文档(手册、法规、API 文档)用这招,每个 chunk 天然对应一个完整主题,检索精度往往最高

4. 语义切分(Semantic Chunking)

先按句子切开,逐句计算 embedding,相邻句子相似度出现明显「断崖」的地方就是话题转换点,在那里下刀。

优点是边界最贴合语义;代价是要为每个句子算一次 embedding,索引成本明显上升。实践建议:先用递归切分做基线,只有当评测显示分块确实是瓶颈时再上语义切分——别一上来就用最贵的方案。

5. 父子/小到大切分(Parent-Child / Small-to-Big)

一个很妙的解耦思路:用小块去检索,用大块去回答

把文档切成小块(比如 200 token)做向量索引,检索精度高;命中之后不直接把小块给模型,而是回溯它所属的父块(比如整个小节)送进 prompt,保证上下文完整。

这一招同时治好了「切大了检索不准」和「切小了上下文不全」,是进阶回答里的加分项。

关于 overlap(重叠)

设置相邻 chunk 之间重叠一段内容(比如 chunk 512 token、overlap 64 token),目的就是防开头那个「试用期为三个月」被切两半的事故。

行业惯例是 10%–20% 的重叠作为起点。但要知道一个反面证据:有研究在特定检索配置下测出重叠没带来可测收益,只增加了索引成本。所以正确的态度是——overlap 是默认开启的保险,不是必然有效的银弹,你的评测集说了算。

注意:如果你已经用了结构感知或父子切分,overlap 的必要性会明显下降,因为边界本身就落在语义分界处。

工程实践(截至 2026-08)

参数起点(无评测集时的安全默认):

  • chunk 大小:300–500 token。中文场景注意 token 换算——同样字数中文比英文更耗 token,按字符数设参数容易超预期。
  • overlap:chunk 的 10%–20%(如 512 配 64~100)。
  • 有研究显示 400 token 左右的分块在通用检索上表现稳定(约 88–89% 召回),可作为参考锚点,但不同语料差异很大,务必自测

选型决策

原文示意
文档有清晰结构(Markdown/手册/法规)?
  ├─ 是 → 结构感知切分(按标题层级),元数据带上标题路径
  └─ 否 → 递归字符切分(默认起点)
          └─ 评测显示分块是瓶颈?→ 上语义切分 或 父子切分
特殊类型:代码 → 按 AST 边界;表格 → 整表 + 摘要;扫描件 → OCR/多模态优先

常见坑:

  • 只按字符数不按 token 数设参,中文文档实际长度爆表。
  • 切完不看样本。最有效的排查动作就是随机抽 20 个 chunk 人眼读一遍——语义断裂肉眼可见,比调任何参数都快。
  • 丢掉元数据。chunk 一定要带上来源文件、标题路径、更新时间、权限标签,这些既是过滤条件也是引用溯源的依据。
  • 忘了 embedding 模型有输入上限,chunk 超限会被静默截断。
文档长什么样,就配什么切法
无评测集时的安全默认:300–500 token 一块、10%–20% 重叠

选型决策树
文档情况怎么切补一句
有清晰结构结构感知切分,按标题层级Markdown / 手册 / 法规首选,元数据带上标题路径
没有清晰结构递归字符切分默认起点:兼顾自然边界与长度控制
评测显示分块是瓶颈上语义切分 或 父子切分先有评测结论再上,别一步到位
代码按 AST 的函数 / 类边界切按行切会切断函数
表格整表存一个 chunk(Markdown)+ 一句摘要拍扁成文本几乎必丢语义
扫描件 / 图片OCR,或直接交给多模态模型识别根本没有文字层
参数起点与常见坑
chunk 大小
300–500 token;有研究显示 400 token 左右在通用检索上约 88–89% 召回,可作锚点,但务必自测
overlap
chunk 的 10%–20%(如 512 配 64~100),它是默认开启的保险,不是必然有效的银弹
反面证据
有研究在特定检索配置下测出重叠没带来可测收益,只增加索引成本 —— 你的评测集说了算
中文换算
同样字数中文比英文更耗 token,只按字符数设参,实际长度会爆表
最有效的排查
随机抽 20 个 chunk 人眼读一遍,语义断裂肉眼可见,比调任何参数都快
元数据别丢
来源文件、标题路径、更新时间、权限标签 —— 既是过滤条件,也是引用溯源的依据
还有一个静默杀手:embedding 模型有输入上限,chunk 超限会被直接截断,日志里一声不响。所以定 chunk 大小之前,先去查你那个模型的上限是多少。

面试视角

说 512/64 只是背数字,说验证才是做过
追问路径:chunk 多大 → 怎么验证 → 固定切分的问题 → 表格扫描件怎么办

  1. 先讲那对矛盾太大太小各坏在哪
  2. 给策略谱系固定 / 递归 / 结构 / 语义 / 父子
  3. 报你的参数不只报数字,说清是怎么定的
  4. 给验证方法抽样人眼检查 + 分桶评召回率
只读过:这些答法一问就穿
  • 张口就报「512 / 64」,再问依据答不上 —— 只是记住了数字
  • 直接从切块开讲,跳过解析 —— 生产里最脏最花时间的一环
  • 「语义切分效果最好」—— 不提每个句子都要算一次 embedding
  • 说不出固定切分坏在哪,只说「简单好用」—— 它只适合原型
  • 切完从不看样本,全靠调参 —— 语义断裂本来肉眼可见
真做过:这些话编不出来
  • 参数后面永远跟着验证:抽样人眼检查 + 分桶评召回率
  • 主动提解析:表格转 Markdown 加摘要,扫描件走 OCR / 多模态
  • 讲语义切分时同时报代价:索引成本明显上升,所以后置
  • 点出递归切分才是工程默认起点,固定切分只用来验原型
  • 「长表格类 badcase 集中,才改成整表加摘要」—— 有归因过程
「先递归切分做基线,抽样人眼检查加分桶评召回率,发现长表格类 badcase 集中才改成整表加摘要」 —— 这句话里有归因、有取舍、有代价,背不出来也编不出来。配套题:Q2-03Q2-04Q2-05

典型追问路径:chunk 多大(Q2-03)→ 为什么是这个值、怎么验证的 → 固定切分的问题(Q2-04)→ 语义切分怎么做、成本如何 → 表格/扫描件怎么办(Q2-05)→ 你实际踩过什么坑。

答题结构建议:先讲清「太大太小各坏在哪」这对矛盾 → 给策略谱系(固定/递归/结构/语义/父子)并说明各自适用 → 给出你的参数和验证方法。最后这一步是分水岭:说「512/64」只是记住了数字,说「先递归切分做基线,抽样人眼检查 + 分桶评召回率,发现长表格类 badcase 集中才改成整表加摘要」——这才是做过的人。

配套题目:Q2-03Q2-04Q2-05

小结与延伸

一句话总结:Chunking 的本质是在「语义完整」和「检索精准」之间找平衡点。递归切分是安全起点,结构感知是规范文档的最优解,父子切分是解耦两难的巧招——而所有参数都应该由评测集而不是博客文章决定。

下一篇 T2-3:切好的块要变成向量,Embedding 模型怎么选。

继续深入

本篇归属第 2 章「RAG 工程化」,去做这一章的题