🔄 ReAct模式
1. 什么是ReAct
ReAct(Reasoning + Acting)是由Yao et al.(2022)提出的一种将推理与行动交织进行的Agent架构模式。 它让LLM在每一步都输出一个"Thought"(思考),然后决定采取什么"Action"(行动),最后观察行动的结果"Observation"(观察), 形成一个Thought → Action → Observation的闭环循环,直到任务完成。
🔄 ReAct核心循环
ReAct的核心是一个三阶段的迭代循环,每一步都包含完整的推理-行动-观察链路:
💭 Thought
推理思考 → ⚡ Action
执行动作 → 👁 Observation
观察结果 → 💭 Thought
继续推理...
推理思考 → ⚡ Action
执行动作 → 👁 Observation
观察结果 → 💭 Thought
继续推理...
各阶段详解
| 阶段 | 作用 | 示例 |
|---|---|---|
| Thought(思考) | 分析当前状态,推理下一步该做什么 | "用户想查天气,我需要先确认城市名称,然后调用天气API" |
| Action(行动) | 执行具体操作(调用工具、检索信息等) | search_weather(city="北京") |
| Observation(观察) | 获取行动结果,为下一次思考提供依据 | {"temp": 25, "weather": "晴"} |
2. ReAct vs 传统Chain-of-Thought
传统Chain-of-Thought(CoT)只是让LLM在输出最终答案前进行逐步推理,但推理过程完全在模型内部完成, 无法与外部世界交互。ReAct将推理与行动能力结合,使Agent能够获取外部信息、调用工具、执行操作。
| 维度 | Chain-of-Thought | ReAct |
|---|---|---|
| 核心机制 | 纯推理链,逐步推导答案 | 推理+行动交替,与环境交互 |
| 外部交互 | ❌ 无 | ✅ 可调用工具、API、检索系统 |
| 信息获取 | 仅依赖模型参数内知识 | 可获取实时外部信息 |
| 错误纠正 | 难以自我纠正(可能陷入幻觉) | 通过观察反馈自我纠正 |
| Token消耗 | 较低(仅推理文本) | 较高(推理+工具调用+结果) |
| 适用场景 | 数学推理、逻辑问题 | 信息检索、工具编排、Agent任务 |
| 事实准确性 | 可能产生幻觉 | 通过外部信息降低幻觉率 |
🔬 研究发现
Yao et al. 的实验表明,ReAct在HotpotQA(多跳问答)上的表现显著优于纯CoT,幻觉率降低约20%。
但ReAct也会因为工具调用失败而引入新的错误类型。
3. ReAct实现机制
核心伪代码
def react_agent(query, tools, max_steps=10):
"""
ReAct Agent 核心循环
"""
context = [{"role": "system", "content": SYSTEM_PROMPT}]
context.append({"role": "user", "content": query})
for step in range(max_steps):
# 1. 调用LLM,获取Thought + Action
response = llm.generate(context)
# 2. 解析出 Thought 和 Action
thought = parse_thought(response)
action = parse_action(response) # e.g. {"tool": "search", "args": {...}}
# 3. 检查是否为最终答案
if action.type == "FINISH":
return action.answer
# 4. 执行 Action,获取 Observation
observation = execute_tool(action.tool, action.args)
# 5. 将 Thought/Action/Observation 追加到上下文
context.append({
"role": "assistant",
"content": f"Thought: {thought}\nAction: {format_action(action)}"
})
context.append({
"role": "system",
"content": f"Observation: {observation}"
})
return "Max steps reached"
执行流程
单步流程详解
- 组装上下文:将系统提示、用户输入、历史Thought/Action/Observation序列拼接
- LLM推理:模型输出 "Thought: ... \n Action: ..." 格式文本
- 解析输出:从文本中提取动作类型和参数(正则解析或JSON Schema约束)
- 判断终止:如果Action类型为FINISH,返回最终答案
- 执行工具:调用对应的工具函数,获取Observation
- 追加反馈:将Observation注入上下文,进入下一轮循环
4. 循环终止条件设计
ReAct的核心挑战之一是何时停止循环。终止条件设计直接影响Agent的效率和准确性。
| 终止策略 | 描述 | 优点 | 缺点 |
|---|---|---|---|
| 显式终止信号 | Agent输出特定的"FINISH"动作,附带最终答案 | 语义清晰,答案质量可控 | Agent可能过早或过晚终止 |
| 最大步数限制 | 设置 max_steps,达到上限时强制返回 |
简单可靠,防止无限循环 | 可能截断有效探索 |
| Token预算限制 | 当上下文总Token数超过阈值时终止 | 直接控制成本 | 需要在性能和成本间权衡 |
| 连续失败检测 | 连续N次工具调用失败或Observation无进展时终止 | 智能检测卡死 | 阈值设置需要调优 |
| 置信度判断 | 当Agent对结果的置信度超过阈值时自动终止 | 语义级控制 | 置信度评估本身不可靠 |
⚠️ 常见陷阱:无限循环
Agent在遇到工具调用失败或信息不足时,可能陷入"调用-失败-重试"的死循环。
建议:始终设置最大步数 + 连续失败检测双保险。
5. 适用场景与局限性
✅ 适用场景
- 信息检索与问答:需要联网搜索或多步查询的任务
- 工具调用编排:需要动态选择和组合多个工具的场景
- 简单的Agent任务:如客服问答、数据查询、内容生成
- 需要实时信息的任务:天气查询、股票行情、新闻摘要
❌ 局限性
- 复杂多步骤规划能力弱:ReAct是贪心式决策,缺乏全局规划
- Token消耗高:每步都需要完整的Thought文本,长任务累积成本显著
- 缺乏并行执行能力:天然串行,无法同时执行多个独立动作
- 长上下文退化:随着循环增多,长上下文中的信息检索能力下降
- 错误传播:早期工具调用的错误可能误导后续推理
6. Token消耗优化
💰 ReAct的Token消耗优化策略
- 精简Observation:对工具返回结果做摘要压缩,裁剪无关信息
- 滑动窗口上下文:只保留最近N步的完整信息,早期步骤做摘要处理
- System Prompt优化:精心设计Prompt,减少解释性文字,提高指令密度
- 早期退出:在置信度足够高时提前返回,避免多余循环
- 批量工具调用:支持单步内并行调用多个独立工具,减少总步数
- 模型选择:简单任务使用小型模型处理Thought,仅在关键步骤调用大模型
- 缓存复用:对重复出现的Thought模式做缓存,减少重复推理开销