夜雨聆风学习资料网

ARTICLE · 1095709

AI 知识库检索准不准,关键看文档怎么切:6 种分片方式详解

AI 知识库检索准不准,关键看文档怎么切:6 种分片方式详解
昨天聊到 AI 运维平台可以加 QA 知识库,把每个组件的常见问题和答案加载进去,实现智能问答。
但这里有个关键问题:文档怎么分片?
别小看这个问题,分片方式直接决定了知识库的检索准确率。切得不好,用户问的问题检索不到相关内容,智能体就只能瞎回答。
今天就来聊聊常见的 6 种文档分片方式,以及当前最推荐的做法。

为什么分片这么重要?

很多人做知识库,就是把文档随便切一切,丢进向量数据库就完事了。
但实际上,分片的质量直接影响检索效果:
  • 切得太大:一个 chunk 里塞了太多内容,检索到了但相关信息只占一小部分,LLM 容易被无关内容干扰
  • 切得太小:一个完整的意思被拆成了两半,检索到一半,上下文不完整,LLM 回答不全面
  • 切得不对:把两个不相关的段落切到一起,或者把一个完整的知识点拆碎了,检索精度大打折扣
所以,分片不是技术细节,是决定知识库好不好用的核心环节。

方式一:固定长度切分(基本已被舍弃)

最早的分片方式,很简单:按固定字符数切,比如每 500 个字切一段。
不管内容是什么,到了长度就切。
这种方式的问题很明显:
  • 可能把一句话从中间切断
  • 可能把两个不相关的段落拼到一起
  • 完全不考虑语义和结构
现在基本已经被舍弃了,只有一些非常简单的场景还在用。

方式二:按分隔符切分(最常用)

这是目前最常用的分片方式。
思路:优先按大的分隔符切,切出来太大再按小的分隔符切,逐级尝试,凑够目标长度为止。
优先级一般是这样的:
  • 段落分隔符\n\n:先按段落切,段落是天然的语义边界
  • 换行符\n:段落太大的话,再按行切
  • 句号 / 标点。!?:还是太大的话,按句子切
  • 最后才按字符硬切:实在不行了才按固定长度切
这样做的好处是:
  • 尽量保持语义完整,不会把一句话切断
  • 实现简单,性能好
  • 大部分场景都够用
缺点是:
  • 还是可能把一个完整的知识点拆到两个 chunk 里
  • 对结构复杂的文档(比如代码、表格)处理不好

方式三:按语义切分(质量好但开销大)

这种方式更智能:计算相邻句子的 embedding,找语义相似度骤降的地方作为切分边界。
比如一段话里,前 3 句在讲 "怎么安装",第 4 句突然开始讲 "怎么配置",那这两句之间的语义相似度就会很低,这里就是一个天然的切分点。
优点:
  • 能保证一个 chunk 讲一件事,语义最完整
  • 检索精度最高
缺点:
  • 计算开销大,每个句子都要算 embedding
  • 分片速度慢,不适合大批量文档
  • 适合对召回质量要求高的场景
简单说就是:质量最好,但最贵。

方式四:结构感知分片(适合结构化文档)

这种方式利用文档自带的结构来切,不同格式用不同的解析器:
  • Markdown / HTML:按标题层级/ h1/h2 切,天然保持章节边界。一个标题下面的内容就是一个 chunk,太大了再往下细分。
  • 代码:按函数、类、文件切,用 AST 解析。不会把一个函数从中间切断。
  • 表格:整表或按行分组,不能按字符硬切。表格按字符切的话,数据就乱了。
  • PDF:按页 + 段落 + 标题,先做版面分析,识别出标题、正文、图表,再按结构切。
优点:
  • 最符合文档本身的逻辑结构
  • 对代码、表格、PDF 等特殊格式特别友好
  • 检索精度高
缺点:
  • 实现复杂,不同格式要写不同的解析器
  • 对格式混乱的文档处理不好

方式五:LLM 分片(质量最好但成本最高)

这种方式最 "奢侈":让大模型读文档后自己决定在哪里切分。
你把文档丢给 LLM,告诉它 "请把这篇文档按语义分成若干个 chunk,每个 chunk 讲一个完整的主题",LLM 会自己理解内容,然后给出切分方案。
优点:
  • 质量最好,LLM 能真正理解文档内容
  • 能处理各种复杂情况
缺点:
  • 成本高,每篇文档都要调用一次 LLM
  • 不可控,LLM 可能切得不一致
  • 速度慢,不适合大批量文档
适合小批量、高价值的文档,比如产品手册、合同、技术规范这些,切好了能反复用,值得花这个成本。

方式六:小分片 + 大上下文(当前最推荐)

这是目前业界最推荐的架构,叫small-to-big或者parent-child(父子分片)。
核心思路:检索和阅读用不同大小的分片。
  • 检索时用小分片:比如 200 token,小而精准,能精确定位到相关内容
  • 返回给 LLM 时带上大分片:比如命中的小分片所属的父级章节,1000 token 左右,补足上下文
这样做的好处是:
  • 小分片检索精准,不会漏
  • 大分片上下文完整,LLM 能看懂
同时拿到 "精准召回" 和 "完整上下文"
实现方式有两种

第一种:父子文档

建两张表:
chunks表:存小分片,每个小分片有一个parent_id
parent_chunks表:存大分片(父级章节)
检索的时候,先在小分片中检索,命中后根据parent_id把对应的父内容取回来,一起给 LLM。

第二种:上下文扩展

不用两张表,命中小分片后,根据doc_id和位置信息,把前后相邻的几个 chunk 一起捞回来,拼成一个大的上下文给 LLM。
两种方式都可以,父子文档更清晰,上下文扩展更简单。
代价是:多一张表或者多一次关联查询,但这个代价完全值得

元数据要跟着切分

最后说一个容易被忽略的点:每个 chunk 都要保留来源信息(元数据)。
  • 元数据包括:
  • 文档 ID
  • 文档标题
  • 章节标题
  • 页码
  • 分片序号
  • 自定义标签(比如属于哪个组件、哪个产品)
为什么元数据重要?
  • 第一,可以做过滤检索。比如昨天说的,每个组件的 QA 要隔离,就可以给每个 chunk 加一个kb_id元数据,检索的时候按kb_id过滤,不会串。
  • 第二,可以溯源。LLM 回答完之后,用户想知道答案来自哪里,可以根据元数据定位到原始文档的具体位置。
  • 第三,可以做权限控制。有些文档只有特定人能看,检索的时候按权限过滤元数据就行。
所以,分片的时候一定要把元数据一起存好,不要只存向量。

最后

文档分片这件事,看起来是个技术细节,但实际上决定了整个知识库的体验。
很多人做知识库效果不好,不是模型不行,不是向量数据库不行,就是分片没做好。
把分片做好了,知识库就成功了一半。

相关学习资料