引言:从对话到行动,AI Agent 的演进之路

人工智能的发展,一直在追寻一个宏伟的目标:创造一个能够理解世界、推理决策并与物理或数字世界交互的智能体 (Agent)。在这条漫长的演进之路上,我们见证了几个关键的范式跃迁。

最初,我们拥有的是对话式 AI。它们擅长基于海量文本数据,与人类进行流畅的、特定领域的对话。这些系统是出色的语言模型,但本质上是“静态”的——它们的世界仅限于它们的训练数据,无法感知或影响此时此地的现实。

随后,大型语言模型 (LLM) 的出现带来了指令遵循 (Instruction Following) 的浪潮。模型如 GPT-3.5、GPT-4 不仅能对话,还能理解并执行复杂的指令,比如总结文章、翻译文本、编写代码。这标志着 AI 从“对话者”向“执行者”迈出了第一步。然而,这种执行仍然局限于文本生成,是一种“虚拟”的执行。

为了让模型能够处理更复杂、需要多步逻辑推理的任务,研究者们提出了思维链 (Chain-of-Thought, CoT)。CoT 引导模型在给出最终答案之前,先生成一步步的推理过程。这极大地增强了 LLM 在数学、逻辑和常识推理任务上的表现。CoT 让模型学会了“思考”,但这种思考依然是“闭门造车”。它在一个封闭的、与外部世界隔离的环境中进行推理,无法验证信息的时效性,也无法获取训练数据之外的知识。

这就引出了一个根本性的问题:一个只会在自己脑子里思考,却无法与世界互动的智能体,其能力边界在哪里?如果一个任务需要查询最新的股价、预订一张机票、或者操作一个软件 API,纯粹的 CoT 就无能为力了。

智能的本质,不仅仅是内在的推理,更是与环境的动态交互。正是在这个背景下,一种新的、更强大的范式应运而生。2022 年底,来自 Google Research 和普林斯顿大学的研究人员发表了一篇名为《ReAct: Synergizing Reasoning and Acting in Language Models》的论文,正式提出了 ReAct 框架 par.nsf.gov

ReAct 的核心思想,正如其名,是**推理 (Reasoning)行动 (Acting)**的协同。它不再将思考和行动看作两个独立的阶段,而是将它们交织在一起,形成一个动态的循环。这个框架的提出,被认为是 AI Agent 发展的一个里程碑事件 ibm.com。它为我们构建能够真正“干活”的 AI Agent 提供了一套简洁而强大的设计哲学和实现蓝图。

这篇文章将深入探讨 ReAct 的技术世界。我们不仅会解析它的工作原理,更会剖析其背后的设计思想,探讨它如何解决了传统方法的局限,并将其与其他主流 Agent 范式进行比较。我们将穿梭于理论与实践之间,从 Prompt 设计的细节到工程部署的挑战,为你勾勒出一幅关于 ReAct 的完整技术图景。

问题分析:当“思考者”撞上现实的墙

在 ReAct 出现之前,学术界和工业界主要沿着两条路径探索如何让 LLM 解决复杂问题:一条是增强其“推理能力”,另一条是赋予其“规划与行动能力”。然而,这两条看似平行的路径,各自都遇到了难以逾越的瓶颈。

纯推理 (CoT) 的“真空”困境

思维链 (CoT) 的提出,无疑是 LLM 发展中的一次巨大飞跃。它通过让模型模仿人类的思考过程——“让我一步一步来想”——显著提升了处理复杂问题的能力。一个典型的 CoT 过程看起来是这样的:

问题: 一个篮子里有 5 个苹果,小明拿走了 2 个,又放进去了 3 个,现在篮子里有几个苹果?
CoT 推理: 开始时篮子里有 5 个苹果。小明拿走了 2 个,所以剩下 5 - 2 = 3 个苹果。然后他又放进去了 3 个,所以现在有 3 + 3 = 6 个苹果。
答案: 6 个。

这个过程非常漂亮,模型展示了清晰的逻辑分解能力。但是,如果问题稍微改变一下呢?

问题: 根据今天的收盘价,特斯拉的市值比福特高多少?

一个只具备 CoT 能力的模型会陷入困境。它可能会这样“思考”:

CoT 推理 (虚构): 我需要找到特斯拉和福特今天的收盘价。假设特斯拉的收盘价是 $200,流通股数是 30 亿股,那么它的市值大约是 $6000 亿。假设福特的收盘价是 $12,流通股数是 40 亿股,那么它的市值大约是 $480 亿。所以特斯拉的市值比福特高 $5520 亿。
答案: $5520 亿。

这个答案看起来逻辑通顺,但数据完全是模型“编造”的。这就是 CoT 的核心局限——知识静态事实幻觉 (Factual Hallucination)

  1. 知识静态性:LLM 的知识被冻结在训练数据截止的那个时刻。它不知道“今天”的收盘价,也无法获取任何新发生的事件信息。对于需要实时数据的任务,CoT 爱莫能助。

  2. 事实幻觉:当模型缺乏某个事实性知识时,它不会说“我不知道”,而是倾向于根据其学到的语言模式,生成一个看起来最“合理”的答案。这种“一本正经地胡说八道”在需要高事实准确性的场景中是致命的。CoT 虽然能规划出“需要查找数据”这一步骤,但它没有手和脚去执行这个查找动作。它的整个推理过程发生在一个与现实世界隔离的“真空”里。

纯规划系统的“僵化”弊病

另一条路径是规划与执行 (Plan-and-Execute)。这种方法的思路很直接:先让 LLM 制定一个完整的行动计划,然后由一个执行器 (Executor) 依次执行这个计划中的每一步。

例如,对于上面的查股价问题,一个 Plan-and-Execute 系统可能会这样工作:

第一步:规划 (Planning)
LLM 生成计划:

  1. 调用 search_stock_price 工具,查询特斯拉 (TSLA) 的当前价格。
  2. 调用 search_stock_price 工具,查询福特 (F) 的当前价格。
  3. 调用 get_outstanding_shares 工具,查询特斯拉的流通股数。
  4. 调用 get_outstanding_shares 工具,查询福特的流通股数。
  5. 使用 calculator 工具,计算 (特斯拉价格 * 特斯拉股数) - (福特价格 * 福特股数)。
  6. 输出最终计算结果。

第二步:执行 (Execution)
执行器按顺序调用工具,完成计算,最后得出答案。

这种模式看起来很美好,它清晰、结构化,而且确实能够与外部工具交互。但它的问题在于僵化缺乏适应性

  1. 对完美规划的苛求:这个模式假设 LLM 能够在一开始就预见所有可能的情况,并制定出一个完美无缺的计划。但现实世界是复杂的。如果在执行第 1 步时,search_stock_price 工具因为网络问题失败了怎么办?或者,如果 get_outstanding_shares 这个工具根本就不存在怎么办?预先制定的静态计划无法应对这些执行过程中的意外。

  2. 信息依赖的断裂:计划中的后续步骤往往依赖于前面步骤的结果。例如,第 5 步的计算依赖于前 4 步的查询结果。但在制定计划的阶段,这些结果都是未知的。LLM 是在“盲目”地规划,它无法根据“特斯拉股价是 $250”这个新信息来动态调整后续的行动。如果查询到的结果和预期不符(比如返回了一个错误信息),整个计划就会崩溃。

真正的需求:推理与行动的共生

CoT 是一个聪明的“思考者”,但手无寸铁。Plan-and-Execute 是一个刻板的“执行者”,缺乏灵活的头脑。这就揭示了一个深刻的洞见:智能决策并非一个线性过程,而是一个循环往复、不断调整的动态过程。

人类专家在解决复杂问题时,并不会先在脑海里构思一个天衣无缝的完美计划再开始动手。相反,我们通常是:

  1. 思考一下:我应该先做什么?(比如,先上网搜一下背景资料)
  2. 行动一步:执行搜索。
  3. 观察结果:看了搜索结果,我发现了一个之前没想到的关键点。
  4. 再次思考:基于这个新发现,我下一步不应该按原计划做了,而是应该去查阅另一份报告。
  5. 再行动一步:……

这个“思考-行动-观察”的循环,才是真实世界中解决问题的核心模式。推理为行动指明方向,而行动的结果又为推理提供了新的素材和修正依据。二者互为前提,共生共荣。

ReAct 正是抓住了这一核心思想。它设计的目的,就是要打破 CoT 的“真空”和 Plan-and-Execute 的“僵化”,在 LLM 内部建立起这样一套动态的、自适应的“思考-行动-观察”闭环。

ReAct 核心设计:思考-行动-观察的舞蹈

ReAct 的设计哲学,可以用“优雅的简洁”来形容。它没有引入复杂的外部模块或需要重新训练模型,而是通过一种巧妙的 Prompting 策略,引导 LLM 自主地在推理和行动之间进行切换,从而实现一个动态的反馈循环。这个循环的核心就是**“思考-行动-观察” (Thought-Action-Observation, 简称 T-A-O)**。

T-A-O 循环:AI Agent 的心跳

让我们把 T-A-O 循环拆解开来,看看每一步都在做什么。

  1. Thought (思考):这是 Agent 的“内心独白”。在这一步,LLM 会对当前的任务状态进行分析。它会回顾已经做了什么 (Previous Observations),评估当前的目标是什么 (Goal),然后决定下一步应该做什么。这个思考过程是至关重要的,它包括:

    • 分解任务:将一个大问题分解成更小的、可执行的子问题。
    • 制定策略:决定是需要调用工具获取信息,还是已经可以根据现有信息得出结论。
    • 自我修正:如果上一步的行动失败或结果不理想,思考下一步如何补救。
    • 综合信息:将来自不同工具的观察结果进行整合和推理。
  2. Action (行动):这是 Agent 与外部世界交互的唯一途径。根据上一步 Thought 的决策,LLM 会生成一个具体的可执行动作。在 ReAct 的原始实现中,这个动作是一个特定格式的字符串,通常是 [工具名称] [工具输入]。例如:

    • Action: search[特斯拉最新市值]
    • Action: calculator[180 * 3.14]
    • Action: finish[最终答案]

    这里的 searchcalculator 就是事先定义好的外部工具 (Tools),而 finish 是一个特殊的动作,表示任务已完成,可以输出最终答案。

  3. Observation (观察):当 Action 被生成后,它并不会直接进入下一次 LLM 的推理。而是由一个外部的“执行器”来解析这个动作,调用相应的工具,并将工具返回的结果作为 Observation

    • 如果 Actionsearch[特斯拉最新市值],执行器会调用搜索 API,并将返回的搜索摘要作为 Observation,例如:Observation: 根据 xxx 数据,截至 xxxx,特斯拉的市值为 7800 亿美元。
    • 如果 Actioncalculator[180 * 3.14],执行器会调用计算器,返回 Observation: 565.2
    • 如果工具调用失败,Observation 应该是一个清晰的错误信息,例如:Observation: Error: search API is currently unavailable.

这三步构成了一个完整的循环。Observation 会被附加到历史记录中,然后 LLM 基于包括这个新 Observation 在内的所有信息,开始新一轮的 Thought。这个循环会一直持续下去,直到 Agent 认为任务已经完成,并生成一个 finish 动作。

整个过程就像一个人在跳舞,思考一步,行动一步,观察一下周围的反馈,再调整下一步的舞姿。

交替之舞:为什么是“交替”而不是“分离”

ReAct 设计中最深刻的洞见在于,它坚持让推理和行动交替 (interleaved) 进行,而不是像 Plan-and-Execute 那样分离 (separated)。正如之前分析的,分离式设计的主要缺陷在于其僵化性。

交替模式的优势体现在“适应性”上:

  • 处理动态环境:世界是不断变化的。一个预先制定的计划很可能在执行中途就因为环境变化而失效。ReAct 的交替模式让 Agent 可以在每一步行动之后,重新评估环境 (Observation),并动态调整其后续策略 (Thought)。
  • 处理不确定性:工具的调用本身就充满不确定性。API 可能超时,返回的数据可能格式不符,搜索结果可能并不包含想要的信息。ReAct 允许 Agent 在 Thought 阶段识别这些意外情况,并生成补救措施。例如,如果 search[问题A] 没有得到好结果,Agent 可以在下一步 Thought 中决定换一个关键词 search[问题B] 试试。
  • 探索式学习:对于一些开放式问题(例如“调研一下 AI Agent 的最新进展”),根本不可能在一开始就制定出完整的计划。Agent 需要一边探索,一边学习,一边规划。ReAct 的循环完美地支持了这种探索式的工作模式。每一步的 Observation 都是新的知识输入,帮助 Agent 逐步构建对问题的完整理解。

这种交替执行的方式,使得 LLM 从一个静态的知识库和推理引擎,转变为一个能够与环境持续互动的动态学习者。

反馈闭环的魔力

从控制论的角度看,ReAct 的 T-A-O 循环本质上是一个反馈闭环 (Feedback Loop)

  • 目标 (Setpoint):用户的原始指令。
  • 控制器 (Controller):LLM 及其 Thought 过程。
  • 执行器 (Actuator)Action 的解析和工具调用。
  • 传感器 (Sensor)Observation 的获取,即对外部世界状态的测量。
  • 反馈 (Feedback)Observation 的结果被送回控制器 (LLM),用于下一次决策。

一个没有反馈的系统(开环系统),就像一个设定好时间的烤箱,时间到了就停止,不管面包是否真的烤好了。而一个有反馈的系统(闭环系统),则像一个带温度传感器的智能烤箱,它会持续监控面包的温度,并动态调整加热时间和功率,以确保面包达到完美的烘焙状态。

CoT 就是一个开环系统,它的推理过程一路向前,没有回头路,没有修正机制。ReAct 则通过 T-A-O 循环,构建了一个强大的闭环系统。这个闭环赋予了 Agent 惊人的鲁棒性和智能。它能够在执行过程中发现自己的错误(例如,一个不恰当的 Action 导致了错误的 Observation),并在后续的 Thought 中进行“自我批判”和修正。

正是这个看似简单的反馈闭环,让 ReAct Agent 的行为展现出一种超越传统程序的“智能感”。它不再是死板地执行代码,而是在动态地、试探性地解决问题。

技术实现深度解析:驯服 LLM 进行 ReAct

理解了 ReAct 的设计哲学,我们接下来深入其技术实现的核心。如何让一个只会生成文本的 LLM,乖乖地按照 T-A-O 的格式来工作呢?答案藏在 Prompt Engineering 的艺术之中。

Prompting 策略:与 LLM 的契约

ReAct 的实现并不需要对 LLM 进行微调 (Fine-tuning),它完全是通过精心设计的 Prompt 来引导模型行为的。这个 Prompt 就像是开发者与 LLM 之间签订的一份“工作合同”,详细规定了任务目标、可用工具、工作流程以及输出格式。

一个典型的 ReAct Prompt 主要由以下几个部分构成:

  1. 角色指令 (Role Instruction) / 系统提示 (System Prompt):这是“合同”的开篇,告诉 LLM 它将扮演一个怎样的角色(例如,“你是一个能干的助手”),以及它必须遵守的核心工作流程,即 T-A-O 循环。它会明确定义 Thought, Action, Observation 的含义和格式。

  2. 工具描述 (Tool Descriptions):这是“合同”的附件,列出了所有可供 LLM 使用的工具。每一个工具的描述都至关重要,它必须清晰地说明:

    • name: 工具的名称,例如 search
    • description: 这个工具是做什么的。这部分是给 LLM 看的,需要用自然语言描述清楚,例如 “当需要查询最新的、实时的信息或训练数据中可能不包含的知识时,使用此工具”。
    • parameters: 工具需要哪些输入参数,每个参数的名称、类型和描述。例如,query: str, a string to search for
  3. 任务示例 (Few-shot Examples):这部分是“岗前培训”,通过提供一到两个完整的 T-A-O 循环解决问题的例子,向 LLM “演示”一遍正确的工作流程。这极大地帮助模型理解抽象的指令,并学会如何正确地生成 ThoughtAction

  4. 当前任务 (Current Task):这是“合同”的正式工作内容,包括:

    • Question: 用户提出的具体问题。
    • Thought:: 留白,等待 LLM 填写它的第一个思考步骤。

将以上部分拼接起来,形成一个完整的 Prompt,输入给 LLM。LLM 会续写 Thought: 后面的内容,然后生成 Action:。我们的程序捕获到 Action:,执行它,得到 Observation:,再把 Observation: 拼接到 Prompt 的末尾,送回给 LLM,开启下一轮循环。

下面是一个简化的 Prompt 结构示例:

你是一个能够使用工具来回答问题的智能助手。
对于每个用户问题,你需要遵循以下的思考-行动-观察循环,直到你找到最终答案。

# 可用工具:
[
  {
    "name": "search",
    "description": "用于在互联网上搜索信息,适用于查询时事、股价、定义等。",
    "parameters": {
      "query": "需要搜索的关键词"
    }
  },
  {
    "name": "calculator",
    "description": "用于执行数学计算。",
    "parameters": {
      "expression": "要计算的数学表达式"
    }
  }
]

# 工作流程示例:
Question: 当前苹果公司的 CEO 是谁,他出生那年的道琼斯工业平均指数是多少?
Thought: 我需要分两步解决这个问题。第一步,找到苹果公司现任 CEO 是谁。第二步,找到这位 CEO 的出生年份,然后查询那一年的道琼斯指数。我先从第一步开始。
Action: search[苹果公司现任 CEO]
Observation: 苹果公司现任 CEO 是蒂姆·库克 (Tim Cook)。
Thought: 好的,现在我知道 CEO 是蒂姆·库克。接下来我需要找到他的出生年份。
Action: search[蒂姆·库克出生年份]
Observation: 蒂姆·库克出生于 1960 年 11 月 1 日。
Thought: 很好,年份是 1960 年。现在我需要查询 1960 年的道琼斯工业平均指数。由于这是一个历史数据,我同样可以使用搜索工具。
Action: search[1960 年道琼斯工业平均指数]
Observation: 1960 年,道琼斯工业平均指数在 600 点到 700 点之间波动。例如,年底收于 615.89 点。
Thought: 我已经获得了所有需要的信息。苹果公司的 CEO 是蒂姆·库克,他出生于 1960 年,那一年道琼斯指数大约在 615 点左右。我可以给出最终答案了。
Action: finish[苹果公司现-任 CEO 是蒂姆·库克,他出生于 1960 年,当年的道琼斯工业平均指数年底收于 615.89 点。]

# 当前任务:
Question: {用户的实际问题}
Thought:

Few-shot vs. Zero-shot

上面的例子采用的是 Few-shot Prompting,即提供了一些完整的示例。这种方法的优点是稳定性和可靠性高,因为它给了模型一个非常明确的模仿对象。缺点是 Prompt 会变得很长,增加了成本和处理时间。

随着 LLM 能力的增强(尤其是 GPT-4 级别的模型),Zero-shot ReAct 也变得可行。在 Zero-shot 模式下,我们不再提供完整的 Work-flow examples。取而代之的是,在系统提示中用更详细的文字来描述规则。

例如,系统提示可能会包含这样的指令:

“…你的思考过程应该被包裹在 <thought></thought> 标签中。如果你决定调用工具,你应该生成一个 <tool_call> XML 标签,包含工具名称和参数。如果你认为任务已完成,就直接回答问题…”

Zero-shot 的好处是 Prompt 更短、更灵活,更容易动态地增删工具。但它对模型本身的能力要求更高,模型需要有足够强的泛化能力来理解指令并遵循格式。对于一些复杂的工具调用逻辑或任务流程,Zero-shot 的表现可能不如 Few-shot 稳定。

工具调用机制 (Tool Calling / Function Calling)

ReAct 论文的原始实现中,Action 是一个需要手动解析的字符串,例如 search[query]。这种方式简单直观,但不够健壮。如果模型生成的字符串格式稍有偏差(例如,用了中文括号 search【query】),解析就会失败。

为了解决这个问题,现代的 LLM API(如 OpenAI 的 API)引入了结构化的工具调用 (Structured Tool Calling)函数调用 (Function Calling) 功能。

这是一个巨大的进步。在使用这个功能时,我们不再要求模型生成 Action 字符串,而是在 API 请求中声明我们的工具(函数)及其参数的 JSON Schema。如果 LLM 决定调用工具,它的返回结果中会包含一个结构化的 JSON 对象,明确指明了要调用的函数名和传递的参数。

例如,代替生成 Action: search[特斯拉股价],模型会输出类似这样的结构:

{
  "tool_calls": [
    {
      "id": "call_abc123",
      "type": "function",
      "function": {
        "name": "search",
        "arguments": "{\"query\": \"特斯拉股价\"}"
      }
    }
  ]
}

这种方式的好处是显而易见的:

  • 鲁棒性:不再需要脆弱的字符串解析。API 保证了输出格式的正确性。
  • 减少幻觉:模型被限制只能调用你声明过的工具,并且参数也必须符合你定义的 Schema,这大大减少了模型“幻想”出不存在的工具或参数的可能性。
  • 并行调用:如果模型在一个 Thought 步骤中认为可以同时执行多个互不依赖的动作(例如,同时查询特斯拉和福特的股价),新的工具调用标准允许它在一个响应中返回多个 tool_calls 对象,为并行执行提供了可能。

可以说,Function Calling/Tool Calling 是对 ReAct 原始思想的一次重要的工程优化,它让 Agent 的“行动”部分变得更加可靠和标准化。

记忆系统:让 Agent 记住过去

一个简单的 ReAct 循环会将每一次的 T-A-O 历史都完整地附加到下一次的 Prompt 中。这构成了一种最基础的短期记忆。然而,当交互轮次增多时,Prompt 会变得越来越长,最终超出模型的上下文窗口限制,而且成本也会急剧上升。

因此,在实际的 Agent 系统设计中,需要一个更复杂的记忆系统 (Memory System)

  • 滑动窗口记忆 (Sliding Window Memory):只保留最近的 N 轮交互历史。这是一种简单有效的截断方法,但可能丢失早期的重要信息。
  • 摘要记忆 (Summarization Memory):当历史记录过长时,调用一个 LLM 将早期的交互历史进行总结,用一个简短的摘要来代替冗长的原文。这可以在保留关键信息的同时,有效缩短上下文长度。
  • 向量记忆 (Vector Memory):将每一轮的 ObservationThought 存入向量数据库。在新的 Thought 阶段,Agent 可以根据当前需求,从向量数据库中检索最相关的历史记忆片段,而不是把所有历史都塞进 Prompt。这使得 Agent 能够拥有跨越很长对话周期的“长期记忆”。

记忆系统的设计是构建复杂、持久 Agent 的关键,它直接决定了 Agent 能处理的任务的时间跨度和复杂度。

与其他 Agent 范式的思辨对比

ReAct 并非唯一的 Agent 构建范式。为了更深刻地理解 ReAct 的设计精髓,我们需要将它置于更广阔的技术图谱中,与其它主流范式进行对比。

ReAct vs. Plan-and-Execute

这是最经典的对比。我们之前已经触及了它们的核心区别,现在可以进行更深入的总结。

  • 核心区别:ReAct 将规划与执行交织在一起,形成一个动态调整的循环。Plan-and-Execute 则将二者严格分离,先完整规划,再批量执行。
  • 适用场景
    • ReAct:非常适合探索性强、不确定性高、需要根据中间结果动态调整策略的任务。例如,进行开放式课题研究、与用户进行多轮对话式问答、调试代码等。它的优势在于灵活性和适应性。
    • Plan-and-Execute:适用于流程固定、步骤明确、环境稳定的任务。例如,一个“每日新闻报告生成器”,其步骤(抓取来源 A、B、C 的新闻 -> 总结 -> 格式化输出)是高度确定的。它的优势在于结构清晰,易于理解和调试,并且在某些情况下可能因为 LLM 调用次数较少而更高效。

可以把 ReAct 看作一个经验丰富的老师傅,边干边想,随时应对意外。而 Plan-and-Execute 则像一条精密的自动化生产线,一旦设定好,就高效地、一成不变地执行。

ReAct vs. ReWOO (Reasoning without Observation)

ReWOO 是对 ReAct 的一种有趣的变体和优化,它试图解决 ReAct 中频繁 LLM 调用带来的高延迟和高成本问题。ReWOO 的全称可能有些误导,它并非完全没有观察,而是将观察过程与推理过程解耦。

ReWOO 的工作流通常包含三个角色:

  1. Planner :使用一个强大的 LLM,它只负责思考和规划。它会分析用户问题,并生成一个包含多个工具调用步骤的“计划”。但与 Plan-and-Execute 不同的是,它的计划中会包含占位符,表示这些步骤的结果将如何被用于最终的答案合成。
  2. Worker:Worker 是执行具体工具调用的单元。它们可以是小型的、廉价的 LLM,甚至是简单的 API 调用脚本。它们接收 Planner 的指令,执行工具调用,然后返回结果。
  3. Solver / Aggregator (解决者 / 聚合者):在所有 Worker 完成工作后,Solver (通常是另一个强大的 LLM) 会接收到最初的计划和所有工具调用的结果,然后整合信息,生成最终的答案。

与 ReAct 的对比:

  • 执行流:ReAct 是串行的“思考-行动-观察”循环。ReWOO 是分阶段的“规划 -> 并行行动 -> 解决”流程。
  • 效率:ReWOO 的一个主要优势是效率。多个不依赖的 Worker(工具调用)可以并行执行,大大减少了总耗时。同时,因为它将昂贵的 LLM 调用集中在 Planner 和 Solver 两个阶段,可能比 ReAct 每一步循环都调用大模型更节省成本。
  • 适应性:这是 ReWOO 的牺牲。由于 Planner 在制定计划时并不知道 Worker 的执行结果,它失去了 ReAct 那种根据 Observation 动态调整下一步 Action 的能力。如果某个 Worker 执行失败或返回了意外的结果,整个 ReWOO 流程可能会中断,或者 Solver 拿到的信息质量不高。

ReWOO 可以看作是在 ReAct 的灵活性和 Plan-and-Execute 的结构化之间做出的一种权衡。它更像一个项目经理 (Planner) 把任务分包给不同的专家 (Workers),最后自己汇总报告 (Solver)。

ReAct vs. Reflexion

Reflexion 是另一种增强 Agent 能力的范式,但它的关注点与 ReAct 不同。ReAct 关注的是单次任务执行过程中的动态调整,而 Reflexion 关注的是跨任务的自我反思与学习

Reflexion 的核心思想是,当 Agent 一次尝试失败后,不应该就此结束。它应该增加一个“反思” (Reflection) 阶段。

  1. 执行:Agent (可以是 ReAct Agent) 尝试完成任务。
  2. 评估:一个评估器判断任务是否成功。如果失败,进入反思阶段。
  3. 反思 :Agent 对失败的轨迹进行自我批判。它会生成一段关于“为什么会失败”以及“下次应该如何改进”的文字描述。
  4. 记忆:这段反思的文字会被存储到一个特殊的“记忆库”中。
  5. 再次执行:当 Agent 下一次面临相同或类似的任务时,它会在 Prompt 中带上从记忆库中检索到的相关反思内容,从而避免犯同样的错误。

与 ReAct 的对比:

  • 修正循环的层级:ReAct 的 T-A-O 循环是任务内 (intra-trial) 的快速修正循环。Reflexion 的“执行-反思”循环是任务间 (inter-trial) 的慢速学习循环。
  • 目标:ReAct 的目标是成功完成当前任务。Reflexion 的目标是从失败中学习,提升未来任务的成功率
  • 协同关系:Reflexion 和 ReAct 并不是互斥的,而是可以协同工作的。我们可以构建一个 Reflexion 框架,其内部的执行 Agent 就是一个 ReAct Agent。当这个 ReAct Agent 最终失败后(例如,陷入循环或给出了错误答案),外层的 Reflexion 机制启动,对整个 ReAct 的执行轨迹进行反思,从而在下一次尝试中指导 ReAct Agent 做出更好的 Thought

总结来说,如果 ReAct 让 Agent 学会了“边走边看”,那么 Reflexion 就让 Agent 学会了“吃一堑,长一智”。

范式 核心思想 优点 缺点 适用场景
ReAct 推理与行动交替循环 灵活,适应性强,能处理不确定性 延迟高,成本高,串行执行 探索性、交互性强的任务
Plan-and-Execute 规划与执行严格分离 结构清晰,可预测,可能更高效 僵化,无法适应意外,对规划要求高 流程固定的确定性任务
ReWOO 规划-并行工作-解决 高效,可并行,成本较低 适应性差,规划阶段是盲目的 I/O 密集型、可并行化的任务
Reflexion 从失败中反思和学习 具有学习和进化能力,能持续改进 需要评估和反思机制,流程更复杂 需要重复执行和持续优化的任务

工程实践中的关键问题:从理论到代码的鸿沟

将 ReAct 的理论应用到生产环境中,会遇到一系列在学术论文中可能被简化的工程挑战。一个健壮的 ReAct Agent 系统,需要在以下几个方面进行精心的设计和打磨。

1. 如何设计高质量的工具描述?

这是构建 ReAct Agent 最关键也是最容易被忽视的一步。LLM 对工具的理解完全来自于你提供的描述 (description) 和参数定义。工具描述就是给 LLM 的 Prompt

  • 清晰、无歧义:描述应该准确说明工具的用途。避免使用模糊的词语。例如,不要说“用于处理数据”,而要说“用于从指定的 URL 下载 CSV 文件,并以 JSON 格式返回其内容”。
  • 说明何时使用:在描述中明确指出该工具适用于哪些场景。例如,对于 search 工具,可以补充一句:“当问题涉及近期事件、实时数据或你不确定的专有名词时,你应该使用此工具。” 这能有效引导 LLM 在恰当的时候选择正确的工具。
  • 举例说明:在参数描述中提供示例值,可以帮助 LLM 更好地理解参数的格式和含义。例如,对于一个日期查询工具,可以写 date (str): 查询的日期,格式为 'YYYY-MM-DD',例如 '2024-10-26'
  • 区分相似工具:如果你有两个功能相似的工具,例如 web_searchdatabase_lookup,必须在描述中清晰地界定它们的区别。“web_search 用于搜索公开的互联网信息,而 database_lookup 用于查询公司内部的客户数据库。”

高质量的工具描述,是 Agent 能够做出正确 ThoughtAction 的基石。

2. 如何优雅地终止循环?

一个潜在的风险是 Agent 陷入无限循环。例如,Agent 可能反复调用同一个工具,但总是得不到想要的结果,又不知道该如何改变策略。必须设置有效的终止条件。

  • finish 动作:最理想的终止方式是 Agent 自主判断任务完成,并调用一个特殊的 finishfinal_answer 动作。
  • 最大迭代次数:设置一个 T-A-O 循环的上限(例如 10-15 次)。这是防止无限循环和失控的最基本保险丝。达到上限后,可以强制终止并返回一个错误信息或当前的部分结果。
  • **超时 **:为整个任务或单次工具调用设置一个时间上限。防止因为某个工具 API 长时间无响应而导致整个系统卡死。
  • Token 限制:监控 Prompt 的总长度,在接近上下文窗口极限时提前终止,避免因超出限制而引发 API 错误。

3. 如何设计强大的错误处理和容错机制?

现实世界中的工具调用充满了失败的可能:网络抖动、API 认证失败、参数错误、第三方服务宕机等。一个生产级别的 Agent 必须能够优雅地处理这些错误。

  • 将错误作为 Observation:当一个工具调用失败时,执行器不应该让程序崩溃,而应该捕获这个异常,并将其格式化成一段有意义的错误信息,作为 Observation 返回给 LLM。例如:Observation: Error calling weather API: API key is invalid.
  • 引导 LLM 理解错误:LLM 需要被“训练”或“提示”来理解这些错误 Observation 并作出反应。在 Few-shot 示例中,可以故意包含一个工具调用失败,然后演示 Agent 如何在下一个 Thought 中进行补救(例如,“天气 API 密钥无效,我无法获取天气信息。我将跳过这一步,并告知用户我无法完成该请求。”)。
  • 重试机制:对于一些瞬时性错误(如网络超时),可以在工具执行层实现自动重试逻辑(例如,最多重试 3 次,每次间隔 1 秒)。这可以对 LLM 透明,减少不必要的思考负担。

4. 性能优化与成本控制

ReAct 因为其多轮 LLM 调用的特性,天然地存在延迟高和成本高的问题。

  • 模型选择:并非每一步都需要最强大的模型。可以考虑使用一种级联 策略:用一个强大的模型 (如 GPT-4) 来进行关键的 Thought 推理,而用一个更小、更快的模型 (如 GPT-3.5-Turbo 或开源模型) 来执行一些简单的任务,比如格式转换或摘要生成。
  • 并行工具调用:如前所述,如果 Agent 的 Thought 能够规划出多个可以并行执行的 Action,那么支持并行工具调用将极大地缩短任务耗时。这需要底层的执行器和上层的 LLM 支持(例如,使用 Tool Calling 功能)。
  • 缓存:对工具调用的结果进行缓存。如果 Agent 在短时间内用完全相同的参数请求同一个工具(例如,反复 search[苹果股价]),可以直接返回缓存的结果,避免重复的 API 调用和网络延迟。缓存是降低成本和延迟最有效的方法之一。
  • 流式响应:对于最终的答案生成,使用流式输出可以让用户更快地看到结果,改善用户体验。同时,也可以流式地展示 Agent 的 Thought 过程,让用户了解 Agent 当前“正在想什么”,缓解等待的焦虑。

这些工程实践,是将 ReAct 从一个有趣的学术原型,转变为一个可靠、高效、可维护的生产力工具所必须跨越的桥梁。

实际应用案例分析:ReAct 在真实世界中的身影

理论和工程细节最终要服务于应用。让我们通过两个典型的场景,深入分析 ReAct 在其中如何发挥作用,以及会涉及哪些设计决策。

案例一:复杂信息研究助理

任务:一位金融分析师需要撰写一份关于“半导体行业在 AI 浪潮下的投资机会”的报告。她向 AI 助理下达指令:“帮我调研一下英伟达 (NVIDIA)、AMD 和英特尔 (Intel) 在 AI 领域的最新动态,比较它们的 AI 芯片性能和市场份额,并总结各自的优势和风险。”

这是一个典型的开放式研究任务,非常适合 ReAct。

设计决策与 ReAct 流程分析:

  1. 工具集设计

    • web_search: 用于查询新闻、财报、技术文章等公开信息。
    • read_pdf_document: 用于读取在线的 PDF 研究报告。
    • financial_data_api: 用于获取精确的股价、市值、市盈率等财务数据。
    • summarizer: 一个内部工具,用于将长文本(如新闻稿或 PDF 内容)总结成要点。
    • note_taker: 用于在研究过程中暂存关键发现,如 save_note(topic, content)get_notes()。这是一个简单的内存工具。
  2. ReAct 执行轨迹(模拟)

    • T1: “任务是分析三家公司在 AI 领域的动态。我需要分解任务。首先,我将分别调研每家公司。从英伟达开始。我需要了解它的主要 AI 芯片、市场份额和最新新闻。”
    • A1: web_search[NVIDIA AI chips latest news]
    • O1: (返回一系列关于 H100、B200 芯片的新闻链接和摘要,以及其在数据中心市场接近垄断的地位。)
    • T2: “好的,英伟达非常强势,B200 是最新的旗舰。我需要记录下这个关键点,并查找更具体的市场份额数据。”
    • A2: save_note[NVIDIA, "旗舰AI芯片为B200,数据中心市场份额主导"]
    • O2: “Note saved successfully.”
    • T3: “现在查找市场份额的精确数据。我应该使用那个金融数据 API,但它可能没有市场份额数据。我先用 web search 尝试寻找权威的市场研究报告。”
    • A3: web_search[data center AI chip market share report 2024]
    • O3: (返回一个指向 Gartner 或 IDC 报告的 PDF 链接 https://.../report.pdf)
    • T4: “太好了,找到了一份研究报告。我需要阅读这份 PDF 文档来提取市场份额数据。”
    • A4: read_pdf_document[https://.../report.pdf]
    • O4: (返回 PDF 的文本内容,很长。)
    • T5: “文本太长了。我需要使用 summarizer 工具来提取关于英伟达、AMD 和英特尔市场份额的关键句子。”
    • A5: summarizer[<PDF文本>, "NVIDIA, AMD, Intel market share"]
    • O5: (返回总结后的要点,例如 “2024年Q1,英伟达占据数据中心AI加速器市场约 85% 的份额,AMD 约 10%,英特尔约 5%。”)
    • … 循环继续 … Agent 会以类似的方式调研 AMD 和 Intel,记录笔记,最后在 Thought 阶段整合所有笔记 (get_notes()),形成一份结构化的比较,并通过 finish 动作输出最终报告。

关键洞察:在这个案例中,ReAct 的动态性至关重要。Agent 不可能预先知道会找到一个 PDF 报告,也不知道报告内容会很长需要总结。每一步的 Observation 都为下一步的 Thought 提供了新的决策依据,完美地模拟了人类专家的研究过程。

案例二:智能电商导购助理

任务:用户想要购买一台新的笔记本电脑,他对 AI 导购说:“我想买一台适合编程和偶尔玩游戏的笔记本,预算在 1 万元以内,希望轻薄一点。”

这是一个需要结合结构化数据查询和用户偏好理解的交互式任务。

设计决策与 ReAct 流程分析:

  1. 工具集设计

    • query_products: 根据筛选条件(如品类、品牌、价格区间、CPU、内存等)查询商品数据库。
    • get_product_details: 获取单个商品的详细规格、用户评价。
    • compare_products: 接收两个商品 ID,以表格形式返回它们的规格对比。
    • ask_user: 当信息不足时,向用户提问以澄清需求。这是一个特殊的工具,它会暂停 Agent 的执行,等待用户输入。
  2. ReAct 执行轨迹(模拟)

    • T1: “用户需要一台用于编程和玩游戏的笔记本,预算 1 万内,要求轻薄。‘编程’通常意味着需要不错的 CPU 和至少 16GB 内存。‘玩游戏’意味着需要独立显卡。‘轻薄’是一个相对概念,我需要先找一些符合基本条件的机器,再让用户选择。”
    • A1: query_products[category='笔记本', price_max=10000, ram_min=16, has_dedicated_gpu=true]
    • O1: (返回 5 个符合条件的商品列表,包含商品 ID、名称、价格。)
    • T2: “找到了 5 款产品。直接全部列出来可能信息量太大。我应该先挑出两款看起来不错的进行比较,或者询问用户更具体的偏好。比如,他对品牌有偏好吗?”
    • A2: ask_user[我们找到了几款符合您要求的电脑。请问您对品牌有什么偏好吗,比如联想、戴尔或者苹果?]
    • O2: (程序暂停,等待用户输入。用户回复:“我对联想比较有好感。”)
    • T3: “用户偏好联想。我应该从之前的 5 个结果中筛选出联想的型号,并展示给用户。”
    • A3: (内部逻辑处理,筛选出联想的两款电脑 ID: 123ID: 456,然后在 Thought 中决定下一步。) “我将为用户展示这两款联想电脑的详细信息。” -> get_product_details[123]get_product_details[456]
    • … 循环继续 … 如果用户接着问“这两款的屏幕有什么区别?”,Agent 会在下一个 Thought 中决定调用 compare_products 工具,并聚焦于屏幕参数的对比。

关键洞察:在这个交互场景中,ReAct 的 T-A-O 循环与用户的对话轮次天然地结合在一起。用户的每一次回复,都成为 Agent 的下一个 Observation,直接影响 Agent 的下一步思考和行动。ask_user 这个特殊工具的设计,使得 Agent 能够主动地寻求信息,从而更智能地引导对话,而不是被动地一问一答。

局限性与未来方向:ReAct 之后,路在何方?

尽管 ReAct 取得了巨大成功,但它远非 AI Agent 的终极形态。在实践中,它仍然面临着一些固有的局限性,而学术界和工业界也正在探索更为先进的范式。

ReAct 当前的挑战

  1. 上下文长度的诅咒:随着 T-A-O 循环的增加,Prompt 的长度会线性增长。这不仅带来了高昂的成本,更会触及模型的上下文窗口上限。虽然有记忆系统来缓解,但信息的有损压缩和检索的准确性本身就是新的挑战。
  2. 串行执行的延迟:ReAct 的核心循环是串行的,每一步都需要一次 LLM 调用和一次工具执行。对于一个复杂任务,10 轮循环就可能意味着几十秒甚至数分钟的等待,这在很多实时交互场景中是难以接受的。
  3. 推理的脆弱性:Agent 的表现高度依赖于 LLM 在每一步 Thought 中的推理质量。有时,模型可能会陷入逻辑怪圈(如反复执行两个无效的 Action),或者对 Observation 做出错误的解读,导致整个任务失败。这种“一步错,步步错”的现象时有发生。
  4. 工具使用的幻觉:尽管 Function Calling 改善了此问题,但模型有时仍然会“幻想”出最适合的工具或参数组合,即使它们并不存在或不合理。这需要更精细的 Prompt 设计和后处理验证来约束。

学术界的最新研究方向

为了克服这些局限,研究者们正在探索更前沿的理念:

  • 层次化与并发 Agent:借鉴 ReWOO 的思想,并将其推广。例如,设计一个“主管 Agent”,它负责将任务分解给多个“下属 ReAct Agent”。这些下属 Agent 可以并行工作,各自处理子任务,最后由主管 Agent 整合结果。这形成了 Agent 的层次化(Hierarchical) 和并发 (Concurrent) 结构。
  • 更强的自省与学习能力:将 Reflexion 的思想进一步深化。Agent 不仅应该从失败中学习,还应该能够主动评估自己计划的置信度,在执行前预判可能的风险,甚至动态地学习和优化自己 Prompt 的一部分。
  • 多模态 Agent:未来的 Agent 不仅能处理文本和调用 API,还应该能“看懂”图片和视频(视觉输入),并能生成和操作用户界面(GUI 操作)。像 GPT-4V 这样的多模态模型和相关研究正在为构建能够操作真实软件界面的 Agent 铺平道路。

工业界的实践创新

在工业落地层面,重点则在于提升 Agent 的可靠性、可观测性和效率。

  • Agent 调试与可观测性平台:构建专门的平台来追踪 Agent 的每一步 T-A-O 轨迹,可视化其决策过程,分析其失败原因。这对于定位问题、优化 Prompt 和工具至关重要。类似于 LangSmith 这样的工具就是很好的例子。
  • 混合式 Agent 框架:在工程上,很少有系统会“纯粹”地只使用一种范式。更常见的是混合式框架,它会根据任务的特点动态选择最合适的策略。例如,对于一个任务的某个阶段,如果步骤是确定的,就切换到 Plan-and-Execute 模式以提高效率;当遇到不确定性时,再切换回 ReAct 模式。
  • 领域特定的 Agent (Domain-Specific Agent):与其追求一个无所不能的通用 Agent,工业界更倾向于在特定领域(如电商、旅游、软件测试)构建高度优化的 Agent。通过在该领域的数据上进行微调,使用精心设计的专用工具集,可以达到比通用 Agent 高得多的性能和可靠性。

总结与思考

从 CoT 的闭门思考,到 ReAct 的开环互动,我们见证了 AI 从一个“象牙塔里的学者”向一个“深入实践的工程师”的转变。ReAct 的核心贡献,不在于它发明了多么复杂的技术,而在于它提出了一个极其深刻且简洁的设计哲学:智能源于世界与头脑的持续对话

T-A-O 循环,这个看似简单的模式,第一次系统性地为 LLM 赋予了试错、修正和适应环境的能力。它将模型的推理能力与外部世界的真实反馈结合起来,创造了一个能够动态解决问题的闭环系统。这不仅仅是一种 Prompting 技巧,更是一种全新的 AI 编程范式。

当然,ReAct 不是终点,它更像是一个坚实的基石。在此之上,层次化、并发、自省、多模态等更先进的 Agent 架构正在被构建。但无论未来的 Agent 会演变成何种复杂的形态,ReAct 所揭示的“推理与行动协同”的核心思想,都将是其不可或缺的灵魂。

作为开发者和实践者,理解 ReAct 的设计哲学,掌握其工程实践中的种种权衡,将是我们驾驭这股 AI Agent 浪潮,构建出真正有价值、能够解决现实世界问题的智能应用的关键。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐