Splitter 文档分割器
1. 核心概念
在 RAG(Retrieval-Augmented Generation)场景中,文档往往过长,直接喂入大模型可能导致性能低下或上下文截断。文档分割器(Document Splitter) 的作用就是将长文档拆分成多个逻辑段落或 token 块,保证每一块都在语义或长度上合理,同时便于后续向量化和检索。
1.1 DocumentSplitter 接口
DocumentSplitter 是所有分割器的统一接口,核心方法为:
java
List<Document> split(Document document, DocumentIdGenerator idGenerator);- document:待拆分的文档对象。
- idGenerator:可选,用于为拆分后的每个文档生成唯一 ID。
splitAll(List<Document>, idGenerator):支持对文档列表进行批量拆分。
1.2 核心实现类型
Agents-Flex 提供了多种 DocumentSplitter 实现,适用于不同场景:
| 分割器 | 特点 | 适用场景 |
|---|---|---|
SimpleDocumentSplitter | 按固定字符长度拆分,可设置 overlap | 文本长度固定或无需语义感知 |
SimpleTokenizeSplitter | 按 token(编码)拆分,可解决 Unicode/中文字符问题 | 对接 LLM,保证 token 对齐 |
RegexDocumentSplitter | 按正则表达式拆分 | 文本有固定分隔符,如段落、换行符、符号 |
MarkdownHeaderSplitter | 按 Markdown 标题层级拆分 | 保留章节结构和父级标题路径 |
MarkdownTableSplitter | 按完整数据行拆分长表格,并在每块重复表头 | OCR、报表等包含长表格的 Markdown |
AIDocumentSplitter | 基于 LLM/AI 语义拆分,保持逻辑完整 | 文档长度长,语义复杂,需 AI 感知 |
2. 快速入门
2.1 示例:字符块拆分
java
Document doc = new Document();
doc.setContent("这里是一段很长的文本,需要拆分为多个小块以便检索。");
// 每块 100 字,重叠 10 字
SimpleDocumentSplitter splitter = new SimpleDocumentSplitter(100, 10);
List<Document> chunks = splitter.split(doc, id -> "doc-" + System.nanoTime());
chunks.forEach(c -> System.out.println(c.getContent()));2.2 示例:正则拆分
java
// 按双换行拆分
RegexDocumentSplitter regexSplitter = new RegexDocumentSplitter("\\n\\n");
List<Document> regexChunks = regexSplitter.split(doc, id -> "doc-" + System.nanoTime());2.3 示例:AI 语义拆分
java
// 假设 chatModel 为已初始化
AIDocumentSplitter aiSplitter = new AIDocumentSplitter(chatModel);
aiSplitter.setMaxChunks(10); // 最大拆分块数
aiSplitter.setFallbackSplitter(new SimpleDocumentSplitter(200)); // 设置 fallback 拆分器
List<Document> aiChunks = aiSplitter.split(doc, id -> "doc-" + System.nanoTime());2.4 示例:Markdown 长表格拆分
java
// 每块最多约 1000 个字符,并在相邻块间重复最后 1 行数据
MarkdownTableSplitter tableSplitter = new MarkdownTableSplitter(1000, 1);
List<Document> tableChunks = tableSplitter.split(markdownDocument);MarkdownTableSplitter 只拆分超过 maxChunkSize 的 GFM 风格表格。每个表格块都会重复原表头和分隔行,且不会截断数据行;若单行本身超过限制,该块会保留完整行并允许超过限制。围栏代码块中的表格语法不会被识别为表格。表格块会附加 content_type=markdown_table、table_index、table_chunk_index 和 table_chunk_count 元数据。
3. 配置与高级应用
3.1 AI 拆分器(AIDocumentSplitter)高级配置
java
aiSplitter.setSplitPromptTemplate(
"请将以下文档按语义拆分,每块不超过300字,用 分隔:\n{document}"
);
ChatOptions options = new ChatOptions.Builder()
.temperature(0.1f)
.maxTokens(500)
.build();
aiSplitter.setChatOptions(options);自定义 fallback
java
AIDocumentSplitter aiSplitter = new AIDocumentSplitter(chatModel);
SimpleDocumentSplitter fallback = new SimpleDocumentSplitter(200);
aiSplitter.setFallbackSplitter(fallback);- 如果 AI 拆分失败,会自动调用 fallback。
- fallback 可是任何实现了
DocumentSplitter的类。
3.2 Token 拆分器(SimpleTokenizeSplitter)注意事项
SimpleTokenizeSplitter 使用 jtokkit 编码器,能保证与 OpenAI token 对齐:
java
SimpleTokenizeSplitter tokenSplitter = new SimpleTokenizeSplitter(256, 32);
tokenSplitter.setEncodingType(EncodingType.CL100K_BASE);- chunkSize:token 数量,而非字符数。
- overlapSize:token 重叠数量。
- 自动处理 Unicode Replacement Character(0xFFFD)问题,避免中文乱码。
3.3 批量拆分
java
List<Document> docs = Arrays.asList(doc1, doc2, doc3);
List<Document> allChunks = splitter.splitAll(docs, id -> "doc-" + System.nanoTime());splitAll会自动处理空文档。- 支持任意
DocumentSplitter实现。
4. 实践建议
- 文本长度与模型上下文:AI 拆分器最好不要直接喂入超过模型最大上下文的文档,可先使用简单字符/Token 拆分器做初步截断。
- fallback:建议总是配置 fallback,保证拆分鲁棒性。
- 重叠:适用于 token 拆分器,可在长文本中保留语义连续性,避免段落被截断。
- 正则拆分:适合固定格式文档,如 Markdown、HTML 或日志文件。
- 调优 prompt(AI 拆分器):可根据文档类型定制拆分规则,比如按章节、表格、代码块等。