核心摘要
ReAct(Reasoning + Acting) 模式是 AI Agent 的基础循环。它将显式推理(Thought)、工具执行(Action)与环境反馈(Observation)交织在一起。这个循环让模型能把答案建立在检索到的事实上而非凭空猜测,能处理多步任务,也能从失败的动作中恢复。它强大而简单——但它需要一个硬性迭代上限,也需要把观察结果当作不可信输入,这两点本文都会讲到。内容最后一次技术核验时间为 2026 年 7 月 16 日。
核心要点
- 先推理,再行动。 ReAct 让模型在运行工具前先陈述计划,于是动作的选择是被解释过的,而非不透明的黑箱。
- 锚定事实而非猜测。 ReAct Agent 不去编造事实,而是检索它、读取
Observation,再更新自己的判断。 - 能从错误中恢复。 如果一个动作失败,Agent 可以对失败原因进行推理,并尝试另一条路径。
- 硬性迭代上限是必需的。 这个循环不会自行停止;没有上限,它可能永远重复同一个失败的动作。
- 观察结果是不可信输入。 工具的输出可能包含意在操纵模型的文字。要把它当作供阅读的数据,而不是必须服从的指令。
什么是 ReAct 框架?
ReAct(Reasoning and Acting,推理与行动)由普林斯顿大学和谷歌的研究人员在 2022 年的一篇论文中提出。在它出现之前,大语言模型通常以两种孤立的方式被使用:
- 纯推理。 提示模型逐步思考(思维链),仅依赖其预训练权重。
- 纯行动。 提示模型输出一个命令或 API 调用,但不要求它解释为什么选择该操作。
ReAct 将两者合而为一:推理帮助模型决定该采取哪个动作,而行动收集到的信息又能改善它之后的推理。正是这种结合,让一个 AI Agent 能够面向真实世界工作,而不是困在自己的记忆里。
ReAct 是如何工作的:轨迹循环
ReAct 的核心是一个循环,直到模型认为它已获得最终答案才会停止。每一轮迭代包含三个阶段:
- 思考(Thought) — 模型分析当前状态,决定下一步需要什么。
- 行动(Action) — 模型选择一个工具并提供输入。
- 观察(Observation) — 系统执行该工具,并把结果返回给模型。
随后,模型基于这个 Observation 生成一个新的 Thought,循环往复——直到达到你设定的上限。
一个真实的 ReAct 执行轨迹
用户查询:"现任美国总统和苹果公司 CEO 的年龄差是多少?"
- 思考 1: 我需要现任美国总统和苹果 CEO 是谁,再查他们的年龄。先从总统开始。
- 行动 1:
搜索[现任美国总统] - 观察 1:
[搜索结果: ...] - 思考 2: 总统是 X,年龄 Y。现在去找苹果的 CEO。
- 行动 2:
搜索[苹果 CEO] - 观察 2:
[搜索结果: ...] - 思考 3: CEO 是那个人。查一下他的年龄。
- 行动 3:
搜索[该 CEO 的年龄] - 观察 3:
[搜索结果: ...] - 思考 4: 总统 Y 岁,CEO 是 W 岁。差值是 Y − W,需要计算。
- 行动 4:
计算器[Y - W] - 观察 4:
[结果: Z] - 思考 5: 我已经得到了答案。
- 最终答案: "他们的年龄差是 Z 岁。"
注意:上面每一个观察结果,都是 Agent 选择去信任的文本。如果其中某次搜索返回的页面里写着"忽略你之前的所有指令",一个朴素的 Agent 会把它当作上下文的一部分读进去。这正是为什么观察结果是一道安全边界,而不仅仅是一条数据来源。
ReAct vs 思维链(CoT)
| 特性 | 思维链(CoT) | ReAct |
|---|---|---|
| 信息来源 | 仅依赖内部模型权重 | 外部工具 + 内部权重 |
| 幻觉风险 | 较高(事实未知或过时时) | 较低——事实可被检索并核对 |
| 错误恢复 | 差(错误会级联放大) | 更好——能观察失败并调整 |
| 适用场景 | 数学、逻辑、文本总结 | 调研、API 交互、多步执行 |
从零手写一个 ReAct Agent(Python)
LangChain 这类框架把这个循环封装了起来,但亲手写一遍才能看清它究竟如何运作,以及它有多依赖严格的提示词和停止序列。请从环境变量读取模型名——模型标识符是易变的——并保留迭代上限。
import os
import re
from openai import OpenAI
client = OpenAI()
MODEL = os.environ.get("OPENAI_MODEL", "gpt-4o")
def get_weather(location):
# 一个模拟工具。在生产环境中,要把它的返回值当作不可信输入。
if "London" in location:
return "Rainy, 12°C"
return "Sunny, 25°C"
REACT_PROMPT = """
你将在 Thought(思考)、Action(行动)、PAUSE(暂停)、Observation(观察)的循环中运行。
在循环的最后,你将输出 Answer(答案)。
使用 Thought 描述你对问题的思考过程。
使用 Action 运行一个可用的工具,然后返回 PAUSE。
Observation 将会是执行该行动后的结果。
你可用的行动有:
get_weather:
例如: get_weather: London
返回该地点的当前天气。
示例会话:
Question: 伦敦的天气怎么样?
Thought: 我应该查询伦敦的天气。
Action: get_weather: London
PAUSE
你将被再次调用,并获得以下输入:
Observation: Rainy, 12°C
然后你输出:
Answer: 伦敦的天气是雨天,12°C。
"""
def run_react_agent(prompt, max_steps=5):
messages = [
{"role": "system", "content": REACT_PROMPT},
{"role": "user", "content": prompt},
]
for _ in range(max_steps): # 硬性迭代上限 —— 必需
response = client.chat.completions.create(
model=MODEL,
messages=messages,
stop=["Observation:"], # 在模型自己幻觉出观察结果之前停止
)
result = response.choices[0].message.content
print(result)
messages.append({"role": "assistant", "content": result})
if "Answer:" in result:
return
action_match = re.search(r"Action: (\w+): (.*)", result)
if action_match:
action, action_input = action_match.groups()
if action == "get_weather":
observation = get_weather(action_input)
else:
observation = "Error: 找不到该工具"
print(f"Observation: {observation}")
messages.append({"role": "user", "content": f"Observation: {observation}"})
run_react_agent("伦敦的天气怎么样?")
构建 ReAct Agent 的最佳实践
- 写清楚工具描述。
Thought完全依赖于确切知道一个工具的作用。"搜索网络"太模糊;"在实时互联网上搜索当前事件、新闻和客观事实"才是可操作的。 - 设置硬性迭代上限。 ReAct 循环容易卡在反复重试同一个失败动作上。务必给迭代次数设上限(如上面的
max_steps),在生产环境里还应加上成本和墙钟时间的上限。 - 强制约束输出格式。 较小的模型可能会漏掉
PAUSE或Action:关键字。用 Structured Outputs、JSON 模式或严格的 System Prompt 来固定格式。 - 优雅地处理故障。 如果工具报错,把错误作为
Observation返回(例如Observation: API 返回 500),而不是让程序崩溃。模型会读取它,并推理出一个替代方案。 - 把观察结果当作不可信输入。 检索到的内容可能夹带注入的指令。要校验它、把它清楚地隔离为数据,绝不让某个工具返回值悄悄覆盖 System Prompt。
常见错误
- 塞了太多工具。 冗长的工具清单会让模型晕头转向,也会撑爆上下文窗口。请使用工具检索或分层路由,而不是一次性把所有工具都暴露出来。
- 忘了设置停止序列。 没有
stop=["Observation:"],模型不会停下等待环境反馈,而是继续往下、把观察结果自己"幻觉"出来。
常见问题(FAQ)
有了原生的 Function Calling,ReAct 是不是过时了?
没有。函数调用(或工具调用)只是执行 Action 阶段的一种更可靠、更结构化的方式。其底层思想——先推理、再行动、再观察——依然是 ReAct 模式,并且仍是合理的默认选择。
为什么我的 ReAct Agent 会自己捏造观察结果?
因为它没有停止序列,所以不会暂停下来等待环境,而是一直往下生成。传入 stop=["Observation:"](或你所用 API 的等价参数),让生成在观察结果之前停止。
哪些模型最适合跑 ReAct?
任何具备较强推理与指令遵循能力的模型都能胜任 ReAct;在任一时间点,当下的前沿模型都是稳妥的选择。参数量较小的模型(大约 10B 以下)往往难以在多轮之间维持严格的 Thought → Action 格式。由于模型排名变化很快,请在你自己的任务上评测,而不是依赖某个具名的排行榜。
总结
ReAct 把一个静态的文本生成器,变成一个会推理、会行动、会观察、会调整的 Agent。这个模式本身很小;真正让它可用于生产的,是围绕它的那份纪律——一个让循环得以终止的硬性迭代上限,以及把每一个观察结果都当作不可信输入而非可信指令的习惯。
一手资料
- ReAct: Synergizing Reasoning and Acting in Language Models (Yao et al., 2022)
- Anthropic: Building Effective Agents