检索增强型智能体¶
在本教程中,我们将向您展示如何将我们的 FunctionAgent 或 ReActAgent 实现与工具检索器结合使用,以增强现有代理功能并存储/索引任意数量的工具。
我们的索引/检索模块有助于解决因工具函数过多而无法全部放入提示中的复杂性。
初始设置¶
让我们从导入一些基础构建模块开始。
我们主要需要的是:
- OpenAI API
- 存储对话历史记录的位置
- 定义智能体可使用的工具
如果您在 Colab 上打开此 Notebook,可能需要安装 LlamaIndex 🦙。
In [ ]:
Copied!
%pip install llama-index
%pip install llama-index
In [ ]:
Copied!
import os
os.environ["OPENAI_API_KEY"] = "sk-..."
import os
os.environ["OPENAI_API_KEY"] = "sk-..."
让我们为智能体定义一些非常简单的计算器工具。
In [ ]:
Copied!
from llama_index.core.tools import FunctionTool
def multiply(a: int, b: int) -> int:
"""Multiply two integers and returns the result integer"""
return a * b
def add(a: int, b: int) -> int:
"""Add two integers and returns the result integer"""
return a + b
def useless(a: int, b: int) -> int:
"""Toy useless function."""
pass
multiply_tool = FunctionTool.from_defaults(multiply, name="multiply")
add_tool = FunctionTool.from_defaults(add, name="add")
# toy-example of many tools
useless_tools = [
FunctionTool.from_defaults(useless, name=f"useless_{str(idx)}")
for idx in range(28)
]
all_tools = [multiply_tool] + [add_tool] + useless_tools
all_tools_map = {t.metadata.name: t for t in all_tools}
from llama_index.core.tools import FunctionTool
def multiply(a: int, b: int) -> int:
"""Multiply two integers and returns the result integer"""
return a * b
def add(a: int, b: int) -> int:
"""Add two integers and returns the result integer"""
return a + b
def useless(a: int, b: int) -> int:
"""Toy useless function."""
pass
multiply_tool = FunctionTool.from_defaults(multiply, name="multiply")
add_tool = FunctionTool.from_defaults(add, name="add")
# toy-example of many tools
useless_tools = [
FunctionTool.from_defaults(useless, name=f"useless_{str(idx)}")
for idx in range(28)
]
all_tools = [multiply_tool] + [add_tool] + useless_tools
all_tools_map = {t.metadata.name: t for t in all_tools}
构建对象索引¶
LlamaIndex 中有一个 ObjectIndex 结构,允许用户在任意对象上使用我们的索引数据结构。该对象索引会处理对象的序列化/反序列化,并使用底层索引(如 VectorStoreIndex、SummaryIndex 或 KeywordTableIndex)作为存储机制。
在本例中,我们拥有大量 Tool 对象集合,需要为这些工具定义一个对象索引。
该索引捆绑了一个检索机制——ObjectRetriever。
这可以传递给我们的智能体,使其能够在查询时执行工具检索。
In [ ]:
Copied!
# define an "object" index over these tools
from llama_index.core import VectorStoreIndex
from llama_index.core.objects import ObjectIndex
obj_index = ObjectIndex.from_objects(
all_tools,
index_cls=VectorStoreIndex,
# if we were using an external vector store, we could pass the stroage context and any other kwargs
# storage_context=storage_context,
# embed_model=embed_model,
# ...
)
# define an "object" index over these tools
from llama_index.core import VectorStoreIndex
from llama_index.core.objects import ObjectIndex
obj_index = ObjectIndex.from_objects(
all_tools,
index_cls=VectorStoreIndex,
# if we were using an external vector store, we could pass the stroage context and any other kwargs
# storage_context=storage_context,
# embed_model=embed_model,
# ...
)
稍后要重新加载索引,我们可以使用 from_objects_and_index 方法。
In [ ]:
Copied!
# from llama_index.core import StorageContext, load_index_from_storage
# saving and loading from disk
# obj_index.index.storage_context.persist(persist_dir="obj_index_storage")
# reloading from disk
# vector_index = load_index_from_storage(StorageContext.from_defaults(persist_dir="obj_index_storage"))
# or if using an external vector store, no need to persist, just reload the index
# vector_index = VectorStoreIndex.from_vector_store(vector_store=vector_store, ...)
# Then, we can reload the ObjectIndex
# obj_index = ObjectIndex.from_objects_and_index(
# all_tools,
# index=vector_index,
# )
# from llama_index.core import StorageContext, load_index_from_storage
# saving and loading from disk
# obj_index.index.storage_context.persist(persist_dir="obj_index_storage")
# reloading from disk
# vector_index = load_index_from_storage(StorageContext.from_defaults(persist_dir="obj_index_storage"))
# or if using an external vector store, no need to persist, just reload the index
# vector_index = VectorStoreIndex.from_vector_store(vector_store=vector_store, ...)
# Then, we can reload the ObjectIndex
# obj_index = ObjectIndex.from_objects_and_index(
# all_tools,
# index=vector_index,
# )
具备工具检索功能的智能体¶
LlamaIndex 中的智能体(Agent)可与 ToolRetriever 配合使用,在查询时动态检索工具。
在查询过程中,系统会首先通过 ObjectRetriever 检索出一组相关工具。这些工具随后会被传入智能体——更准确地说,它们的函数签名会被传入 OpenAI 的函数调用接口。
In [ ]:
Copied!
from llama_index.core.agent.workflow import FunctionAgent, ReActAgent
from llama_index.core.workflow import Context
from llama_index.llms.openai import OpenAI
agent = FunctionAgent(
tool_retriever=obj_index.as_retriever(similarity_top_k=2),
llm=OpenAI(model="gpt-4o"),
)
# context to hold the session/state
ctx = Context(agent)
from llama_index.core.agent.workflow import FunctionAgent, ReActAgent
from llama_index.core.workflow import Context
from llama_index.llms.openai import OpenAI
agent = FunctionAgent(
tool_retriever=obj_index.as_retriever(similarity_top_k=2),
llm=OpenAI(model="gpt-4o"),
)
# context to hold the session/state
ctx = Context(agent)
In [ ]:
Copied!
resp = await agent.run(
"What's 212 multiplied by 122? Make sure to use Tools", ctx=ctx
)
print(str(resp))
print(resp.tool_calls)
resp = await agent.run(
"What's 212 multiplied by 122? Make sure to use Tools", ctx=ctx
)
print(str(resp))
print(resp.tool_calls)
The result of multiplying 212 by 122 is 25,864.
[ToolCallResult(tool_name='multiply', tool_kwargs={'a': 212, 'b': 122}, tool_id='call_4Ygos3MpRH7Gj3R79HISRGyH', tool_output=ToolOutput(content='25864', tool_name='multiply', raw_input={'args': (), 'kwargs': {'a': 212, 'b': 122}}, raw_output=25864, is_error=False), return_direct=False)]
In [ ]:
Copied!
resp = await agent.run(
"What's 212 added to 122 ? Make sure to use Tools", ctx=ctx
)
print(str(resp))
print(resp.tool_calls)
resp = await agent.run(
"What's 212 added to 122 ? Make sure to use Tools", ctx=ctx
)
print(str(resp))
print(resp.tool_calls)
The result of adding 212 to 122 is 334.
[ToolCallResult(tool_name='add', tool_kwargs={'a': 212, 'b': 122}, tool_id='call_rXUfwQ477bcd6bxafQHgETaa', tool_output=ToolOutput(content='334', tool_name='add', raw_input={'args': (), 'kwargs': {'a': 212, 'b': 122}}, raw_output=334, is_error=False), return_direct=False)]