节点解析器使用模式(Node Parser Usage Pattern)
概念解释
节点解析器(Node Parser)是一个简单的抽象,它接受一组文档,并将它们分割成节点对象,每个节点是父文档的一个特定块。当一个文档被分割成节点时,它的所有属性(如元数据、文本和元数据模板等)都会继承给子节点。你可以在这里阅读更多关于节点和文档属性的信息。
入门
独立使用
节点解析器可以单独使用:
from llama_index.core import Document
from llama_index.core.node_parser import SentenceSplitter
node_parser = SentenceSplitter(chunk_size=1024, chunk_overlap=20)
nodes = node_parser.get_nodes_from_documents(
[Document(text="long text")], show_progress=False
)
转换使用
节点解析器可以包含在任何一组转换中,通过摄取管道(Ingestion Pipeline)使用:
from llama_index.core import SimpleDirectoryReader
from llama_index.core.ingestion import IngestionPipeline
from llama_index.core.node_parser import TokenTextSplitter
documents = SimpleDirectoryReader("./data").load_data()
pipeline = IngestionPipeline(transformations=[TokenTextSplitter(), ...])
nodes = pipeline.run(documents=documents)
索引使用
或者在转换或全局设置中设置,以便在使用 .from_documents()
构建索引时自动使用:
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
from llama_index.core.node_parser import SentenceSplitter
documents = SimpleDirectoryReader("./data").load_data()
# 全局设置
from llama_index.core import Settings
Settings.text_splitter = SentenceSplitter(chunk_size=1024, chunk_overlap=20)
# 每个索引设置
index = VectorStoreIndex.from_documents(
documents,
transformations=[SentenceSplitter(chunk_size=1024, chunk_overlap=20)],
)
节点解析器模块
基于文件的节点解析器
有几种基于文件的节点解析器,它们会根据被解析的内容类型(JSON、Markdown等)创建节点。
最简单的流程是结合 FlatFileReader
和 SimpleFileNodeParser
,自动为每种类型的内容使用最佳的节点解析器。然后,你可能希望将基于文件的节点解析器与基于文本的节点解析器链接起来,以考虑文本的实际长度。
SimpleFileNodeParser
from llama_index.core.node_parser import SimpleFileNodeParser
from llama_index.readers.file import FlatReader
from pathlib import Path
md_docs = FlatReader().load_data(Path("./test.md"))
parser = SimpleFileNodeParser()
md_nodes = parser.get_nodes_from_documents(md_docs)
HTMLNodeParser
这个节点解析器使用 beautifulsoup
解析原始 HTML。
默认情况下,它会解析一组选定的 HTML 标签,但你可以覆盖这些标签。
默认标签是:[“p”, “h1”, “h2”, “h3”, “h4”, “h5”, “h6”, “li”, “b”, “i”, “u”, “section”]
from llama_index.core.node_parser import HTMLNodeParser
parser = HTMLNodeParser(tags=["p", "h1"]) # 可选的标签列表
nodes = parser.get_nodes_from_documents(html_docs)
JSONNodeParser
JSONNodeParser
解析原始 JSON。
from llama_index.core.node_parser import JSONNodeParser
parser = JSONNodeParser()
nodes = parser.get_nodes_from_documents(json_docs)
MarkdownNodeParser
MarkdownNodeParser
解析原始 Markdown 文本。
from llama_index.core.node_parser import MarkdownNodeParser
parser = MarkdownNodeParser()
nodes = parser.get_nodes_from_documents(markdown_docs)
文本分割器
CodeSplitter
根据编写的语言分割原始代码文本。
查看支持的语言的完整列表这里。
from llama_index.core.node_parser import CodeSplitter
splitter = CodeSplitter(
language="python",
chunk_lines=40, # 每个块的行数
chunk_lines_overlap=15, # 块之间的行重叠
max_chars=1500, # 每个块的最大字符数
)
nodes = splitter.get_nodes_from_documents(documents)
LangchainNodeParser
你也可以用节点解析器包装任何现有的 langchain
文本分割器。
from langchain.text_splitter import RecursiveCharacterTextSplitter
from llama_index.core.node_parser import LangchainNodeParser
parser = LangchainNodeParser(RecursiveCharacterTextSplitter())
nodes = parser.get_nodes_from_documents(documents)
SentenceSplitter
SentenceSplitter
尝试在尊重句子边界的同时分割文本。
from llama_index.core.node_parser import SentenceSplitter
splitter = SentenceSplitter(
chunk_size=1024,
chunk_overlap=20,
)
nodes = splitter.get_nodes_from_documents(documents)
SentenceWindowNodeParser
SentenceWindowNodeParser
类似于其他节点解析器,但它将所有文档分割成单个句子。结果节点还包含每个节点周围句子的“窗口”,这些信息存储在元数据中。注意,这些元数据对 LLM 或嵌入模型不可见。
这对于生成具有非常特定范围的嵌入非常有用。然后,结合 MetadataReplacementNodePostProcessor
,你可以在将节点发送到 LLM 之前用其周围的上下文替换句子。
设置解析器的示例如下。在实践中,你通常只需要调整句子的窗口大小。
import nltk
from llama_index.core.node_parser import SentenceWindowNodeParser
node_parser = SentenceWindowNodeParser.from_defaults(
# 每边捕获多少个句子
window_size=3,
# 存储周围句子窗口的元数据键
window_metadata_key="window",
# 存储原始句子的元数据键
original_text_metadata_key="original_sentence",
)
完整的示例可以在这里找到,结合 MetadataReplacementNodePostProcessor
。
SemanticSplitterNodeParser
“语义分块”是 Greg Kamradt 在他的视频教程《5 levels of embedding chunking》中提出的新概念:https://youtu.be/8OJC21T2SL4?t=1933。
与使用固定块大小分割文本不同,语义分割器自适应地在句子之间选择断点,使用嵌入相似性。这确保了一个“块”包含语义上相关的句子。
我们将其改编成了一个 LlamaIndex 模块。
查看我们的笔记本这里!
注意事项:
- 正则表达式主要适用于英语句子
- 你可能需要调整断点百分位阈值
from llama_index.core.node_parser import SemanticSplitterNodeParser
from llama_index.embeddings.openai import OpenAIEmbedding
embed_model = OpenAIEmbedding()
splitter = SemanticSplitterNodeParser(
buffer_size=1, breakpoint_percentile_threshold=95, embed_model=embed_model
)
完整的示例可以在我们的《使用 SemanticSplitterNodeParser 的指南》中找到。
TokenTextSplitter
TokenTextSplitter
尝试根据原始标记计数分割成一致的块大小。
from llama_index.core.node_parser import TokenTextSplitter
splitter = TokenTextSplitter(
chunk_size=1024,
chunk_overlap=20,
separator=" ",
)
nodes = splitter.get_nodes_from_documents(documents)
基于关系的节点解析器
HierarchicalNodeParser
这个节点解析器将节点分割成层次节点。这意味着单个输入将被分割成几个层次的块大小,每个节点包含对其父节点的引用。
当与 AutoMergingRetriever
结合使用时,这使我们能够在大多数子节点被检索时自动用其父节点替换检索到的节点。这个过程为 LLM 提供了更完整的上下文用于响应合成。
from llama_index.core.node_parser import HierarchicalNodeParser
node_parser = HierarchicalNodeParser.from_defaults(
chunk_sizes=[2048, 512, 128]
)
通过这些详细的解释和示例,希望你能更好地理解和使用 LlamaIndex 中的节点解析器功能。