50.llama_index-文档分割器(文本)

内容参考于:图灵AI大模型全栈

分割(分割也叫分片)器的作用

1.限制LLM上下文窗口的数据,问题内容和大模型输出的内容被看作为一次上下文大小,现在的模型都有上下文的限制,没办法传递给大模型一个很大的文档

2.分片之后可以提高检索效率和提高相关性,文档越小语义越准确

在LLama_Index里分割之后的文档叫Node(节点)

在Node中有三个重要的类型,Textnode、imagesNode、indexnode

Textnode是文本数据,如下图红框它的内容

上图红框JSON的说明

json 复制代码
{
  // 【字段名】id_
  // 【字段说明】当前文本节点的全局唯一标识符,是节点在索引、向量库、关系映射中的主键
  // 【值来源】默认由 LlamaIndex 自动生成 UUID 唯一值;支持开发者手动传入自定义ID
  // 【值类型】字符串
  // 【可选值】任意全局唯一的字符串,默认自动生成标准UUID格式
  "id_": "3cffafe6-116b-41e2-b314-5a814ee15cbe",

  // 【字段名】embedding
  // 【字段说明】当前节点文本对应的向量嵌入数组,用于语义相似度检索
  // 【值来源】仅执行文本分块时默认为null;调用嵌入模型向量化后,会被填充为浮点数组
  // 【值类型】null 或 float类型数组
  // 【可选值】null(未向量化状态)、对应嵌入模型维度的浮点数组(如BGE-M3为1024维)
  "embedding": null,

  // 【字段名】metadata
  // 【字段说明】节点元数据字典,存储文本附属结构化信息,用于检索过滤、文档溯源、业务标识
  // 【值来源】基础文件属性由文件读取器(如SimpleDirectoryReader)自动提取;支持开发者自定义追加业务字段
  // 【值类型】键值对字典,键为字符串,值支持字符串、数字、布尔等基础类型
  "metadata": {
    // 源文件在本地的完整相对/绝对路径,由文件读取器自动从文件系统获取
    "file_path": "data_file\\公司规章制度.txt",
    // 源文件的文件名(含后缀),由文件读取器自动获取
    "file_name": "公司规章制度.txt",
    // 源文件的MIME媒体类型,由文件类型识别模块自动生成
    "file_type": "text/plain",
    // 源文件的大小,单位为字节,读取文件系统属性获得
    "file_size": 9387,
    // 文件创建日期,读取文件系统属性获得
    "creation_date": "2026-07-06",
    // 文件最后修改日期,读取文件系统属性获得
    "last_modified_date": "2026-03-16"
    // 【可扩展字段】可自定义追加章节号、作者、分类、页码等任意业务字段
  },

  // 【字段名】excluded_embed_metadata_keys
  // 【字段说明】生成文本向量时,此列表内的元数据键不会被拼接入待向量化的文本,避免无关信息污染向量质量
  // 【值来源】LlamaIndex 默认配置;可通过全局Settings或节点属性手动修改
  // 【值类型】字符串数组
  // 【可选值】metadata字典中的任意键名;默认通常包含文件名、大小、日期等非内容属性
  "excluded_embed_metadata_keys": [
    "file_name",
    "file_type",
    "file_size",
    "creation_date",
    "last_modified_date",
    "last_accessed_date"
  ],

  // 【字段名】excluded_llm_metadata_keys
  // 【字段说明】将节点内容拼接进LLM提示词时,此列表内的元数据键不会展示给大模型
  // 【值来源】LlamaIndex 默认配置;支持开发者手动自定义
  // 【值类型】字符串数组
  // 【可选值】metadata中的任意键名;默认与嵌入排除列表通常一致,避免无关信息干扰大模型回答
  "excluded_llm_metadata_keys": [
    "file_name",
    "file_type",
    "file_size",
    "creation_date",
    "last_modified_date",
    "last_accessed_date"
  ],

  // 【字段名】relationships
  // 【字段说明】节点关联关系字典,存储当前节点与其他节点的关联,用于上下文扩展、层级检索、文档溯源
  // 【值来源】SentenceSplitter自动建立前后文、源文档关系;也可手动构建父子层级
  // 【值类型】字典,键为关系类型编号(对应NodeRelationship枚举),值为RelatedNodeInfo对象
  // 【键可选值】详见下方「NodeRelationship枚举说明」
  "relationships": {
    // 键"1" = SOURCE:指向当前分块所属的原始源文档节点(Document)
    "1": {
      // 关联节点的唯一ID,与对应节点的id_字段一致
      "node_id": "3d10bb55-087a-4a93-bb9b-29c720c8a19a",
      // 关联节点的类型编号(对应NodeType枚举),4 = DOCUMENT(原始文档节点)
      "node_type": "4",
      // 关联节点携带的元数据快照,用于快速溯源无需二次查询
      "metadata": {
        "file_path": "data_file\\公司规章制度.txt",
        "file_name": "公司规章制度.txt",
        "file_type": "text/plain",
        "file_size": 9387,
        "creation_date": "2026-07-06",
        "last_modified_date": "2026-03-16"
      },
      // 关联节点的内容哈希值,用于校验内容一致性、去重判断
      "hash": "7ffc947cf677b316bafd6944dbeeb2e9d2f54cc60c1e5bfe7db357df402449c5",
      // 关联信息对象的类名,固定为RelatedNodeInfo
      "class_name": "RelatedNodeInfo"
    },
    // 键"2" = PREVIOUS:指向同文档内上一个相邻的文本块
    "2": {
      "node_id": "5fea98a6-0817-473b-a569-06fee03b5c33",
      // node_type = 1:TEXT 普通文本节点(TextNode)
      "node_type": "1",
      "metadata": {
        "file_path": "data_file\\公司规章制度.txt",
        "file_name": "公司规章制度.txt",
        "file_type": "text/plain",
        "file_size": 9387,
        "creation_date": "2026-07-06",
        "last_modified_date": "2026-03-16"
      },
      "hash": "40b13d5a13374fa298414001154711bcbf12d2901140d0dc34a73f2e28eebfbe",
      "class_name": "RelatedNodeInfo"
    },
    // 键"3" = NEXT:指向同文档内下一个相邻的文本块
    "3": {
      "node_id": "9e9bd1d5-24a4-4796-8685-ca1203df9256",
      // node_type = 1:TEXT 普通文本节点
      "node_type": "1",
      "metadata": {},
      "hash": "de7dcacdb5c98e8207a44682a4ac71f2285ca3ebbe47f16a49367737a2a87e95",
      "class_name": "RelatedNodeInfo"
    }
  },

  // 【字段名】metadata_template
  // 【字段说明】单条元数据拼接为文本时的格式模板
  // 【值来源】LlamaIndex 默认配置,支持全局或节点级自定义
  // 【值类型】字符串模板,{key}、{value}为固定占位符
  // 【默认值】"{key}: {value}"
  "metadata_template": "{key}: {value}",

  // 【字段名】metadata_separator
  // 【字段说明】多条元数据项拼接成完整元数据文本时的分隔符
  // 【值来源】默认配置,支持自定义
  // 【值类型】字符串
  // 【可选值】默认"\n"(换行),也可配置为分号、空格、逗号等任意字符串
  "metadata_separator": "\n",

  // 【字段名】text
  // 【字段说明】当前分块的实际文本内容,是RAG检索与向量化的核心数据
  // 【值来源】SentenceSplitter从原始文档中按chunk_size、chunk_overlap规则切分得到
  // 【值类型】字符串
  "text": "xxxxxxxxxxxxxxxxxxxxxxxxx",

  // 【字段名】mimetype
  // 【字段说明】节点内容的MIME媒体类型标识
  // 【值来源】继承自源文档的文件类型
  // 【值类型】字符串
  // 【可选值】text/plain、text/markdown、application/pdf、text/html等标准MIME类型
  "mimetype": "text/plain",

  // 【字段名】start_char_idx
  // 【字段说明】当前文本块在原始文档全文中的起始字符偏移位置(从0开始计数)
  // 【值来源】分块器自动计算生成
  // 【值类型】整数
  "start_char_idx": 817,

  // 【字段名】end_char_idx
  // 【字段说明】当前文本块在原始文档全文中的结束字符偏移位置
  // 【值来源】分块器自动计算生成
  // 【值类型】整数
  "end_char_idx": 1750,

  // 【字段名】text_template
  // 【字段说明】元数据与正文拼接为最终完整文本时的模板
  // 【值来源】默认配置,支持自定义
  // 【值类型】字符串模板,{metadata_str}是格式化后的元数据文本,{content}是正文文本
  // 【默认值】"{metadata_str}\n\n{content}"
  "text_template": "{metadata_str}\n\n{content}",

  // 【字段名】class_name
  // 【字段说明】当前节点对象的类名称,用于序列化/反序列化时识别节点类型
  // 【值来源】对象序列化时自动生成
  // 【值类型】字符串
  // 【可选值】TextNode、Document、ImageNode、IndexNode等,文本分块节点固定为TextNode
  "class_name": "TextNode"
}

SentenceSplitter句子分割器代码

python 复制代码
# 从 LlamaIndex 核心节点解析器模块导入句子分割器
# 类全称:SentenceSplitter
# 核心定位:智能语义文本分块(Chunk)工具,是 RAG 场景最常用的文本切分器
# 切分原理:优先在句号、问号、换行符、段落边界等语义边界处拆分,再结合设定的块大小微调
# 核心优势:相比纯按字符数硬切,能最大程度保证每个文本块的句子完整性,避免语义断裂
# 可配置核心参数(实例化时传入):
#   - chunk_size:单个文本块的最大字符数,默认值 1024
#   - chunk_overlap:相邻两个文本块的重叠字符数,默认值 200,避免跨块上下文丢失
#   - separator:切分分隔符优先级列表,按顺序依次尝试在对应分隔符处拆分
# 输出产物:TextNode 对象列表,每个节点代表一个独立的语义文本块
from llama_index.core.node_parser import SentenceSplitter
# 导入目录文件加载器,负责读取本地文件并封装为 Document 对象
from llama_index.core import SimpleDirectoryReader


# 加载指定的单个本地文件,返回 Document 对象列表
# 入参说明:
#   input_files:列表类型,直接指定具体文件路径,支持单个或多个文件
#   与 input_dir 的区别:input_files 精准命中目标文件,无需扫描整个目录,适合少量明确文件的场景
# load_data():执行文件读取解析,返回 List[Document] 类型,每个文件对应一个 Document 对象
documents = SimpleDirectoryReader(input_files=['./data_file/公司规章制度.txt']).load_data()

# 实例化句子分割器对象
# 无参实例化使用框架默认配置:chunk_size=1024、chunk_overlap=20
# chunk_size是tokens的数量(用的什么tokens识别不清楚),chunk_overlap是重叠数量
# 自定义粒度示例:SentenceSplitter(chunk_size=512, chunk_overlap=50)
parser = SentenceSplitter()

# 将文档列表批量解析为文本节点列表
# 方法名:get_nodes_from_documents
# 必填入参:documents,List[Document] 类型,待切分的原始文档集合
# 执行逻辑:遍历每一个 Document,按句子边界规则将长文本拆分为多个符合大小要求的文本块
# 元数据特性:每个生成的 Node 会完整继承原 Document 的所有 metadata(文件名、路径、自定义字段等)
# 返回值:List[TextNode] 类型,每个元素是一个独立的文本节点,可直接用于后续向量化与索引构建
nodes = parser.get_nodes_from_documents(documents)

# 打印第二个节点(索引从 0 开始,nodes[1] 对应第二个文本块)的结构化表示
# repr() 输出对象的完整属性概览,可快速查看节点的 id、文本片段、元数据、起止位置等核心信息
print(repr(nodes[1]))

# 以格式化 JSON 形式打印节点的完整数据结构
# model_dump_json 是 Pydantic 模型的内置方法,作用是将节点对象序列化为标准 JSON 字符串
# 入参 indent=2:设置 JSON 缩进为 2 空格,提升输出可读性
# 输出完整字段包含:节点ID、文本内容、元数据、向量化排除字段、在原文档中的字符起止索引等全部属性
print(nodes[1].model_dump_json(indent=2))

上方的Node是通过SentenceSplitter给我得到的,我们也可以自己创建Node

python 复制代码
# 从 LlamaIndex 核心数据结构模块导入三个节点关系相关的核心类
# 模块定位:定义了 LlamaIndex 所有节点、关系的基础数据结构,是整个框架的数据底座
# 1. TextNode:文本节点类
#    核心作用:LlamaIndex 最基础的文本数据单元,承载切分后的文本内容、元数据、关联关系等信息
#    核心属性:text(正文内容)、metadata(元数据)、relationships(节点关联关系字典)、id_(节点唯一标识)
#    数据流向:由文档切分生成,最终用于构建向量索引、语义检索
# 2. NodeRelationship:节点关系类型枚举类
#    核心作用:统一定义节点间的标准关系语义,避免手写字符串出错,保证全框架关系类型的一致性
#    常用枚举值:
#       - NEXT:表示当前节点的下一个节点,用于维护顺序关系
#       - PREVIOUS:表示当前节点的上一个节点,用于维护顺序关系
#       - PARENT:表示父节点,用于层级结构(如文档-片段)
#       - CHILD:表示子节点,用于层级结构
#       - SOURCE:表示源文档节点,用于溯源原始文档
# 3. RelatedNodeInfo:关联节点信息封装类
#    核心作用:标准化存储被关联节点的信息,作为节点 relationships 字典的值类型
#    核心属性:node_id(被关联节点的唯一ID)、metadata(关系的附加元数据,可自定义)
from llama_index.core.schema import TextNode, NodeRelationship, RelatedNodeInfo


# 自定义工具函数:为两个文本节点建立双向前后顺序关系
# 函数功能:给节点 a 和节点 b 建立「a 的下一个是 b,b 的上一个是 a」的双向关联
# 典型使用场景:文本切分后,维护相邻节点的上下文顺序,检索时可通过关系找回前后文节点补充语义
# 入参说明:
#   a: TextNode:前置节点,将通过 NEXT 关系指向后置节点 b
#   b: TextNode:后置节点,将通过 PREVIOUS 关系指向前置节点 a
#   a_note: str:附加到 a→b 关系上的描述元数据,用于标注关系含义
#   b_note: str:附加到 b→a 关系上的描述元数据,用于标注关系含义
def link_bidirectional(a: TextNode, b: TextNode, a_note: str, b_note: str):
    # 给节点 a 添加「下一个节点」关系
    # relationships 是 TextNode 内置的字典属性,键为 NodeRelationship 枚举,值为 RelatedNodeInfo 对象
    # NodeRelationship.NEXT:语义为「当前节点的下一个节点」
    a.relationships[NodeRelationship.NEXT] = RelatedNodeInfo(
        node_id=b.node_id,  # 关联的目标节点ID,即 b 节点的唯一标识
        metadata={"desc": a_note}  # 关系的附加描述元数据,可自定义字段,用于后续追溯、调试
    )
    # 给节点 b 添加「上一个节点」关系,形成双向关联
    # NodeRelationship.PREVIOUS:语义为「当前节点的上一个节点」
    b.relationships[NodeRelationship.PREVIOUS] = RelatedNodeInfo(
        node_id=a.node_id,  # 关联的目标节点ID,即 a 节点的唯一标识
        metadata={"desc": b_note}  # 关系的附加描述元数据
    )


# 创建第一个文本节点实例
# 必填入参 text:节点的正文内容
# 节点 id_ 会由框架自动生成唯一值,无需手动指定
node1 = TextNode(text="deepseek")  # 节点1:文本内容"deepseek"
# 创建第二个文本节点实例
node2 = TextNode(text="chatgpt")   # 节点2:文本内容"chatgpt"

# 打印建立关系前的 node1 完整结构
# 此时 node1 的 relationships 为空字典,没有任何关联关系
print(repr(node1))

# 调用双向关联函数,为 node1 和 node2 建立前后顺序关系
# 传入关系描述:node1 指向 node2 的备注为"这是节点2",node2 指向 node1 的备注为"这是节点1"
link_bidirectional(node1, node2, a_note="这是节点2", b_note="这是节点1")

# 打印建立关系后的 node1 完整结构
# 此时 node1 的 relationships 字典中已存在 NEXT 关系,指向 node2 的节点 ID 并附带描述元数据
print(repr(node1))

NodeRelationship可写值

关系枚举 语义 典型使用场景
NEXT 下一个节点 维护同文档内节点的先后顺序
PREVIOUS 上一个节点 同上述反向关联
PARENT 父节点 层级结构,如大章节 → 小片段
CHILD 子节点 父节点的下级拆分节点
SOURCE 源节点 标记节点来源于哪份原始 Document

SentenceSplitter句子分割器的分割逻辑

先按照句子拆分,比如按照标点符号拆分,句子拆分完后会有这样的情况,第一组50个字符,第二组10个字符,第三组30个字符,第四组550个字符,第五组30个字符

SentenceSplitter设置的最大长度是512,重叠是20,第一组+第二组+第三组是90个字符,这时再加第四组就会是640个字符,就超过了512了,这时它会把第一组+第二组+第三组拼接成一组,然后第四组大于512就再次拆分,比如拆分成512和38两组,这时38这一组才会有重叠20这个东西,注意38会和第五组拼接

如下图,如果小于512它并不会有重叠

如下图超过512或正好512才会有重叠

当出现超过最大长度后,拆分后还是会出现语义问题,所以LLama_Index中会有上下节点的关系,当出现语义问题后就带着上下节点一起去问大模型,或者让大模型还选当前节点是否可以回答问题,是否需要上一个或下一个节点中的内容


相关推荐
ahauedu3 小时前
多租户 RAG 知识库系统基于Spring Boot 4.0.5+Spring AI 2.0.0 + Milvus
spring·rag·springai2.0
前端Baymax1 天前
Agent工具调用中无限重试死循环的根因与修复
ai·agent·rag
接着奏乐接着舞。2 天前
【2026年7月最新】69道RAG面试题
前端·人工智能·后端·aigc·embedding·rag
大鹅同志2 天前
Agent Runtime Evaluation Platform — AI Agent 运行时全维度质量评估平台
ai·langchain·agent·rag·langgraph·vibecoding·llm-as-judge
荣--2 天前
业务智能体实战笔记:分层消除不确定性(一)|总纲:把不确定性从 LLM 侧转移到工程侧
prompt·rag·ai agent·spring ai·业务智能体
Scabbards_2 天前
经典大语言模型框架整理(gpt/llama/chatglm/qwen/deepseek)
gpt·语言模型·llama
阿拉斯攀登3 天前
Prompt 工程与答案生成优化
prompt·agent·memory·知识库·向量数据库·rag
阿拉斯攀登3 天前
企业知识库实战:从 0 到 1 落地全记录
agent·ai编程·loop·rag
阿拉斯攀登3 天前
检索效果评估与 Bad Case 分析
chatgpt·agent·ai编程·loop·rag