RAG 分块策略深度解析

发布: (2025年12月14日 GMT+8 04:13)
7 min read
原文: Dev.to

Source: Dev.to

切块挑战

如果没有合适的切块,RAG 系统会出现:

  • 上下文丢失 – 在任意边界处拆分文本会破坏语义。
  • 检索效果差 – 过大的块降低精度;过小的块又失去上下文。
  • 嵌入效率低 – 向量数据库在语义连贯的单元上表现最佳。
  • 令牌浪费 – 无关信息占用宝贵的上下文窗口空间。

内置的切块策略通过提供智能、领域感知的文本分段来解决这些问题,既保留语义边界,又优化检索性能。

什么是切块?

切块(Chunking) 是将大文档拆分为更小、语义上有意义的片段的过程,这些片段可以:

  • 嵌入 为稠密向量以进行相似度搜索。
  • 独立检索,根据查询的相关性返回。
  • 喂入 LLM,满足其上下文窗口限制。

有效的切块需要在两个相互竞争的目标之间取得平衡:

  1. 块必须足够小,以保证精确并符合嵌入模型的限制(通常 512–8192 令牌)。
  2. 块必须足够大,以包含足够的上下文,从而实现准确的检索和生成。

最佳的切块策略取决于文档类型、检索任务以及下游 LLM 的使用方式。

框架概览

Agentic Memory 库包含一个可扩展的切块框架,帮助你将文档拆分为适合语义搜索和检索的最佳块。

架构

所有切块策略都位于 io.github.vishalmysore.rag.chunking 包的 核心框架 中。下面的示例代码演示了如何使用这些策略。

核心组件

  • ChunkingStrategy 接口 – 所有切块策略的基接口。

    List chunk(String content);   // 将内容拆分为块
    String getName();            // 返回策略名称
    String getDescription();     // 返回策略描述
  • RAGService.addDocumentWithChunking() – 用于自动切块的便利方法。

    int chunkCount = rag.addDocumentWithChunking(
        "document_id",
        content,
        chunkingStrategy
    );

内置策略

1. 滑动窗口切块

包名: io.github.vishalmysore.rag.chunking.SlidingWindowChunking

创建重叠块以在边界之间保留上下文。

技术细节

  • 可配置大小和重叠度的滑动窗口。
  • 基于单词的分词,支持自定义分隔符。
  • 保持块大小大致相等,以确保嵌入质量一致。
ChunkingStrategy strategy = new SlidingWindowChunking(150, 30);
// 每块 150 个单词,重叠 30 个单词(20%)

参数

  • windowSize – 每块的单词数(典型值:100–300)。
  • overlap – 块之间的重叠单词数(典型值:窗口大小的 10–20 %)。

适用场景: 医疗记录、连续叙事、患者笔记等上下文跨越边界的文档。


2. 自适应切块

包名: io.github.vishalmysore.rag.chunking.AdaptiveChunking

在保持自然文档边界的同时,确保块大小符合令牌限制。

技术细节

  • 使用正则表达式匹配语义边界(章节、段落等)。
  • 根据边界位置动态调整块大小。
  • 强制最小/最大令牌约束,以平衡精度和上下文。
ChunkingStrategy strategy = new AdaptiveChunking(
    "(?m)^SECTION \\d+:",  // 边界模式(正则)
    800,                     // 最小令牌数
    1200                     // 最大令牌数
);

参数

  • boundaryPattern – 用于识别切分点的正则(如章节标题)。
  • minTokens – 为保持上下文所需的最小块大小。
  • maxTokens – 为适配嵌入模型限制的最大块大小。

适用场景: 法律合同、结构化文档、带有明确章节标记的政策文件。


3. 基于实体的切块

包名: io.github.vishalmysore.rag.chunking.EntityBasedChunking

按提及的实体(人物、公司、地点)对句子进行分组。

技术细节

  • 对输入文本执行命名实体识别(NER)。
  • 将引用相同实体的连续句子归为一组。
  • 使用实体共现分析决定块边界。
String[] entities = {"Elon Musk", "Tesla", "SpaceX"};
ChunkingStrategy strategy = new EntityBasedChunking(entities);

参数

  • entities – 要追踪的实体名称数组(人物、组织、地点等)。
  • 可选:实体类型(PERSON、ORG、LOCATION)用于自动检测。

算法

  1. 扫描文本中的实体提及。
  2. 将共享实体引用的句子分组。
  3. 当实体焦点转移时创建新块。
  4. 保留实体共现关系。

适用场景: 新闻文章、研究论文、多人物传记、涉及多个参与者的文档。


4. 基于主题的切块

包名: io.github.vishalmysore.rag.chunking.TopicBasedChunking

按底层主题或议题对内容进行分组。

技术细节

  • 使用主题建模或关键词匹配识别主题转变。
  • 对结构化文档使用正则表达式检测主题边界。
  • 可选:使用潜在狄利克雷分配(LDA)进行无监督主题发现。
ChunkingStrategy strategy = new TopicBasedChunking(
    "(EDUCATION|CAREER|PATENTS):"
);

参数

  • topicPattern – 用于识别主题边界的正则。
  • 可选:主题模型配置,用于无监督切块。

适用场景: 研究论文、技术文档、带有显式主题标记的结构化内容。


5. 混合切块

包名: io.github.vishalmysore.rag.chunking.HybridChunking

在流水线中组合多种策略。

ChunkingStrategy adaptive = new AdaptiveChunking("(?m)^===\\s*$");
ChunkingStrategy topic = new TopicBasedChunking("(INTRO|BODY|CONCLUSION):");

ChunkingStrategy strategy = new HybridChunking(adaptive, topic);

适用场景: 需要多阶段处理的复杂文档。


6. 任务感知切块

包名: io.github.vishalmysore.rag.chunking.TaskAwareChunking

根据下游任务(摘要、搜索、问答)自适应切块。

技术细节

  • 实现针对不同任务的启发式规则,以获得最佳块大小。
任务典型块大小描述
摘要50–100 令牌小而聚焦的块,便于生成细粒度摘要。
搜索200–400 令牌中等块(如函数签名 + 文档字符串),适合检索匹配。
问答500–1000 令牌大块保留完整上下文,以确保答案的准确性。
// 摘要(小块)
ChunkingStrategy strategy = new TaskAwareChunking(TaskType.SUMMARIZATION);

// 搜索(中块)
ChunkingStrategy strategy = new TaskAwareChunking(TaskType.SEARCH);

// 问答(大块)
ChunkingStrategy strategy = new TaskAwareChunking(TaskType.QA);
Back to Blog

相关文章

阅读更多 »

揭秘检索增强生成 (RAG)

大型语言模型(LLMs)彻底改变了我们与信息交互的方式,但它们有一个根本性的限制:它们的知识在训练时点被冻结。