LlamaIndex
4、教程
本章你将能看到LlamaIndex可以使用的各种应用设置,从简单的Jupyter笔记本到聊天机器人再到全栈Web应用程序。
- 发现LlamaIndex视频系列
- 如何构建聊天机器人
- 使用LLamaIndex构建全栈Web应用的指南
- 使用Delphic构建全栈LlamaIndex Web应用程序指南
- LlamaIndex + 结构化数据指南
- 提取术语和定义指南
- 创建统一查询框架索引指南
- Airbyte SQL 索引指南
- SEC 10k分析
- 使用本地模型的LlamaIndex
4.1 探索LlamaIndex系列
SubQuestionQueryEngine + 10K Analysis
介绍了 SubQuestionQueryEngine
,将其应用于财务文件,以帮助将复杂的查询分解为多个子问题。
# 导入必要的库
import nest_asyncio
nest_asyncio.apply()
from llama_index import SimpleDirectoryReader, LLMPredictor, ServiceContext, VectorStoreIndex
from llama_index.response.pprint_utils import pprint_response
from langchain import OpenAI
from llama_index.tools import QueryEngineTool, ToolMetadata
from llama_index.query_engine import SubQuestionQueryEngine
# 配置LLM服务
llm_predictor = LLMPredictor(llm=OpenAI(temperature=0, model_name="text-davinci-003", max_tokens=-1, streaming=True))
service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor)
# 加载数据
lyft_docs = SimpleDirectoryReader(input_files=["../data/10k/lyft_2021.pdf"]).load_data()
uber_docs = SimpleDirectoryReader(input_files=["../data/10k/uber_2021.pdf"]).load_data()
# 构建索引
lyft_index = VectorStoreIndex.from_documents(lyft_docs)
uber_index = VectorStoreIndex.from_documents(uber_docs)
# 构建查询引擎
lyft_engine = lyft_index.as_query_engine(similarity_top_k=3)
uber_engine = uber_index.as_query_engine(similarity_top_k=3)
query_engine_tools = [
QueryEngineTool(
query_engine=lyft_engine,
metadata=ToolMetadata(name='lyft_10k', description='Provides information about Lyft financials for year 2021')
),
QueryEngineTool(
query_engine=uber_engine,
metadata=ToolMetadata(name='uber_10k', description='Provides information about Uber financials for year 2021')
),
]
s_engine = SubQuestionQueryEngine.from_defaults(query_engine_tools=query_engine_tools)
# 查询并打印结果
response = s_engine.query('Compare and contrast the customer segments and geographies that grew the fastest')
print(response)
response = s_engine.query('Compare revenue growth of Uber and Lyft from 2020 to 2021')
print(response)
response = s_engine.query('Compare revenue growth of Uber and Lyft from 2020 to 2021')
print(response)
该代码使用LLM模型和语言链技术,对Lyft和Uber的财务数据进行了查询和比较。
通过构建索引和查询引擎,可以快速地对大量数据进行查询和分析。
Document Management
介绍了如何管理来自不断更新的来源(例如Discord)的文档,以及如何避免文档重复和保存嵌入令牌。
文本转SQL和语义搜索
介绍了LlamaIndex内置的工具,用于将SQL和语义搜索结合成一个统一的查询界面。
4.2 如何构建聊天机器人
LlamaIndex是我们数据和LLM之间的接口;
它提供了工具包,让我们可以为任何下游任务设置围绕自己的数据的查询接口,无论是问答、摘要还是其他任务。
在本教程中,我们将向您展示如何构建一个上下文增强的聊天机器人。
- 使用Langchain作为底层代理/聊天机器人抽象
- 使用LlamaIndex进行数据检索/查找/查询
- 结果是一个聊天机器人代理,它可以访问LlamaIndex提供的丰富的“数据接口”工具,以回答有关您的数据的查询。
在本教程中,我们通过从Dropbox下载原始的UBER 10-K HTML文件,构建了一个“10-K Chatbot”。用户可以选择就10-K文件提出问题。
摄取数据
下载2019年至2022年的原始10-k文件。
# NOTE: the code examples assume you're operating within a Jupyter notebook.
# download files
!mkdir data
!wget "https://www.dropbox.com/s/948jr9cfs7fgj99/UBER.zip?dl=1" -O data/UBER.zip
!unzip data/UBER.zip -d data
使用Unstructured库将HTML文件解析为格式化文本。我们通过LlamaHub与Unstructured直接集成,这使我们能够将任何文本转换为LlamaIndex可以摄取的文档格式。
from llama_index import download_loader, VectorStoreIndex, ServiceContext, StorageContext, load_index_from_storage
from pathlib import Path
years = [2022, 2021, 2020, 2019]
UnstructuredReader = download_loader("UnstructuredReader", refresh_cache=True)
loader = UnstructuredReader()
doc_set = {}
all_docs = []
for year in years:
year_docs = loader.load_data(file=Path(f'./data/UBER/UBER_{year}.html'), split_documents=False)
# insert year metadata into each year
for d in year_docs:
d.extra_info = {"year": year}
doc_set[year] = year_docs
all_docs.extend(year_docs)
为每年设置向量索引
- 为每年设置一个向量索引。每个向量索引都允许我们查询给定年份的10-K申报文件。
- 构建每个索引并将其保存到磁盘。
# initialize simple vector indices + global vector index
service_context = ServiceContext.from_defaults(chunk_size=512)
index_set = {}
for year in years:
storage_context = StorageContext.from_defaults()
cur_index = VectorStoreIndex.from_documents(
doc_set[year],
service_context=service_context,
storage_context=storage_context,
)
index_set[year] = cur_index
storage_context.persist(persist_dir=f'./storage/{year}')
从磁盘加载索引,请执行以下操作:
# Load indices from disk
index_set = {}
for year in years:
storage_context = StorageContext.from_defaults(persist_dir=f'./storage/{year}')
cur_index = load_index_from_storage(storage_context=storage_context)
index_set[year] = cur_index
合成一张图表以综合10-K文件中的答案
由于我们可以访问4年的文件,我们不仅可以询问有关特定年份10-K文件的问题,还可以提出需要对所有10-K文件进行分析的问题。
为了解决这个问题,我们构建了一个“图形”,它由定义在4个向量索引上的列表索引组成。查询这个图形将首先从每个向量索引中检索信息,并通过列表索引将信息组合在一起。
from llama_index import ListIndex, LLMPredictor, ServiceContext, load_graph_from_storage
from langchain import OpenAI
from llama_index.indices.composability import ComposableGraph
# describe each index to help traversal of composed graph
index_summaries = [f"UBER 10-k Filing for {year} fiscal year" for year in years]
# define an LLMPredictor set number of output tokens
llm_predictor = LLMPredictor(llm=OpenAI(temperature=0, max_tokens=512))
service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor)
storage_context = StorageContext.from_defaults()
# define a list index over the vector indices
# allows us to synthesize information across each index
graph = ComposableGraph.from_indices(
ListIndex,
[index_set[y] for y in years],
index_summaries=index_summaries,
service_context=service_context,
storage_context = storage_context,
)
root_id = graph.root_id
# [optional] save to disk
storage_context.persist(persist_dir=f'./storage/root')
# [optional] load from disk, so you don't need to build graph from scratch
graph = load_graph_from_storage(
root_id=root_id,
service_context=service_context,
storage_context=storage_context,
)
设置工具和Langchain聊天机器人代理
使用Langchain来设置外部聊天机器人代理,该代理可以访问一组工具。LlamaIndex提供了一些包装器,使得指数和图表可以在工具界面内轻松使用。
# do imports
from langchain.chains.conversation.memory import ConversationBufferMemory
from langchain.agents import initialize_agent
from llama_index.langchain_helpers.agents import LlamaToolkit, create_llama_chat_agent, IndexToolConfig
我们希望为每个指数(对应于给定年份)定义一个单独的工具,以及相应的图表。我们可以在一个中央 LlamaToolkit
界面下定义所有工具。
下面,我们为我们的图定义一个 IndexToolConfig
。请注意,我们还导入了一个 DecomposeQueryTransform
模块,以便在图中的每个向量索引中使用 - 这使我们能够将整个查询“分解”为可以从每个子索引中回答的查询。
# define a decompose transform
from llama_index.indices.query.query_transform.base import DecomposeQueryTransform
decompose_transform = DecomposeQueryTransform(
llm_predictor, verbose=True
)
# define custom retrievers
from llama_index.query_engine.transform_query_engine import TransformQueryEngine
custom_query_engines = {}
for index in index_set.values():
query_engine = index.as_query_engine()
query_engine = TransformQueryEngine(
query_engine,
query_transform=decompose_transform,
transform_extra_info={'index_summary': index.index_struct.summary},
)
custom_query_engines[index.index_id] = query_engine
custom_query_engines[graph.root_id] = graph.root_index.as_query_engine(
response_mode='tree_summarize',
verbose=True,
)
# construct query engine
graph_query_engine = graph.as_query_engine(custom_query_engines=custom_query_engines)
# tool config
graph_config = IndexToolConfig(
query_engine=graph_query_engine,
name=f"Graph Index",
description="useful for when you want to answer queries that require analyzing multiple SEC 10-K documents for Uber.",
tool_kwargs={"return_direct": True}
)
除了图表的 IndexToolConfig
对象之外,我们还定义了一个与每个索引相对应的 IndexToolConfig
:
# define toolkit
index_configs = []
for y in range(2019, 2023):
query_engine = index_set[y].as_query_engine(
similarity_top_k=3,
)
tool_config = IndexToolConfig(
query_engine=query_engine,
name=f"Vector Index {y}",
description=f"useful for when you want to answer queries about the {y} SEC 10-K for Uber",
tool_kwargs={"return_direct": True}
)
index_configs.append(tool_config)
最后,我们将这些配置与我们的 LlamaToolkit
结合起来:
toolkit = LlamaToolkit(
index_configs=index_configs + [graph_config],
)
最后,我们调用 create_llama_chat_agent
来创建我们的Langchain聊天机器人代理,该代理可以访问我们上面定义的5个工具:
memory = ConversationBufferMemory(memory_key="chat_history")
llm=OpenAI(temperature=0)
agent_chain = create_llama_chat_agent(
toolkit,
llm,
memory=memory,
verbose=True
)
测试代理人
我们现在可以使用各种查询来测试代理。
如果我们使用一个简单的“你好”查询进行测试,代理程序不使用任何工具。
agent_chain.run(input="hi, i am bob")
如果我们使用有关某一年度10-K的查询进行测试,代理将使用相关的向量索引工具。
agent_chain.run(input="What were some of the biggest risk factors in 2020 for Uber?")
最后,如果我们使用查询来比较/对比不同年份的风险因素,代理将使用图形索引工具。
cross_query_str = (
"Compare/contrast the risk factors described in the Uber 10-K across years. Give answer in bullet points."
)
agent_chain.run(input=cross_query_str)
设置聊天机器人循环
现在我们已经设置好了聊天机器人,只需要再进行几个步骤,就可以设置一个基本的交互循环,与我们的SEC增强聊天机器人进行对话了!
while True:
text_input = input("User: ")
response = agent_chain.run(input=text_input)
print(f'Agent: {response}')