hierarchical : [haɪəˈrɑːrkɪkl] 分层的
# 进行层次节点解析器 chunk_sizes=每层目标Token数(从粗到细)
node_parser = HierarchicalNodeParser.from_defaults(
chunk_sizes=[512, 300],
chunk_overlap=70
)
这段代码使用了 LlamaIndex(一个流行的用于构建大语言模型应用的框架)中的 HierarchicalNodeParser 组件。它的主要作用是将长文档按照层级结构进行分割,以便在后续的检索(如 RAG 系统)中既能保留上下文,又能精确定位。
以下是对这段代码的详细解释:
1. 代码含义与参数解析
-
HierarchicalNodeParser:层级节点解析器。与普通的文本切分器(只生成单一层级的文本块)不同,它会将文档切分成具有父子关系的树状结构(例如:大块包含中块,中块包含小块)。 -
from_defaults():使用默认配置创建解析器实例的工厂方法。 -
chunk_sizes=[512, 300]:定义了层级的切分大小。这里有两个值,表示生成两层节点结构:- 第一层(父节点) :最大尺寸为 512 个 Token(或字符,取决于底层分词器,LlamaIndex 默认通常为 Token)。
- 第二层(子节点) :最大尺寸为 300 个 Token。
- 原理:解析器会先把文档尽量按 512 切分成大块,然后再把每个大块尽量按 300 切分成小块。这就形成了一个树状结构:文档 -> 512大块 -> 300小块。
-
chunk_overlap=70:切分时的重叠区域大小为 70。在切分文本时,相邻的两个文本块会有 70 个 Token 的重叠部分。
2. 实现原理
- 层级切分:当输入一篇长文档时,解析器首先尝试将其分割成不超过 512 的文本块。随后,针对每一个 512 的文本块,再次进行分割,提取出不超过 300 的文本块。300 的子节点在逻辑上属于 512 的父节点。
- 滑动窗口与重叠:为了保证切分后的文本语义连贯,避免关键信息被生硬截断,解析器在切分时使用了滑动窗口。前后两个相邻的块会共享 70 个 Token 的内容,确保跨块的上下文得以保留。
3. 主要用途
这种层级解析在 RAG(检索增强生成) 系统中非常有用,主要是为了解决“上下文碎片化”问题:
- 小块用于精准匹配:在用户提问时,使用较小的文本块(如 300)进行向量检索,可以提高检索的准确性(语义更集中,噪音更少)。
- 大块用于上下文补充:当检索到某个 300 的小块后,系统可以自动向上追溯,将其所属的 512 的父节点(甚至更上层)送入大模型。这样既保证了检索精准,又为大模型提供了充足的上下文,避免回答断章取义。
- LlamaIndex 的
AutoMergingRetriever就是专门配合此解析器设计的,当检索到的多个小块属于同一个父节点时,它会自动将它们合并为父节点再喂给 LLM。
4. 注意事项
- 参数递减逻辑:
chunk_sizes列表中的值应该是严格递减的。如果写成[300, 512]会导致逻辑错误,因为父节点不可能比子节点还小。 - 重叠参数的共享:代码中的
chunk_overlap=70是一个全局设置,这意味着所有层级(512切分和300切分时)的重叠大小都是 70。如果你希望不同层级有不同的重叠度,需要在from_defaults中传入自定义的chunk_parser(即底层的SentenceSplitter)。 - 单位问题:LlamaIndex 默认的切分单位是 Token(通常通过
tiktoken计算),而不是单纯的字符。中文字符和英文单词在 Token 化时的长度计算是不同的,调试时需注意。 - 层级深度:
chunk_sizes可以包含更多值,例如[1024, 512, 256],这会生成三层树结构。但层级越深,解析和存储的复杂度越高,通常两层或三层足以满足大部分 RAG 需求。 - 配合存储:使用层级解析器后,生成的节点包含父子关系,在存入 Vector Store(向量数据库)时,需要确保这些关系元数据被正确保存,否则后续的父节点检索将无法工作。