我们用一个非常通俗易懂的方式来讲解 ReAct 框架,并附上常见的面试题,代码案例
一、ReAct 框架是什么?(通俗易懂版)
想象一下,你要解决一个复杂的任务,比如 "帮妈妈找出房间里最旧的那本书,并拍张照片发给她"。
一个笨办法是:你不动脑子,直接冲进房间,看到一本拍一本,把所有书都拍完再慢慢找最旧的。这很费劲,对吧?(这类似于早期一些没有规划的AI模型)
一个好办法 是:你会先思考 ,再行动 ,并且在过程中不断观察和调整。
ReAct 就是这个"好办法"的标准化流程。它的名字就是由三个核心步骤的首字母组成:
- Reason(推理) : "动脑子想"。分析当前情况,决定下一步该做什么。
- Act(行动) : "动手去做"。执行你想到的那个动作。
- Observe(观察) : "看看结果"。看看你的行动带来了什么结果,这个结果会成为下一步推理的新信息。
这三步会循环进行,直到任务完成。
现在,我们用这个"找书"的任务来模拟一个 AI 智能体使用 ReAct 框架的过程:
-
循环 1:
- 推理: "我的最终目标是找到最旧的书。首先,我需要知道房间里有哪些书。我应该先搜索房间。"
- 行动: 执行
搜索房间("书架")
。 - 观察: 观察到书架上有很多书,比如《三体》、《红楼梦》、《XX杂志2022》等。
-
循环 2:
- 推理: "我现在知道有哪些书了。要找到最旧的,我需要知道它们的出版日期。我应该检查《红楼梦》的出版日期,因为它可能比较老。"
- 行动: 执行
检查出版日期(《红楼梦》)
。 - 观察: 观察到出版日期是"2018年"。
-
循环 3:
- 推理: "2018年不算很旧。《三体》可能更新。那本《XX杂志》看起来有点旧,我应该检查它。"
- 行动: 执行
检查出版日期(《XX杂志2022》)
。 - 观察: 观察到出版日期是"2022年"。
-
循环 4:
- 推理: "这些书都不够旧。也许旧书不在书架上,可能在床底的箱子里。我应该搜索床底。"
- 行动: 执行
搜索房间("床底箱子")
。 - 观察: 观察到一本《新华字典》,看起来破破旧旧的。
-
循环 5:
- 推理: "这本书看起来很旧,很可能就是最旧的。我需要确认它的出版日期。"
- 行动: 执行
检查出版日期(《新华字典》)
。 - 观察: 观察到出版日期是"1995年"。
-
循环 6:
- 推理: "1995年比之前所有的书都早。我确认这就是最旧的书。现在我的最终行动是给它拍照。"
- 行动: 执行
拍照(《新华字典》)
并发送给妈妈
。 - 任务完成!
总结一下核心思想:
ReAct 让 AI 智能体像人一样,"走一步,看一步,想一步"。它通过不断的"思考-行动-观察"循环,将一个大任务拆解成小步骤,并能根据新获得的信息灵活地调整计划,而不是一条路走到黑。
二、常见的 ReAct 框架面试题
以下问题通常在考察你是否真正理解了 ReAct 的原理、优势以及如何应用它。
1. 概念理解题
-
问题:请解释一下 ReAct 框架是什么?它的三个核心步骤分别起什么作用?
- 考察点: 对基础概念的掌握。
- 回答思路: 按照上面的讲解,强调它是一个"推理-行动-观察"的循环交互过程。Reason 是大脑,Act 是手脚,Observe 是眼睛。
-
问题:ReAct 框架与传统的 Chain-of-Thought(思维链) 有什么区别?
- 考察点: 对 ReAct 独特价值的理解。
- 回答思路:
- Chain-of-Thought: 主要是"纯思考 "。它在模型的内部进行推理,一步步推导出答案,但没有外部行动。适合解答数学题、逻辑推理等纯脑力问题。
- ReAct: 是"思考+行动"。它允许模型调用外部工具(如搜索引擎、计算器、API)来获取未知信息,从而解决需要外部知识的问题。
- 举例: 问题"特朗普今年多大了?" CoT 会努力回忆训练数据里的信息;而 ReAct 会推理出"我需要搜索特朗普的出生日期",然后调用搜索工具得到答案。
2. 设计与应用題
-
问题:如果要你设计一个基于 ReAct 的天气查询智能体,它的模块和工作流程是怎样的?
- 考察点: 将理论应用于实践的能力。
- 回答思路:
- 感知模块: 接收用户输入"北京今天天气怎么样?"。
- 推理模块: 识别用户意图是查询天气,需要知道"北京"和"今天"这两个关键信息。
- 行动模块: 调用"天气查询工具"(一个API),并传入参数
城市=北京
,日期=今天
。 - 观察模块: 接收 API 返回的结果,如
{"天气": "晴", "温度": "25°C"}
。 - 推理模块: 将获取到的信息组织成自然语言回复。
- 行动模块: 输出最终答案"北京今天晴天,气温25摄氏度。"
-
问题:ReAct 框架在处理任务时,最大的优势是什么?它可能有什么缺点?
- 考察点: 辩证思考能力。
- 回答思路:
- 优势:
- 透明可解释: 我们可以清楚地看到智能体的思考过程,方便调试和信任。
- 减少幻觉: 对于事实性问题,通过调用工具获取真实数据,比依赖模型内部可能过时或错误的知识更可靠。
- 灵活性强: 可以根据观察到的结果动态改变计划,应对复杂任务。
- 缺点/挑战:
- 延迟较高: 每一步都需要调用模型推理和外部工具,整体响应速度可能较慢。
- 依赖工具: 工具的质量和可靠性直接决定了任务的成功率。
- 推理错误累积: 如果某一步推理错了,可能会导致后续步骤全部跑偏。
- 优势:
3. 场景分析题
- 问题:用户问"请总结一下 OpenAI 最新发布的模型的特点。" 请描述一个基于 ReAct 的智能体如何解决这个问题。
- 考察点: 在具体场景中运用 ReAct 的能力。
- 回答思路:
- Reason 1: "用户需要的是最新信息,我的内部知识可能已过时。我需要使用搜索引擎。"
- Act 1:
调用搜索("OpenAI 最新发布模型")
。 - Observe 1: 获取到一系列搜索结果链接和摘要。
- Reason 2: "第一个结果看起来是官方博客,很可靠。我需要阅读它的内容。"
- Act 2:
抓取网页内容(官方博客链接)
。 - Observe 2: 获取到博客的全文。
- Reason 3: "现在我有最新信息了,需要从中提取出模型的特点,并总结成一段话。"
- Act 3:
调用总结功能(博客全文)
并输出给用户。
三、代码案例
import datetime
import json
from openai import OpenAI # 需要安装: pip install openai
# 设置 OpenAI API 密钥
# https://platform.closeai-asia.com/developer/api
client = OpenAI(
base_url='https://api.openai-proxy.org/v1',
api_key='sk-xxxx',
)
# ==============================
# 1. 模拟外部工具函数
# ==============================
def get_current_time(location):
"""工具函数:获取指定城市的时间"""
timezone_map = {
"new york": -4,
"beijing": 8,
"london": 1,
"tokyo": 9
}
if location.lower() in timezone_map:
tz_offset = timezone_map[location.lower()]
utc_time = datetime.datetime.utcnow()
local_time = utc_time + datetime.timedelta(hours=tz_offset)
return local_time.strftime("%Y-%m-%d %H:%M:%S")
else:
return f"无法找到 {location} 的时区信息"
def get_current_weather(location):
"""工具函数:获取指定城市的天气"""
weather_data = {
"new york": {"temperature": "15°C", "condition": "晴朗"},
"beijing": {"temperature": "25°C", "condition": "多云"},
"london": {"temperature": "10°C", "condition": "下雨"},
"tokyo": {"temperature": "18°C", "condition": "多云"}
}
if location.lower() in weather_data:
return weather_data[location.lower()]
else:
return {"temperature": "未知", "condition": "未知"}
def search_web(query):
"""工具函数:模拟网络搜索"""
# 实际应用中会调用真实的搜索API
search_results = {
"openai latest model": "OpenAI最近发布了GPT-4 Turbo,具有128K上下文窗口和更快的推理速度。",
"python latest version": "Python最新稳定版本是3.12,发布于2023年10月。"
}
return search_results.get(query.lower(), f"未找到关于'{query}'的信息")
# ==============================
# 2. 使用大模型的 ReAct 智能体
# ==============================
class ReActAgentWithLLM:
def __init__(self):
self.available_tools = {
"get_current_time": get_current_time,
"get_current_weather": get_current_weather,
"search_web": search_web
}
# 工具描述,用于构建提示词
self.tool_descriptions = {
"get_current_time": "获取指定城市的当前时间。参数: location (城市名)",
"get_current_weather": "获取指定城市的当前天气。参数: location (城市名)",
"search_web": "搜索网络获取最新信息。参数: query (搜索查询)"
}
def run(self, query, max_steps=6):
"""运行ReAct循环,使用大模型进行推理"""
print(f"用户问题: {query}")
print("-" * 50)
# 初始化
context = [] # 存储之前的行动和结果
steps = 0
while steps < max_steps:
steps += 1
print(f"\n步骤 {steps}:")
# === Reason: 使用大模型生成推理和行动计划 ===
thought, action = self.reason_with_llm(query, context)
print(f"思考: {thought}")
# 检查是否应该结束
if action is None or action.get("name") == "final_answer":
final_answer = action.get("parameters", {}).get("answer", thought) if action else thought
print(f"\n最终答案: {final_answer}")
return final_answer
print(f"行动: {action}")
# === Act: 执行行动 ===
action_name = action["name"]
action_params = action["parameters"]
result = self.act(action_name, action_params)
print(f"结果: {result}")
# === Observe: 观察结果并存储到上下文 ===
context.append({
"thought": thought,
"action": action,
"result": result
})
return "达到最大步数限制,未能完成查询。"
def reason_with_llm(self, query, context):
"""使用大模型进行推理,决定下一步行动"""
# 构建系统提示词
system_prompt = """你是一个ReAct智能体,遵循思考-行动-观察的循环。
你可以使用以下工具:
- get_current_time: 获取指定城市的当前时间。参数: {"location": "城市名"}
- get_current_weather: 获取指定城市的当前天气。参数: {"location": "城市名"}
- search_web: 搜索网络获取最新信息。参数: {"query": "搜索查询"}
- final_answer: 当你有足够信息回答用户问题时使用。参数: {"answer": "你的回答"}
请严格按照以下JSON格式响应:
{
"thought": "你的推理思考过程",
"action": {
"name": "工具名或final_answer",
"parameters": {"参数名": "参数值"}
}
}
请基于当前上下文决定下一步行动。如果已有足够信息,请使用final_answer。"""
# 构建对话历史
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"用户问题: {query}"}
]
# 添加上下文(之前的思考-行动-观察)
for i, step in enumerate(context, 1):
messages.append({"role": "assistant",
"content": f"思考: {step['thought']}\n行动: {json.dumps(step['action'], ensure_ascii=False)}"})
messages.append({"role": "user", "content": f"结果: {step['result']}"})
try:
# 调用大模型
response = client.chat.completions.create(
model="gpt-3.5-turbo", # 或 "gpt-4"
messages=messages,
temperature=0,
response_format={"type": "json_object"} # 强制JSON输出
)
print('大模型参数=>', messages)
print('大模型响应=>', response)
# 解析响应
result = json.loads(response.choices[0].message.content)
thought = result["thought"]
action = result["action"]
return thought, action
except Exception as e:
print(f"大模型调用错误: {e}")
return "出现错误,尝试生成最终答案", {"name": "final_answer",
"parameters": {"answer": "抱歉,处理您的问题时出现了错误。"}}
def act(self, action_name, parameters):
"""行动部分:调用工具"""
if action_name in self.available_tools:
return self.available_tools[action_name](**parameters)
else:
return f"错误:未知工具 {action_name}"
def run_simple(self, query):
"""简化版本:单次调用处理简单问题"""
system_prompt = """你是一个智能助手,可以回答各种问题。"""
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": query}
],
temperature=0.7
)
return response.choices[0].message.content
# ==============================
# 3. 运行演示和对比
# ==============================
if __name__ == "__main__":
agent = ReActAgentWithLLM()
print("=" * 60)
print("测试1: 简单问题(直接回答)")
print("=" * 60)
result = agent.run_simple("法国的首都是什么?")
print(f"直接回答: {result}")
print("\n" + "=" * 60)
print("测试2: 需要工具查询的问题(ReAct流程)")
print("=" * 60)
user_query = "现在东京几点?天气怎么样?"
result = agent.run(user_query)
print("\n" + "=" * 60)
print("测试3: 需要搜索的问题")
print("=" * 60)
user_query = "Java程序员转大模型应用开发难么?"
result = agent.run(user_query)
准备这些题目时,关键是展现出你理解 ReAct 是一个将大模型"思考"能力与外部"行动"能力相结合的、循环的、可解释的框架。祝你面试顺利!