news 2026/8/28 6:48:40

ReAct模式解析:大模型如何通过思考与行动协同完成复杂任务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ReAct模式解析:大模型如何通过思考与行动协同完成复杂任务

大模型本身是“回答问题”的高手,但在“完成复杂任务”这件事上却经常捉襟见肘。你问它“北京今天适合带伞吗”,它能给出一个听起来合理但可能是编造的回答;你让它帮你对比三份方案并给出结论,它往往只在文字层面打转,既不会主动去查最新数据,也不会发现自己的推理已经偏离事实。真实世界里的任务,哪是只靠一次问答就能完成的?

这正是 ReAct 出现的契机。ReAct 不是某个前端框架,而是一套让大模型像人一样“先思考、再行动、看结果、再思考”的工作模式。它的名字来自 Reasoning + Acting,直译过来就是“推理与行动协同”。自 2022 年底论文《ReAct: Synergizing Reasoning and Acting in Language Models》发表以来,这个概念已经成了 AI Agent 领域最基础、也最常被引用的控制流范式之一——今天绝大多数 Agent 应用,底层都能看到 ReAct 的影子。

这篇文章的目标很简单:用最短时间帮你建立对 ReAct 的正确认知,然后给出一份可以直接复制运行的最小代码。读完你会明白三件事:ReAct 和 React 框架到底有什么关系;它和 CoT、RAG、Plan-and-Execute 这些概念的区别在哪里;以及不依赖重量级框架,怎么用朴素代码手写一个最小可用的 ReAct Agent。如果你想快速判断这个模式适不适合自己的项目,读第 1 到第 4 节就够了;想动手实践,直接跳到第 5、6 节。

1. 先澄清:ReAct 不是 React 框架

很多第一次接触 ReAct 的开发者,都会把它和前端框架 React 搞混。这不能怪大家,因为从拼写上看,ReAct 和 React 只差了一个字母的大小写。你去搜索引擎里搜“ReAct 入门”,前面几页大概率是 JSX、组件生命周期、虚拟 DOM 这类前端教程。中文语境下,这两者的名字几乎无法区分,给学习 AI Agent 的人造成了不小的困扰。

从词源上就能看出本质区别。React 是 Facebook 开发的 UI 库,因为“构建响应式界面”而得名;ReAct 则来自学术论文,它的初衷是让语言模型在推理(Reasoning)和行动(Acting)之间来回切换,从而解决单纯问答回答不了的问题。一个是前端渲染方案,一个是 Agent 控制流模式,根本不在同一个技术层次上。

如果你在面试中被问到 Agent 相关内容,提到的 ReAct 通常都是论文里的这个模式,而不是前端框架。建议无论如何都先确认对方指的是哪一个,避免鸡同鸭讲。React 前端框架解决的是“界面怎么渲染”,ReAct 解决的是“智能体要怎么一步步完成任务”,两者唯一的共同点,就是名字看起来很像。

2. 为什么需要 ReAct:传统提示词方法的三个瓶颈

在 ReAct 提出之前,用大模型做任务有三种常见思路,但它们各自都有明显短板。

第一种是普通的少样本提示(Few-shot Prompting)。给模型几个示例,让它照着格式回答。这种方式适合单轮问答,但模型一旦遇到没见过的问题,很容易一本正经地给出错误答案。第二种是思维链(Chain-of-Thought,CoT),让模型先把推理过程写出来,再给出最终结论。这一步能提升数学题、逻辑题的正确率,但本质上仍然是“闭卷答题”——模型从头到尾都在自己脑补,没有外部信息进来,也没有纠错机制。第三种是先写一段计划,再让模型按计划执行,看起来更接近真实工作,但计划一旦出错,模型往往没有能力在执行中途修正。

这三条路线共同的问题是:大模型只有“思考”这一根支柱,没有“行动”。它不会主动查资料,不会调用工具,也不会因为中途发现信息错误而停下来调整。而 ReAct 的突破点恰恰在这里:它把“思考”和“行动”放到同一个循环里,模型可以一边推理,一边选择调用外部工具,拿到工具返回的真实结果后再继续推理。

打个比方,CoT 是闭卷考试时在草稿纸上打草稿,ReAct 是允许你开卷考试,并且可以随时翻书、查资料、做完一步再回头改草稿。后者显然更接近人类解决复杂问题的过程,也正是真实业务对 Agent 的期待。

3. ReAct 核心机制:Thought / Action / Observation 循环

ReAct 的整个循环,可以浓缩成一句话:遇到任务时,按照“思考 → 行动 → 观察 → 再思考”的顺序推进,直到得到最终答案。

这个流程可以表示为:

Thought → Action → Observation → Thought → Action → Observation → …… → Final Answer

其中三个关键组件分别承担不同职责。

Thought(思考)是模型对当前状态的分析,作用是决定下一步应该做什么。这一步不需要特别复杂,但必须让后续动作有依据。Action(行动)是模型选择要调用的工具,比如“搜索天气”“查询数据库”“执行某个内部 API”。模型输出的 Action 通常需要附上一个 Action Input,也就是给工具的输入参数。Observation(观察)是工具执行后返回的结果,模型拿到这个外部反馈之后,再进入下一轮 Thought。如此反复,直到模型判断信息已经足够,才输出 Final Answer 结束循环。

拿最开始的问题举例。用户问“北京今天适合带伞吗”,一个 ReAct Agent 的完整过程可能是这样:

第一轮,模型先推理:用户想知道北京天气情况,我还没有数据,所以先查天气。于是输出:

Thought: 我需要先查询北京的天气信息,再判断是否需要带伞。 Action: search Action Input: 北京天气

工具返回:

Observation: 北京今天晴,最高气温25摄氏度,最低气温12摄氏度。

模型看到这个结果,再进入第二轮:今天是晴天,没有降雨,所以不需要带伞;如果白天在户外时间长,可以提醒注意防晒。于是输出:

Thought: 查询结果显示北京今天是晴天,没有降雨迹象。 Final Answer: 北京今天晴,不需要带伞;户外时间长的话,建议注意防晒。

整个过程中,模型每轮只推进一小步,而且每一步的推理都留下了文字轨迹。这就是 ReAct 的重要价值:它不止让智能体“会做事”,还让做事过程“可解释、可审计、可排查”。一旦最终结果出错,你能顺着推理轨迹找到是哪一步决策失误,这是黑盒式单轮问答做不到的。

还有一个容易被忽略的优势:因为行动能带来外部事实,模型可以在不确定时主动选择“检索”而不是“编造”,这在降低幻觉上会比纯粹脑补稳定不少。当然,它不能根治幻觉——如果工具本身返回了错误信息,模型依然可能基于错误继续推理,这一点后面在工程建议里会再提到。

4. 与主流方案对比:CoT、RAG、Plan-and-Execute 到底什么关系

很多初学者会把 ReAct 和另外几个高频概念搞混,这里用一张表直接对比。

方法核心动作是否可以调用工具是否在执行中调整典型场景
CoT仅推理数学题、逻辑推理题
RAG先检索再生成仅一次检索知识库问答、文档问答
ReAct推理 + 行动循环可以,多轮调用多步任务、实时信息查询、工具编排
Plan-and-Execute先规划再执行可以是通常否步骤明确、可预先拆解的任务

CoT 最接近“想一想再回答”,适合不需要外部信息的纯推理任务。RAG 则多了一个“查资料”的动作,但通常只查一次,查到结果后直接生成答案,不会因为答案不完整而再次检索。ReAct 更像是 RAG 的加强版——它把“检索”变成一个可复用的行动,并且允许模型在一轮检索之后发现问题,再决定是否进行第二轮。

Plan-and-Execute 和 ReAct 的差别更微妙。前者先让模型生成一个完整计划,再按顺序执行,执行过程中一般不重新规划;ReAct 则是边执行边看结果,每走一步都重新评估下一步。打个比方,Plan-and-Execute 是出发前规划好所有路线的自驾游,ReAct 是边走边查地图、遇到封路随时掉头的自由行。对天气变化、信息不确定的场景,ReAct 的容错能力明显更强;但对步骤非常明确、几乎没有意外的任务,Plan-and-Execute 的成本通常更低。

现实项目中,ReAct 和 RAG 不是只能二选一。一个常见的组合是把“检索知识库”包装成 ReAct 的一个工具,这样模型可以根据用户问题的复杂度,决定要不要检索、检索几次、还需要检索什么。你可以把它理解成 RAG 是插在 Agent 手里的一个工具包,而 ReAct 是使用工具包的决策流程。

5. 环境准备:你需要哪些依赖和 API Key

这一节我们准备写代码。为了让示例足够“朴素”,不依赖 LangChain 或 LlamaIndex 这类重量级 Agent 框架,直接用 OpenAI 兼容接口手写循环。这样做的好处是,你能看到 ReAct 的全部骨骼,而不是被框架封装的黑盒。

环境准备清单如下:

  • Python 3.9 或更高版本。
  • 安装 OpenAI Python SDK。终端执行:
pip install openai
  • 一个支持 OpenAI 兼容接口的大模型 API Key,并配置环境变量。
export OPENAI_API_KEY="你的APIKey"

如果你的模型服务商提供了自定义接口地址,也可以额外配置 base_url。比如某些国内云厂商提供 OpenAI 兼容接口,可以把服务地址设置成对应的 base_url。没有 OpenAI 官方账号完全不影响学习,关键是这个 API 必须支持 Chat Completions 格式。

需要提醒的是,如果你手头暂时没有可用的 API Key,依然可以先把代码写好,用一个假的 Key 跑一遍,观察模型输出位置的报错流程。真正的 ReAct 循环逻辑与具体 Key 无关,后续换成可用 Key 即可。另外,由于 ReAct 每次循环都要调用一次大模型接口,务必注意 API 服务的计费规则,建议先在测试环境用最小模型跑通。

6. ReAct 最小实现:用 OpenAI 兼容 API 手写 Agent 循环

下面这份代码是本文的核心示例。它没有使用任何 Agent 框架,而是自己维护一段对话消息列表,按照 ReAct 协议循环调用大模型。

# 文件路径:react_demo.py import os import re from openai import OpenAI client = OpenAI( api_key=os.environ.get("OPENAI_API_KEY", "sk-你的APIKey"), base_url=os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1"), ) SYSTEM_PROMPT = """ 你是一个通过“思考-行动-观察”循环来完成任务的 AI 助手。 你必须严格遵守以下协议: 1. 每一轮先输出 Thought: 用一句话描述你当前的推理。 2. 如果你需要调用工具,继续输出 Action 和 Action Input。 3. 拿到工具返回的 Observation 结果后,继续进入下一轮推理。 4. 当你确信已经得到最终答案,直接输出 Final Answer: 最终答案。 你可以使用的工具如下: - search(query): 返回一段与 query 相关的本地信息。 - calculator(expression): 计算一个数学表达式并返回结果。 输出示例: Thought: 我需要先查出目标城市的天气数据。 Action: search Action Input: 北京天气 Observation: 北京今天晴,25摄氏度。 Thought: 我现在得到了足够信息,可以给出答案。 Final Answer: 北京今天晴,25摄氏度。 """ TOOL_TABLE = { "北京天气": "北京今天晴,最高气温25摄氏度,最低气温12摄氏度,无降雨。", "上海天气": "上海今天多云,最高气温23摄氏度,最低气温16摄氏度,午后可能有阵雨。", } def search(query: str) -> str: """教学演示工具:返回本地字典中的数据。""" if query in TOOL_TABLE: return TOOL_TABLE[query] return f"没有找到与‘{query}’相关的数据,请尝试更精确的关键词。" def calculator(expression: str) -> str: """教学演示工具:计算数学表达式。生产环境请勿直接使用 eval。""" try: result = eval(expression, {"__builtins__": {}}, {}) return str(result) except Exception as e: return f"计算出错: {e}" def run_agent(user_input: str, max_steps: int = 6) -> str: messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": user_input}, ] for step in range(max_steps): response = client.chat.completions.create( model="gpt-4o-mini", messages=messages, temperature=0, ) answer = response.choices[0].message.content print(f"===== Step {step + 1} =====") print(answer) print() if "Final Answer:" in answer: return answer.split("Final Answer:", 1)[1].strip() action_match = re.search(r"Action:\s*(\w+)", answer) input_match = re.search(r"Action Input:\s*(.+)", answer) if action_match and input_match: action = action_match.group(1) action_input = input_match.group(1).strip() if action == "search": observation = search(action_input) elif action == "calculator": observation = calculator(action_input) else: observation = f"未知工具: {action}" messages.append({"role": "assistant", "content": answer}) messages.append({"role": "user", "content": f"Observation: {observation}"}) else: messages.append({"role": "assistant", "content": answer}) messages.append({"role": "user", "content": "请严格按协议输出 Thought/Action/Action Input/Final Answer。"}) return "达到最大步数,未得到最终答案。" if __name__ == "__main__": result = run_agent("北京今天天气怎么样?如果带伞合适吗?") print("最终答案:", result)

这段代码的关键逻辑可以拆成四步看。

第一步,维护 messages 列表。这是 ReAct 循环的数据基础,每轮都会把模型输出和工具观察结果追加进去,让模型在下一次调用时能看到完整的执行历史。

第二步,调用大模型。用 chat.completions.create 让模型按照 system prompt 给定的 ReAct 协议输出文本。temperature 设为 0,是为了减少随机性,让模型的工具选择更稳定。

第三步,解析模型输出。用正则匹配 Action 和 Action Input,然后根据动作名分发到具体工具。这里用了 search 和 calculator 两个工具,search 返回的是本地字典里的固定信息,实际项目中可以换成搜索引擎接口或内部知识库 API。

第四步,把 Observation 放回上下文。这是 ReAct 循环最核心的一步——模型输出的内容作为 assistant 消息,工具返回的结果作为一条新的 user 消息。下一轮模型调用时,就能基于 Observation 继续推理。

需要特别提醒的是,示例中的 calculator 使用了 eval,这在生产环境是非常危险的,存在任意代码执行风险。这里纯粹为了演示循环协议,生产环境请使用专门的计算库或沙箱执行。search 工具也只是一个教学演示,不要直接搬到线上。

另外,示例代码默认使用 gpt-4o-mini 模型。你可以根据自己实际可用的模型服务改成其他模型名称,比如某些云厂商提供的 qwen-plus、deepseek-chat 等,只要 base_url 对应兼容接口即可。这部分配置写成环境变量,方便在不同服务之间切换。

7. 运行结果与效果验证

运行方式很简单,终端执行:

python react_demo.py

正常情况下,你会看到类似下面的输出(实际内容取决于模型生成,不一定逐字一致):

===== Step 1 ===== Thought: 用户想知道北京的天气情况,以及是否需要带伞。我需要先查询北京的天气信息。 Action: search Action Input: 北京天气 ===== Step 2 ===== Thought: 查询结果显示北京今天是晴天,没有降雨,所以不需要带伞。 Final Answer: 北京今天晴,不需要带伞;户外时间长的话建议注意防晒。 最终答案: 北京今天晴,不需要带伞;户外时间长的话建议注意防晒。

判断循环是否成功的标准有三个。第一,模型没有一次给出最终答案,而是先选择了工具;第二,工具返回的 Observation 确实被展示在了助手输出里,并且后续模型推理引用了这个结果;第三,循环在有限步内终止,输出 Final Answer,而且没有报错。

如果模型只输出了 Thought 而没有 Action,或者出现了“达到最大步数”的提示,排除时先打印每轮 messages 内容,重点看模型是否按照 system prompt 里的协议输出。很多情况下,这是提示词描述不够清楚导致的,而不是代码逻辑问题。可以适当在 SYSTEM_PROMPT 里增加一个完整的 few-shot 示例,模型通常会立刻改观。

8. 常见问题与排查思路

ReAct 循环本身不复杂,但在实际运行中会遇到各种意外。这里整理了一份排查清单,遇到问题时按表定位。

问题现象可能原因排查方式解决方案
模型只输出 Thought,没有 Action提示词工具描述不明确,或模型想直接回答打印模型完整输出,检查是否提前出现 Final Answer在 SYSTEM_PROMPT 中补充工具说明和示例,必要时增加 few-shot
在同一个 Action 上反复循环工具返回没有新信息,或 Observation 没有正确拼入上下文打印每轮 messages 内容精简工具返回内容,设置 max_steps 上限,检查解析规则
上下文越来越长、成本上升ReAct 每轮都会追加消息,多次调用 token 消耗叠加观察 API 调用计费和 token 用量降低 max_steps,工具返回长文本时先做摘要
模型输出格式混乱,正则解析失败模型没有严格遵守协议打开日志记录完整输出改用 function calling 或结构化输出,减少文本解析脆弱性
调接口报 401 错误API Key 无效或没有权限检查环境变量和控制台配置重新生成 Key,配置最小权限
使用其他模型服务,接口报连接错误base_url 配置不正确检查 base_url 是否与模型服务商文档一致换成可用的兼容服务地址或云厂商接口
本地小模型生成结果不稳定模型指令跟随能力较弱换大模型或调整采样参数降低 temperature,或换用指令遵循能力更强的模型

这里重点展开两个高频问题。

第一,模型输出格式不稳定。这是文本协议方案最主要的痛点。即使 SYSTEM_PROMPT 写得再详细,模型依然可能偶尔不按格式输出。工程上更稳妥的解法是用 OpenAI 的 function calling 或结构化输出,让模型直接返回一个结构化的工具调用对象,而不是让文本解析器去猜。但理解 ReAct 思想时,文本协议是最好懂的入门方式,因为它把循环机制完整暴露了出来。

第二,长短上下文与成本控制。ReAct 每轮循环都要携带全部历史消息,包括所有 Thought、Action、Observation。随着步数增加,上下文会快速膨胀,不仅影响速度,也影响成本。建议在实际项目中给工具返回设置长度上限,或者在 Observation 进入上下文之前做一次摘要压缩。另一个思路是限制 Agent 只处理必要信息,不要把一大段原始文档塞回上下文。

9. 工程化建议与使用边界

理解了 ReAct 的循环原理之后,接下来要回答一个更实际的问题:真实项目里,要不要上 ReAct、以及怎么上。

先给判断标准。如果你的任务满足以下条件,ReAct 是一个比较合适的选择:任务需要多步推理;任务需要访问实时或外部数据;执行过程中存在不确定性,需要根据中间结果调整;过程需要可审计。典型场景包括个人知识库问答助手、营销素材自动整理、客服工单跟进、需要跨多个内部系统查询数据的 Agent。

反过来,如果任务只是单轮知识问答,或者对响应延迟非常敏感,ReAct 反而不是好选择。因为 ReAct 每走一步都要调用一次大模型,多轮循环意味着延迟和成本的多倍放大。一个简单的“今天是几号”问题如果非要套 ReAct,纯属杀鸡用牛刀。很多工具,包括搜索引擎、数据库查询、代码执行器,单独就能解决一轮任务,不需要让模型反复决策。

工程上落地时,有几个经验值得参考。工具描述要写得足够具体,模型是通过工具描述来判断该调用哪个工具的,描述模糊会直接导致选错工具。比如一个检索公司内部文档的工具,描述最好写成“输入员工姓名,返回其所在部门和入职时间”,而不是一句含糊的“查询员工信息”。循环要有边界,max_steps 和超时时间必须设置,否则模型可能在某个奇怪的问题上无限循环。日志要记录每一步的 Thought、Action、Observation,排错和审计都依赖这些中间信息。

安全边界是最不能忽略的部分。Agent 能调用的工具必须白名单化,不要让 Agent 自由选择任意系统命令。涉及数据库写操作、生产环境变更、支付、删除等高风险操作时,必须设置人工审批环节,不能让 Agent 直接执行。API Key 要遵循最小权限原则,只授予 Agent 完成任务所需的必要权限。所有涉及生产环境的改动,都应该先在测试环境验证,再逐步放量。

关于框架的选择,我的建议是入门阶段先手写一遍最小循环,理解协议之后再去使用 LangChain、LangGraph、LlamaIndex 这类工具。框架可以帮你省去消息拼装和工具分发的重复劳动,但也可能把循环机制封装成黑盒,遇到问题时不方便排查。用 LangGraph 这类图编排框架时,尤其要理解节点的执行顺序和状态传递,否则写出来的 Agent 依然难以维护。需要提醒的是,框架版本迭代很快,Agent API 在不同版本之间差异很大,使用前一定要核对当前文档。

10. 总结:ReAct 到底改变了什么

ReAct 看起来结构简单,但它对 LLM 应用范式的影响非常深远。在 ReAct 之前,大模型和外部世界的交互是割裂的:要么模型独立思考回答,要么通过 RAG 查一次资料直接生成。ReAct 把“思考”和“行动”组合成了一个紧密的循环,让模型可以在执行过程中不断吸收新信息、修正判断,最终给出来自推理与实证共同支撑的答案。

真正值得记住的点是:ReAct 解决的核心问题不是“调用一个工具”,而是“如何让一个语言模型在不迷失方向的情况下完成多步任务”。Thought 负责方向,Action 负责触碰外部世界,Observation 负责把外部世界的结果反馈回模型。三者交替出现,才构成了 Agent 的基本工作单元。理解了这一点,再看各种 Agent 框架,你会发现自己已经能看懂它们的骨架了。

建议的下一步是:把本文的示例代码跑通,然后把 search 换成真实的数据源,比如天气 API、数据库查询、内部系统接口。观察它在真实数据下的表现,再评估延迟和成本。等你对循环机制足够熟悉后,再去研究 LangGraph、多智能体协作、Agent 自我改进等进阶方向。AI Agent 领域发展很快,但 ReAct 作为最基础的控制流范式之一,值得你花一个下午彻底搞懂。收藏这篇文章,动手跑一遍,比看十篇概念科普都管用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/28 6:44:42

从FLOPs到内存流量:HarDNet如何优化神经网络访存效率

1. 从“算力瓶颈”到“访存瓶颈”的范式转移如果你在2018年前后开始接触深度学习模型部署,尤其是尝试在嵌入式设备或移动端跑一个像样的视觉模型,那你大概率经历过一段“内存焦虑”的时期。那时候,模型设计的焦点几乎完全集中在“计算量”&am…

作者头像 李华
网站建设 2026/8/28 6:44:10

Python实现混合搜索引擎:关键词检索与向量语义检索实战

1. 背景:为什么还需要一种“新类型”的搜索引擎先看一个我们都很熟悉的场景:在传统的搜索引擎里输入“如何用Python做文本去重”,返回的结果往往是关键词匹配的页面集合,用户需要自己打开三到五个网页,把碎片化的答案拼…

作者头像 李华
网站建设 2026/8/28 6:43:57

控制系统Matlab仿真:数学模型建立与Simulink实现全解析

1. 项目概述:从理论到实践的桥梁搞控制系统,尤其是自动控制、机器人或者机电一体化方向的工程师和学生,估计都绕不开一个环节:仿真。而一提到仿真,Matlab/Simulink几乎是我们的“第二工作台”。但不知道你有没有过这样…

作者头像 李华
网站建设 2026/8/28 6:43:43

AI Agent文档层设计:DocuQueue如何构建可检索的RAG异步管道

AI Agent 能调模型、能写代码、能操作工具,但一遇到企业内部 PDF、Word、Excel 组成的长文档,问题就出来了:上下文窗口放不下,文件格式又杂,文档还在不断更新。这个问题不能靠 prompt 修补,需要一个专门的文…

作者头像 李华
网站建设 2026/8/28 6:43:00

AI对冲基金濒临崩盘:自动化决策如何用四道闸门防失控

AI 进入金融交易的时间并不算短,但真正让人后背发凉的,是它开始自己下决定之后的那一瞬间。最近,一只名为 Situational Awareness 的 AI 对冲基金被曝险些崩盘,并且正在遭受 SEC 调查。标题里的几个词放到一起,几乎戳中…

作者头像 李华
网站建设 2026/8/28 6:42:53

使用codexpro实现网页端chatgpt操作本地项目

1.安装codexpro MCP https://github.com/rebel0789/codexpro/blob/main/README_ZH.md 先按照md启动起来,配置网页端插件,新增插件名称codexpro,url填写启动的cmd最后的url,认证方式选none,初步能用以后,由于…

作者头像 李华