文档chunk切片
- 切片大小配置 (chunk size)
- 分块重叠字符配置 (chunk overlap)
- 分块之间保留一小段的重复内容
- 作用: 防止关键词被分割,相当于做一个边界兼容的处理,保证语义的完整性
为什么大分块会导致不准确
- 大分块chunk会导致噪音问题
- 我以512为单位去查询,最终无论需要多少信息,都是回复512的⻓度,给到LLM
例子:
假设您设置的切片大小是 512 个 Token。
-
用戶查询: "保罗·格雷厄姆大学做了什么?" (答案只有一句话)
-
检索结果: 向量数据库返回了包含答案的那个 512 Token 的大块。
-
问题: 在这 512 个 Token 中,可能只有 20 个 Token 是答案,剩下的 492 个 Token 都是关于他童 年或创业的无关信息(即“噪音”)。
-
LLM 困惑: LLM 接收到这堆“噪音”和查询,虽然它能找到答案,但这些噪音:
- 稀释了上下文: 导致 LLM 在合成答案时引入不必要的细节或偏离焦点。
- 增加了成本: 为这 492 个不必要的 Token 付费
业内一般使用多大的 chunk
- 业内没有一个绝对标准的切片大小,因为最佳大小取决于数据类型和使用场景
- 行业项目一般不会对所有文档统一使用一个chunk来切一次
- 而是按照文档类型选择不同策略
按照文档类型分块
- Unstructured库:支持自动识别类型并分块
| 文档类型 | 实际分块方式 |
|---|---|
| Markdown | 按 H1、H2、H3 标题切分 |
| HTML | 按标题、Section、DOM 结构切分 |
| 按页面布局、标题、段落、表格切分 | |
| Word | 按标题样式和段落切分 |
| PPT | 通常一页或一个内容区域作为一个单元 |
| Excel | 按工作表、表格区域、行组切分 |
| 代码 | 按类、函数、方法切分 |
| 对话记录 | 按连续轮次或会话主题切分 |
| FAQ问答类型 | 一组问题和答案作为一个 Chunk |
Unstructured库识别文档类型拆分
by_title已经根据标题、段落等完整元素组合 Chunk。正常 Chunk 通常具有比较干净的语义边界, 因此可以设置overlap_all=False
| 配置 | 作用 | 简单理解 |
|---|---|---|
chunking_strategy="by_title" | 根据识别出的标题、章节结构进行分块 | 遇到新标题时,尽量开启一个新的 Chunk |
overlap_all=False | 不让所有相邻 Chunk 都产生重叠 | 正常章节之间不重复内容,避免引入噪声 |
overlap=100 | 超长内容被强制拆分时,前后保留 100 个字符的重复内容 | 防止一句话或一个知识点在切片边界处断开 |
from unstructured.partition.auto import partition
chunks = partition(
filename="book.pdf",
chunking_strategy="by_title",
# 字符数,不是 token
max_characters=2000,
new_after_n_chars=1500,
# 合并过短的小章节
combine_text_under_n_chars=300,
# 只在超长元素被强制拆分时重叠
overlap=100,
overlap_all=False,
)
主流文档分块参考
- 问题类的使用 100~300,普通知识库使用 300~600,书籍和论文使用 500~1000 tokens;512 tokens 是最适合普通知识库的通用起点
| 场景 | 建议分块范围 | 建议重叠 | 为什么这样选 |
|---|---|---|---|
| FAQ、问答库 | 100~300 tokens | 20~50 | 每条问答通常只表达一个知识点。小切片可以减少无关内容,提高精确匹配能力 |
| 名词解释、百科词条 | 150~350 tokens | 20~50 | 用户问题通常很短,例如“什么是 HNSW”,小块更容易集中表达一个概念 |
| 普通企业知识库 | 300~600 tokens | 50~100 | 同时兼顾检索精度和上下文完整性,是最常见的通用范围 |
| 产品说明、帮助文档 | 300~600 tokens | 50~100 | 一个操作步骤或功能说明通常能在这个范围内完整表达 |
| 技术文档、API 文档 | 300~700 tokens | 50~120 | 需要保留参数、示例和上下文,但切片太长会混入多个接口或概念 |
| 教程、课程资料 | 400~800 tokens | 80~150 | 教程内容往往前后依赖,需要比 FAQ 保留更多解释过程 |
| 书籍、长篇文章 | 500~1000 tokens | 100~200 | 书籍段落上下文依赖较强,切片过小容易把论述、例子和结论拆开 |
| 规章制度、公司制度 | 300~700 tokens | 50~120 | 应优先保证一个条款完整,同时避免多个不同条款被放进同一个 chunk |
| 法律合同 | 400~800 tokens | 80~150 | 条款中存在定义、条件和例外,切得太小容易改变条款含义 |
| 学术论文 | 500~1000 tokens | 100~200 | 需要保留论点、实验条件、结果和上下文,适合按章节或段落切分 |
| 新闻、短文章 | 200~500 tokens | 30~80 | 信息密度较高,一个 chunk 通常保留一个事件或一个主题即可 |
| 对话、客服记录 | 200~500 tokens | 50~100 | 应按连续对话轮次切分,避免把问题和对应回答拆开 |
| 代码 | 按函数、类切分 | 通常不固定 | 代码必须保持语法和逻辑完整,不适合单纯按照 token 数硬切 |
| 表格 | 按完整表格或行组切分 | 重复表头 | 表头和数据行必须一起保留,否则单独的数据值没有含义 |
| Markdown、HTML | 按标题层级切分,再限制到 300~700 tokens | 50~100 | 标题是天然的语义边界,应保留标题及其正文。LangChain 也提供按 Markdown 标题和 HTML 结构切分的方式。(Docs by LangChain) |
最常见的三个档位
| 分块大小 | 特点 | 适用场景 |
|---|---|---|
| 256 tokens | 检索精准,但上下文较少,chunk 数量多 | FAQ、名词解释、短问题 |
| 512 tokens | 精度与上下文比较均衡 | 普通知识库、技术文档、产品文档 |
| 1024 tokens | 上下文完整,但容易混入多个知识点 | 书籍、论文、复杂制度、长篇教程 |
子父分块
子父分块就是“子块负责精准召回,父块负责完整回答”;它同时兼顾了小 Chunk 的检索精度和大 Chunk 的上下文完整性
用小块找到答案位置,用大块(父块)给模型完整上下文
- 会把同一份文档切成两种粒度
父 Chunk:较大,保存完整上下文
子 Chunk:较小,用于精准检索
- 核心流程是
- 切成较大的父 Chunk
- 每个父 Chunk 再切成多个较小的子 Chunk
文档
↓
切成较大的父 Chunk
↓
每个父 Chunk 再切成多个较小的子 Chunk
↓
对子 Chunk 生成向量
↓
用户查询时检索子 Chunk
↓
根据子 Chunk 找到对应父 Chunk
↓
把父 Chunk 交给大模型回答
为什么子 Chunk 用于检索
- 子 Chunk 内容集中,语义更纯
- 小 Chunk 和用户问题的语义更接近,因此检索更精准
为什么父 Chunk 用于生成
- 父 Chunk 保留了更多上下文
相关问题
- 我假设512为单位切片,但实际上我问的问题很短,对应书里的内容也很短,会不会回复不精准呢?
- 不一定,短问题可以正常匹配 512-token Chunk;影响精准度的不是问题短,而是 Chunk 是否包含答案、以及检索和 Rerank 是否合理
- 检索和 Rerank 方案
- 检索阶段有没有把真正包含答案的 Chunk 找出来
- Rerank 阶段有没有把最相关的 Chunk 排到前面并保留下来
- 检索和 Rerank 方案
- 不一定,短问题可以正常匹配 512-token Chunk;影响精准度的不是问题短,而是 Chunk 是否包含答案、以及检索和 Rerank 是否合理
- 假如我以512切片,最终查询给到LLM的数据大小是512吗
- chunk_size = 512 表示:单个文档切片最多约 512 tokens。
- 它不代表最终只给 LLM 512 tokens。
- 最终给 LLM 的知识库内容,取决于保留了多少个 chunk文档(top-k)
chunk_size = 512
检索 top_k = 10
Rerank 后保留 3 个
- 最终发送给 LLM 的知识库内容大约是
- 512 × 3 ≈ 1536 tokens