RAG:知识库分段

12 min read

在构建知识库时,分段(Chunking)是一个至关重要的步骤,尤其是在与大型语言模型(LLM)结合使用,例如在检索增强生成(RAG)系统中。分段的目的是将长文本分割成较小的、可管理的块,以便:

  1. 适应LLM的上下文窗口限制: LLM有输入Token数量的限制,过长的文本需要被切分。
  2. 提高检索相关性: 较小的、语义连贯的块更容易在向量搜索中被精确匹配到。
  3. 减少计算成本: 处理更小的块可以降低嵌入(embedding)和检索的计算量。
  4. 降低“幻觉”风险: 提供更精确、上下文相关的知识块有助于LLM生成更准确的回答。

以下是常见的知识库分段方式,以及它们各自的优缺点和适用场景:

1. 基于固定大小的分段 (Fixed-Size Chunking)

这是最简单、最直接的分段方式。

  • 方式: 将文档按照固定的字符数或Token数进行切分,通常会设置一个重叠量(overlap)。
    • 示例: 每500个字符切成一个块,重叠100个字符。
  • 优点:
    • 实现简单,处理速度快。
    • 适用于任何文本类型。
  • 缺点:
    • 破坏语义完整性: 可能会在一个句子的中间或段落的中间进行切分,导致上下文缺失或语义中断。
    • 检索到的块可能不包含完整的概念,降低RAG的效果。
  • 适用场景:
    • 对语义完整性要求不高的简单文本。
    • 初步处理或需要快速处理大量文档时。

2. 基于标点符号或结构的分段 (Delimiter-Based / Structural Chunking)

这种方式尝试在文本的自然断点处进行切分,以保留更多的语义完整性。

  • 方式:
    • 句子级分段: 将文档按句子切分(例如,遇到句号、问号、叹号等)。
    • 段落级分段: 将文档按段落切分(例如,遇到连续的换行符)。
    • 标题/章节级分段: 根据文档的标题、副标题、章节等结构信息进行切分。这通常需要解析文档的格式(如Markdown、HTML、PDF结构等)。
  • 优点:
    • 语义完整性较好: 尽量保持句子或段落的完整性,减少语义中断。
    • 实现相对简单,处理效率较高。
  • 缺点:
    • 无法处理长句子/长段落: 如果一个句子或段落太长,仍然可能超出LLM的上下文限制。
    • 依赖文档结构: 对于结构不明确或混杂的文档,效果可能不佳。
  • 适用场景:
    • 大多数散文体文档(文章、报告、博客)。
    • 有清晰标题和章节结构的文档。

3. 递归字符文本拆分器 (Recursive Character Text Splitter)

这是 LangChain 等框架中推荐的通用文本分段策略,结合了固定大小和结构化切分的思想。

  • 方式: 尝试按一系列分隔符(如 "\n\n""\n"" """)递归地切分文本。它会优先使用更高级别(通常表示更大语义单元)的分隔符进行切分,如果切分后的块仍然过大,则继续使用下一个分隔符进行切分,直到所有块都小于指定大小,并通常带有重叠。
  • 优点:
    • 兼顾语义和长度: 尽可能保持语义完整性的同时,确保块大小符合要求。
    • 通用性强,适用于多种文本类型。
    • 提供重叠机制,有助于保留上下文信息。
  • 缺点:
    • 对于高度非结构化或语义关联性复杂的文本,可能仍有局限。
  • 适用场景:
    • 目前最常用且推荐的通用分段策略,适用于绝大多数知识库场景。

4. 父子分段 (Parent-Child Chunking / Small-to-Large Chunking)

这是一种更高级的策略,旨在平衡检索精度和上下文完整性。

  • 方式:
    • 小块检索: 创建较小的、语义独立的子块用于向量搜索(例如,单个句子或短段落)。
    • 大块提供上下文: 为每个小块关联一个更大的“父块”(可能是原始文档的整个段落、章节,甚至整个文档),当小块被检索到时,将对应的父块提供给LLM作为上下文。
  • 优点:
    • 高检索精度: 小块有助于精确匹配用户查询。
    • 丰富上下文: 大块确保LLM获得足够的背景信息,生成更准确、连贯的回答。
    • 有效解决“金句问题”:当查询只需要文档中的某一句时,直接提供该句及其上下文,而不是整个大文档。
  • 缺点:
    • 实现复杂度较高。
    • 存储和处理成本增加(需要存储两套块:子块的嵌入和父块的文本)。
  • 适用场景:
    • 需要高精度检索和丰富上下文的复杂文档(如研究论文、法律文件、技术手册)。
    • 对RAG系统性能要求较高的场景。

5. 语义分段 (Semantic Chunking)

这是一种利用大模型或嵌入模型的能力来智能切分的策略。

  • 方式:
    • 将文本切分成句子或小段落。
    • 对每个小单元生成嵌入向量。
    • 计算相邻单元之间嵌入向量的相似度(例如,余弦相似度)。
    • 在相似度低于某个阈值的地方(表示语义发生了较大转变)进行切分。
    • 有时会结合LLM来判断最佳切分点。
  • 优点:
    • 高度保留语义完整性: 确保每个块都包含一个相对完整的、连贯的概念或主题。
    • 更智能的切分: 不依赖于固定的规则,而是根据文本的实际含义进行调整。
  • 缺点:
    • 实现复杂,计算成本较高(需要生成大量嵌入并进行相似度计算)。
    • 依赖于嵌入模型和可能的LLM的性能。
  • 适用场景:
    • 对语义连贯性和RAG系统效果要求极高的场景。
    • 处理复杂、多主题或非结构化文本时效果更佳。

哪种方式更好?

没有“最好”的方式,只有“最适合”的方式。选择哪种分段策略取决于以下几个因素:

  • 您的数据类型和结构: 文档是结构化的(如手册、报告)还是非结构化的(如聊天记录、邮件)?
  • LLM的上下文窗口大小: 您的LLM能处理多长的文本?
  • 性能要求: 您对检索的精度和生成答案的质量有什么要求?
  • 计算资源和成本: 您愿意投入多少计算资源进行分段和存储?
  • 实现复杂度: 您有多少时间和精力投入到分段策略的实现上?

一般推荐:

  • 通用场景(推荐首选): 递归字符文本拆分器 (Recursive Character Text Splitter) 是一个非常好的起点。它在简单性和效果之间取得了很好的平衡,并且易于在 LangChain 等框架中实现。
  • 追求更高精度和上下文完整性: 考虑 父子分段。它能够有效解决“金句问题”,并为LLM提供更丰富的上下文。
  • 处理复杂语义或对效果有极致要求: 探索 语义分段。虽然计算成本高,但它在保留语义连贯性方面表现最佳。
  • 对于极度简单的文本或初步测试: 固定大小或基于标点符号的分段可以作为快速解决方案。

在实际操作中,通常会尝试不同的分段策略和参数(如块大小、重叠量),并通过**评估RAG系统的性能(例如,检索召回率、答案的准确性和连贯性)**来找到最适合您知识库的最佳分段方案。

Last updated on 2025-06-09