5.3 ReAct 与规划框架:Thought–Action–Observation 循环到落地

3 阅读1分钟

基于《大规模语言模型:从理论到实践(第2版)》第8章 大模型智能体

爆款小标题:原书第8章规划与执行:ReAct 怎么想、怎么动、怎么观察


为什么这一节重要

上两节讲了智能体架构与 LangChain/Coze 的用法,但「模型如何一步步推理并调用工具」的具体形式有多种:有的框架采用 ReAct(Reasoning + Acting),让模型交替输出「思考—行动—观察」;有的采用 Plan-and-Execute,先让模型生成多步计划再按步执行。原书第 8 章对这两种范式都有介绍。本节把 ReAct 的 Thought–Action–Observation 循环、与 Plan-and-Execute 的差异、以及实现时的解析与步数控制讲清,便于你在单轮工具调用、ReAct 多轮与「先规划再执行」之间做正确选型并落地。


学习目标

  • 理解 ReAct(Reasoning + Acting)的「Thought → Action → Observation」循环及在工具调用中的具体表现。
  • 掌握「规划—执行」类框架(如 Plan-and-Execute)与 ReAct 的差异:先整体规划再逐步执行 vs 边推理边行动。
  • 能根据任务复杂度选择「单轮工具调用」「ReAct 多轮」或「先规划再执行」(原书第8章)。

一、ReAct:Thought–Action–Observation 循环(原书第 8 章)

Thought(思考):模型用自然语言简述「下一步该做什么、为什么」,例如「需要先查北京今天天气,再根据是否下雨决定是否带伞」。Thought 让模型的推理过程显式化,便于调试与引导;也帮助模型在复杂任务中「先想后做」,减少盲目调用。

Action(行动):模型输出具体工具调用,如 Search("北京今天天气") 或结构化 JSON {"tool": "weather", "args": {"city": "北京"}}。框架解析后执行工具,并将返回作为 Observation。

Observation(观察):工具返回的结果被拼回上下文,作为新一轮的输入。模型根据观察决定:是继续调用工具(如再查伞店位置)、还是可以给出最终答案。

循环与终止:模型根据 Observation 继续 Thought → Action → Observation,直到在 Thought 中给出最终答案并结束,或达到 max_steps 上限(必须设置,避免无限循环耗尽 token)。原书第 8 章指出,ReAct 依赖模型能正确生成工具名与参数格式,故工具描述与 few-shot 示例至关重要;实现时可用正则或结构化输出(如 JSON 模式)约束模型输出格式,便于解析。


二、Plan-and-Execute 与 ReAct 的差异(原书第 8 章)

Plan-and-Execute:先让模型一次性生成多步计划(如步骤 1 查天气、步骤 2 若下雨则查伞店、步骤 3 汇总建议…),再由执行器按步调用工具并检查结果;若某步失败可重试、修正计划或回滚。何时做规划:在任务开始时做完整规划。适用:步骤相对清晰、可预先分解、且分支不多的任务(如「订机票+订酒店」的固定流程)。

ReAct边推理边行动,每步只决定「当前这一步」做什么,根据观察再决定下一步;不做一次性全局计划。何时做规划每一步都是「小规划」。适用:需要试错、分支多、或中间结果会影响后续步骤的任务(如「根据搜索结果再决定查什么」)。选型:简单单步任务用 Function Calling 即可;多步且需试错用 ReAct;多步但可预先列计划、步骤稳定用 Plan-and-Execute。原书第 8 章对两种范式的对比与选型有说明。


三、实现要点:解析、步数控制与异常处理(原书第 8 章)

解析 Action:需从模型输出中准确识别「工具名」与「参数」。可用正则匹配(如 Search("..."){"tool": "search", "args": {...}})、或要求模型输出 JSON 并用 schema 校验;结构化输出(如 response_format 指定 JSON)可降低解析失败率。解析失败时,应把「解析错误」作为 Observation 反馈给模型,让其有机会修正输出格式,而不是直接终止;可设置重试次数,超过后再终止。

max_steps 与超时:必须设置最大步数(如 5–10),避免模型陷入无效循环;对长时间运行的工具可设超时,超时后返回错误信息作为 Observation,让模型决定重试或换策略。max_steps 过小可能导致复杂任务未完成就终止,过大则浪费 token 与成本;可根据任务类型设定,简单单步任务 3–5 步足够,多步推理可设 8–15 步。

人工确认与回滚:对关键操作(如付款、发邮件),可在架构上加入「人工确认」步骤;或对可逆操作设计回滚机制,防止错误行动造成损失。原书第 8 章对 Agent 的实现与安全有讨论。实现时可将「高风险工具」单独标记,调用时先暂停并推送至人工审核队列,通过后再执行。

Observation 的格式与长度:工具返回作为 Observation 拼入上下文时,需控制格式与长度。建议统一格式(如 Observation: ...),便于模型识别;超长返回做截断或摘要,避免挤占上下文。若工具返回为结构化数据(如 JSON),可提取关键字段转为自然语言描述,再拼入上下文,减少噪声。


四、案例:ReAct prompt 模板与解析实现

ReAct prompt 模板示例

你是一个助手,可以调用以下工具完成任务:
- get_weather(city): 查询城市天气
- search(query): 检索知识库

输出格式:每步先写 Thought:(思考下一步),再写 Action:(工具调用 JSON)。
完成时在 Thought 中写 Final Answer:(最终答案)。

示例:
Thought: 需要先查北京天气。
Action: {"tool": "get_weather", "args": {"city": "北京"}}
Observation: 北京今天晴,25°C
Thought: 天气晴朗,无需带伞。Final Answer: 北京今天晴,25°C,无需带伞。

解析逻辑:用正则提取 Action: {...},解析 JSON 得到 toolargs;执行工具后将结果拼成 Observation: ... 追加到上下文,再次调用模型。若解析失败,将 Observation: 解析失败,请按 {"tool":"xxx","args":{}} 格式输出 拼入,给模型一次修正机会。


五、工程实战要点

1. 解析与格式约束

实现 ReAct 时需解析模型输出中的「Action」与「Observation」边界,可用正则或结构化输出(如 JSON)约束。在 prompt 中明确写出「输出格式示例」,如 Thought: ... Action: {"tool": "xxx", "args": {...}},可显著降低解析失败率。若使用支持 JSON mode 的 API,可要求模型严格输出 JSON,进一步减少解析错误。

2. 步数、超时与成本控制

设置最大步数或超时,避免模型陷入无效循环;对关键操作可加人工确认或回滚。同时注意每步都会消耗 token(Thought + Action + Observation),多轮 ReAct 成本较高;可根据业务设定「单次对话最大 token 预算」,超出时提前终止并提示用户简化问题。

3. 任务类型与框架选型

简单单步任务(如「查今天天气」)用 Function Calling 即可,无需 ReAct 的完整循环;多步且需试错的任务(如「根据搜索结果再决定查什么」)适合 ReAct;多步但步骤可预先列出的任务(如「订机票+订酒店」)可考虑 Plan-and-Execute。选型错误会导致要么过度复杂(简单任务用 ReAct 浪费)、要么能力不足(复杂任务用单步调用难以完成)。


六、常见误区 & 避坑指南

  • 误区:所有任务都上 ReAct。避坑:简单单步任务用 Function Calling 即可,ReAct 适合需要多步推理与试错的场景。
  • 误区:不限制步数。避坑:无限循环会耗尽 token 与预算,必须设 max_steps 并做异常退出。

七、小结与衔接

本节基于原书第 8 章梳理了 ReAct 的 Thought–Action–Observation 循环、与 Plan-and-Execute 的「先规划再执行」的差异,以及实现时的解析与 max_steps 控制。下一模块将进入推理、部署与评估:量化、vLLM、评估体系与多模态(原书第 10–11 章及第 7 章)。


课后思考题

  1. 用「Thought—Action—Observation」各写一句示例,完成「查北京今天天气并决定是否带伞」的一轮 ReAct。
  2. ReAct 与 Plan-and-Execute 在「何时做规划」上有什么本质不同?各更适合哪类任务(举一例)?