递归检索器与文档代理:在异构文档中进行高级决策
在处理大量异构文档时,如何进行高效且智能的决策是一个常见挑战。本文将介绍一种名为“递归检索器与文档代理”的技术,通过结合递归检索和文档代理,实现对异构文档的高级决策。我们将通过一个实际示例,展示如何在LlamaIndex中应用这一技术,帮助你更好地理解和应用。
动机
在处理文档时,我们常常面临两个主要问题:
- 检索嵌入与块基合成解耦:通常通过文档摘要进行检索会比通过原始块进行检索返回更相关的上下文。递归检索直接支持这一点。
- 文档内动态任务:用户可能需要在文档内执行超出基于事实的问答的任务。我们引入了“文档代理”的概念——代理可以访问给定文档的向量搜索和摘要工具。
前置知识
在深入学习递归检索器与文档代理之前,你需要了解以下基础知识:
- Python编程:熟悉Python语言及其常用库。
- 自然语言处理(NLP):了解基本的NLP概念和技术。
- 向量数据库:了解向量数据库的基本概念和使用方法。
安装与配置
首先,我们需要安装必要的库,并配置OpenAI API密钥。
%pip install llama-index-llms-openai
%pip install llama-index-agent-openai
!pip install llama-index
import os
os.environ["OPENAI_API_KEY"] = "sk-..."
下载数据
我们将从Wikipedia下载关于不同城市的文章,并将其存储在单独的文件中。
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core import SummaryIndex
from llama_index.core.schema import IndexNode
from llama_index.core.tools import QueryEngineTool, ToolMetadata
from llama_index.llms.openai import OpenAI
wiki_titles = ["Toronto", "Seattle", "Chicago", "Boston", "Houston"]
from pathlib import Path
import requests
for title in wiki_titles:
response = requests.get(
"https://en.wikipedia.org/w/api.php",
params={
"action": "query",
"format": "json",
"titles": title,
"prop": "extracts",
"explaintext": True,
},
).json()
page = next(iter(response["query"]["pages"].values()))
wiki_text = page["extract"]
data_path = Path("data")
if not data_path.exists():
Path.mkdir(data_path)
with open(data_path / f"{title}.txt", "w") as fp:
fp.write(wiki_text)
加载文档
我们将加载所有Wikipedia文章。
city_docs = {}
for wiki_title in wiki_titles:
city_docs[wiki_title] = SimpleDirectoryReader(
input_files=[f"data/{wiki_title}.txt"]
).load_data()
定义LLM + 服务上下文 + 回调管理器
from llama_index.core import Settings
Settings.llm = OpenAI(temperature=0, model="gpt-3.5-turbo")
为每个文档构建文档代理
我们将为每个文档定义“文档代理”。首先,我们为每个文档定义一个向量索引(用于语义搜索)和一个摘要索引(用于摘要)。然后将这两个查询引擎转换为工具,传递给OpenAI函数调用代理。
from llama_index.agent.openai import OpenAIAgent
agents = {}
for wiki_title in wiki_titles:
# 构建向量索引
vector_index = VectorStoreIndex.from_documents(
city_docs[wiki_title],
)
# 构建摘要索引
summary_index = SummaryIndex.from_documents(
city_docs[wiki_title],
)
# 定义查询引擎
vector_query_engine = vector_index.as_query_engine()
list_query_engine = summary_index.as_query_engine()
# 定义工具
query_engine_tools = [
QueryEngineTool(
query_engine=vector_query_engine,
metadata=ToolMetadata(
name="vector_tool",
description=(
f"Useful for retrieving specific context from {wiki_title}"
),
),
),
QueryEngineTool(
query_engine=list_query_engine,
metadata=ToolMetadata(
name="summary_tool",
description=(
"Useful for summarization questions related to"
f" {wiki_title}"
),
),
),
]
# 构建代理
function_llm = OpenAI(model="gpt-3.5-turbo-0613")
agent = OpenAIAgent.from_tools(
query_engine_tools,
llm=function_llm,
verbose=True,
)
agents[wiki_title] = agent
在这些代理上构建可组合检索器
我们将定义一组摘要节点,每个节点链接到相应的Wikipedia城市文章。然后在这些节点上定义一个可组合检索器 + 查询引擎,以将查询路由到给定节点,进而路由到相关的文档代理。
objects = []
for wiki_title in wiki_titles:
# 定义链接到这些代理的索引节点
wiki_summary = (
f"This content contains Wikipedia articles about {wiki_title}. Use"
" this index if you need to lookup specific facts about"
f" {wiki_title}.\nDo not use this index if you want to analyze"
" multiple cities."
)
node = IndexNode(
text=wiki_summary, index_id=wiki_title, obj=agents[wiki_title]
)
objects.append(node)
# 定义顶级检索器
vector_index = VectorStoreIndex(
objects=objects,
)
query_engine = vector_index.as_query_engine(similarity_top_k=1, verbose=True)
运行示例查询
# 应该使用Boston代理 -> 向量工具
response = query_engine.query("Tell me about the sports teams in Boston")
print(response)
# 应该使用Houston代理 -> 向量工具
response = query_engine.query("Tell me about the sports teams in Houston")
print(response)
# 应该使用Seattle代理 -> 摘要工具
response = query_engine.query("Give me a summary on all the positive aspects of Chicago")
print(response)
总结
通过使用递归检索器与文档代理,我们可以在处理大量异构文档时,显著提升决策的准确性和效率。本文通过实际示例,展示了如何在LlamaIndex中构建和使用递归检索器与文档代理,希望对你有所帮助。
参考文献:
扩展阅读:
希望这篇博客能为你带来启发和帮助,让我们在编程的世界里,更加高效地驾驭数据和信息!