RAG 分块策略深度解析
Source: Dev.to
切块挑战
如果没有合适的切块,RAG 系统会出现:
- 上下文丢失 – 在任意边界处拆分文本会破坏语义。
- 检索效果差 – 过大的块降低精度;过小的块又失去上下文。
- 嵌入效率低 – 向量数据库在语义连贯的单元上表现最佳。
- 令牌浪费 – 无关信息占用宝贵的上下文窗口空间。
内置的切块策略通过提供智能、领域感知的文本分段来解决这些问题,既保留语义边界,又优化检索性能。
什么是切块?
切块(Chunking) 是将大文档拆分为更小、语义上有意义的片段的过程,这些片段可以:
- 嵌入 为稠密向量以进行相似度搜索。
- 独立检索,根据查询的相关性返回。
- 喂入 LLM,满足其上下文窗口限制。
有效的切块需要在两个相互竞争的目标之间取得平衡:
- 块必须足够小,以保证精确并符合嵌入模型的限制(通常 512–8192 令牌)。
- 块必须足够大,以包含足够的上下文,从而实现准确的检索和生成。
最佳的切块策略取决于文档类型、检索任务以及下游 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)用于自动检测。
算法
- 扫描文本中的实体提及。
- 将共享实体引用的句子分组。
- 当实体焦点转移时创建新块。
- 保留实体共现关系。
适用场景: 新闻文章、研究论文、多人物传记、涉及多个参与者的文档。
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);