这篇学完你能回答什么
- 「chunk 切多大?重叠设多少?依据是什么?」
- 「固定长度切分会出什么问题?语义切分是怎么做的、值不值得?」
- 「表格、扫描件、代码这类脏文档怎么进 RAG?」
从一个真实故障讲起
你的员工手册问答系统上线,用户问「试用期多久转正」,系统答不出来。你翻原文,白纸黑字写着:
员工试用期为三个月,考核合格后予以转正。转正后享受完整福利待遇……
排查发现:这句话被切在了两个 chunk 的边界上——「员工试用期为」在第 7 块结尾,「三个月,考核合格后……」在第 8 块开头。两块单独看都不成话,向量化之后都不像答案,检索自然捞不到。
这就是 Chunking 的核心矛盾。切太大:一块里混了七八个主题,向量被稀释成「大概是讲人事的」,检索精度下降,还浪费上下文预算。切太小:语义不完整,代词失去指代(「它」是谁?),模型拿到碎片照样答错。
分块质量是 RAG 效果的天花板之一——后面的 embedding 再强、rerank 再准,都救不回一个被切碎的答案。
用户提问
「试用期多久转正」
原文白纸黑字写着
「员工试用期为三个月,考核合格后予以转正」
切在了 chunk 边界断点
「员工试用期为」在第 7 块尾,后半句在第 8 块头
两块都不像答案
向量化之后都捞不到,系统答不出来
上游:先把文档解析干净
面试里很多人直接从「切块」开讲,跳过了解析——这恰恰是生产中最脏最花时间的一环。
| 文档类型 | 难点 | 常用手段 |
|---|---|---|
| 原生 PDF | 多栏排版、页眉页脚、跨页段落 | pdfplumber / PyMuPDF;先做版面分析再抽文字 |
| 扫描件 PDF / 图片 | 根本没有文字层 | OCR;或直接交给多模态模型识别 |
| Word / PPT | 样式噪音多 | python-docx / python-pptx,保留标题层级 |
| 表格 | 一行行抽出来语义全丢 | 转 Markdown 表格或整表加一句自然语言摘要 |
| 网页 | 导航栏、广告污染 | 正文抽取(trafilatura 等) |
| 代码 | 按行切会切断函数 | 按 AST 的函数/类边界切 |
两条实用经验:
- 保住标题层级。把「一级标题 > 二级标题」作为元数据挂在每个 chunk 上,检索时既能过滤又能在 prompt 里给模型交代上下文——这是投入产出比最高的一招。
- 表格单独处理。表格拍扁成文本几乎必丢语义。常见做法是整张表存为一个 chunk(Markdown 格式),额外用模型生成一句「本表描述 X 产品各型号的功率参数」作为检索用的摘要向量。
原理拆解:五种切分策略
- 固定长度切分按字符或 token 数硬切,如每 512 一块
- 递归字符切分按优先级尝试分隔符,逐级递归
- 结构感知切分按标题、函数与类、报告章节切
- 语义切分逐句算 embedding,相似度断崖处下刀
- 父子 / 小到大小块去检索,大块去回答
递归字符切分是无脑起步的最优解(LangChain 的 RecursiveCharacterTextSplitter 就是它):先用段落分隔符 \n\n 切,切完还超长就用 \n,再超长用句号,逐级递归到都落进目标大小。它同时兼顾了「尊重自然边界」和「控制长度」。
父子切分一招治两头:用小块(比如 200 token)做向量索引保精度,命中后不给小块,而是回溯它所属的父块(比如整个小节)送进 prompt 保上下文 —— 这是进阶回答里的加分项。
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 超限会被静默截断。
| 文档情况 | 怎么切 | 补一句 |
|---|---|---|
| 有清晰结构 | 结构感知切分,按标题层级 | Markdown / 手册 / 法规首选,元数据带上标题路径 |
| 没有清晰结构 | 递归字符切分 | 默认起点:兼顾自然边界与长度控制 |
| 评测显示分块是瓶颈 | 上语义切分 或 父子切分 | 先有评测结论再上,别一步到位 |
| 代码 | 按 AST 的函数 / 类边界切 | 按行切会切断函数 |
| 表格 | 整表存一个 chunk(Markdown)+ 一句摘要 | 拍扁成文本几乎必丢语义 |
| 扫描件 / 图片 | OCR,或直接交给多模态模型识别 | 根本没有文字层 |
- chunk 大小
- 300–500 token;有研究显示 400 token 左右在通用检索上约 88–89% 召回,可作锚点,但务必自测
- overlap
- chunk 的 10%–20%(如 512 配 64~100),它是默认开启的保险,不是必然有效的银弹
- 反面证据
- 有研究在特定检索配置下测出重叠没带来可测收益,只增加索引成本 —— 你的评测集说了算
- 中文换算
- 同样字数中文比英文更耗 token,只按字符数设参,实际长度会爆表
- 最有效的排查
- 随机抽 20 个 chunk 人眼读一遍,语义断裂肉眼可见,比调任何参数都快
- 元数据别丢
- 来源文件、标题路径、更新时间、权限标签 —— 既是过滤条件,也是引用溯源的依据
面试视角
- 先讲那对矛盾太大太小各坏在哪
- 给策略谱系固定 / 递归 / 结构 / 语义 / 父子
- 报你的参数不只报数字,说清是怎么定的
- 给验证方法抽样人眼检查 + 分桶评召回率
- 张口就报「512 / 64」,再问依据答不上 —— 只是记住了数字
- 直接从切块开讲,跳过解析 —— 生产里最脏最花时间的一环
- 「语义切分效果最好」—— 不提每个句子都要算一次 embedding
- 说不出固定切分坏在哪,只说「简单好用」—— 它只适合原型
- 切完从不看样本,全靠调参 —— 语义断裂本来肉眼可见
- 参数后面永远跟着验证:抽样人眼检查 + 分桶评召回率
- 主动提解析:表格转 Markdown 加摘要,扫描件走 OCR / 多模态
- 讲语义切分时同时报代价:索引成本明显上升,所以后置
- 点出递归切分才是工程默认起点,固定切分只用来验原型
- 「长表格类 badcase 集中,才改成整表加摘要」—— 有归因过程
Q2-03、Q2-04、Q2-05。小结与延伸
一句话总结:Chunking 的本质是在「语义完整」和「检索精准」之间找平衡点。递归切分是安全起点,结构感知是规范文档的最优解,父子切分是解耦两难的巧招——而所有参数都应该由评测集而不是博客文章决定。
下一篇 T2-3:切好的块要变成向量,Embedding 模型怎么选。
继续深入
本篇归属第 2 章「RAG 工程化」,去做这一章的题。