--- title: Beyond Chatbots:ReAct 框架如何让 LLM 进化成真正的 Agent author: Gamehu date: 2026-04-12 22:00:00 tags: - AI - Agent - ReAct - LLM - 架构设计 categories: - AI ---
AI ReAct Agent
## 前言 > **⚠️ 时间线说明:** 这篇文章实际上是在《{% post_link Agent-production-landing-plan 'Agent 生产落地:从 demo 到产品的血泪经验' %}》之前完成的,一直躺在草稿箱里忘了发。阅读顺序上,建议先看这篇理解 ReAct 原理,再看那篇的生产实践经验。 想象一下你现在要煮盆饺子。烧水、打料内心独白支配着每一个动作:"水开了,我该下饺子了。"当发现缺少关键调料,内心独白会调整策略:"没辣椒了?我用老干妈代替。"面对技术难点时,这个思维过程会触发外部行动:"我不确定需要煮多久,我需要打开美食APP查下。" 这种边想边做、边做边调整的能力,是人类解决问题的基本方式。但传统的大语言模型(LLM)完全没有这种能力——它们更像一个闭卷考试的学生,只能凭记忆一口气写到底,错了也没法改。 在人工智能领域,传统的大语言模型(LLM)一直像静态黑盒一样运作。虽然这些模型擅长语言模仿,但它们缺乏功能性的"工作记忆"和与世界动态交互的能力。这种隔离滋生了两种系统性失败:"幻觉循环",即模型自信地编造事实;以及"错误传播",即单一的逻辑失误会毁掉整个回答。 **ReAct(Reason + Act)框架代表了 AI 架构的范式转变。** 通过在孤立认知与外部执行之间搭建结构性桥梁,ReAct 将 LLM 从对话者转变为能够规划、执行和自我纠正的自主 Agent。 这篇是我学习 ReAct 的笔记,想把它讲清楚,也给自己留个档。 --- ## 一、ReAct 到底在解决什么问题 传统的 AI 能力其实是分裂的。要么你用 Chain-of-Thought(CoT)让模型在脑子里一步步推理,要么你用 Action-generation 让模型调用外部工具——但两者各自有坑: **纯推理(CoT)的问题:** 模型完全依赖内部参数知识,是个封闭系统。它没法查资料,没法更新自己的认知,结果就是自信满满地编事实(幻觉),而且一步错步步错(错误传播)。 **纯行动(Act-only)的问题:** 模型可以调用工具,但缺乏显式的长期规划能力。它没法跟踪子目标,也没法系统地探索环境,很容易陷入重复或无意义的操作。 **ReAct 的做法是:把两者缝合起来。** 推理痕迹帮助模型诱导、跟踪和更新行动计划,处理异常情况;而行动让模型能够对接外部信息源(Wikipedia API、浏览器、数据库)来获取实时信息。 ### 核心机制:反馈循环 ReAct 把 Agent 的活动结构化成一个三段式交替序列: ``` Thought(思考)→ Action(行动)→ Observation(观察)→ Thought(再思考)... ``` {% asset_img Xnip2026-04-13_10-13-37.jpg ReAct 反馈循环示意图 %} 1. **Thought:** LLM 用思维链把大任务拆成可管理的小任务,分析数据,决定下一步做什么 2. **Action:** 模型输出使用某个预定义工具的意图(比如搜索数据库)。注意:LLM 自己不执行工具,只输出工具名和参数 3. **Observation:** 外部系统执行工具,把结果反馈给 LLM Agent 基于这个观察重新评估进度,生成下一个 Thought。循环往复,直到输出最终答案。 这个循环看起来直白,但效果非常显著。在 HotpotQA 基准测试里,传统 CoT 的幻觉率(编瞎话的概率)是 14%,上了 ReAct 之后直接降到 6%[^1]。
关键洞察:ReAct 不是让模型"更聪明",而是给它一套"查资料→推理→再查资料"的机制,让它有机会认错和修正。
--- ## 二、五个核心要点:为什么 ReAct 有效 ### 要点 1:推理与行动的协同 ReAct 范式打破了传统上推理与执行的二分。其核心是形式化表达 **Â = A ∪ L**。在这个等式中,Agent 的行动空间从物理或程序步骤(A)扩展到包含内部的"语言空间"(L)。通过将"思考"视为模型轨迹中的另一种行动类型,ReAct 允许 Agent 生成口头推理痕迹——或称"想法"——与特定任务的动作交错进行。 这种协同使模型能够诱导、跟踪和更新计划,同时实时处理异常。正如 Yao 等人在其奠基性研究中所言:
"这种'行动'与'推理'之间的紧密协同使人类能够快速学习新任务,并在前所未有的情况下进行稳健的决策或推理。"
通过交错这些痕迹,模型使用推理来决定检索什么信息,而由此产生的观察又为后续推理提供基础。 ### 要点 2:通过观察环节打破幻觉循环 传统的思维链(Chain-of-Thought, CoT)提示鼓励模型"一步步思考",但它完全依赖模型的内部参数知识——一个容易"幻觉"不存在事实的封闭系统。ReAct 通过引入强制的 **Observation(观察)** 步骤来解决这个问题,将模型锚定在外部现实中。 在知识密集型任务中,ReAct 使用特定的动作词汇——包括 `search[entity]`、`lookup[string]` 和 `finish[answer]`——与 Wikipedia 等外部实体交互。这种迭代的 Thought-Action-Observation 循环迫使模型在继续之前根据真实知识库验证其逻辑。结果是统计学上显著的改进:在 HotpotQA 基准测试中,误报率(幻觉事实或逻辑的频率)从标准 CoT 的 **14%** 暴跌至 ReAct 框架下的 **6%**[^1]。这种锚定将 Agent 从创意作家转变为可信的调查者。 ### 要点 3:代理技能的效率悖论 ReAct 扩展分析中最深刻的见解之一是:"代理技能"通常比原始模型大小更具参数效率。 我们在"小模型悖论"中看到了突破:教模型如何推理和行动,比强迫它在权重中记忆海量事实更具泛化能力。 数据揭示了一个惊人的层级关系:一个较小的 PaLM-8B 模型,仅在 3,000 条 ReAct 轨迹上微调,就能胜过完全依赖提示的巨大 PaLM-540B 模型。更令人印象深刻的是,微调的 62B 模型超过了 540B 提示版本的性能[^1]。这表明 AI 的未来不在于构建越来越大的记忆数据仓库,而在于提炼模型导航工具集和环境的程序能力。 | 模型 | 方式 | 表现 | |------|------|------| | PaLM-540B | Zero-shot 提示 | 基准线 | | PaLM-8B | ReAct 微调(3,000 轨迹) | **超越 540B** | | PaLM-62B | ReAct 微调 | **大幅超越 540B** | *数据来源:Yao et al., *ReAct: Synergizing Reasoning and Acting in Language Models*[^1]* ### 要点 4:可解释性:终于能看懂 AI 在想什么了 传统模型的黑盒问题一直让人头疼。输入一个问题,输出一个答案,中间发生了什么?不知道。 ReAct 的"草稿本(scratchpad)"机制解决了这个问题。每一轮循环的 Thought、Action、Observation 都被记录下来,形成一条完整的"思维链"。 如果出错了,你能精确定位到是哪一步出的问题: - **推理错误**:模型陷入了重复循环,比如一直问同一个问题 - **检索错误**:外部 API 返回了不相关的信息 - **行动错误**:调用了错误的工具或参数 更有意思的是,这种透明性支持**人在回路(Human-in-the-loop)**的干预。这有点像你带新人:他在那自言自语分析问题,你说"这一步想偏了",他马上就能纠正。 ReAct 通过其人类可读的"草稿本",为 AI 的"黑盒"提供了一个罕见的窗口。Agent 过程的每一步都被记录为想法、行动和观察的序列,提供了以前不可能的诊断水平。 如果 Agent 失败,开发者可以精确定位确切的失败模式——比如模型陷入重复循环的"推理错误",或外部 API 返回无信息结果的"搜索错误"。这种透明性还促进了"人在回路(Human-in-the-loop)"的纠正。在 ALFWorld 环境(一个基于文本的任务模拟器)中,研究人员证明,人类可以通过简单编辑草稿本上的"想法"来引导失败的 Agent 回到正轨——删除幻觉或添加提示——使 AI 能够立即重新校准其计划[^1]。 **示例:ReAct 轨迹** ``` Thought: 用户询问 2024 年诺贝尔物理学奖得主,我需要确认最新获奖信息。 Action: search[2024 Nobel Prize in Physics winner] Observation: John J. Hopfield and Geoffrey Hinton were awarded... Thought: 好的,我已获得准确信息,现在可以回答用户了。 Action: finish[约翰·霍普菲尔德和杰弗里·辛顿] ``` ### 要点 5:复杂环境的动态规划 虽然标准 LLM 在多步骤任务上挣扎,但 ReAct 在 ALFWorld(合成家庭任务)和 WebShop(拥有 118 万产品的在线购物环境)等交互式环境中表现出色。与遵循 rigid 脚本的"仅行动(Act-only)"Agent 不同,ReAct Agent 利用动态推理将高级目标分解为可管理的子目标。 所以ReAct 的真正威力,在处理多步骤、需要探索的任务时才会显现出来。 ALFWorld 里有个典型任务:”把一个发烫的平底锅放到冷却架上”。这看起来简单,但模型需要: - 找到平底锅(可能在灶台上) - 判断它是不是”发烫”的状态 - 找到冷却架(可能在橱柜里) - 规划一条合理的移动路径 传统”只行动不思考”的 Agent(Act-only)在这种任务上成功率只有 45%,而 ReAct 能达到 71%[^1]。 ReAct 利用预训练的"常识知识"——例如,知道胡椒罐更可能在橱柜里而不是冰箱里——以手术般的效率探索环境。通过维护其进度的内部记录,ReAct Agent 避免了困扰纯反应式系统的无产出循环。 --- ## 三、如何构建一个 ReAct Agent 你可以用 LangChain、LangGraph 或 BeeAI 等开源框架快速搭建(比如 LangChain 的 `ZERO_SHOT_REACT_DESCRIPTION`),也可以从零用纯 Python 手写。下面是手写版本的逻辑拆解: ### 步骤 1:定义工具集 首先确定模型能用的具体行动。写 Python 函数(计算器、搜索等),然后把它们的签名和描述提取成 LLM 能理解的格式(JSON 或字符串)。 ```python # 示例工具定义 tools = { "search": { "description": "搜索 Wikipedia 获取实体信息", "parameters": {"entity": "要搜索的关键词"} }, "calculator": { "description": "执行数学计算", "parameters": {"expression": "数学表达式"} } } ``` ### 步骤 2:编写 ReAct 提示词 ReAct Agent 极度依赖特定的提示技巧来结构化输出。系统提示必须: - 引导模型一步步思考,交错想法和行动 - 提供可用工具列表 - 定义严格的输出格式,通常用标签如 `Thought:`、`Action:`、`Action Input:`、`Observation:` **提示词模板示例:** ``` 你是一个能够使用工具的 AI 助手。按以下格式解决问题: Thought: 分析当前情况,决定下一步行动 Action: 要使用的工具名称(从 [{tool_names}] 中选择) Action Input: 传递给工具的参数 Observation: 工具执行结果 ...(重复 Thought/Action/Observation 直到得出结论) Thought: 我现在知道最终答案了 Final Answer: 用户的最终答案 可用工具: {tools} 开始: Question: {input} ``` ### 步骤 3:构建执行循环 把提示词和用户问题传给 LLM 后,你需要一个程序循环来处理执行: 1. **解析输出:** 拦截 LLM 的文本输出,提取 `Action`(工具名)和 `Action Input`(参数) 2. **执行工具:** 你的 Python 代码调用对应的函数 3. **返回观察:** 把函数结果格式化为 `Observation`,追加到对话历史 4. **重复:** 把更新后的上下文传回 LLM,让它基于新数据生成下一个 `Thought` 5. **终止:** 当 LLM 确定有最终答案并使用 "Finish" 动作或输出最终响应标签时,循环结束 **伪代码示意:** ```python max_iterations = 10 history = prompt_template.format(input=user_question) for i in range(max_iterations): response = llm.generate(history) # 解析 Thought/Action/Observation thought = extract_thought(response) action = extract_action(response) action_input = extract_action_input(response) if action == "Finish": return action_input # 最终答案 # 执行工具 observation = execute_tool(action, action_input) # 追加到历史 history += f"\nThought: {thought}\nAction: {action}\nAction Input: {action_input}\nObservation: {observation}" ``` --- ## 四、生产环境的优化技巧 要让 ReAct Agent 稳定、高效地运行,避免常见陷阱,你需要以下优化: ### 1. 使用少样本示例(Few-Shot Exemplars) 虽然可以构建"零样本"ReAct Agent,但性能会在你加入人工编写的完整 Thought-Action-Observation 轨迹示例后显著提升。提供 **3 到 6 个** 高质量、任务特定的示例,能教会模型如何格式化想法、分解任务、处理不同工具。
技巧:示例要覆盖成功路径和典型的错误恢复场景,让模型学会"碰壁后怎么绕路"。
### 2. 与 Chain-of-Thought 和自一致性结合 研究表明,ReAct 高度依赖搜索结果质量;如果工具返回无用数据,模型的推理会跑偏。反过来,标准 CoT 受困于幻觉。 **最佳实践是构建混合系统:** - 如果 ReAct Agent 在给定步数内无法返回答案,回退到内部 CoT 推理(使用 Self-Consistency,即采样多条 CoT 路径并取多数答案) - 如果 CoT-SC 置信度低,切换到 ReAct 收集外部事实 这种"双保险"策略在知识密集型任务上效果最好。 ### 3. 设置严格的循环限制 因为框架本质上是反馈循环,ReAct Agent 有时会陷入重复生成相同想法和行动的困境,导致高延迟和 token 成本爆炸。你必须在代码中设置最大迭代次数或特定结束条件(如置信度阈值)来防止无限循环。 ```python # 示例:多层防护 MAX_ITERATIONS = 10 MAX_COST = 0.5 # 美元 seen_actions = set() for step in range(MAX_ITERATIONS): action_signature = (action_name, action_input) if action_signature in seen_actions: # 检测到循环,触发终止或切换策略 break seen_actions.add(action_signature) ``` ### 4. 微调实现可扩展性 纯粹从上下文提示中学习复杂推理和行动是困难的,尤其是对较小语言模型。然而,在几千条正确的 ReAct 轨迹上微调较小模型(如 8B 参数模型),能让它们大幅超越仅依赖标准提示的更大模型(如 PaLM-540B)。 **工程建议:** - 收集生产环境中的高质量轨迹作为微调数据 - 使用 LoRA 等高效微调技术降低计算成本 - 小模型+ReAct 往往比大模型裸跑更省算力、更可控 ### 5. 实现人在回路(Human-in-the-Loop)纠正 因为 ReAct 生成可读的、 verbalized 的推理痕迹,系统具有高度可解释性。你可以设计 Agent 允许人类检查其内心独白。如果模型产生了幻觉想法或走错了路,人类可以直接编辑生成的 `Thought` 文本。这能纠正模型的后续行为,引导它成功,无需重写代码或手动执行动作。 **典型应用场景:** - 客服 Agent 遇到边界案例时,人工客服介入修正推理方向 - 代码生成 Agent 逻辑走偏时,程序员编辑 Thought 引导它回到正轨 - 研究 Agent 检索到无关信息时,研究员删除幻觉并提供正确线索 --- ## 五、写在最后 ReAct 给我的最大启发,不是技术细节,而是一种设计哲学的转变。 以前我们总想造一个"什么都知道"的 AI——把人类知识全塞进模型参数里。ReAct 走的是另一条路:承认模型不可能全知,给它一套"查资料+推理"的机制,让它像人一样边做边学。 当前 AI 的最先进水平并不依赖单一框架,而是协同的切换方法。最有能力的系统将 ReAct 与 CoT-自一致性结合,对逻辑任务利用内部参数知识,当内部置信度低时切换到 ReAct 进行外部锚定。 随着我们从对话式聊天机器人过渡到能够浏览网页、使用软件工具和管理工作流的自主 Agent,Thought-Action-Observation 循环正在成为安全和可靠性的行业标准。我们不再只是构建会说话的模型;我们正在构建为了行动而思考的 Agent。 --- **参考** [^1]: [arxiv.org/abs/2210.03629](https://arxiv.org/abs/2210.03629) [^2]: [ReAct Prompting - Prompting Guide](https://www.promptingguide.ai/techniques/react) [^3]: [What is a ReAct Agent? - IBM](https://www.ibm.com/think/topics/react-agent) [^4]: [ReAct Paper (PDF) - arXiv](https://arxiv.org/pdf/2210.03629)