简介
众所周知,LLM不能单独用于复杂的、高度细粒度的和上下文感知的实现。
LLM 不仅需要通过外部工具来增强,还需要成为代理框架的支柱。这可以通过利用外部工具和语义反馈来实现。
外部工具可以包括网络搜索、访问特定API、文档搜索等功能。
研究发现,大多数对话式用户界面往往达不到人类水平的深思熟虑决策。此外,许多方法在考虑多种推理路径或提前规划方面也存在不足。
这些方法通常是孤立运行的,缺乏可改善推理的外部反馈。
语言代理树搜索统一了语言模型中的推理、行动和规划。
实际工作示例
像 LATS 这样的框架起初可能看起来很不透明,但在本文的后面部分,我将逐步介绍该框架的 LlamaIndex 实现。当我们看到框架的实际运作时,就会对它的神秘性有很大的了解。
返回 LATS
初步考虑
实用 LATS 实施
LlamaIndex 实现
笔记本从初始设置开始:
%pip install llama-index-agent-lats
%pip install llama-index-program-openai
%pip install llama-index-llms-openai
%pip install llama-index-embeddings-openai
%pip install llama-index-core llama-index-readers-file
然后定义 OpenAI API 密钥:
import os
os.environ["OPENAI_API_KEY"] = "<Your API Key Goes Here>"
import nest_asyncio
nest_asyncio.apply()
然后定义 LLM 和嵌入模型:
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core import Settings
# NOTE: a higher temperate will help make the tree-expansion more diverse
llm = OpenAI(model="gpt-4-turbo", temperature=0.6)
embed_model = OpenAIEmbedding(model="text-embedding-3-small")
Settings.llm = llm
Settings.embed_model = embed_model
下载相关数据:
!mkdir -p 'data/10k/''data/10k/'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/10k/uber_2021.pdf' -O 'data/10k/uber_2021.pdf'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/10k/lyft_2021.pdf' -O 'data/10k/lyft_2021.pdf'
索引文档
import os
from llama_index.core import (
SimpleDirectoryReader,
VectorStoreIndex,
load_index_from_storage,
)
from llama_index.core.storage import StorageContext
if not os.path.exists("./storage/lyft"):
# load data
lyft_docs = SimpleDirectoryReader(
input_files=["./data/10k/lyft_2021.pdf"]
).load_data()
uber_docs = SimpleDirectoryReader(
input_files=["./data/10k/uber_2021.pdf"]
).load_data()
# build index
lyft_index = VectorStoreIndex.from_documents(lyft_docs)
uber_index = VectorStoreIndex.from_documents(uber_docs)
# persist index
lyft_index.storage_context.persist(persist_dir="./storage/lyft")
uber_index.storage_context.persist(persist_dir="./storage/uber")
else:
storage_context = StorageContext.from_defaults(
persist_dir="./storage/lyft"
)
lyft_index = load_index_from_storage(storage_context)
storage_context = StorageContext.from_defaults(
persist_dir="./storage/uber"
)
uber_index = load_index_from_storage(storage_context)
设置两个工具或引擎:
lyft_engine = lyft_index.as_query_engine(similarity_top_k=3)3)
uber_engine = uber_index.as_query_engine(similarity_top_k=3)
按照典型的代理方式,两个代理工具都有一个说明,这个说明非常重要,因为它可以帮助代理决定何时以及如何使用该工具。
显然,代理可以使用多种工具,代理可以使用的工具越多,代理就越强大。
from llama_index.core.tools import QueryEngineTool, ToolMetadata
query_engine_tools = [
QueryEngineTool(
query_engine=lyft_engine,
metadata=ToolMetadata(
name="lyft_10k",
description=(
"Provides information about Lyft financials for year 2021. "
"Use a detailed plain text question as input to the tool. "
"The input is used to power a semantic search engine."
),
),
),
QueryEngineTool(
query_engine=uber_engine,
metadata=ToolMetadata(
name="uber_10k",
description=(
"Provides information about Uber financials for year 2021. "
"Use a detailed plain text question as input to the tool. "
"The input is used to power a semantic search engine."
),
),
),
]
这是 LATS 代理的设置...
这里也定义了代理的预算...
你还可以查看 LLM 和工具的参考信息。
from llama_index.agent.lats import LATSAgentWorker
agent_worker = LATSAgentWorker.from_tools(
query_engine_tools,
llm=llm,
num_expansions=2,
max_rollouts=3, # using -1 for unlimited rollouts
verbose=True,
)
agent = agent.as_worker()
下面是向代理人提出的一个问题,注意这个问题是多么模棱两可,有不同的条件和细微差别。
task = agent.create_task(
"Given the risk factors of Uber and Lyft described in their 10K files, ""Given the risk factors of Uber and Lyft described in their 10K files, "
"which company is performing better? Please use concrete numbers to inform your decision."
)