切分方式,是 RAG 系统里最早、也最难回头的选择
在 RAG 项目里,切分方式通常是最早被确定的部分之一:
-
文档进来
-
切一切
-
建向量
-
后面再慢慢调
而且在当时,这个选择往往显得并不重要:
“反正后面还有 embedding、TopK、rerank、模型兜底。”
但你只要做过一两个完整项目,就会慢慢意识到一件事:
**切分方式不是一个“前处理细节”,
而是整个系统如何理解世界的第一步。**
尤其是在 语义切分 和 结构切分 之间,
它们的差异,远远不只是“切得聪不聪明”。
先给一个非常明确的结论(一定要先看)
在展开之前,我先把这篇文章最重要的一句话写出来:
**语义切分和结构切分的差异,
不在“切得准不准”,
而在“谁在为理解负责”。**
如果你只用“召回效果”来比较这两种方式,
你一定会选错。
第一层:两种切分方式,到底在做什么(先对齐认知)
我们先不用任何评价,只说事实。
基于结构的切分
结构切分依赖的是:
-
标题
-
段落
-
列表
-
HTML / Markdown 结构
-
文档层级
它的核心假设是:
文档作者已经帮你做过一次“语义组织”。
切分做的事情是:
-
尊重原始组织方式
-
不跨越结构边界
-
尽量保持上下文完整性
基于语义的切分
语义切分依赖的是:
-
embedding 相似度
-
语义边界检测
-
内容相似性聚类
它的核心假设是:
模型比文档结构更懂“哪里该断”。
切分做的事情是:
-
打破原始结构
-
按“语义连续性”重新分块
-
追求 chunk 内语义一致
结构切分 vs 语义切分 示意
第二层:语义切分的“聪明”,来自哪里
先说清楚语义切分为什么这么吸引人。
在很多 demo 或小样本测试中,语义切分往往表现得非常好:
-
chunk 内主题集中
-
相似问题召回更稳定
-
Top1 看起来“更准”
这是因为语义切分擅长做一件事:
**把“看起来相关的内容”,
紧密地绑在一起。**
在以下场景中,它非常有优势:
-
FAQ
-
知识点型文档
-
概念解释类内容
你会明显感觉到:
“模型好像更懂了。”
但这个“懂”,是有前提条件的。
第三层:结构切分的“笨”,其实是一种约束
结构切分经常被嫌弃:
-
chunk 里内容不够集中
-
有些地方看起来“多余”
-
召回结果不如语义切分“干净”
但这些“缺点”,其实来自它的一个核心特性:
它不替你重新组织意义。
结构切分选择的是:
-
保留作者的表达顺序
-
保留条件、例外、上下文
-
哪怕它们看起来“不够语义纯净”
这意味着:
**结构切分,把“理解责任”,
明确地留给了模型和系统。**
而不是提前在切分阶段“替模型做决定”。
第四层:真正的分水岭——“责任转移”发生在切分阶段
这是很多人没意识到的关键点。
当你选择 语义切分 时,你其实在做一件事:
**把“哪些内容应该被放在一起”的判断,
提前交给了 embedding 模型。**
这意味着:
-
切分阶段已经做了一次“隐式理解”
-
后续系统默认这个理解是对的
而当你选择 结构切分 时:
你刻意避免在切分阶段做理解判断。
你说的是:
-
“我尊重原文”
-
“理解发生在后面”
这两种选择,决定了后面系统犯错的方式完全不同。
第五层:语义切分,如何系统性放大“适用范围错误”
这是语义切分在工程中最危险的地方。
语义切分往往会:
-
把相似主题的内容合并
-
把“规则 + 例外”拆散
-
或把“条件语句”与上下文分离
结果是:
-
chunk 内语义一致
-
但逻辑条件丢失
模型面对的是:
一个“看起来完整,但缺乏边界”的知识块。
于是模型很容易:
-
把局部规则当成全局规则
-
把“在某些情况下成立”
当成“普遍成立”
这类错误往往:
-
不明显
-
不好评估
-
非常像“模型理解错误”
但实际上:
理解已经在切分阶段被误导了。
第六层:结构切分,如何把风险“暴露”出来
相比之下,结构切分更容易产生的问题是:
-
信息看起来分散
-
需要多个 chunk 才能拼出结论
-
模型更容易说“不知道”
但从风险角度看,这是一个更健康的失败模式。
因为:
-
模型能感知信息不足
-
证据缺失更容易被察觉
-
TopK 的问题更容易定位
换句话说:
**结构切分更容易失败,
但失败得更诚实。**
第七层:TopK 介入后,两种切分方式的差异被进一步放大
TopK 的作用是:
从“候选世界”里选 K 个最相关 chunk。
但它不会:
-
判断 chunk 内部是否自洽
-
判断 chunk 之间是否冲突
在语义切分下:
- TopK 往往召回多个
“语义高度相似的大块”
-
冲突被掩盖
-
模型更敢综合
在结构切分下:
- TopK 更像是
“上下文片段集合”
- 冲突和缺失更容易显现
这意味着:
**TopK 在语义切分中是“放大器”,
在结构切分中更像“探照灯”。**
TopK × 切分方式 行为差异
第八层:一个极简伪代码,看责任是怎么被提前决定的
# 语义切分
chunks = semantic_split(document)
# chunk 已被 embedding 判定“语义完整”
# 结构切分
chunks = structural_split(document)
# chunk 只是原文片段
这两行代码的差异在于:
- 第一种:
> chunk 本身就带着“理解假设”
- 第二种:
> chunk 只是原始材料
后面你再怎么 rerank、再怎么 prompt,
都已经是在这个前提之上修修补补。
第九层:什么时候语义切分是“更合理的选择”
说清楚风险,不代表否定它。
语义切分在以下场景中,往往是合适的:
-
知识点高度独立
-
文档结构本身混乱
-
内容天然是“平铺式”的
-
错误成本相对低
一句话总结:
**当“适用范围错误”不是主要风险时,
语义切分可以提高效率。**
第十层:什么时候结构切分是“更安全的选择”
结构切分更适合:
-
强规则文档
-
有大量条件、例外
-
法规、流程、说明书
-
错误成本高的场景
因为它的核心优势是:
**不替你理解,
也不替你犯错。**
一个非常实用的判断问题(强烈建议)
在你决定用哪种切分方式前,可以问自己一句话:
**如果模型答错了,
我更希望错误来自
“没看到”,
还是
“看错了”?**
-
“没看到” → 结构切分
-
“看错了” → 语义切分风险更大
这个问题,比任何指标都重要。
很多团队在 RAG 项目中选择语义切分,是因为它在早期 demo 中更“好看”,但长期风险往往被低估。用LLaMA-Factory online对比不同切分策略下的模型输出,更容易判断:你的系统是在“提前理解”,还是在“诚实暴露不确定性”。
总结:切分方式,决定系统将以什么方式犯错
我用一句话,把这篇文章彻底收住:
**语义切分和结构切分的区别,
不在于谁更聪明,
而在于:
谁替你做了决定。**
当你开始:
-
把切分当成“责任分配”
-
而不是“文本处理”
-
在系统早期就思考“错误形态”
你才真正开始工程化地设计 RAG 系统。