为什么要文本分块?
先说不分块会怎样
假设你有一本 500 页的技术手册,用户问了一个问题,你把整本书塞给大模型:
问题 1:上下文窗口装不下
大模型有 token 限制(比如 GPT-4 是 128k tokens,约 10 万汉字)。一个稍大点的企业知识库轻松就有几千万字,根本塞不进去。
问题 2:即使装得下,效果也很差
研究表明,大模型对超长上下文的处理能力会显著下降——中间部分的内容容易被”遗忘”,这个现象叫 Lost in the Middle(中间丢失问题)。
开头内容← 模型注意力强,记得好
中间内容← 模型注意力弱,容易忽略 ⚠️
结尾内容← 模型注意力强,记得好
问题 3:检索精度极差
RAG 的核心是”检索相关内容”。如果不分块,每个文档就是一个整体向量。用户问一个很细的问题,返回的是整篇文章的向量,语义高度稀释,根本找不准。
不分块:用户问”退款政策是几天?”
→ 检索到《用户服务协议》整篇(8000字)
→ 相关内容只占 2%,大量噪音
分块后:用户问”退款政策是几天?”
→ 精准检索到”7.3 退款条款:用户可在购买后7天内申请退款”这一小段
→ 信噪比极高
问题 4:成本爆炸
每次查询都把整篇文档塞入 LLM,token 费用会高出几十倍甚至上百倍。
分块的本质是什么?
分块解决的核心问题是:让每个向量只代表一个”语义单元”。
向量是对文本语义的压缩表示。文本越长,压缩进一个向量里的信息越杂,语义越模糊,检索匹配就越不准。
一个块的最佳状态:
内容聚焦 → 向量语义清晰 → 检索时能精准命中
一整篇文章作为一个块:
内容庞杂 → 向量语义稀释 → 检索时什么都沾点边,什么都不准
可以类比搜索引擎的索引逻辑——Google 索引的是网页中的段落和句子,而不是整个网站的全部内容打成一个向量。
分块大小怎么取舍?
分块也不是越小越好:
| 分块太小 | 分块太大 |
|---|---|
| 语义不完整,上下文断裂 | 语义稀释,检索不精准 |
| 召回的内容缺乏背景,模型无法理解 | 噪音多,影响生成质量 |
| 需要召回更多块,成本上升 | token 占用大,成本上升 |
实践中有一个常用技巧叫 父子分块(Parent-Child Chunking):父子扩展
检索时用小块(语义精准,容易命中)
↓ 命中后
送给模型时用大块(上下文完整,理解准确)
比如索引时切成 128 token 的小块,命中后自动扩展返回它所在的 512 token 父块给 LLM,兼顾检索精度和上下文完整性。
一句话总结
分块 = 把大海捞针变成从小盒子里找针。 不分块的话,针在大海里,即使找到了那片海,针还是在里面找不着。