Google:ReAct 推理与行动协同框架

论文信息

  • 论文标题:ReAct: Synergizing Reasoning and Acting in Language Models

  • 论文链接arXiv:2210.03629

  • 论文作者:Shunyu Yao, Jeffrey Zhao, Dian Yu, Nan Du, Izhak Shafran, Karthik Narasimhan, Yuan Cao

  • 一句话总结:ReAct 把"思考文字(Thought)"和"外部动作(Action)"交错写进同一条推理轨迹,让大模型一边想、一边查、一边改计划,从而显著降低纯 CoT 的幻觉问题,并提升交互式任务成功率。

背景与动机

过去两条路线各自很强,但都缺一块:

  1. CoT / Reason-only 会推理,但它只能在模型参数里"闭门思考",一旦内部知识不够新、不够准,就容易把后续整条链条带偏。

  2. Act-only 会调用环境,但如果没有显式的中间思考,它常常不知道下一步为什么要搜、搜什么、什么时候该停。

论文要解决的是:能不能把 reasoning 和 acting 交错起来,让两者互相补短板

作者给出的核心 insight 很直接:

  • reason to act:先写出思路,帮助模型拆目标、定子目标、决定下一步动作;

  • act to reason:先去环境里拿信息,再把新观察塞回上下文,支撑后续推理。

这使得 LLM 不再只是一次性吐完答案,而是在一条显式轨迹里循环执行:Thought → Action → Observation → Thought ...

ReAct 不是再造一个新网络,而是重新定义了 LLM 在推理时该输出什么:除了最终答案,它还要输出中间想法和可执行动作。

整体架构

下面这张图就是全文最核心的总览图:左上是标准问答,左下是纯 CoT,右上/右下是 ReAct 在 HotpotQA 和 ALFWorld 里的实际轨迹。

端到端数据流可以概括成 6 步:

  1. 输入任务描述(问题、指令、当前环境观察)和少量 ReAct 示例;

  2. LLM 基于当前上下文先生成一段 Thought,用于分解目标、提炼线索、决定下一步;

  3. LLM 再生成一个 Action ,例如 Search[...]Lookup[...]click[...]Finish[...]

  4. 外部环境执行动作,返回 Observation

  5. Thought / Action / Observation 追加到上下文,形成新的轨迹前缀;

  6. 重复循环,直到输出 Finish[...] 或到达步数上限。

论文在形式化定义里给了这个交互框架:

o t ∈ O , a t ∈ A , c t = ( o 1 , a 1 , ... , o t − 1 , a t − 1 , o t ) , π ( a t ∣ c t ) o_t \in \mathcal{O},\quad a_t \in \mathcal{A},\quad c_t=(o_1,a_1,\ldots,o_{t-1},a_{t-1},o_t),\quad \pi(a_t\mid c_t) ot∈O,at∈A,ct=(o1,a1,...,ot−1,at−1,ot),π(at∣ct)

变量说明:

  • o_t \in \mathcal{O}:第 t 步环境返回的观察。

  • a_t \in \mathcal{A}:第 t 步可执行动作。

  • c_t:到第 t 步时,模型当前能看到的完整历史上下文。

  • \pi(a_t\mid c_t):给定上下文后,模型输出动作的策略。

如果把这套流程展开成 LLM 的 token 级实现,可把上下文看成:

  • C_t \in \mathbb{N}^{B \times L_t}:batch 内第 t 轮 prompt token 序列;

  • B:batch size;

  • L_t:当前上下文 token 长度,会随着交互轮次增加。

模块拆解

3.1 轨迹上下文构造器:把任务状态压成一条可续写的文本轨迹

模块作用:把问题、历史 Thought、Action、Observation 统一拼成 LLM 可继续生成的单条上下文。

输入:

  • 初始任务文本 x \in \mathbb{N}^{B \times L_x}

  • 历史 thought token T_{1:t-1}

  • 历史 action token A_{1:t-1}

  • 历史 observation token O_{1:t}

输出:

  • 当前上下文 C_t \in \mathbb{N}^{B \times L_t}

可写成:

C t = C o n c a t ( X , T 1 , A 1 , O 1 , ... , T t − 1 , A t − 1 , O t ) C_t = \mathrm{Concat}(X, T_1, A_1, O_1, \ldots, T_{t-1}, A_{t-1}, O_t) Ct=Concat(X,T1,A1,O1,...,Tt−1,At−1,Ot)

变量说明:

  • X \in \mathbb{N}^{B \times L_x}:任务输入,例如问题、指令、few-shot exemplars。

  • T_i \in \mathbb{N}^{B \times l_i^{th}}:第 i 轮 thought 的 token 序列。

  • A_i \in \mathbb{N}^{B \times l_i^{act}}:第 i 轮 action 的 token 序列。

  • O_i \in \mathbb{N}^{B \times l_i^{obs}}:第 i 轮 observation 的 token 序列。

  • L_t = L_x + \sum_{i=1}^{t-1}(l_i^{th}+l_i^{act}) + \sum_{i=1}^{t}l_i^{obs}:第 t 轮上下文总长度。

这里没有额外编码器、检索器或控制器,核心实现就是 prompt 轨迹本身

3.2 Thought 生成器:先想,再决定下一步怎么动

模块作用:在当前上下文上生成自由形式语言 thought,用来拆任务、抽线索、修正计划。

输入:

  • 当前上下文 C_t \in \mathbb{N}^{B \times L_t}

输出:

  • 当前 thought T_t \in \mathbb{N}^{B \times l_t^{th}}

论文把语言空间加入动作空间后,定义为:

A ^ = A ∪ L , a ^ t ∈ L \hat{\mathcal{A}} = \mathcal{A} \cup \mathcal{L}, \quad \hat{a}_t \in \mathcal{L} A^=A∪L,a^t∈L

并把 thought 写入下一轮上下文:

C t + 1 ( p r e − a c t ) = ( C t , a ^ t ) C_{t+1}^{(pre-act)} = (C_t, \hat{a}_t) Ct+1(pre−act)=(Ct,a^t)

变量说明:

  • \mathcal{A}:原始外部动作空间,例如 Wikipedia API、网页点击动作。

  • \mathcal{L}:自然语言 thought 空间。

  • \hat{\mathcal{A}}:扩展后的动作空间,既能输出可执行动作,也能输出语言 thought。

  • \hat{a}_t \in \mathcal{L}:第 t 轮 thought,本质上是不会直接改变环境的"语言动作"。

  • C_{t+1}^{(pre-act)}:加上 thought 后、还没执行真实动作时的中间上下文。

论文明确列出的 thought 用途包括:

  • 分解问题和制定计划;

  • 从 observation 中抽取关键事实;

  • 做常识推断或简单算术;

  • 判断当前搜索无效,决定换关键词;

  • 跟踪子目标是否完成。

3.3 Action 生成器:把 thought 落成外部可执行动作

模块作用:基于 thought 更新后的上下文,生成真正会作用于环境的动作。

输入:

  • C_{t+1}^{(pre-act)} \in \mathbb{N}^{B \times (L_t + l_t^{th})}

输出:

  • 动作 A_t \in \mathbb{N}^{B \times l_t^{act}},以及环境回传观察 O_{t+1} \in \mathbb{N}^{B \times l_{t+1}^{obs}}

抽象写法:

a t ∼ π ( ⋅ ∣ C t + 1 ( p r e − a c t ) ) , o t + 1 ∼ E ( a t ) a_t \sim \pi(\cdot \mid C_{t+1}^{(pre-act)}), \quad o_{t+1} \sim E(a_t) at∼π(⋅∣Ct+1(pre−act)),ot+1∼E(at)

变量说明:

  • a_t:第 t 轮动作。

  • \pi:LLM 在当前 prompt 下的条件生成策略。

  • E(\cdot):外部环境执行器,例如 Wikipedia API、ALFWorld、WebShop。

  • o_{t+1}:环境反馈。

  • l_t^{act}:动作 token 长度,通常很短,因为动作是结构化字符串。

  • l_{t+1}^{obs}:环境返回文本长度。

不同任务里的动作空间不同:

  1. HotpotQA / FEVERsearch[entity]lookup[string]finish[answer]

  2. ALFWorldgo to ...open ...take ...put ... 等文本动作

  3. WebShopsearch[...]click[...]Buy Now 等网页交互动作

3.4 Observation 回写与闭环控制:把外部世界重新接入推理链

模块作用:把环境返回的 observation 再塞回上下文,驱动下一轮 thought。

输入:

  • 上一步动作 a_t

  • 环境反馈 o_{t+1}

输出:

  • 新上下文 C_{t+1}

公式就是论文最关键的闭环更新:

C t + 1 = ( C t , a ^ t , a t , o t + 1 ) C_{t+1} = (C_t, \hat{a}t, a_t, o{t+1}) Ct+1=(Ct,a^t,at,ot+1)

变量说明:

  • C_t:旧上下文。

  • \hat{a}_t:thought。

  • a_t:action。

  • o_{t+1}:新 observation。

  • C_{t+1}:下一轮完整上下文。

这一层解决了纯 CoT 的核心短板:模型不再只依赖参数里的静态知识,而是可以用动作把新信息拉进来,再继续推理

3.5 稠密 thought 与稀疏 thought:两类任务对应两种轨迹节奏

模块作用:根据任务类型控制 thought 的出现频率。

输入:

  • 任务类型标签 d

  • 当前上下文 C_t

输出:

  • 当前轮是否触发 thought 的决策 m_t \in \{0,1\}

可概括为:

m t = g ( d , C t ) m_t = g(d, C_t) mt=g(d,Ct)

变量说明:

  • d:任务域。知识密集型 QA / FEVER 属于"每步都要想"的 dense-thought 模式;ALFWorld / WebShop 属于"关键位置才想"的 sparse-thought 模式。

  • m_t:是否插入 thought。1 表示当前步先生成 thought,0 表示直接行动。

  • g(\cdot):不是单独训练出来的分类器,而是通过 prompt 设计隐式实现的策略。

论文中的具体做法:

  • 知识密集型推理任务:Thought-Action-Observation 交替更密,因为每步都在围绕搜索和证据整合。

  • 长程决策任务:Thought 只出现在"定子目标、判断是否完成、决定下一个探索方向"这些关键位置,避免每步都写长思路把轨迹拖爆。

训练目标 / 损失函数

4.1 核心主结果:few-shot prompting,本身不训练参数

论文最主要的结果来自 PaLM-540B few-shot prompting。这一部分没有新增参数,也没有单独设计 loss;模型只是基于 prompt 直接解码 Thought / Action / Observation 轨迹。

所以如果只看主实验,ReAct 更像一种 推理时协议(inference-time protocol),不是一个额外训练出来的模块。

4.2 附录里的微调:标准自回归轨迹建模

论文在附录 B.1 里补充了微调实验:使用 3000 条由 ReAct 生成且答案正确的轨迹,去微调较小的 PaLM-8B / 62B,让模型直接按输入问题生成整段轨迹。

虽然论文没有把 loss 公式显式写出来,但根据原文"decode trajectories conditioned on input questions/claims"的描述,微调目标就是标准 next-token NLL:

L FT = − ∑ i = 1 L y log ⁡ p θ ( y i ∣ x , y < i ) \mathcal{L}{\text{FT}} = - \sum{i=1}^{L_y} \log p_\theta(y_i \mid x, y_{<i}) LFT=−i=1∑Lylogpθ(yi∣x,y<i)

变量说明:

  • x \in \mathbb{N}^{B \times L_x}:输入问题或 claim。

  • y \in \mathbb{N}^{B \times L_y}:目标轨迹 token 序列,里面包含 Thought、Action、Observation 以及最终 Finish。

  • y_i:第 i 个目标 token。

  • L_y:目标轨迹长度。

  • p_\theta:微调后的语言模型。

  • \mathcal{L}_{\text{FT}}:标准语言建模负对数似然损失。

附录 B.1 给出的训练细节:

  • batch size = 64

  • PaLM-8B:ReAct / Act 微调 4000 steps;Standard / CoT 微调 2000 steps

  • PaLM-62B:ReAct / Act 微调 4000 steps;Standard / CoT 微调 1000 steps

实验与分析

5.1 论文看什么任务

作者覆盖了四类完全不同的任务:

任务 环境 / 数据集 ReAct 主要动作 核心挑战
多跳问答 HotpotQA search / lookup / finish 多跳证据检索 + 答案合成
事实核验 FEVER search / lookup / finish 需要最新、精确、可核验证据
文本环境决策 ALFWorld 导航、开关、拿取、放置等文本动作 长程规划、子目标跟踪、常识探索
网页购物决策 WebShop 搜索、点商品、选属性、购买 噪声网页文本理解 + 属性匹配

5.2 知识密集型推理:ReAct 让检索更"有脑子"

论文主表中的关键数字如下:

Prompt Method HotpotQA EM FEVER Acc
Standard 28.7 57.1
CoT 29.4 56.3
CoT-SC 33.4 60.4
Act 25.7 58.9
ReAct 27.4 60.9
CoT-SC → ReAct 34.2 64.6
ReAct → CoT-SC 35.1 62.0

这张表要读出 3 个结论:

  1. ReAct 一定强于 Act-only:HotpotQA 27.4 vs 25.7,FEVER 60.9 vs 58.9。

  2. ReAct 在 FEVER 上优于 CoT:60.9 vs 56.3,说明"先拿证据再判断"对事实核验非常重要。

  3. 最强不是单独 ReAct,而是 ReAct 与 CoT-SC 的切换组合 :HotpotQA 最强是 ReAct → CoT-SC,FEVER 最强是 CoT-SC → ReAct

作者还做了人工错误分析:

类别 定义 ReAct CoT
True positive 推理链和事实都对 94% 86%
False positive 答案碰巧对,但推理链或事实有幻觉 6% 14%
Failure: reasoning error 推理步骤错误,含重复循环 47% 16%
Failure: search result error 搜索结果空或无信息 23% ​-
Failure: hallucination 虚构推理或虚构事实 0% 56%
Failure: label ambiguity 预测合理,但和标注不完全匹配 29% 28%

最值得记住的一点:ReAct 的代价不是"更容易幻觉",而是"更容易因为检索 / 轨迹结构受限而卡住";相反,CoT 最大的问题恰恰是幻觉。

5.3 微调后,ReAct 的优势会被放大

论文的发现很有意思:

  • 只做 prompting 时,小模型(8B / 62B)很难同时学会 thought 和 act,所以 ReAct 不占优;

  • 但用 3000 条正确轨迹做微调后,ReAct 直接跃升成最强方法;

  • PaLM-8B 微调版 ReAct 超过所有 62B prompting 方法,PaLM-62B 微调版 ReAct 甚至超过 540B prompting 方法

这说明 ReAct 的真正价值不只是在"当场 prompting",还在于它提供了一个非常好的 可监督轨迹格式:模型学到的不是死记答案,而是"如何一边想一边查"。

5.4 决策任务:稀疏 thought 对长程任务特别关键

论文在 ALFWorld 和 WebShop 的结果如下。

任务 指标 Act ReAct
ALFWorld best-of-trials success rate 45 71
WebShop Score 62.3 66.6
WebShop Success Rate 30.1 40.0

对比基线时,作者还给出:

WebShop 方法 Score SR
IL 59.9 29.1
IL + RL 62.4 28.7
ReAct 66.6 40.0
Human 82.1 59.6

这里最强的信息是:只靠 1-shot / few-shot prompting,ReAct 就已经超过了专门训练的 imitation / RL 基线

5.5 论文里的两个代表性案例

案例 A:用真实交互补上"知识过时"

Figure 4 展示了一个很典型的问题:数据集标注里的酒店规模已经过时,但 ReAct 通过真实检索 + 推理拿到了更新答案。这个案例说明:

  • CoT 的问题不是不会推,而是没有新证据;

  • Act-only 的问题不是拿不到网页,而是不知道该怎么沿着证据链继续找;

  • ReAct 两边都补上了。

案例 B:人类只改两句 thought,就能把失败轨迹扳回来

Figure 5 表明 ReAct 还有一个额外优点:可编辑。人不需要重写几十个动作,只要改两句 thought,后续动作就会整体转向正确轨迹。这件事对 agent 可控性很重要。

优势与局限

优势

  • 显著降低纯推理幻觉:在 HotpotQA 的人工分析里,ReAct 的 hallucination failure 为 0%,CoT 为 56%。

  • 跨任务通用:同一范式覆盖 QA、事实核验、文本环境、网页交互四类任务。

  • 解释性强:Thought、Action、Observation 分层清楚,人能直接检查哪一步错了。

  • 可人类干预:Figure 5 证明人可以直接改 thought,而不是只能改最终答案。

  • 非常适合后续监督学习:用正确轨迹微调后,ReAct 从 prompting 最弱变成 finetuning 最强。

局限

  • 结构约束会限制纯推理自由度:在 HotpotQA 上,ReAct 比 CoT 略低(27.4 vs 29.4),作者认为是因为交错结构降低了自由推理能力。

  • 搜索质量是瓶颈:ReAct 的一大错误来源就是 search result error(23%)。一旦第一次搜歪,后面很难恢复。

  • 长程任务对 prompt 容量敏感:复杂任务需要更多 demonstrations,但 in-context length 很快会顶满。

  • 主实验依赖超大闭源模型:核心 prompting 结果在 PaLM-540B 上完成,复现门槛高。

  • 环境交互仍受动作空间限制:论文里的 Wikipedia API 很简化,WebShop 也不是真实购买闭环,现实系统会更复杂。

我对这篇论文的核心提炼

ReAct 最重要的贡献,不是"让模型多写几句 thought",而是把 LLM 从一次性文本生成器 改造成了显式闭环决策器:模型先用语言组织计划,再通过动作拿外部信息,再把新信息回灌到后续推理里。

从今天看,ReAct 已经是很多 agent 框架的祖先形态:

  1. Thought / Action / Observation 的轨迹接口,后来几乎成了 agent 论文的通用母版;

  2. 把推理链暴露出来,让诊断、纠错、人工接管都变得可做;

  3. 把"工具调用"从外挂变成推理主循环的一部分,这点比单纯 tool-use 更关键。