这是一个展示 ReAct 代理使用非常简单的计算器工具的 Notebook(不涉及复杂的 RAG 流水线或 API 调用)。
我们展示了它如何一步步通过不同的工具进行推理,以达到最终目标。
ReAct 代理相比函数调用代理的主要优势在于它可以与任何 LLM 配合使用,无论该 LLM 是否支持函数调用。
如果你在 colab 上打开这个 Notebook,你可能需要安装 LlamaIndex 🦙。
输入 [ ]
%pip install llama-index
我们设置了一些简单的 multiply
和 add
工具。请注意,你可以定义任意函数并将其传递给 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 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
from llama_index.llms.openai import OpenAI from llama_index.core.agent.workflow import ReActAgent from llama_index.core.workflow import Context llm = OpenAI(model="gpt-4o-mini") agent = ReActAgent(tools=[multiply, add], llm=llm) # 创建一个上下文来存储对话历史/会话状态 ctx = Context(agent)
from llama_index.llms.openai import OpenAI
from llama_index.core.agent.workflow import ReActAgent
from llama_index.core.workflow import Context
llm = OpenAI(model="gpt-4o-mini")
agent = ReActAgent(tools=[multiply, add], llm=llm)
# Create a context to store the conversation history/session state
ctx = Context(agent)
通过流式传输结果,我们可以看到完整的响应,包括思考过程和工具调用。
如果我们只想流式传输结果,我们可以缓冲流,并在响应中出现 Answer:
后开始流式传输。
from llama_index.core.agent.workflow import AgentStream, ToolCallResult handler = agent.run("What is 20+(2*4)?", ctx=ctx) async for ev in handler.stream_events(): # if isinstance(ev, ToolCallResult): # print(f"\nCall {ev.tool_name} with {ev.tool_kwargs}\nReturned: {ev.tool_output}") if isinstance(ev, AgentStream): print(f"{ev.delta}", end="", flush=True) response = await handler
from llama_index.core.agent.workflow import AgentStream, ToolCallResult
handler = agent.run("What is 20+(2*4)?", ctx=ctx)
async for ev in handler.stream_events():
# if isinstance(ev, ToolCallResult):
# print(f"\nCall {ev.tool_name} with {ev.tool_kwargs}\nReturned: {ev.tool_output}")
if isinstance(ev, AgentStream):
print(f"{ev.delta}", end="", flush=True)
response = await handler
Thought: The current language of the user is: English. I need to use a tool to help me answer the question. Action: multiply Action Input: {"a": 2, "b": 4}Thought: Now I have the result of the multiplication, which is 8. I will add this to 20 to complete the calculation. Action: add Action Input: {'a': 20, 'b': 8}Thought: I can answer without using any more tools. I'll use the user's language to answer. Answer: The result of 20 + (2 * 4) is 28.
print(str(response))
The result of 20 + (2 * 4) is 28.
[ToolCallResult(tool_name='multiply', tool_kwargs={'a': 2, 'b': 4}, tool_id='a394d807-a9b7-42e0-8bff-f47a432d1530', tool_output=ToolOutput(content='8', tool_name='multiply', raw_input={'args': (), 'kwargs': {'a': 2, 'b': 4}}, raw_output=8, is_error=False), return_direct=False), ToolCallResult(tool_name='add', tool_kwargs={'a': 20, 'b': 8}, tool_id='784ccd85-ae9a-4184-9613-3696742064c7', tool_output=ToolOutput(content='28', tool_name='add', raw_input={'args': (), 'kwargs': {'a': 20, 'b': 8}}, raw_output=28, is_error=False), return_direct=False)]
让我们看看驱动 ReAct 代理的核心系统提示词!
在代理内部,当前的对话历史记录会在此行下方转储。
prompt_dict = agent.get_prompts() for k, v in prompt_dict.items(): print(f"Prompt: {k}\n\nValue: {v.template}")
prompt_dict = agent.get_prompts()
for k, v in prompt_dict.items():
print(f"Prompt: {k}\n\nValue: {v.template}")
Prompt: react_header Value: You are designed to help with a variety of tasks, from answering questions to providing summaries to other types of analyses. ## Tools You have access to a wide variety of tools. You are responsible for using the tools in any sequence you deem appropriate to complete the task at hand. This may require breaking the task into subtasks and using different tools to complete each subtask. You have access to the following tools: {tool_desc} ## Output Format Please answer in the same language as the question and use the following format: ``` Thought: The current language of the user is: (user's language). I need to use a tool to help me answer the question. Action: tool name (one of {tool_names}) if using a tool. Action Input: the input to the tool, in a JSON format representing the kwargs (e.g. {{"input": "hello world", "num_beams": 5}}) ``` Please ALWAYS start with a Thought. NEVER surround your response with markdown code markers. You may use code markers within your response if you need to. Please use a valid JSON format for the Action Input. Do NOT do this {{'input': 'hello world', 'num_beams': 5}}. If this format is used, the tool will respond in the following format: ``` Observation: tool response ``` You should keep repeating the above format till you have enough information to answer the question without using any more tools. At that point, you MUST respond in one of the following two formats: ``` Thought: I can answer without using any more tools. I'll use the user's language to answer Answer: [your answer here (In the same language as the user's question)] ``` ``` Thought: I cannot answer the question with the provided tools. Answer: [your answer here (In the same language as the user's question)] ``` ## Current Conversation Below is the current conversation consisting of interleaving human and assistant messages.
为了好玩,我们尝试指示代理以项目符号列表的形式输出答案和推理过程。请参阅“## Additional Rules”部分。
from llama_index.core import PromptTemplate react_system_header_str = """\ 你旨在帮助完成各种任务,包括回答问题、提供摘要以及其他类型的分析。 ## 工具 你可以使用各种工具。你有责任以你认为适当的任何顺序使用这些工具来完成手头的任务。这可能需要将任务分解为子任务,并使用不同的工具来完成每个子任务。你可以使用以下工具: {tool_desc} ## 输出格式 为了回答问题,请使用以下格式。 ``` Thought: 我需要使用工具来帮助我回答问题。 Action: 工具名称 (以下之一: {tool_names}) 如果使用工具。 Action Input: 工具的输入,采用 JSON 格式表示 kwargs (例如 {{"input": "hello world", "num_beams": 5}}) ``` 请 ALWAYS 从 Thought 开始。请为 Action Input 使用有效的 JSON 格式。不要这样做 {{'input': 'hello world', 'num_beams': 5}}。如果使用此格式,用户将以下列格式回复: ``` Observation: 工具响应 ``` 你应该重复上述格式,直到你有足够的信息来回答问题而无需使用任何其他工具。那时,你必须以以下两种格式之一回复: ``` Thought: 我无需使用其他工具即可回答。 Answer: [你的答案在这里] ``` ``` Thought: 我无法使用提供的工具回答问题。 Answer: 抱歉,我无法回答你的查询。 ``` ## Additional Rules - 答案必须包含一系列项目符号点,解释你如何得出答案。这可以包括之前对话历史的各个方面。 - 你必须遵守每个函数的签名。如果函数需要参数,请勿传递任何参数。 ## 当前对话 以下是包含人类和助手交错消息的当前对话。 """ react_system_prompt = PromptTemplate(react_system_header_str)
from llama_index.core import PromptTemplate
react_system_header_str = """\
You are designed to help with a variety of tasks, from answering questions \
to providing summaries to other types of analyses.
## Tools
You have access to a wide variety of tools. You are responsible for using
the tools in any sequence you deem appropriate to complete the task at hand.
This may require breaking the task into subtasks and using different tools
to complete each subtask.
You have access to the following tools:
{tool_desc}
## Output Format
To answer the question, please use the following format.
```
Thought: I need to use a tool to help me answer the question.
Action: tool name (one of {tool_names}) if using a tool.
Action Input: the input to the tool, in a JSON format representing the kwargs (e.g. {{"input": "hello world", "num_beams": 5}})
```
Please ALWAYS start with a Thought.
Please use a valid JSON format for the Action Input. Do NOT do this {{'input': 'hello world', 'num_beams': 5}}.
If this format is used, the user will respond in the following format:
```
Observation: tool response
```
You should keep repeating the above format until you have enough information
to answer the question without using any more tools. At that point, you MUST respond
in the one of the following two formats:
```
Thought: I can answer without using any more tools.
Answer: [your answer here]
```
```
Thought: I cannot answer the question with the provided tools.
Answer: Sorry, I cannot answer your query.
```
## Additional Rules
- The answer MUST contain a sequence of bullet points that explain how you arrived at the answer. This can include aspects of the previous conversation history.
- You MUST obey the function signature of each tool. Do NOT pass in no arguments if the function expects arguments.
## Current Conversation
Below is the current conversation consisting of interleaving human and assistant messages.
"""
react_system_prompt = PromptTemplate(react_system_header_str)
agent.get_prompts()
{'react_header': PromptTemplate(metadata={'prompt_type': <PromptType.CUSTOM: 'custom'>}, template_vars=['tool_desc', 'tool_names'], kwargs={}, output_parser=None, template_var_mappings=None, function_mappings=None, template='You are designed to help with a variety of tasks, from answering questions to providing summaries to other types of analyses.\n\n## Tools\n\nYou have access to a wide variety of tools. You are responsible for using the tools in any sequence you deem appropriate to complete the task at hand.\nThis may require breaking the task into subtasks and using different tools to complete each subtask.\n\nYou have access to the following tools:\n{tool_desc}\n\n\n## Output Format\n\nPlease answer in the same language as the question and use the following format:\n\n```\nThought: The current language of the user is: (user\'s language). I need to use a tool to help me answer the question.\nAction: tool name (one of {tool_names}) if using a tool.\nAction Input: the input to the tool, in a JSON format representing the kwargs (e.g. {{"input": "hello world", "num_beams": 5}})\n```\n\nPlease ALWAYS start with a Thought.\n\nNEVER surround your response with markdown code markers. You may use code markers within your response if you need to.\n\nPlease use a valid JSON format for the Action Input. Do NOT do this {{\'input\': \'hello world\', \'num_beams\': 5}}.\n\nIf this format is used, the tool will respond in the following format:\n\n```\nObservation: tool response\n```\n\nYou should keep repeating the above format till you have enough information to answer the question without using any more tools. At that point, you MUST respond in one of the following two formats:\n\n```\nThought: I can answer without using any more tools. I\'ll use the user\'s language to answer\nAnswer: [your answer here (In the same language as the user\'s question)]\n```\n\n```\nThought: I cannot answer the question with the provided tools.\nAnswer: [your answer here (In the same language as the user\'s question)]\n```\n\n## Current Conversation\n\nBelow is the current conversation consisting of interleaving human and assistant messages.\n')}
agent.update_prompts({"react_header": react_system_prompt})
handler = agent.run("What is 5+3+2")
async for ev in handler.stream_events():
# if isinstance(ev, ToolCallResult):
# print(f"\nCall {ev.tool_name} with {ev.tool_kwargs}\nReturned: {ev.tool_output}")
if isinstance(ev, AgentStream):
print(f"{ev.delta}", end="", flush=True)
response = await handler
Thought: The current language of the user is: English. I need to use a tool to help me answer the question. Action: add Action Input: {"a": 5, "b": 3}Thought: I need to add the result (8) to the remaining number (2). Action: add Action Input: {'a': 8, 'b': 2}Thought: I can answer without using any more tools. I'll use the user's language to answer. Answer: The result of 5 + 3 + 2 is 10.
print(response)
The result of 5 + 3 + 2 is 10.