深入理解RAG:文本分片(Chunking)

前言

上一篇我们已经详细讲解了RAG的总体流程和第一步:文件解析

那么接下来我们来深入研究文本分片与向量化

一、为什么要分片(Chunking)?

1.1 向量语义的"稀释效应" (Semantic Dilution)

原理 :Embedding 模型将文本映射为一个固定长度的向量(如 1536 维)。这个向量本质上是文本所有语义的加权平均

  • 场景 A(不分片) :一本 10 万字的员工手册 -> 1 个向量。
    • 结果:这个向量代表了"手册的整体氛围",但丢失了"年假具体几天"的细节。向量空间中的位置会偏向"中心",与任何具体问题的相似度都不高。
    • 比喻:把"苹果、香蕉、橘子、冰箱、电视"全部榨成一杯果汁。你再也尝不出苹果的味道了。
  • 场景 B(分片) :手册切成 200 个段落 -> 200 个向量。
    • 结果:其中有一个向量专门代表"年假政策"。当用户问"年假"时,能精准匹配到这个向量。
    • 比喻:水果切块。想吃苹果就捞苹果块。

结论 :分片是为了保持向量语义的纯度 (Semantic Purity)。文本越短,向量代表的意图越单一,检索越精准。

1.2 Embedding 模型的输入硬限制 (Input Limit)

事实:所有的 Embedding 模型都有最大输入长度限制。

模型 最大输入 Tokens 后果
text-embedding-ada-002 8191 超过部分会被截断 (Truncated)
text-embedding-3-small 8191 超过部分会被截断
bge-large-zh 512 超过部分会被截断 (注意!很多中文模型限制较小)

风险:如果你不分片,直接送入 1 万字的文档给限制 512 的模型:

  1. 报错:API 直接返回 Error。
  2. 静默失败:模型只计算前 512 个 Token,后面 9000 字完全被忽略。你的知识库实际上丢失了 90% 的内容。

结论 :分片是为了适配模型物理限制,防止数据丢失。

1.3 LLM 的"中间丢失"现象 (Lost in the Middle)

研究发现 :LLM 在处理长上下文时,对开头结尾 的信息记忆最深,对中间的信息容易忽略。

  • 不分片 :检索返回 5 万字的文档给 LLM。关键信息在第 2 万字处。
    • 结果:LLM 大概率忽略关键信息,产生幻觉。
  • 分片 :检索返回 5 个 1000 字的片段。关键信息在某一片段的开头。
    • 结果:LLM 能清晰看到关键信息。

结论 :分片是为了优化 LLM 的注意力机制,提高生成质量。

1.4 噪声抑制与成本 (Noise & Cost)

  • 噪声:文档中包含大量无关内容(页眉、页脚、免责声明)。不分片会将噪声与正文一起向量化,干扰检索。
  • 成本 :LLM 按 Token 收费。
    • 不分片:每次问答输入 10,000 Tokens -> 成本高,速度慢。
    • 分片:每次问答输入 5 x 500 Tokens = 2,500 Tokens -> 成本低,速度快

二、主流分片策略

我们将策略分为naive (朴素) heuristic (启发式)和 semantic (语义式)三类。

2.1 固定长度分片 (Fixed-Size Chunking)

算法逻辑

python 复制代码
def fixed_chunk(text, size):
    return [text[i:i+size] for i in range(0, len(text), size)]

深度分析

  • 优点:计算复杂度 O(n),速度最快,实现最简单。
  • 缺点语义破坏者
    • 例子size=10。文本"我喜欢吃苹果"。
    • 切片 1:"我喜欢吃"
    • 切片 2:"苹果"
    • 如果用户搜"喜欢吃苹果",向量匹配度会下降,因为语义被切断了。
    • 中文灾难:可能在汉字中间切断(如果是按字节),或在词语中间切断。
  • 适用场景几乎不推荐用于 RAG。仅适用于日志分析或对语义不敏感的场景。

2.2 递归字符分片 (Recursive Character Chunking) ------ 工业界标准

算法逻辑 : 维护一个分隔符列表 separators = ["\n\n", "\n", " ", ""]

  1. 尝试用 separators[0] (\n\n) 分割文本。
  2. 如果分割后的片段长度 <= chunk_size,保留。
  3. 如果片段长度 > chunk_size,对该片段递归使用 separators[1] (\n) 分割。
  4. 以此类推,直到用完所有分隔符。
  5. 如果最后还太大,强制按字符切断。

深度分析

  • 优点语义保持最好。优先保留段落,其次保留句子。符合人类阅读习惯。
  • 缺点:计算稍慢(递归),需要调整分隔符列表。
  • 适用场景90% 的通用 RAG 场景(文档、手册、文章)。
  • Spring AI 实现RecursiveCharacterTextSplitter

2.3 语义分片 (Semantic Chunking)

算法逻辑

  1. 将文本按句子分割。
  2. 计算每个句子的 Embedding。
  3. 计算相邻句子的余弦相似度
  4. 如果相似度低于阈值(如 0.5),说明语义发生了跳跃,在此处切断。

深度分析

  • 优点语义连贯性最强。保证每个 Chunk 内部话题一致。
  • 缺点成本极高。需要预先计算所有句子的 Embedding。如果文档更新,需要重新计算所有。
  • 适用场景: 高质量知识库、对精度要求极高、预算充足的场景。
  • Spring AI 实现 :需自定义 DocumentTransformer 实现此逻辑。

2.4 父子分片 (Parent-Child / Small-to-Big)

算法逻辑: 建立两层索引。

  1. Parent Chunk:大块文本(如 2000 字),包含完整上下文。
  2. Child Chunk:小块文本(如 200 字),用于检索。
  3. 关联:Child 记录 Parent 的 ID。

检索流程

  1. 用户查询 -> 匹配到 Child Chunk (因为小,向量准)。
  2. 系统通过 ID 找到对应的 Parent Chunk
  3. Parent Chunk 发送给 LLM 生成答案。

深度分析

  • 优点解决了"检索准"与"上下文足"的矛盾。检索用小块(精准),生成用大块(完整)。
  • 缺点:存储成本增加(存两份),逻辑复杂。
  • 适用场景: 复杂文档、法律合同、技术文档(需要上下文才能理解)。
  • Spring AI 实现 :需在 Metadata 中维护 parent_id 映射。

2.5 结构感知分片 (Structure-Aware Chunking)

算法逻辑: 根据文件本身的结构标记进行切分。

  • Markdown :按 #, ##, ### 标题切分。
  • Code :按 class, function, def 切分。
  • HTML :按 <p>, <div>, <table> 标签切分。

深度分析

  • 优点:天然符合文档逻辑。代码检索必用。
  • 缺点:依赖文件格式解析器的质量。
  • 适用场景: 代码库检索 (Code RAG)、技术文档 (Markdown)。
  • Spring AI 实现MarkdownTextSplitter, LanguageSpecificSplitter

三、分片参数调优物理课

这是最核心的部分。参数不是拍脑袋决定的,是有物理意义的。

3.1 Chunk Size (分片大小)

单位陷阱

  • Characters (字符):Spring AI 默认单位。中文 1 字=1 字符。
  • Tokens (词元):LLM 和 Embedding 模型的实际计算单位。
  • 换算率
    • 英文:1 Token ≈ 4 字符。
    • 中文:1 Token ≈ 1.5 字符 (约 0.6-0.8 个汉字)。
    • 警告 :如果你设置 chunk_size=1000 (字符),对于 Embedding 模型可能是 600 Tokens,对于 LLM 可能是 600 Tokens。但如果模型限制是 512 Tokens,你就超了!

调优指南

场景 推荐 Size (字符) 推荐 Size (Tokens) 物理依据
FAQ / 问答对 256 - 512 100 - 250 问题通常很短,需要精准匹配,避免噪声。
通用文档 512 - 1024 250 - 500 平衡点。既能容纳完整段落,又不至于语义稀释。
法律/合同 1024 - 2048 500 - 1000 条款之间逻辑紧密,需要更多上下文才能理解。
代码文件 512 - 1024 250 - 500 按函数切分,通常一个函数在这个范围。

调优方法

  1. 下限:不能小于 Embedding 模型的最小有效输入(通常无限制,但太短无意义)。
  2. 上限:不能超过 Embedding 模型的最大输入(如 512/8191 Tokens)。
  3. 测试 :如果检索结果太碎(只返回半句话),调大 。如果检索结果包含太多无关段落,调小

3.2 Chunk Overlap (重叠大小)

物理意义 :防止边界效应 (Boundary Effect)

Chunk重叠的核心原因主要是我们的文件的内容被分割,导致关键词被分割成俩部分,导致语义被破坏使得我们prompt的相似度太低,从而降低检索质量

调优指南

  • 推荐比例 :Chunk Size 的 10% - 20%
  • 示例:Size=1000, Overlap=200。
  • 极端情况
    • 如果文档中有很多跨段落的引用(如"见上文"),增大 Overlap 到 30%。
    • 如果存储成本敏感,减小 Overlap 到 10%。
  • 警告:Overlap 太大会导致向量库冗余,检索时出现大量重复内容,干扰 LLM。

3.3 Separators (分隔符优先级)

物理意义:定义"语义单元"的边界。

英文默认["\n\n", "\n", " ", ""] 中文优化:中文没有空格,必须加入标点符号。

推荐中文分隔符列表

java 复制代码
List.of(
    "\n\n",      // 1. 段落 (最高优先级)
    "\n",        // 2. 换行
    "。", "!", "?", // 3. 句子结束 (中文特有)
    ";", ";",   // 4. 分句
    ",", ",",   // 5. 逗号
    " ",         // 6. 空格 (兼容英文)
    ""           // 7. 强制字符 (保底)
)

调优技巧

  • 如果文档是代码 :优先按 \n, {, } 分。
  • 如果文档是Markdown :优先按 #, ##, \n\n 分。
  • 如果文档是日志 :优先按 \n (行) 分。

四、分片调优方法论 (Methodology)

不要猜参数,要测量

4.1 构建黄金测试集 (Golden Dataset)

这是调优的基石。

  1. 收集:挑选 20-50 个真实用户问题。
  2. 标注 :人工阅读文档,标注出每个问题对应的正确文档片段 (Ground Truth Chunk)
    • 问题:"年假几天?" -> 正确 Chunk ID: doc_1_chunk_5
  3. 存储:保存为 JSON 文件。

4.2 评估指标 (Metrics)

运行不同的分片参数配置,对比以下指标:

  1. Recall@K (召回率)
    • 定义:正确答案所在的 Chunk,是否出现在检索结果的前 K 个中?
    • 公式:正确命中的问题数 / 总问题数
    • 目标:> 80%
  2. MRR (平均倒数排名)
    • 定义:正确答案排得越靠前,分数越高。
    • 目标:越接近 1 越好。
  3. Context Precision (上下文精度)
    • 定义:检索到的 Chunk 中,有多少比例是真正有用的?
    • 目标:> 70%

4.3 A/B 测试流程

  1. baseline:使用默认参数 (Size=1000, Overlap=200)。运行测试集,记录分数。
  2. 实验 A :减小 Size (500)。运行测试集。
    • 如果 Recall 上升 -> 说明之前太大,语义稀释。
    • 如果 Recall 下降 -> 说明之前合适,现在太碎,上下文丢失。
  3. 实验 B :增大 Overlap (300)。运行测试集。
    • 如果 Recall 上升 -> 说明之前边界切断严重。
  4. 决策:选择分数最高的配置。

总结

本文咱们介绍了chunking的原因、策略和调优等,chunking是我们工程化agent项目中必须考虑的问题!下一篇我们讲解:Embedding!

相关推荐
人工智能小豪6 小时前
LLM的具身鸿沟有解了!微调让大模型真正学会人类的感官与动作感知
人工智能·ai·llm·prompt·embedding·agent·rag
mo_alo1 天前
Everything Claude Code 完全指南:给 Claude Code 装上涡轮增压【安装和使用超详细教程!!!】
笔记·embedding·ai编程·claude·ecc
大傻^10 天前
LangChain4j RAG 核心:Document、Embedding 与向量存储抽象
开发语言·人工智能·python·embedding·langchain4j
青火coding10 天前
Embedding是什么?从文本转向量
java·机器学习·ai·embedding
L-影11 天前
下篇:从静态到动态,Embedding的进化之路
人工智能·ai·embedding
ん贤13 天前
一文读懂 Go-Eino 的 Embedding
开发语言·golang·embedding
智慧地球(AI·Earth)13 天前
谷歌发布 Gemini Embedding 2:首个原生全模态向量模型,打通音视频与图文!
音视频·语音识别·embedding
小蜗牛~向前冲15 天前
大模型学习系列-Embedding与向量数据库
人工智能·python·神经网络·学习·机器学习·embedding
新缸中之脑15 天前
Gemini Embedding 2
embedding