前言
ReAct = Reason + Action
ReAct的核心概念
- 推理和行动协同:利用数据和选项进行推理,根据推理选择行动
- 透明的决策:记录想法和行动
- 迭代处理:推理和行动可以重复执行,初始行动没有达到预期,就继续完善其方法
ReAct的步骤
- 定义环境和目标:描述环境、定义Agent的目标
- 例举支持的行动:枚举出所有支持的行动,比如查询数据库、调用API等
- 记录观察:记录行动执行的结果(行动执行成功或失败)
- 生成推理(基于上面的观察,推理下一次的行动,直到目标达成)
- 执行动作:推理完成后,选择行动并执行。
在LangGraph中实现ReAct架构如下
构建ReAct的最佳实践
- 结构化推理和行动的循环
- 有效的工具集成
- 使用记忆
- 多次迭代推理和行动
- 错误处理和反馈
ReAct示例1
使用create_react_agent快速构建一个ReAct的代理
- 这里提供了add和multiply的工具
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from dotenv import load_dotenv
import os
load_dotenv()
llm = ChatOpenAI(model="qwen-max",
base_url=os.getenv("BASE_URL"),
api_key=os.getenv("OPENAI_API_KEY"),
streaming=True)
# tools
def add(a: int, b: int) -> int:
"""Add two numbers together."""
return a + b
def multiply(a: int, b: int) -> int:
"""Multiply two numbers together."""
return a * b
tools = [add, multiply]
# ReAct agent
graph = create_react_agent(model=llm, tools=tools, debug=True)
# 计算 (3+4)x2
inputs = {"messages": [("user", "先计算3加4,然后把结果乘以2")]}
messages = graph.invoke(inputs)
for message in messages["messages"]:
print(message.content)
中间步骤和结果输出为
[values] {'messages': [HumanMessage(content='先计算3加4,然后把结果乘以2', additional_kwargs={}, response_metadata={}, id='9907aa98-0c48-4293-8218-d0de4436b437')]}
[updates] {'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_968d3dd3f37341c3aa3945', 'function': {'arguments': '{"a": 3, "b": 4}', 'name': 'add'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'qwen-max'}, id='run--e62988af-a468-4dad-8107-ad8c5fe96493-0', tool_calls=[{'name': 'add', 'args': {'a': 3, 'b': 4}, 'id': 'call_968d3dd3f37341c3aa3945', 'type': 'tool_call'}])]}}
[values] {'messages': [HumanMessage(content='先计算3加4,然后把结果乘以2', additional_kwargs={}, response_metadata={}, id='9907aa98-0c48-4293-8218-d0de4436b437'), AIMessage(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_968d3dd3f37341c3aa3945', 'function': {'arguments': '{"a": 3, "b": 4}', 'name': 'add'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'qwen-max'}, id='run--e62988af-a468-4dad-8107-ad8c5fe96493-0', tool_calls=[{'name': 'add', 'args': {'a': 3, 'b': 4}, 'id': 'call_968d3dd3f37341c3aa3945', 'type': 'tool_call'}])]}
[updates] {'tools': {'messages': [ToolMessage(content='7', name='add', id='01486876-06ca-489e-8049-809de856105c', tool_call_id='call_968d3dd3f37341c3aa3945')]}}
[values] {'messages': [HumanMessage(content='先计算3加4,然后把结果乘以2', additional_kwargs={}, response_metadata={}, id='9907aa98-0c48-4293-8218-d0de4436b437'), AIMessage(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_968d3dd3f37341c3aa3945', 'function': {'arguments': '{"a": 3, "b": 4}', 'name': 'add'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'qwen-max'}, id='run--e62988af-a468-4dad-8107-ad8c5fe96493-0', tool_calls=[{'name': 'add', 'args': {'a': 3, 'b': 4}, 'id': 'call_968d3dd3f37341c3aa3945', 'type': 'tool_call'}]), ToolMessage(content='7', name='add', id='01486876-06ca-489e-8049-809de856105c', tool_call_id='call_968d3dd3f37341c3aa3945')]}
[updates] {'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_477ab8b4c8a44c8e8ef777', 'function': {'arguments': '{"a": 7, "b": 2}', 'name': 'multiply'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'qwen-max'}, id='run--c00a4c74-13bc-4ae5-b4ea-e6e49c525fe2-0', tool_calls=[{'name': 'multiply', 'args': {'a': 7, 'b': 2}, 'id': 'call_477ab8b4c8a44c8e8ef777', 'type': 'tool_call'}])]}}
[values] {'messages': [HumanMessage(content='先计算3加4,然后把结果乘以2', additional_kwargs={}, response_metadata={}, id='9907aa98-0c48-4293-8218-d0de4436b437'), AIMessage(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_968d3dd3f37341c3aa3945', 'function': {'arguments': '{"a": 3, "b": 4}', 'name': 'add'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'qwen-max'}, id='run--e62988af-a468-4dad-8107-ad8c5fe96493-0', tool_calls=[{'name': 'add', 'args': {'a': 3, 'b': 4}, 'id': 'call_968d3dd3f37341c3aa3945', 'type': 'tool_call'}]), ToolMessage(content='7', name='add', id='01486876-06ca-489e-8049-809de856105c', tool_call_id='call_968d3dd3f37341c3aa3945'), AIMessage(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_477ab8b4c8a44c8e8ef777', 'function': {'arguments': '{"a": 7, "b": 2}', 'name': 'multiply'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'qwen-max'}, id='run--c00a4c74-13bc-4ae5-b4ea-e6e49c525fe2-0', tool_calls=[{'name': 'multiply', 'args': {'a': 7, 'b': 2}, 'id': 'call_477ab8b4c8a44c8e8ef777', 'type': 'tool_call'}])]}
[updates] {'tools': {'messages': [ToolMessage(content='14', name='multiply', id='e26c5f7c-f3fc-40fc-a03a-17c1feafe13b', tool_call_id='call_477ab8b4c8a44c8e8ef777')]}}
[values] {'messages': [HumanMessage(content='先计算3加4,然后把结果乘以2', additional_kwargs={}, response_metadata={}, id='9907aa98-0c48-4293-8218-d0de4436b437'), AIMessage(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_968d3dd3f37341c3aa3945', 'function': {'arguments': '{"a": 3, "b": 4}', 'name': 'add'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'qwen-max'}, id='run--e62988af-a468-4dad-8107-ad8c5fe96493-0', tool_calls=[{'name': 'add', 'args': {'a': 3, 'b': 4}, 'id': 'call_968d3dd3f37341c3aa3945', 'type': 'tool_call'}]), ToolMessage(content='7', name='add', id='01486876-06ca-489e-8049-809de856105c', tool_call_id='call_968d3dd3f37341c3aa3945'), AIMessage(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_477ab8b4c8a44c8e8ef777', 'function': {'arguments': '{"a": 7, "b": 2}', 'name': 'multiply'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'qwen-max'}, id='run--c00a4c74-13bc-4ae5-b4ea-e6e49c525fe2-0', tool_calls=[{'name': 'multiply', 'args': {'a': 7, 'b': 2}, 'id': 'call_477ab8b4c8a44c8e8ef777', 'type': 'tool_call'}]), ToolMessage(content='14', name='multiply', id='e26c5f7c-f3fc-40fc-a03a-17c1feafe13b', tool_call_id='call_477ab8b4c8a44c8e8ef777')]}
[updates] {'agent': {'messages': [AIMessage(content='计算3加4的结果是7,然后将这个结果乘以2得到14。', additional_kwargs={}, response_metadata={'finish_reason': 'stop', 'model_name': 'qwen-max'}, id='run--a4d69a92-11aa-4730-a5a1-47e14de7ffba-0')]}}
[values] {'messages': [HumanMessage(content='先计算3加4,然后把结果乘以2', additional_kwargs={}, response_metadata={}, id='9907aa98-0c48-4293-8218-d0de4436b437'), AIMessage(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_968d3dd3f37341c3aa3945', 'function': {'arguments': '{"a": 3, "b": 4}', 'name': 'add'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'qwen-max'}, id='run--e62988af-a468-4dad-8107-ad8c5fe96493-0', tool_calls=[{'name': 'add', 'args': {'a': 3, 'b': 4}, 'id': 'call_968d3dd3f37341c3aa3945', 'type': 'tool_call'}]), ToolMessage(content='7', name='add', id='01486876-06ca-489e-8049-809de856105c', tool_call_id='call_968d3dd3f37341c3aa3945'), AIMessage(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_477ab8b4c8a44c8e8ef777', 'function': {'arguments': '{"a": 7, "b": 2}', 'name': 'multiply'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'qwen-max'}, id='run--c00a4c74-13bc-4ae5-b4ea-e6e49c525fe2-0', tool_calls=[{'name': 'multiply', 'args': {'a': 7, 'b': 2}, 'id': 'call_477ab8b4c8a44c8e8ef777', 'type': 'tool_call'}]), ToolMessage(content='14', name='multiply', id='e26c5f7c-f3fc-40fc-a03a-17c1feafe13b', tool_call_id='call_477ab8b4c8a44c8e8ef777'), AIMessage(content='计算3加4的结果是7,然后将这个结果乘以2得到14。', additional_kwargs={}, response_metadata={'finish_reason': 'stop', 'model_name': 'qwen-max'}, id='run--a4d69a92-11aa-4730-a5a1-47e14de7ffba-0')]}
先计算3加4,然后把结果乘以2
7
14
计算3加4的结果是7,然后将这个结果乘以2得到14。
上面我们创建了一个基本的ReAct Agent,可以执行加法和乘法的混合计算。关键的步骤如下
- 用户输入,这部分用自然语言描述问题
- 推理,用LLM处理输入,确定是否调用工具
- 工具调用,如需调用工具,就自行调用工具节点
- 结果集成,工具的执行结果被传回给代理做下一步推理
- 输出,完成所有工具调用后,做出最终响应
create_react_agent 最核心的方法是create_react_agent,方法的参数为
- model 大模型api
- tools,集成的工具
- state_schema: 定义图状态结构,包括跟踪消息和其他元数据
- state_modifier 允许在将图形状态发送到语言模型之前对其进行修改
- checkpointer,store 管理保存和检索状态,以便跨会话持久化
- interrupt_before,interrupt_after 流中可以注入外部中断的点
- debug 调试模式
示意图为
工作流程如下
- 代理节点: 调用大模型(消息列表)
- 工具节点: 执行大模型返回的工具调用,反馈结果给大模型
- 条件路由:代理继续调用工具并根据工具输出进行推理,直到不再需要工具调用。一旦代理确定所有必要的作都已完成,它就会进入结束节点并返回最终结果
- StateGraph:定义图的节点和边的状态图
所以上面的示例的分解步骤如下
1. 初始输入:
○ 用户输入:“添加 3 和 4。将结果乘以 2。
○ 代理处理此输入并识别两个运算:加法和乘法。
2. 工具调用1 加法:
○ 工具叫做:add(3, 4)。
○ 结果:7。
3. 工具调用 2(乘法):
○ 工具叫做:multiply(7, 2)。
○ 结果:14。
4. 最终输出:
○ 智能体返回:“将 3 和 4 相加,然后将结果乘以 2 的结果是 14。
- 代理节点处理输入和输出的推理
- 工具节点执行特定动作(加法和乘法)