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 的一个强大功能,旨在在语义边界处进行分割,而不是机械地按字符数切割。

  • 工作原理

    1. 使用嵌入模型(Embedding Model)计算句子或段落的向量。

    2. 通过计算向量之间的相似度来识别文本中的“边界”。当嵌入向量的相似度出现显著变化时,意味着话题可能发生了转变,此处就是一个理想的分割点。

  • 优点:生成的节点在语义上更加连贯,能显著提升检索质量。

  • 代码示例

    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 等具有层级结构的文档,这是最关键、最强大的解析策略

  • 工作原理

    1. 解析结构:使用像 unstructured 这样的库,不仅提取文本,还提取元信息(如字体大小、样式、位置),从而推断出标题层级(H1, H2, H3 等)。

    2. 创建节点层级:将不同层级的内容创建为父节点和子节点。

      • 父节点:可能包含一个章节的标题和简介。

      • 子节点:包含该章节下的具体段落和细节。

  • 检索优势(小到大检索)

    • 首先检索到一个小而精确的子节点(例如,回答某个具体问题的段落)。

    • 然后,检索器可以自动将父节点的信息作为上下文一并提供给 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:序列中的下一个节点。

  • 作用:这些关系是实现“小到大检索”等高级查询模式的基础。


如何选择与配置?

官方文档的建议是:

  1. 尝试默认设置:对于大多数格式(如 .pdf.docx),SimpleDirectoryReader 会自动选择最佳的解析器(通常是基于 unstructured 的、支持分层解析的解析器)。这通常是效果最好的选择

  2. 追求简单和可控时:如果文档是纯文本(.txt)或你需要完全控制块大小,使用 SentenceSplitter

  3. 追求最高检索质量时:对质量要求极高的项目,可以尝试 SemanticSplitterNodeParser,尽管它计算成本更高。

  4. 自定义:你可以实现自己的 NodeParser 来满足任何特殊需求。

总结:LlamaIndex 分片的先进之处

与简单的分块库不同,LlamaIndex 的分片策略是为检索效果服务的。其先进性体现在:

  1. 上下文感知:通过分层解析保留文档的原始结构,理解内容的语义边界。

  2. 关系维护:通过节点关系显式地记录文本块之间的逻辑联系,而不仅仅是序列关系。

  3. 检索优化:这些设计直接赋能了像小到大检索这样的高级查询模式,使其能从庞大的知识库中先定位到最相关的细节,再自动扩展上下文,从根本上提升了 RAG 系统的答案质量。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐