ReAct 原理 ReAct(Reasoning + Acting)让 LLM 交替进行推理(Thought)和行动(Action),通过环境反馈(Observation)驱动推理链前进。
问题 → Thought → Action → Observation → Thought → Action → ... → Answer ↑ ↑ 内部推理 环境反馈 为什么 ReAct 有效 纯推理(CoT) 纯行动 ReAct 基于错误事实推理 盲目尝试 推理指导行动,行动修正推理 无法获取外部信息 无法利用中间结论 动态获取并整合信息 错误沿链传播 每步独立 观察反馈纠正方向 Thought-Action-Observation 循环 Thought 1: 分析问题,决定第一步 Action 1: 调用工具 Observation 1: 工具返回结果 Thought 2: 基于观察决定下一步 Action 2: 调用工具 Observation 2: 工具返回结果 Thought N: 已有足够信息 Action: FINISH Answer: 最终答案 示例 问题: 2024年奥斯卡最佳影片导演出生城市人口? Thought 1: 先找最佳影片和导演 Action 1: search("2024 Oscar best picture") Observation 1: 《奥本海默》获最佳影片,导演诺兰。 Thought 2: 诺兰出生城市 Action 2: search("Nolan birthplace") Observation 2: 出生于伦敦。 Thought 3: 伦敦人口 Action 3: search("London population") Observation 3: 约898万。 Thought 4: 信息齐全 Action 4: FINISH Answer: 诺兰出生于伦敦,人口约898万。 ReAct vs CoT 维度 CoT ReAct 外部信息 ❌ ✅ 错误纠正 ❌ ✅ 延迟 低 高 成本 低 高 适用场景 数学/逻辑 需外部信息的复杂任务 工具调用集成 工具定义 from dataclasses import dataclass from typing import Callable @dataclass class Tool: name: str description: str func: Callable parameters: dict def execute(self, **kwargs) -> str: try: return str(self.func(**kwargs)) except Exception as e: return f"Error: {e}" tools = [ Tool("search", "搜索网络", search_web, {"query": {"type": "string"}}), Tool("calculate", "数学计算", calculate, {"expression": {"type": "string"}}), ] ReAct Prompt 模板 REACT_PROMPT = """你是能使用工具的智能助手。 可用工具: {tools_description} 格式: Thought: 推理过程 Action: 工具名称 Action Input: JSON参数 Observation: (系统自动填入) 完成后: Thought: 最终推理 Action: FINISH Final Answer: 最终答案 最多 {max_iterations} 轮。 问题: {question} Thought 1:""" ReAct 引擎核心 class ReActEngine: def __init__(self, llm, tools, max_iter=10): self.llm = llm self.tools = {t.name: t for t in tools} self.max_iter = max_iter def run(self, question: str) -> dict: history = "" for i in range(self.max_iter): response = self.llm.generate(self._build_prompt(question, history), temperature=0) parsed = self._parse(response) if parsed.get('action') == 'FINISH': return {'answer': parsed.get('final_answer', ''), 'iterations': i+1} name = parsed.get('action', '') obs = self.tools[name].execute(**parsed.get('input', {})) if name in self.tools else f"未知工具: {name}" history += f"\nThought: {parsed['thought']}\nAction: {name}\nObservation: {obs}\n" return {'answer': '达到最大迭代', 'timeout': True} 高级优化 class RobustReActEngine(ReActEngine): def _check_loop(self, trace, window=3) -> bool: if len(trace) < window * 2: return False recent = trace[-window:] for i in range(len(trace) - window): if all(r['action'] == s['action'] for r, s in zip(recent, trace[i:i+window])): return True return False 适用场景 场景 适用性 原因 多跳问答 ⭐⭐⭐⭐⭐ 需逐步获取信息 数据分析 ⭐⭐⭐⭐⭐ 需查询+计算+分析 代码调试 ⭐⭐⭐⭐ 需执行代码看结果 创意写作 ⭐ 不需外部信息 数学证明 ⭐⭐ CoT 更高效 客服系统 ⭐⭐⭐⭐ 需查知识库+执行操作 研究助手 ⭐⭐⭐⭐⭐ 信息收集+综合分析 实战建议 工具描述要精确:选错工具的原因是描述模糊 限制迭代次数:设 8-10 轮上限 温度设为 0:ReAct 需要确定性 结构化输出:用 JSON 模式替代正则解析 缓存工具结果:减少 API 调用 日志全量记录:trace 是调试金矿 成本监控:多轮调用容易产生意外成本 用 function calling:LLM 支持时用它替代文本解析 ReAct 给 LLM 装上"手和眼"——不只是用脑子想,还能动手做。 加入讨论 这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
...