ReAct(Reasoning + Acting)是让大模型像人类一样**"边思考边行动"**的提示工程框架。它通过让模型在生成最终答案前,先输出推理步骤(Reasoning),再根据推理调用工具或采取行动(Acting),来解决复杂问题。
ReAct 的核心机制是思考与行动的循环。ReAct 不是一次性输出答案,而是构建了一个 **"思考 → 行动 → 观察 → 再思考"** 的循环闭环:
-
思考(Think):模型分析当前状况,决定下一步该做什么(例如:"我需要查询北京的天气来确定穿什么")。
-
行动(Act) :执行决策,通常是调用外部工具或 API(例如:调用
search_weather(Beijing))。 -
观察(Observe):获取工具返回的结果(例如:"北京今日气温 15°C,多云")。
-
循环:基于观察结果进行下一轮思考,直到问题解决。
典型应用场景
- 知识检索:先思考关键词,再调用搜索工具,最后综合信息给出答案。
- 数学计算:先制定解题计划,再调用计算器工具,避免大模型数学计算失误。
- 决策支持:在智能体(Agent)中,通过 ReAct 循环决定下一步动作。
需求分析:构建模块化的工具调用框架
下面示例的核心需求是创建一个基于ReAct(Reasoning+Acting)模式的智能体系统,使大语言模型能够通过工具调用来解决复杂任务。
具体需求包括:需要提供一个标准化的工具接口,使各种功能函数能够被智能体调用;实现一个推理-执行循环,让模型在解决问题时能够分步骤思考、调用工具、观察结果;需要处理用户输入到最终答案的完整流程,包括对模型输出的解析、工具执行和结果整合。代码还需要考虑实际应用中的容错性,如工具不存在、参数错误等异常情况。
示例中特别展示了对天气查询和百科搜索这两个典型场景的支持,体现了系统的实用性。这种架构的需求源于纯语言模型在信息实时性和准确性上的局限,需要通过工具来扩展其能力边界。
架构设计:分层解耦的智能体系统
该示例代码采用分层设计理念,将系统分为工具层、智能体层和模型适配层。工具层通过Tool类封装功能函数,提供统一的接口(名称、描述、执行函数),这是典型的适配器模式应用。智能体层以ReActAgent为核心,实现主要的控制逻辑循环,包括提示构建、模型调用、响应解析、工具执行和结果收集,采用了模板方法模式来定义算法的骨架。模型适配层通过llm_model回调函数实现,将具体的大模型实现与智能体逻辑解耦,这是策略模式的应用。设计中特别值得注意的是历史记录机制,每次迭代都将思考、行动和结果添加到历史中,为下一轮提供上下文,这种设计支持了多轮对话和复杂推理。错误处理被分散在各个层级:工具级处理执行异常,解析级处理格式错误,循环级处理超时终止,这种分层容错设计提高了系统的鲁棒性。
代码实现
# -*- coding: utf-8 -*-
"""
Created on Tue Jul 1 09:45:23 2025
@author: liguo
"""
import json
from typing import List, Dict, Any, Optional, Callable
class Tool:
"""表示一个可被智能体调用的工具"""
def __init__(self, name: str, description: str, func: Callable):
self.name = name
self.description = description
self.func = func
def run(self, parameters: Dict) -> Any:
return self.func(**parameters)
class ReActAgent:
"""实现Reasoning+Acting循环的智能体"""
def __init__(self, tools: List[Tool], llm_model: Callable):
self.tools = {tool.name: tool for tool in tools}
self.llm_model = llm_model
self.max_iterations = 10
def _parse_llm_response(self, response: str) -> Dict:
"""解析大语言模型的输出,提取思考和行动"""
try:
# 简单解析,实际应用中可能需要更复杂的解析逻辑
if "Thought:" in response and "Action:" in response:
thought = response.split("Thought:")[1].split("Action:")[0].strip()
action_part = response.split("Action:")[1].strip()
if "Action Input:" in action_part:
action_name = action_part.split("Action Input:")[0].strip()
action_input_str = action_part.split("Action Input:")[1].strip()
try:
# 尝试解析为JSON
action_input = json.loads(action_input_str)
except json.JSONDecodeError:
# 如果不是有效的JSON,作为字符串处理
action_input = {"input": action_input_str}
return {
"thought": thought,
"action": {
"name": action_name,
"parameters": action_input
}
}
except Exception as e:
print(f"解析LLM响应时出错: {e}")
# 默认回退
return {
"thought": "无法解析行动,直接回答",
"action": None,
"answer": response
}
def run(self, query: str) -> str:
"""运行ReAct循环处理用户查询"""
history = []
history.append(f"用户查询: {query}")
for i in range(self.max_iterations):
# 构建提示
prompt = "\n".join(history) + "\n思考:"
# 获取LLM响应
llm_response = self.llm_model(prompt)
# 解析响应
parsed = self._parse_llm_response(llm_response)
# 记录思考
history.append(f"思考: {parsed['thought']}")
# 处理行动
if parsed.get("action"):
action = parsed["action"]
tool_name = action["name"]
parameters = action["parameters"]
# 记录行动
history.append(f"行动: {tool_name}, 参数: {json.dumps(parameters)}")
# 执行工具
if tool_name in self.tools:
try:
result = self.tools[tool_name].run(parameters)
history.append(f"行动结果: {result}")
except Exception as e:
history.append(f"行动执行错误: {str(e)}")
result = None
else:
history.append(f"错误: 未知工具 '{tool_name}'")
result = None
else:
# 如果没有行动,直接返回答案
return parsed.get("answer", "无法生成答案")
return "达到最大迭代次数,未找到确定答案"
# 示例工具实现
def get_weather(city: str) -> str:
"""获取指定城市的天气信息"""
# 实际应用中这里会调用天气API
weather_data = {
"北京": "晴朗,25°C",
"上海": "多云,28°C",
"广州": "小雨,27°C"
}
return weather_data.get(city, "未知天气")
def search_wikipedia(query: str) -> str:
"""在维基百科上搜索信息"""
# 实际应用中这里会调用维基百科API
# 简化示例,返回一些模拟数据
if "Python" in query:
return "Python是一种广泛使用的高级编程语言,由Guido van Rossum于1989年圣诞节期间创建。"
elif "人工智能" in query:
return "人工智能是指计算机系统能够执行通常需要人类智能才能完成的任务的能力,如视觉感知、语音识别等。"
return f"关于'{query}'的信息未找到"
# 示例使用
if __name__ == "__main__":
# 定义工具
tools = [
Tool("get_weather", "获取指定城市的当前天气", get_weather),
Tool("search_wikipedia", "在维基百科上搜索信息", search_wikipedia)
]
# 模拟LLM模型
def mock_llm_model(prompt: str) -> str:
"""模拟大语言模型的输出"""
if "天气" in prompt:
return """思考: 用户想了解北京的天气,我可以使用get_weather工具获取信息
行动: get_weather
Action Input: {"city": "北京"}"""
elif "Python" in prompt or "人工智能" in prompt:
return """思考: 用户的问题需要百科知识,我可以使用search_wikipedia工具查找信息
行动: search_wikipedia
Action Input: {"query": "Python"}"""
return "直接回答: 我不知道这个问题的答案"
# 创建智能体
agent = ReActAgent(tools, mock_llm_model)
# 测试运行
weather_query = "北京现在的天气如何?"
print(f"查询: {weather_query}")
print(f"回答: {agent.run(weather_query)}")
python_query = "Python是什么时候创建的?"
print(f"\n查询: {python_query}")
print(f"回答: {agent.run(python_query)}")
代码结果
C:\Users\xiayu\miniconda3\envs\langgraph\python.exe C:\Users\xiayu\PyCharmMiscProject\AI-Agent-Dev-Practices-Code\第3章代码\3.3-ReAct框架的实现.py
查询: 北京现在的天气如何?
回答: 思考: 用户想了解北京的天气,我可以使用get_weather工具获取信息
行动: get_weather
Action Input: {"city": "北京"}
查询: Python是什么时候创建的?
回答: 思考: 用户的问题需要百科知识,我可以使用search_wikipedia工具查找信息
行动: search_wikipedia
Action Input: {"query": "Python"}
Process finished with exit code 0
代码解析:从静态结构到动态流程
在具体实现上,代码展现了清晰的静态结构和动态执行流程。静态结构上,Tool类的__init__方法定义了工具的元信息,run方法负责参数解包和函数调用;ReActAgent的构造函数建立工具索引,设置最大迭代次数。动态流程上,run方法实现了完整的ReAct循环:首先记录用户查询到历史,然后进入最多10次的迭代,每次迭代构建包含历史的提示,调用大模型,解析响应。解析逻辑_parse_llm_response采用字符串分割的简单方法,先提取思考部分,再尝试提取行动名称和JSON格式的参数,最后根据是否有行动决定是执行工具还是直接回答。工具执行时通过工具名索引获取工具对象,将参数字典解包传递给工具函数。示例使用中展示了典型的调用链:定义工具列表→创建模拟LLM→实例化智能体→执行查询,其中模拟LLM根据提示内容返回不同格式的响应,演示了从查询到工具调用的完整路径。这种实现虽然简洁,但清晰地展示了ReAct模式的核心机制。

