LlamaIndex 在分片上的细节
与简单的分块库不同,LlamaIndex 的分片策略是为检索效果服务的。上下文感知:通过分层解析保留文档的原始结构,理解内容的语义边界。关系维护:通过节点关系显式地记录文本块之间的逻辑联系,而不仅仅是序列关系。检索优化:这些设计直接赋能了像小到大检索这样的高级查询模式,使其能从庞大的知识库中先定位到最相关的细节,再自动扩展上下文,从根本上提升了 RAG 系统的答案质量。
LlamaIndex 的核心抽象是 “节点”(Node)。文档分片的过程就是将原始文档(Document)转换为一组节点的过程。这个过程远不止简单的文本分割,它包含了丰富的策略来优化后续的检索效果。
核心概念:解析器(Parsers)与节点(Nodes)
-
文档(Document):代表一个原始数据源(如一个 PDF 文件、一个 API 响应、一段文本)。
-
节点(Node):文档被解析后生成的基本单元。一个节点包含一段文本(
text
)和相关的元数据(metadata
),如与原始文档的关系、标题等。 -
解析器(Parser):负责将
Document
转换为Node
列表的组件。LlamaIndex 提供了多种解析器,适用于不同类型的文档和需求。
关键分片策略与细节
官方文档中详细介绍了多种解析策略,以下是其中最核心和高级的部分:
1. 基础文本分割器(SentenceSplitter)
这是最直接的方法,类似于 LangChain 的 RecursiveCharacterTextSplitter
。
-
工作原理:基于字符数(
chunk_size
)和重叠区(chunk_overlap
)进行分割。 -
适用场景:通用文本,简单快速。
-
代码示例:
from llama_index.core import SimpleDirectoryReader from llama_index.core.node_parser import SentenceSplitter # 加载文档 documents = SimpleDirectoryReader("./data").load_data() # 创建解析器 parser = SentenceSplitter( chunk_size=512, chunk_overlap=20, ) # 将文档解析为节点 nodes = parser.get_nodes_from_documents(documents)
2. 语义分片(Semantic Splitter) - 高级特性
这是 LlamaIndex 的一个强大功能,旨在在语义边界处进行分割,而不是机械地按字符数切割。
-
工作原理:
-
使用嵌入模型(Embedding Model)计算句子或段落的向量。
-
通过计算向量之间的相似度来识别文本中的“边界”。当嵌入向量的相似度出现显著变化时,意味着话题可能发生了转变,此处就是一个理想的分割点。
-
-
优点:生成的节点在语义上更加连贯,能显著提升检索质量。
-
代码示例:
from llama_index.core.node_parser import SemanticSplitterNodeParser from llama_index.embeddings.openai import OpenAIEmbedding embed_model = OpenAIEmbedding() parser = SemanticSplitterNodeParser( buffer_size=1, # 用于平滑的句子数 breakpoint_percentile_threshold=95, # 相似度差异的百分阈值 embed_model=embed_model ) nodes = parser.get_nodes_from_documents(documents)
3. 基于标题的分层解析(Hierarchical Parsing) - 用于复杂文档
对于 PDF、PPT、Markdown 等具有层级结构的文档,这是最关键、最强大的解析策略。
-
工作原理:
-
解析结构:使用像
unstructured
这样的库,不仅提取文本,还提取元信息(如字体大小、样式、位置),从而推断出标题层级(H1, H2, H3 等)。 -
创建节点层级:将不同层级的内容创建为父节点和子节点。
-
父节点:可能包含一个章节的标题和简介。
-
子节点:包含该章节下的具体段落和细节。
-
-
-
检索优势(小到大检索):
-
首先检索到一个小而精确的子节点(例如,回答某个具体问题的段落)。
-
然后,检索器可以自动将父节点的信息作为上下文一并提供给 LLM。
-
这样既保证了检索的精准度,又提供了丰富的上下文信息,避免了答案缺乏背景的问题。
-
-
代码示例(通常默认启用):
from llama_index.core import SimpleDirectoryReader # 默认的 PDF 阅读器通常会使用支持分层解析的解析器(如 unstructured) documents = SimpleDirectoryReader("./data", filename_as_id=True).load_data() # 查看解析后的文档对象,通常已经包含了结构信息 print(documents[0].metadata) # 可能包含 page_number, file_path 等 # 在创建索引时,LlamaIndex 会自动处理这些层级关系
4. 节点关系(Node Relationships)
解析后生成的节点并非孤立的,它们之间存在关系,这些关系被存储在节点的 relationships
属性中。
-
主要关系类型:
-
NodeRelationship.PARENT
:节点的父节点(如在层级结构中)。 -
NodeRelationship.CHILD
:节点的子节点。 -
NodeRelationship.SOURCE
:节点所属的原始文档。 -
NodeRelationship.NEXT
:序列中的下一个节点。
-
-
作用:这些关系是实现“小到大检索”等高级查询模式的基础。
如何选择与配置?
官方文档的建议是:
-
尝试默认设置:对于大多数格式(如
.pdf
,.docx
),SimpleDirectoryReader
会自动选择最佳的解析器(通常是基于unstructured
的、支持分层解析的解析器)。这通常是效果最好的选择。 -
追求简单和可控时:如果文档是纯文本(
.txt
)或你需要完全控制块大小,使用SentenceSplitter
。 -
追求最高检索质量时:对质量要求极高的项目,可以尝试
SemanticSplitterNodeParser
,尽管它计算成本更高。 -
自定义:你可以实现自己的
NodeParser
来满足任何特殊需求。
总结:LlamaIndex 分片的先进之处
与简单的分块库不同,LlamaIndex 的分片策略是为检索效果服务的。其先进性体现在:
-
上下文感知:通过分层解析保留文档的原始结构,理解内容的语义边界。
-
关系维护:通过节点关系显式地记录文本块之间的逻辑联系,而不仅仅是序列关系。
-
检索优化:这些设计直接赋能了像小到大检索这样的高级查询模式,使其能从庞大的知识库中先定位到最相关的细节,再自动扩展上下文,从根本上提升了 RAG 系统的答案质量。
更多推荐
所有评论(0)