07-ReAct模式详解

0 阅读9分钟

ReAct 模式详解:Agent 是怎么"思考"的

系列:AI Agent 从入门到实战 | 第 7 篇

前面几篇我们一直在用 Agent,调工具、查记忆、生成回答——但 Agent 到底是怎么决定"先做什么、再做什么"的?这一篇我们深入 Agent 的核心思维模式:ReAct,看看它的"脑子"里到底在想什么。


一、什么是 ReAct

ReAct 是 2022 年由 Google 和普林斯顿大学提出的 Agent 范式,论文名字就叫 ReAct: Synergizing Reasoning and Acting in Language Models。

ReAct = Reasoning(推理)+ Acting(行动)

核心思想:让 LLM 交替进行"思考"和"行动",一步一步解决问题。

传统 LLM:
  问题 → 一次性回答(容易瞎编)

ReAct:
  问题 → 思考 → 行动 → 观察 → 思考 → 行动 → 观察 → ... → 最终回答

二、一个直觉类比

想象你是一个侦探在破案:

传统 LLM 的做法(不推理):
  问:"凶手是谁?"
  答:"根据我的直觉,是管家干的。"(瞎猜)

ReAct 的做法(推理 + 行动):
  问:"凶手是谁?"

  💭 思考:我需要先查看案发现场
  🔧 行动:去案发现场勘查
  👁️ 观察:发现了一把带血的刀

  💭 思考:刀上有指纹,我需要比对
  🔧 行动:拿指纹去数据库比对
  👁️ 观察:匹配到了嫌疑人 A

  💭 思考:嫌疑人 A 有作案动机,但需要确认不在场证明
  🔧 行动:调取监控录像
  👁️ 观察:监控显示嫌疑人 A 案发时不在现场

  💭 思考:A 有不在场证明,排除。查看其他线索...
  ...

ReAct 就是这样:每一步都先想清楚为什么做,做完看看结果,再决定下一步。


三、ReAct 的完整流程

                    ┌─────────────┐
                    │  用户输入问题  │
                    └──────┬──────┘
                           │
                           ▼
              ┌────────────────────────┐
              │     💭 Thought(思考)    │
              │  "我需要做什么?为什么?"  │
              └────────────┬───────────┘
                           │
                           ▼
              ┌────────────────────────┐
              │     🔧 Action(行动)    │
              │  调用某个工具执行操作      │
              └────────────┬───────────┘
                           │
                           ▼
              ┌────────────────────────┐
              │     👁️ Observation(观察)│
              │  查看工具返回的结果       │
              └────────────┬───────────┘
                           │
                           ▼
                    ┌─────────────┐
                    │  任务完成了吗? │
                    └──────┬──────┘
                      /         \
                    是           否
                    │            │
                    ▼            │
              ┌──────────┐      │
              │ 输出最终回答│      └──→ 回到 Thought ↑
              └──────────┘

三个核心要素:

要素英文作用
思考Thought分析当前情况,决定下一步该做什么
行动Action调用工具执行具体操作
观察Observation查看行动的结果,为下一轮思考提供信息

四、用代码看 ReAct 的实际运行

LangChain 默认的 Agent 就是基于 ReAct 模式的。我们直接看 verbose 输出:

示例:回答一个需要搜索的问题

from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.tools import tool

# 定义工具
@tool
def search(query: str) -> str:
    """搜索互联网获取最新信息"""
    results = {
        "2024年诺贝尔物理学奖": "2024年诺贝尔物理学奖授予了 John Hopfield 和 Geoffrey Hinton,表彰他们在人工神经网络和机器学习方面的基础性发现。",
        "Geoffrey Hinton": "Geoffrey Hinton,被誉为'深度学习之父',2023年从 Google 离职,专注于 AI 安全研究。",
    }
    for key, value in results.items():
        if key in query:
            return value
    return f"未找到关于 '{query}' 的信息"

# 创建 Agent
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
tools = [search]

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个智能助手,可以使用搜索工具获取信息。回答要简洁准确。"),
    ("human", "{input}"),
    MessagesPlaceholder(variable_name="agent_scratchpad"),
])

agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# 运行
executor.invoke({"input": "2024年诺贝尔物理学奖颁给了谁?他们做了什么贡献?"})

verbose 输出(ReAct 的思考过程)

> Entering new AgentExecutor chain...

# ── 第 1 轮 ReAct ──

💭 Thought:   用户问的是2024年诺贝尔物理学奖,这是一个事实性问题,
              我需要搜索最新信息来回答,不能靠自己的记忆。

🔧 Action:    调用 search 工具
   Action Input: "2024年诺贝尔物理学奖"

👁️ Observation: 2024年诺贝尔物理学奖授予了 John Hopfield 和 Geoffrey Hinton,
               表彰他们在人工神经网络和机器学习方面的基础性发现。

# ── 第 2 轮 ReAct ──

💭 Thought:   我知道了获奖者是谁,但用户还问了"他们做了什么贡献",
              我需要更详细的信息,特别是关于他们贡献的部分。

🔧 Action:    调用 search 工具
   Action Input: "Geoffrey Hinton"

👁️ Observation: Geoffrey Hinton,被誉为'深度学习之父',2023年从 Google 离职,
               专注于 AI 安全研究。

# ── 第 3 轮 ReAct ──

💭 Thought:   我已经收集到了足够的信息,可以回答用户的问题了。
              诺贝尔奖授予了 Hopfield 和 Hinton,
              表彰他们在人工神经网络和机器学习方面的贡献。

🤖 Final Answer: 2024年诺贝尔物理学奖授予了 John Hopfield 和 Geoffrey Hinton,
               表彰他们在人工神经网络和机器学习方面的基础性发现。
               其中 Hinton 被誉为"深度学习之父",
               他于2023年从 Google 离职,专注于 AI 安全研究。

> Finished chain.

看到了吗?Agent 并不是一次性回答的,而是:

思考 → 搜索 → 看结果 → 思考 → 再搜索 → 看结果 → 思考 → 回答

这就是 ReAct 的精髓。


五、ReAct 的思考过程拆解

把上面的例子拆开看每一轮:

第 1 轮

阶段内容
💭 Thought用户问诺贝尔奖,我需要搜索,不能靠记忆
🔧 Actionsearch("2024年诺贝尔物理学奖")
👁️ Observation得到了获奖者名字和贡献概述

第 2 轮

阶段内容
💭 Thought用户还问了具体贡献,信息不够,需要再搜
🔧 Actionsearch("Geoffrey Hinton")
👁️ Observation得到了 Hinton 的详细背景

第 3 轮

阶段内容
💭 Thought信息够了,可以回答了
🤖 Final Answer输出最终回答

关键观察:每一轮的 Thought 都在做判断——该不该搜、搜什么、够不够。 这就是"推理"能力的体现。


六、ReAct vs 其他 Agent 范式

ReAct 不是唯一的 Agent 范式,来对比一下:

1. ReAct(推理 + 行动)

思考 → 行动 → 观察 → 思考 → 行动 → 观察 → ...
  • ✅ 灵活,随时调整策略
  • ✅ 适合不确定性高的任务
  • ❌ 可能走弯路,效率不是最高

2. Plan-and-Execute(先规划后执行)

规划全部步骤 → 按顺序执行 → 汇总结果
  • ✅ 效率高,步骤清晰
  • ✅ 适合目标明确的任务
  • ❌ 计划可能不准,中途调整能力弱

3. Reflexion(反思)

执行 → 评估结果 → 反思哪里做错了 → 改进后再执行
  • ✅ 能从错误中学习
  • ✅ 适合需要反复试错的任务
  • ❌ 需要多次执行,成本高

对比表

范式核心思想适合场景效率灵活性
ReAct边想边做探索性任务中高
Plan-and-Execute先想后做目标明确的任务高中
Reflexion做完再改需要试错的任务低中

七、手写一个 ReAct Agent

不用框架,从零实现一个最简版的 ReAct Agent,帮助理解原理:

from langchain_openai import ChatOpenAI

def simple_react_agent(question: str, tools: dict, max_steps: int = 5):
    """
    最简版 ReAct Agent
    :param question: 用户问题
    :param tools: 工具字典 {工具名: 工具函数}
    :param max_steps: 最大循环次数
    """
    llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)

    # 系统提示词:教 LLM 使用 ReAct 格式
    system_prompt = """你是一个 ReAct Agent。请按以下格式逐步思考和行动:

Thought: 分析当前情况,决定下一步
Action: 工具名称[参数]
Observation: [工具返回的结果,由系统填入]

当你有足够信息回答时,使用:
Thought: 我已经收集到足够信息
Answer: 最终回答

可用工具:{tools}
""".format(tools=", ".join(tools.keys()))

    # 构建对话
    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": question}
    ]

    for step in range(max_steps):
        print(f"\n--- 第 {step + 1} 轮 ---")

        # 让 LLM 思考
        response = llm.invoke(messages)
        output = response.content
        print(output)

        # 检查是否有最终回答
        if "Answer:" in output:
            answer = output.split("Answer:")[-1].strip()
            print(f"\n✅ 最终回答: {answer}")
            return answer

        # 解析 Action
        if "Action:" in output:
            action_line = [l for l in output.split("\n") if l.startswith("Action:")]
            if action_line:
                action_text = action_line[0].replace("Action:", "").strip()
                # 解析:工具名[参数]
                tool_name = action_text.split("[")[0].strip()
                tool_input = action_text.split("[")[1].rstrip("]").strip()

                # 执行工具
                if tool_name in tools:
                    observation = tools[tool_name](tool_input)
                    print(f"Observation: {observation}")

                    # 把结果加入对话
                    messages.append({"role": "assistant", "content": output})
                    messages.append({"role": "user", "content": f"Observation: {observation}"})
                else:
                    print(f"❌ 未知工具: {tool_name}")
                    break

    print("⚠️ 达到最大步数,未能得出最终答案")
    return None


# ============ 测试 ============

def search(query: str) -> str:
    """模拟搜索"""
    data = {
        "Python": "Python 是一种解释型、面向对象的高级编程语言,由 Guido van Rossum 于 1991 年创建。",
        "Java": "Java 是一种面向对象的编程语言,由 Sun Microsystems 于 1995 年发布。",
    }
    for key, value in data.items():
        if key in query:
            return value
    return f"未找到关于 '{query}' 的信息"


# 运行
simple_react_agent(
    question="Python 是谁创造的?什么时候?",
    tools={"search": search}
)

运行输出

--- 第 1 轮 ---
Thought: 用户问的是 Python 的创造者和时间,我需要搜索相关信息
Action: search[Python 是谁创造的]
Observation: Python 是一种解释型、面向对象的高级编程语言,由 Guido van Rossum 于 1991 年创建。

--- 第 2 轮 ---
Thought: 我已经从搜索结果中获得了 Python 的创造者和创建时间,可以回答了
Answer: Python 由 Guido van Rossum 于 1991 年创建。

✅ 最终回答: Python 由 Guido van Rossum 于 1991 年创建。

八、ReAct 的局限性

ReAct 不是万能的,了解它的局限:

局限说明应对方案
依赖 LLM 能力模型太弱,推理就会出错用更强的模型
可能死循环思考不出正确方向,反复尝试设置 max_iterations 限制
效率不高每一步都要调 LLM,token 消耗大用 Plan-and-Execute 替代
工具选择错误可能选错工具或传错参数写清楚工具描述

九、总结

问题答案
ReAct 是什么?Reasoning + Acting,推理和行动交替进行
核心循环是什么?Thought → Action → Observation → 重复
和普通 LLM 的区别?普通 LLM 一次性回答,ReAct 边想边做
适合什么任务?需要多步推理、调用工具的复杂任务
有什么局限?依赖模型能力、可能死循环、效率不是最高

ReAct 是目前最主流的 Agent 范式,理解了它,你就理解了 Agent 的核心工作原理。


下一篇预告

📖 第 8 篇:多 Agent 协作:让 AI 自己组队干活

一个 Agent 能力有限,那如果让多个 Agent 组成团队,分工协作呢?下一篇我们探索 Multi-Agent 系统,看看 Agent 是怎么"组队"完成复杂任务的。

👉 关注我,不迷路!


如果觉得有帮助,点个赞 👍 收藏 ⭐ 支持一下,是我持续更新的动力!