第一章 · 文档解析与分块解析

本章定位:这是整个 RAG 系统的「入口」。用户上传一个文件,到知识库里出现可被向量检索的「块」,中间到底发生了什么?切分质量直接决定检索召回率的上限——后面再好的重排、再聪明的融合,都救不回一个被切碎的条款。

本章分两部分:

  • 上篇 · 概念与策略(科普):为什么必须分块?分块在 RAG 里的位置是什么?chunkSize、overlap、token 这些参数到底是什么意思?业界主流的 5 种分块策略各有什么优劣?——看完这部分,你会「懂为什么」。
  • 下篇 · SparkX 源码落地(实践):SparkX 具体怎么实现这套策略?多引擎解析器、父子分块、自适应切分、保护区域、overlap 计算的每个细节,逐一拆解。——看完这部分,你会「懂怎么做」。

上篇 · 概念与策略

一、为什么不能把整篇文档直接丢给大模型?

假设你在一家电商公司做开发,老板让你搞一个智能客服。公司有一份 200 页的《客服知识库》,涵盖退货政策、物流规则、会员权益、售后流程。用户问「买了 7 天的商品还能退吗?」,系统得从知识库里找答案。

最直觉的做法——把整份知识库一股脑塞给大模型,让它回答。听起来合理,但实际会撞上两堵墙。

1. 大模型的上下文窗口限制

大模型有一个上下文窗口(Context Window),可以理解成它的工作台——一次能摊开看的纸张数量是有限的。

主流模型的上下文窗口大约在 128K ~ 1M 个 token 之间。128K 听起来很多,但一份 200 页的知识库纯文本量轻松超过 30 万字,远超窗口上限。

直接后果:文本塞不进去,或者触发长度限制/截断/费用飙升。

即便现在模型窗口越做越大(从 128K 到 1M 不到一年),全量长提示在成本、延迟、吞吐上都不划算。所以在线客服这类场景,依然偏向 RAG,而不是把所有文本塞给模型。

2. 检索精度的问题——大海捞针

假设你有一个窗口无限大的模型,把整份知识库都塞进去了。用户问「生鲜商品支持七天无理由退货吗?」,模型要从 30 万字里找到相关的那几段。

这就像你去图书馆找一句话,管理员把整个图书馆的书全摊在你面前说「自己找」。信息太多、噪音太大,模型很容易走神——要么找不到重点,要么把不相关的内容混进回答。

RAG 的做法是反过来的:先检索出最相关的几段文本,只把这几段喂给模型。这样模型拿到的上下文精准、干净,回答质量自然就上去了。

但问题来了:要做检索,你得先有可以被检索的单元。一整份知识库没法作为检索单元——粒度太粗了。你需要把它切成一段一段的小块,每一块聚焦一个相对完整的知识点

这就是分块(Chunking)要干的事。


二、分块到底在干什么

1. 分块在 RAG 流程中的位置

完整的 RAG 数据准备链路是这样的:

原始文件 (PDF/Word/Excel...)
   │
   ▼  ① 文档解析(提取纯文本)
纯文本(原材料,还不能直接检索)
   │
   ▼  ② 分块(切成可检索单元)  ← 本章重点
文本块 1、块 2、块 3 ...
   │
   ▼  ③ 向量化(每块转成一组数字)
向量 1、向量 2、向量 3 ...
   │
   ▼  ④ 存入向量库
用户提问 → 向量检索 → 召回最相关的块 → 喂给大模型生成答案

分块紧接着文本提取之后。分块的质量直接决定后续检索的质量——块切得好,检索就准;块切得烂,后面怎么优化都救不回来。这也是为什么本章值得花大篇幅讲透。

2. 三个必须搞懂的关键参数

2.1 chunkSize(块大小)

每个块的长度上限。比如 chunkSize = 512,意思是每块最多 512 个字符。设多大合适?没有标准答案,但有个基本权衡:

后果
块太大(如 2000 字) 每块信息多,但检索时容易混入无关内容,精度下降。用户问退货政策,结果返回了包含退货、换货、维修的一整章
块太小(如 50 字) 每块很精准,但容易把一个完整意思切断,上下文丢失。把一条退货规则从中间劈开,前后半句单独看都不知道在说什么

经验范围:200 ~ 1000 个字符是常见区间,具体看文档类型。

2.2 overlap(重叠量)—— 为什么需要它

overlap 是相邻两个块共享的文本长度

打个比方:你在看小说,每次只能记住一页内容。如果严格按页翻,第 1 页最后一句和第 2 页第一句之间的联系就断了。但如果你每次翻页时,把上一页最后几行重新看一遍,这几行就是重叠,帮你保持上下文连贯。

不加 overlap 会丢什么? 看这个退货政策的例子,chunkSize = 40,无 overlap:

---

## 🔒 以上为本章部分预览(约 10%)

> 本章剩余 **90%** 内容包含:关键源码逐行拆解、设计细节与工程权衡、代码示例与生产实践要点。

<div class="unlock-cta">
  <button class="unlock-btn" onclick="openModal()">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2">
      <rect x="3" y="11" width="18" height="11" rx="2"/>
      <path d="M7 11V7a5 5 0 0 1 10 0v4"/>
    </svg>
    🔑 点击解锁本章完整内容
  </button>
  <span class="unlock-hint">加入知识星球,获取《SparkX 源码深度解析》全部 13 章</span>
</div>

> 💡 **本次展示的仅为部分预览内容(约 10%)**。完整的源码深度解析包含每一个技术点的完整实现细节。点击上方按钮扫码加入知识星球,解锁全部内容。
🔒

本章为知识星球会员专属内容

完整源码解析、设计决策与落地实践,加入知识星球即可解锁全部章节。

知识星球
🌟 加入知识星球
解锁源码与设计详解
知识星球二维码 了解详情