llamaindex 元数据提取使用模式(Metadata Extraction Usage Pattern)

元数据提取使用模式(Metadata Extraction Usage Pattern)

概念解释

你可以使用 LLM(大型语言模型)来自动提取元数据,通过我们的元数据提取器模块实现。

我们的元数据提取器模块包括以下“特征提取器”:

  • SummaryExtractor - 自动提取一组节点的摘要
  • QuestionsAnsweredExtractor - 提取每个节点可以回答的一组问题
  • TitleExtractor - 提取每个节点的标题
  • EntityExtractor - 提取每个节点内容中提到的实体(例如地点、人物、事物的名称)

然后,你可以将元数据提取器与我们的节点解析器链接起来:

使用模式
定义元数据提取器
from llama_index.core.extractors import (
    TitleExtractor,
    QuestionsAnsweredExtractor,
)
from llama_index.core.node_parser import TokenTextSplitter

text_splitter = TokenTextSplitter(
    separator=" ", chunk_size=512, chunk_overlap=128
)
title_extractor = TitleExtractor(nodes=5)
qa_extractor = QuestionsAnsweredExtractor(questions=3)
运行元数据提取器

假设文档已经定义,提取节点:

from llama_index.core.ingestion import IngestionPipeline

pipeline = IngestionPipeline(
    transformations=[text_splitter, title_extractor, qa_extractor]
)

nodes = pipeline.run(
    documents=documents,
    in_place=True,
    show_progress=True,
)

或者插入到索引中:

from llama_index.core import VectorStoreIndex

index = VectorStoreIndex.from_documents(
    documents, transformations=[text_splitter, title_extractor, qa_extractor]
)
自动元数据提取以改善检索和合成

在本教程中,我们展示了如何执行自动元数据提取以获得更好的检索结果。我们使用两个提取器:一个 QuestionsAnsweredExtractor,它从一段文本中生成问答对,以及一个 SummaryExtractor,它不仅在当前文本中提取摘要,还在相邻文本中提取摘要。

我们展示了这允许“块梦境”——每个单独的块可以有更多的“整体”细节,从而在给定检索结果的情况下提高答案质量。

我们的数据来源取自 Eugene Yan 的流行文章《LLM Patterns》:https://eugeneyan.com/writing/llm-patterns/

设置

如果你在 colab 上打开这个 Notebook,你可能需要安装 LlamaIndex 🦙。

%pip install llama-index-llms-openai
%pip install llama-index-readers-web
!pip install llama-index
import nest_asyncio

nest_asyncio.apply()

import os
import openai
# OPTIONAL: setup W&B callback handling for tracing
from llama_index.core import set_global_handler

set_global_handler("wandb", run_args={"project": "llamaindex"})
os.environ["OPENAI_API_KEY"] = "sk-..."
openai.api_key = os.environ["OPENAI_API_KEY"]
定义元数据提取器

这里我们定义元数据提取器。我们定义两个变体:

  • metadata_extractor_1 只包含 QuestionsAnsweredExtractor
  • metadata_extractor_2 包含 QuestionsAnsweredExtractorSummaryExtractor
from llama_index.llms.openai import OpenAI
from llama_index.core.schema import MetadataMode
llm = OpenAI(temperature=0.1, model="gpt-3.5-turbo", max_tokens=512)

我们还展示了如何实例化 SummaryExtractorQuestionsAnsweredExtractor

from llama_index.core.node_parser import TokenTextSplitter
from llama_index.core.extractors import (
    SummaryExtractor,
    QuestionsAnsweredExtractor,
)

node_parser = TokenTextSplitter(
    separator=" ", chunk_size=256, chunk_overlap=128
)

extractors_1 = [
    QuestionsAnsweredExtractor(
        questions=3, llm=llm, metadata_mode=MetadataMode.EMBED
    ),
]

extractors_2 = [
    SummaryExtractor(summaries=["prev", "self", "next"], llm=llm),
    QuestionsAnsweredExtractor(
        questions=3, llm=llm, metadata_mode=MetadataMode.EMBED
    ),
]
加载数据,运行提取器

我们使用 LlamaHub 的 SimpleWebPageReader 加载 Eugene 的文章(https://eugeneyan.com/writing/llm-patterns/)。

然后我们运行提取器。

from llama_index.core import SimpleDirectoryReader
# load in blog

from llama_index.readers.web import SimpleWebPageReader

reader = SimpleWebPageReader(html_to_text=True)
docs = reader.load_data(urls=["https://eugeneyan.com/writing/llm-patterns/"])
print(docs[0].get_content())
orig_nodes = node_parser.get_nodes_from_documents(docs)
# take just the first 8 nodes for testing
nodes = orig_nodes[20:28]
print(nodes[3].get_content(metadata_mode="all"))

运行元数据提取器:

from llama_index.core.ingestion import IngestionPipeline

# process nodes with metadata extractors
pipeline = IngestionPipeline(transformations=[node_parser, *extractors_1])

nodes_1 = pipeline.run(nodes=nodes, in_place=False, show_progress=True)
Parsing documents into nodes:   0%|          | 0/8 [00:00<?, ?it/s]
Extracting questions:   0%|          | 0/8 [00:00<?, ?it/s]
print(nodes_1[3].get_content(metadata_mode="all"))

第二次运行摘要和元数据提取器:

# process nodes with metadata extractor
pipeline = IngestionPipeline(transformations=[node_parser, *extractors_2])

nodes_2 = pipeline.run(nodes=nodes, in_place=False, show_progress=True)
Parsing documents into nodes:   0%|          | 0/8 [00:00<?, ?it/s]
Extracting summaries:   0%|          | 0/8 [00:00<?, ?it/s]
Extracting questions:   0%|          | 0/8 [00:00<?, ?it/s]
可视化一些示例数据
print(nodes_2[3].get_content(metadata_mode="all"))
print(nodes_2[1].get_content(metadata_mode="all"))
设置 RAG 查询引擎,比较结果!

我们在三种节点变体之上设置 3 个索引/查询引擎。

from llama_index.core import VectorStoreIndex
from llama_index.core.response.notebook_utils import (
    display_source_node,
    display_response,
)
# try out different query engines

index0 = VectorStoreIndex(orig_nodes)
index1 = VectorStoreIndex(orig_nodes[:20] + nodes_1 + orig_nodes[28:])
index2 = VectorStoreIndex(orig_nodes[:20] + nodes_2 + orig_nodes[28:])
query_engine0 = index0.as_query_engine(similarity_top_k=1)
query_engine1 = index1.as_query_engine(similarity_top_k=1)
query_engine2 = index2.as_query_engine(similarity_top_k=1)
尝试一些问题

在这个问题中,我们看到朴素的响应 response0 只提到了 BLEU 和 ROUGE,并且缺乏关于其他指标的上下文。

response2 在其上下文中包含了所有指标。

query_str = (
    "Can you describe metrics for evaluating text generation quality, compare"
    " them, and tell me about their downsides"
)

response0 = query_engine0.query(query_str)
response1 = query_engine1.query(query_str)
response2 = query_engine2.query(query_str)
display_response(
    response0, source_length=1000, show_source=True, show_source_metadata=True
)
print(response0.source_nodes[0].node.get_content())
display_response(
    response1, source_length=1000, show_source=True, show_source_metadata=True
)
display_response(
    response2, source_length=1000, show_source=True, show_source_metadata=True
)

在下一个问题中,我们询问 BERTScore/MoverScore。

响应相似。但 response2response0 提供了稍微更多的细节,因为它在元数据中包含了更多关于 MoverScore 的信息。

query_str = (
    "Can you give a high-level overview of BERTScore/MoverScore + formulas if"
    " available?"
)

response0 = query_engine0.query(query_str)
response1 = query_engine1.query(query_str)
response2 = query_engine2.query(query_str)
display_response(
    response0, source_length=1000, show_source=True, show_source_metadata=True
)
display_response(
    response1, source_length=1000, show_source=True, show_source_metadata=True
)
display_response(
    response2, source_length=1000, show_source=True, show_source_metadata=True
)
response1.source_nodes[0].node.metadata

通过这些详细的解释和示例,希望你能更好地理解和使用 LlamaIndex 中的元数据提取功能。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

需要重新演唱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值