侧边栏壁纸
  • 累计撰写 56 篇文章
  • 累计创建 5 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

LlamaIndex 核心包中 15 种分块策略完全指南

温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

LlamaIndex 核心包中 15 种分块策略完全指南

在 RAG(检索增强生成)系统中,分块(Chunking)是影响检索质量最关键的一步。文本被切割成多大、怎么切,直接决定了嵌入向量的语义完整性和检索的准确性。

LlamaIndex 作为当前最流行的 RAG 框架,提供了非常丰富的分块策略。本文将详细介绍 LlamaIndex 核心包中 15 种可用的分块策略,从原理到代码示例,帮助你在不同场景下选择最适合的方案。


目录


一、继承体系概览

LlamaIndex 的分块器都继承自 NodeParser 抽象基类,整体结构如下:

NodeParser (抽象基类)
├── TextSplitter (文本分块基类)
│   ├── MetadataAwareTextSplitter (元数据感知)
│   │   ├── 1. TokenTextSplitter
│   │   └── 2. SentenceSplitter
│   ├── 3. CodeSplitter
│   ├── 4. LangchainNodeParser
│   ├── 5. SemanticSplitterNodeParser
│   └── 6. SemanticDoubleMergingSplitterNodeParser
├── 7. SimpleFileNodeParser
├── 8. HTMLNodeParser
├── 9. MarkdownNodeParser
├── 10. JSONNodeParser
├── 11. SentenceWindowNodeParser
├── 12. HierarchicalNodeParser
├── 13. MarkdownElementNodeParser
├── 14. UnstructuredElementNodeParser
└── 15. LlamaParseJsonNodeParser

共计 15 种可用分块策略,覆盖了从纯文本到结构化文档,从固定大小到语义感知,从单层到层级索引的各种需求。


二、基础文本分块类

1. TokenTextSplitter

原理:按 token 数量精确切分,不保证句子完整性。使用分词器把文本切成 token,然后按 chunk_size 硬切割。

核心参数

参数 默认值 说明
chunk_size 1024 每个块的 token 数
chunk_overlap 200 相邻块重叠 token 数
separator " " 主要分隔符
backup_separators ["\n"] 备用分隔符列表

算法流程

  1. 按分隔符列表逐层切分
  2. 贪婪合并直到接近 chunk_size
  3. 保留 chunk_overlap token 重叠

适用场景:需要严格控制 token 数的场景,比如输入给 LLM 的 prompt 有严格长度限制。

示例代码

from llama_index.core.node_parser import TokenTextSplitter

splitter = TokenTextSplitter(
    chunk_size=512,
    chunk_overlap=50,
)
chunks = splitter.split_text(long_text)

优缺点

  • ✅ 简单、快速,token 计数精确
  • ❌ 会在句子中间切断,破坏语义连贯性

2. SentenceSplitter

原理:优先保持句子完整,在接近 chunk_size 时才切分,是 LlamaIndex 最常用的默认分块器。

核心参数

参数 默认值 说明
chunk_size 1024 目标 token 数
chunk_overlap 200 块间重叠
separator " " 默认分隔符
paragraph_separator "\n\n\n" 段落分隔符
secondary_chunking_regex [^,.;。?!]+[,.;。?!]? 句子切分正则

分层切分逻辑

  1. 先按段落分隔符切分段落
  2. 再按句子 tokenizer(默认 nltk)切分句子
  3. 如果句子还太长,按正则切分句片段
  4. 最后按空格/字符切分

贪婪合并算法

# 伪代码示意
cur_chunk = []
cur_len = 0
for split in splits:
    if cur_len + split.token_size > chunk_size and not new_chunk:
        close_chunk()  # 输出当前块,并保留最后 overlap 个 token 到下一块
    else:
        cur_chunk.append(split)
        cur_len += split.token_size

适用场景通用文本、知识文档、技术手册。本项目就使用了这个分块器:

node_parser = SentenceSplitter(
    chunk_size=settings.chunk_size,  # 512
    chunk_overlap=settings.chunk_overlap,  # 50
)

优缺点

  • ✅ 尽量保持句子完整,语义连贯性好
  • ✅ 支持中文标点(正则包含 。?!
  • ❌ 分块大小会略有浮动,不严格等于 chunk_size

3. CodeSplitter

原理:基于 Python AST 语法树切分代码,保留完整的函数/类结构,避免把一个函数切到两个块中。

核心参数

参数 默认值 说明
language - 必填,编程语言名称
chunk_lines 40 每个块的目标行数
chunk_lines_overlap 15 块间重叠行数
max_chars 1500 每个块最大字符数
count_mode "char" 计数模式:chartoken

适用场景代码仓库、技术文档中含大量代码块

示例代码

from llama_index.core.node_parser import CodeSplitter

splitter = CodeSplitter(
    language="python",
    chunk_lines=50,
    chunk_lines_overlap=10,
)

优缺点

  • ✅ 保留代码语法结构,不会把函数拦腰切断
  • ❌ 需要对应语言的 AST 解析支持

4. LangchainNodeParser

原理:代理包装器,让你可以在 LlamaIndex 中直接使用 LangChain 生态的任何 TextSplitter

核心参数

  • lc_splitter:LangChain 的 TextSplitter 实例

适用场景:已经在使用 LangChain,想复用已有的分块配置。

示例代码

from langchain_text_splitters import RecursiveCharacterTextSplitter
from llama_index.core.node_parser import LangchainNodeParser

lc_splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=50,
)
parser = LangchainNodeParser(lc_splitter)
nodes = parser.get_nodes_from_documents(documents)

优缺点

  • ✅ 无缝集成 LangChain 生态
  • ❌ 需要额外安装 langchain

三、语义分块类

5. SemanticSplitterNodeParser

原理:先切成句子,计算相邻句子组的嵌入相似度,在相似度突变处(语义断点)切分。

核心参数

参数 默认值 说明
buffer_size 1 比较相似度时滑动窗口大小
breakpoint_percentile_threshold 95 断点百分位阈值,越小切分越多
embed_model - 必填,用于计算嵌入的模型

算法流程

  1. 文本切分为句子
  2. 对每个句子计算嵌入向量
  3. 计算连续 buffer_size 个句子与下一个句子的余弦距离(dissimilarity)
  4. 如果距离大于 breakpoint_percentile_threshold 百分位,则在此处切分

适用场景长文档、知识文章,希望切分边界符合语义段落。

示例代码

from llama_index.core.node_parser import SemanticSplitterNodeParser

parser = SemanticSplitterNodeParser(
    buffer_size=1,
    breakpoint_percentile_threshold=95,
    embed_model=embed_model,
)
nodes = parser.get_nodes_from_documents(documents)

优缺点

  • ✅ 语义边界更自然,同一主题更可能在一个块
  • ❌ 需要对每个句子做嵌入,计算开销大

6. SemanticDoubleMergingSplitterNodeParser

原理:在语义分块基础上增加两轮合并,先按阈值合并句子,再按相似度合并相邻块,减少碎片化。

核心参数

参数 默认值 说明
initial_threshold 0.6 初始化新块阈值,相似度低于此才开新块
appending_threshold 0.8 追加句子到当前块阈值
merging_threshold 0.8 第二轮合并相邻块阈值
max_chunk_size 1000 最大块大小(字符数)
merging_range 1 检查前几个相邻块,可选 1 或 2
language_config - Spacy 语言配置(不用 embed_model 时)
embed_model None 使用嵌入模型代替 Spacy(推荐,多语言支持更好)

两次合并

  1. 第一轮:从句子开始,若当前句子与块相似度 > appending_threshold 就追加,否则开新块
  2. 第二轮:检查相邻块,若相似度 > merging_threshold 就合并成一个更大块

适用场景多语言文档、高质量知识库构建

优缺点

  • ✅ 比单次语义分块更紧凑,减少碎片化
  • ✅ 支持 Spacy 或嵌入模型两种后端
  • ❌ 计算开销更大

四、文件格式感知类

7. SimpleFileNodeParser

原理:分发器,根据文件扩展名自动选择对应的解析器。目前支持:

  • .mdMarkdownNodeParser
  • .htmlHTMLNodeParser
  • .jsonJSONNodeParser

适用场景:批量处理多种格式文件,自动路由。

示例代码

from llama_index.core.node_parser import SimpleFileNodeParser

parser = SimpleFileNodeParser.from_defaults()
nodes = parser.get_nodes_from_documents(documents)

8. HTMLNodeParser

原理:按 HTML 标签切分,只提取指定标签内的文本。

默认标签["p", "h1", "h2", "h3", "h4", "h5", "h6", "li", "b", "i", "u", "section"]

适用场景:爬取的网页、HTML 格式文档。


9. MarkdownNodeParser

原理:按 Markdown 标题层级切分,每个标题下的内容作为一个节点,并且会把标题路径写入 header_path 元数据。

核心参数

  • header_path_separator:默认 "/",用于拼接层级路径

示例结果

# 第一章
## 1.1 节 → header_path = "第一章/1.1 节"

适用场景Markdown 文档、笔记、技术文档,天然按标题分段,切分结果语义完整。


10. JSONNodeParser

原理:按 JSON 对象/数组结构递归切分,每个叶子对象成为一个节点。

适用场景:结构化 JSON 数据,比如 API 返回结果、配置文件。


五、关系/层级类

11. SentenceWindowNodeParser

原理:每个句子独立成为一个节点(用于嵌入),但元数据中携带该句子前后 window_size 个句子作为上下文窗口。检索时用句子级嵌入召回,然后把上下文窗口喂给 LLM。

核心参数

参数 默认值 说明
window_size 3 每个句子两侧各取几个句子
window_metadata_key "window" 存储窗口的元数据键

工作流程

切分:句子1 句子2 句子3 句子4 句子5
       ↓
节点2: 句子2 → 窗口 = [句子1, 句子2, 句子3]
节点3: 句子3 → 窗口 = [句子2, 句子3, 句子4]
       ↓
检索:查询 → 嵌入匹配 → 召回节点3 → 取出窗口上下文 → 喂给 LLM

适用场景:追求检索精度,希望召回准确同时给 LLM 足够上下文。

示例代码

from llama_index.core.node_parser import SentenceWindowNodeParser

parser = SentenceWindowNodeParser.from_defaults(
    window_size=3,
)
nodes = parser.get_nodes_from_documents(documents)

优缺点

  • ✅ 嵌入粒度细,检索更精准
  • ✅ 回答时仍有完整上下文
  • ❌ 节点数量多,存储和检索开销更大

12. HierarchicalNodeParser

原理:递归多层分块,建立父子节点关系,支持从根到叶多粒度检索。

典型配置[2048, 512, 128] 三层粒度:

  • 第一层:大块 2048 token
  • 第二层:中块 512 token
  • 第三层:小块 128 token
  • 自动建立 PARENT/CHILD 关系

辅助函数

  • get_leaf_nodes(nodes):取出最细粒度节点用于检索
  • get_root_nodes(nodes):取出顶层节点
  • get_child_nodes(parent_nodes, all_nodes):获取子节点
  • get_deeper_nodes(nodes, depth):获取指定深度节点

适用场景长篇技术手册、书籍,需要多粒度检索策略(比如先粗检索再细检索)。

示例代码

from llama_index.core.node_parser import HierarchicalNodeParser, get_leaf_nodes

parser = HierarchicalNodeParser.from_defaults(
    chunk_sizes=[2048, 512, 128],
)
all_nodes = parser.get_nodes_from_documents(documents)
leaf_nodes = get_leaf_nodes(all_nodes)  # 用叶子节点建索引

13. MarkdownElementNodeParser

原理:专用于处理 Markdown 中的嵌入式元素,把文本和表格等分离,表格单独摘要索引。

工作流程

  1. 从 Markdown 提取文本块和表格
  2. 对表格生成摘要,摘要和原表格分别索引
  3. 返回文本节点和表格索引节点

适用场景含大量表格的 Markdown 文档,比如财报、技术参数表。


14. UnstructuredElementNodeParser

原理:依赖 unstructured 第三方库提取文档元素,分离文本、表格、图片等。

依赖:需要安装 unstructuredlxml

适用场景:处理复杂格式 PDF/DOCX 导出的文本,保留元素结构。


15. LlamaParseJsonNodeParser

原理:解析 LlamaParse(LlamaIndex 官方文档解析服务)输出的 JSON,提取文本和表格元素。

适用场景:使用 LlamaParse 管道处理 PDF,已经拿到 JSON 输出。


六、选择指南

根据你的文档类型和需求,参考下表选择:

文档类型 推荐分块器 理由
通用纯文本/知识文档 SentenceSplitter 平衡速度和质量,够用
代码文件 CodeSplitter 保留语法结构
Markdown 文档 MarkdownNodeParser 按标题天然分段
HTML 网页 HTMLNodeParser 按标签提取
JSON 数据 JSONNodeParser 按结构切分
追求检索精度 SentenceWindowNodeParser 细粒度嵌入 + 上下文窗口
长文档、语义连贯优先 SemanticSplitterNodeParser 按语义断点切分
高质量多语言知识库 SemanticDoubleMergingSplitterNodeParser 两次合并减少碎片化
长篇技术手册/书籍 HierarchicalNodeParser 多粒度分层索引
大量表格 MarkdownElementNodeParser 表格单独索引
已用 LangChain LangchainNodeParser 复用已有分块器

调参建议

  • chunk_size:如果 LLM 上下文窗口 4k → 512;8k → 1024
  • chunk_overlap:一般取 chunk_size 的 1/10 左右,比如 512 → 50
  • 语义分块 breakpoint_percentile_threshold:越小切分越碎,默认 95 合适

七、总结

LlamaIndex 核心包提供了 15 种分块策略,从简单到智能覆盖各种场景:

大类 数量 特点
基础文本 4 简单快速,通用性强
语义分块 2 更智能但计算开销大
格式感知 4 按文件结构天然切分,语义更完整
关系层级 5 支持特殊索引策略(句子窗口、层级检索、元素提取)

对于大多数 RAG 应用,SentenceSplitterchunk_size=512chunk_overlap=50 就是很好的起点。如果效果不满意,再尝试 SentenceWindowNodeParserSemanticSplitterNodeParser 升级。

希望这篇完整指南能帮助你理解 LlamaIndex 的分块策略体系,在实际项目中做出更好的选择。


本文基于 LlamaIndex 0.10+ 核心包编写

0

评论区