按固定长度切块、按语义切块、按结构切块分别适合什么场景
1️⃣ 考察意图
面试官想考察你对 RAG 系统中 chunking 策略的工程选型能力,而非单纯背概念。刁钻点在于:三种策略不是非此即彼,而是要根据文档类型、检索延迟、语义完整性做 trade-off。答好了能展示你对 RAG 整条链路(从预处理到检索到生成)的实战理解,以及面对非结构化数据时的系统设计思维。
2️⃣ 标准答
核心原则:没有万能 chunking 策略,只有适合场景的取舍。选型时需平衡三个维度:语义完整性(检索质量)、计算成本(embedding + 检索延迟)、实现复杂度。
1. 固定长度切块(Fixed-size Chunking)
- 适合场景:通用新闻、社交媒体帖子、日志文件等语义边界不敏感的文本。
- 为什么这么做:实现简单,O(n) 复杂度,只需设定 token 数(如 256/512)和 overlap(如 10-20%)。适合高吞吐量场景(如实时流处理)。
- 实际落地的坑 + 解法:固定长度会切断句子或段落,导致检索到的 chunk 语义不完整。解法:配合 overlap 策略(如滑动窗口),并在检索后做 rerank(如 Cohere Rerank 3)来过滤噪声。另一个坑:不同语言 token 数差异大(中文 1 token ≈ 1.5 字 vs 英文 1 token ≈ 0.75 字),需按字符数或语言模型 tokenizer 动态调整。
- 工程取舍:牺牲语义完整性换取低延迟和易实现。适合对检索精度要求不高(如 FAQ 匹配)或文档长度均匀的场景。
2. 语义切块(Semantic Chunking)
- 适合场景:学术论文、法律合同、技术文档等需要保持完整语义单元的场景。例如,一个段落或一个对话轮次。
- 为什么这么做:利用 NLP 模型(如 Sentence-BERT、LaBSE)检测句子嵌入的余弦相似度变化,当相似度低于阈值(如 0.7)时切分。或使用 LLM 直接分割(如 GPT-4 识别段落边界)。
- 实际落地的坑 + 解法:计算成本高(embedding 每个句子),且阈值敏感。解法:先按段落(\n\n)粗切,再对长段落做语义微调,减少 embedding 调用次数。另一个坑:多语言文档需用跨语言模型(如 LaBSE)保证一致性。
- 工程取舍:高语义完整性 vs 高计算成本(约 5-10 倍于固定长度)。适合离线索引、对检索质量要求高的场景(如法律检索)。
3. 结构切块(Structure-based Chunking)
- 适合场景:HTML 页面、Markdown 文档、JSON/XML、代码文件等有明确层级结构的文档。
- 为什么这么做:利用标签(
<h1>、<section>)、Markdown 标题(#、##)、代码缩进等作为自然分割点。保留层次信息(如标题-子标题),便于后续做 hierarchical retrieval(先检索父节点再定位子节点)。 - 实际落地的坑 + 解法:结构不完整(如 HTML 缺少闭合标签)或嵌套过深。解法:用 BeautifulSoup 或 lxml 解析后做容错处理,对深层嵌套(如 5 层以上)做扁平化处理。另一个坑:代码文件需考虑函数/类边界,而非仅按行数切分。
- 工程取舍:保留结构信息 vs 依赖文档格式。适合网页抓取、代码库索引等场景。
总结:实际生产环境常混合使用。例如,先按结构切(Markdown 标题),再对长段落做语义微调,最后用固定长度做 fallback。推荐工具:LangChain 的 RecursiveCharacterTextSplitter(按结构递归切分)、LlamaIndex 的 SentenceSplitter(语义切分)。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从三个层面回答:第一,固定长度切块适合通用文本,实现简单但会破坏语义边界,需配合 overlap 和 rerank。第二,语义切块适合学术论文等需要完整语义的场景,但计算成本高,可用段落粗切 + 语义微调优化。第三,结构切块适合 HTML、代码等有层级结构的文档,能保留层次信息。总结一句:实际中常混合使用,按结构粗切、语义微调、固定长度 fallback。”
4️⃣ 高频追问 & 应对
追问 1:如果文档是混合格式(如 Markdown 里嵌了代码块和表格),你怎么设计 chunking 策略?
先做格式识别:用正则或解析器(如
markdown-it)提取代码块(`````)和表格(|),对代码块按函数/类边界切分(如 50-100 行),对表格按行切分(每行一个 chunk),其余文本按结构切(标题)。最后用语义模型做一致性校验,确保代码块不被拆分。trade-off:增加预处理复杂度,但提升代码检索准确率约 20-30%。
追问 2:固定长度切块时,overlap 设多少合适?为什么?
通常设 10-20% 的 token 数(如 512 token 的 chunk 设 50-100 token overlap)。太小(<5%)会导致边界信息丢失,太大(>30%)会增加冗余和 embedding 存储成本。实际调优时,用 NDCG@10 或 Recall@5 做评估,在验证集上 grid search。一个经验值:英文文档 15%,中文文档 20%(因中文语义边界更模糊)。
追问 3:语义切块时,阈值怎么选?如果文档是对话(多轮问答)呢?
阈值通常设 0.6-0.8(余弦相似度),低阈值(0.6)切得更细,适合长文档;高阈值(0.8)切得更粗,适合短文档。对话场景需特殊处理:按轮次(
user/assistant)切分,而非按句子相似度,因为同一轮对话内语义可能跳跃(如用户问 A,助手答 B)。推荐用 对话轮次检测(如turn_id)结合语义模型做二次校验。
5️⃣ 避坑 · 常见错误答法
- ❌ 说“固定长度切块最好,因为简单” → ✅ 应指出“简单但会破坏语义,需配合 overlap 和 rerank,适合低精度场景”。
- ❌ 说“语义切块用 BERT 就行” → ✅ 应具体到模型(如 Sentence-BERT
all-MiniLM-L6-v2)和阈值调优方法。 - ❌ 说“结构切块只适合 HTML” → ✅ 应扩展到 Markdown、JSON、代码文件,并提到层次化检索。
6️⃣ 简历呼应
- 如果你有 RAG 项目:从“我在项目中对比了三种 chunking 策略,发现结构切块 + 语义微调在检索准确率上提升 15%,但延迟增加 2 倍,最终用固定长度 fallback 做平衡”切入。
- 如果你只做过传统 NLP:用“文本分类中的句子分割类比 chunking,固定长度类似滑动窗口,语义切块类似基于相似度的聚类”迁移。
- 如果你是校招无项目:聚焦“复现了 LangChain 的 RecursiveCharacterTextSplitter 源码,并对比了三种策略在 WikiQA 数据集上的 Recall@5 差异”。
- LangChain 官方文档:RecursiveCharacterTextSplitter 与 SentenceSplitter 实现
- 论文:Chunking Strategies for Retrieval-Augmented Generation (2024)
- 博客:RAG 系统 Chunking 策略对比与调优(知乎/Medium)
- 工具:LlamaIndex 的 SentenceSplitter 与 HierarchicalNodeParser
- 论文:Dense Passage Retrieval (DPR) 中的段落切分策略