Prompt工程 进阶 ReAct 推理行动 Agent框架 Prompt工程

ReAct模式:推理与行动的协同框架

AIEng Hub
阅读约 20 分钟

ReAct模式:推理与行动的协同框架

ReAct(Reasoning + Acting)是一种将推理行动相结合的 Prompt 设计模式。它让 LLM 交替进行「思考 → 行动 → 观察」的循环,在复杂任务中显著优于纯推理(CoT)或纯行动(Act-only)的方法。

一、从思考到行动

1.1 为什么需要结合?

纯推理(CoT):
思考 → 思考 → 思考 → 答案
(缺少外部信息,可能产生幻觉)

纯行动(Act-only):
行动 → 观察 → 行动 → 观察 → 答案
(缺少推理,行动可能没有方向)

ReAct(结合):
思考 → 行动 → 观察 → 思考 → 行动 → 观察 → 思考 → 答案
↑ 规划  ↑ 执行  ↑ 反馈  ↑ 调整  ↑ 执行  ↑ 验证  ↑ 结论

1.2 三种模式对比

维度CoT(纯推理)Act-only(纯行动)ReAct(结合)
推理深度
信息获取依赖内部知识外部检索内外结合
幻觉风险
可追溯性推理过程可见行动可追踪两者兼有
适用场景纯推理题信息检索复杂任务

二、核心原理

2.1 ReAct 循环

"""
ReAct 的标准循环:

Thought:  当前状态分析,规划下一步
Action:   执行具体操作(搜索、计算、API调用等)
Observation: 获取行动结果,更新状态

重复以上步骤直到得出最终答案
"""

2.2 基础实现

import json
from typing import List, Dict, Optional

class ReActAgent:
    """
    ReAct 模式的基础实现
    """
    
    def __init__(self, llm, tools: Dict, max_steps=10):
        self.llm = llm
        self.tools = tools
        self.max_steps = max_steps
    
    def run(self, question: str) -> str:
        """
        执行 ReAct 循环
        """
        context = f"问题:{question}\n\n"
        
        for step in range(self.max_steps):
            # Step 1: 思考(Thought)
            thought = self._think(context)
            context += f"思考:{thought}\n"
            
            # Step 2: 决定是行动还是给出最终答案
            if "最终答案" in thought or step == self.max_steps - 1:
                return self._extract_answer(thought)
            
            # Step 3: 行动(Action)
            action = self._decide_action(thought)
            context += f"行动:{action}\n"
            
            # Step 4: 观察(Observation)
            observation = self._execute_action(action)
            context += f"观察:{observation}\n"
        
        return "无法在最大步数内完成任务。"
    
    def _think(self, context: str) -> str:
        """生成思考推理步骤"""
        prompt = f"""
{context}
基于以上信息,思考下一步应该怎么做。
如果已有足够信息回答问题,请输出"最终答案:[你的答案]"
否则,考虑需要哪些信息并描述你的思考。
"""
        return self.llm(prompt)
    
    def _decide_action(self, thought: str) -> str:
        """从思考中提取行动指令"""
        prompt = f"""
基于以下思考,决定需要执行什么操作:
{thought}

可用工具:
{json.dumps(list(self.tools.keys()), ensure_ascii=False)}

输出格式:工具名(参数)
示例:search("最新AI新闻")
"""
        return self.llm(prompt)
    
    def _execute_action(self, action: str) -> str:
        """执行工具调用并返回观察结果"""
        for tool_name, tool_func in self.tools.items():
            if tool_name in action:
                try:
                    # 提取参数
                    args = action.split('(')[1].rstrip(')')
                    return tool_func(args)
                except Exception as e:
                    return f"执行错误:{str(e)}"
        return f"未知工具:{action}"

2.3 ReAct Prompt 模板

# ReAct 标准 Prompt
react_prompt = """
请使用 ReAct 模式解决以下问题。

你的工作方式:
1. 思考(Thought):分析当前状态,规划下一步
2. 行动(Action):选择并执行一个操作
3. 观察(Observation):获取操作结果
4. 重复以上步骤,直到得出最终答案

可用工具:
- search(query): 搜索互联网获取信息
- calculate(expression): 执行数学计算
- lookup(key): 在知识库中查找信息

示例:
问题:特斯拉2024年的全球交付量是多少?

思考:我需要查找特斯拉2024年的交付数据。
行动:search("特斯拉 2024 全球交付量")
观察:特斯拉2024年全球交付量为178.9万辆

思考:已经获得数据,可以给出答案。
最终答案:特斯拉2024年全球交付量为178.9万辆。

现在请解决:
问题:{question}
"""

三、实战案例

3.1 信息检索型任务

问题:Python 中列表和元组的主要区别是什么?

# ReAct 执行过程
"""
思考:这是一个常见的 Python 概念对比问题,我可以直接回答。

思考:创建、修改、性能三个维度对比最清晰。

最终答案:

| 特性 | 列表 (list) | 元组 (tuple) |
|------|------------|-------------|
| 可变性 | 可变 | 不可变 |
| 语法 | [] | () |
| 性能 | 较慢 | 较快 |
| 使用场景 | 动态数据 | 固定数据 |
"""

3.2 需要外部信息的任务

问题:2024年诺贝尔物理学奖得主是谁?他们有哪些主要贡献?

# ReAct 执行过程
"""
思考:这需要查询最新信息,我无法只靠训练数据确定。
行动:search("2024 Nobel Prize Physics winners")
观察:2024年诺贝尔物理学奖授予 John Hopfield 和 Geoffrey Hinton

思考:我需要进一步了解他们的贡献。
行动:search("John Hopfield Geoffrey Hinton contributions")
观察:Hopfield 发明了Hopfield网络,Hinton 推动了深度学习

最终答案:
2024年诺贝尔物理学奖授予:
1. John Hopfield - 霍普菲尔德网络
2. Geoffrey Hinton - 深度学习先驱
主要贡献在于人工神经网络和机器学习的基础性发现和发明。
"""

3.3 多步骤推理任务

问题:如果A比B大3岁,B比C大2岁,三人的年龄之和是65岁。求各人年龄。

# ReAct 执行过程
"""
思考:这是一个三元一次方程问题。设C的年龄为x。
行动:我可以用代数方法推理。
观察: 
  设 C = x
  则 B = x + 2
  则 A = (x + 2) + 3 = x + 5
  总和:x + (x+2) + (x+5) = 65

思考:解方程。
行动:calculate("3x + 7 = 65")
观察:3x = 58, x = 19.33... 这不对,让我重新检查。

思考:总和我计算错误。
A + B + C = (x+5) + (x+2) + x = 3x + 7 = 65
3x = 58
x = 19.33... 年龄应该是整数,让我重新检查。

思考:等等,我设定有问题。
A = x + 5, B = x + 2, C = x
但 A + B + C = (x+5) + (x+2) + x = 3x + 7
3x + 7 = 65
3x = 58
x = 19.33 这不合理。

思考:让我再想想。A比B大3岁,B比C大2岁。
所以 A = B + 3, B = C + 2
A + B + C = (C+5) + (C+2) + C = 3C + 7 = 65
3C = 58... 还是不对,65-7=58,58/3不是整数。

思考:让我检查一下年龄之和。
行动:calculate("65 - 7")
观察:58

思考:58/3 ≈ 19.33,这不是整数。
这也许是一个分数年龄的问题?

最终答案:这不是一个整数解问题。
C = 19.33, B = 21.33, A = 24.33
但通常年龄问题有整数解。让我们重新检查题意...
"""

四、ReAct 与 Agent 框架

4.1 现代 Agent 中的 ReAct

当代 Agent 框架普遍采用 ReAct 模式或其变体:

Agent 框架ReAct 变体特色扩展
LangChain Agent标准 ReAct工具注册+错误重试
AutoGen多 Agent ReAct多角色对话+任务委派
CrewAI角色化 ReAct团队协作模式
OpenAI AssistantFunction Calling ReActAPI 原生支持
Claude AgentTool Use ReAct工具调用协议

4.2 ReAct 在 Agent 中的增强模式

"""
增强 ReAct 模式
"""

# 0. 标准 ReAct
# Thought → Action → Observation → Thought → ...

# 1. ReAct + 记忆
# Thought → [检索记忆] → Action → Observation → [存储记忆] → ...

# 2. ReAct + 规划
# [全局规划] → Thought → Action → Observation → [重新规划] → ...

# 3. Multi-Agent ReAct
# Agent A: Thought → Action → Observation → ...
# Agent B: Thought → Action → Observation → ...
# [协调器]: 监控所有 Agent,分配任务

五、ReAct 的局限性及应对

5.1 常见问题

问题表现原因解决方案
循环陷阱重复相同的思考-行动循环无法从观察中学习设置最大步数+去重检测
工具误导过度依赖工具所有问题都先搜索限制工具调用次数
思考过深思考时间过长试图完美推理设置思考超时+渐进式决策
上下文膨胀ReAct 记录太长每步都追加全文定期摘要压缩历史

5.2 改进策略

class ImprovedReAct(ReActAgent):
    """改进版 ReAct:增加循环检测和上下文压缩"""
    
    def __init__(self, llm, tools, max_steps=15):
        super().__init__(llm, tools, max_steps)
        self.visited_states = set()
    
    def _detect_loop(self, state: str) -> bool:
        """检测是否进入循环"""
        state_hash = hash(state)
        if state_hash in self.visited_states:
            return True
        self.visited_states.add(state_hash)
        return False
    
    def _compress_context(self, context: str) -> str:
        """当上下文过长时进行压缩"""
        if len(context) > 4000:
            prompt = f"""
压缩以下 ReAct 执行记录,保留关键信息:
{context[-3000:]}

压缩要求:
- 保留所有观察结果
- 保留最终结论
- 省略重复的思考
"""
            return self.llm(prompt)
        return context

六、最佳实践

6.1 何时使用 ReAct

任务类型推荐模式原因
简单问答CoTReAct 过度设计
需要外部的信息ReAct需要工具交互
代码生成Act-only直接输出代码
复杂推理+信息检索ReAct两者兼顾
多步骤规划ReAct+规划需要全局视角

6.2 Prompt 设计要点

# ✅ 好的 ReAct Prompt
react_prompt_good = """
使用以下格式:

思考:[分析当前状态]
行动:[工具名(参数)]  
观察:[行动结果]
...(可重复)
最终答案:[最终回答]

注意事项:
- 只有需要外部信息时才使用工具
- 一个思考步骤对应一个行动
- 得到足够信息后立即给出答案
"""

# ❌ 差的 ReAct Prompt
react_prompt_bad = """
你是一个Agent,需要思考然后行动。
思考要深入,行动要准确。
但是有时候也需要考虑...
可以多试几次...
"""

总结

ReAct 模式通过「思考→行动→观察」的循环协同,让 LLM 既具备深度推理能力,又能通过工具获取外部信息,有效弥补了纯 CoT 的幻觉问题和纯 Act 的盲目性问题。它在 Agent 系统中已成为事实标准,是构建可靠 LLM 应用的必备模式。