Agent开发(一) - ReACT框详解

173 阅读12分钟

Agent开发(一) - ReACT框架详解

背景

一切的起点要从一篇论文开始:arxiv.org/abs/2210.03…。该论文提出了一种名为 ReAct 的框架,其中 LLMs 以交错的方式生成推理轨迹和特定任务的行动。

ReAct 框架能够生成推理轨迹,使模型能够滚动跟踪并逐步逼近终点以完成目标,甚至可以处理异常。

Action 阶段允许与外部来源(如知识库或环境)交互,或通过 MCP 协议收集外界信息,从而产生更可靠和事实性的响应。

并且,ReAct 通过与外部知识库(如 Wikipedia API)交互,可以克服仅推理方法(如 CoT)的“幻觉”问题,并超越仅行动方法(Act),避免陷入“仅操作不反思”和“仅推理不操作”两大陷阱。

核心在于旨在通过提示(prompting)大型语言模型(LLMs),使其在解决各种任务时能够协同进行推理(Reasoning)和行动(Acting)。

1. 核心思想与动机

  • 人类智能的启发:人类在执行任务(如在厨房做饭)时,会自然地将具体行动(如切菜、开冰箱)与口头推理(如“现在该烧水了”、“没有盐,用酱油代替吧”、“我需要上网查一下面团怎么做”)结合起来。这种“行动”与“推理”的紧密结合,使得人类能够快速学习新任务,并在面对未知情况或信息不确定时做出稳健的决策。

  • 现有方法的局限

    • 仅推理(如 Chain-of-Thought, CoT):模型仅在内部生成思维链,缺乏与外部世界的交互,容易产生事实性幻觉(hallucination)和错误累积。
    • 仅行动(如 WebGPT):模型主要根据语言先验生成动作,缺乏高层次的抽象推理来制定、维护和调整计划,或利用工作记忆来支持行动,导致在复杂任务中表现不佳。
  • ReAct 的解决方案:ReAct 通过提示 LLMs 以交错(interleaved)的方式生成 推理轨迹(Thoughts)任务相关动作(Actions),从而实现两者的协同:

    • 推理指导行动(Reason to Act):推理帮助模型分解目标、制定计划、跟踪进度、处理异常并决定下一步行动。
    • 行动辅助推理(Act to Reason):通过与外部环境(如 Wikipedia API、模拟游戏、购物网站)交互获取新信息,使推理过程更接地气、更准确。

2. ReAct 的工作原理

  • 增强的动作空间:将代理(Agent)的动作空间 AA 扩展为 A^=AL\hat{A} = A \cup L,其中 LL 是语言空间。在 LL 中的动作被称为 Thought,它不改变外部环境,但会更新上下文,为后续的推理或行动提供支持。
  • 灵活的提示设计
    • 对于推理密集型任务(如问答),采用密集思考模式,即 “Thought → Action → Observation” 的循环。
    • 对于决策密集型任务(如文本游戏),采用稀疏思考模式,仅在关键时刻(如分解目标、跟踪进度、处理异常)插入 “Thought”,由模型自行决定何时思考。
  • 实现方式:主要使用少样本提示(few-shot prompting)。提供少量人工编写的、包含 Thought、Action 和 Observation 的成功任务解决轨迹作为示例,引导模型在新任务中模仿这种协同模式。
  • 人机协作:推理轨迹使得“人在回路”(Human-in-the-loop)的干预成为可能。人类可以通过编辑模型的 “Thought” 来轻松纠正其行为,引导其走向成功,这比直接修改动作或模型参数要直观得多。

它是如何工作的?

ReAct 的核心思想是通过提示(prompting)大型语言模型(LLMs),使其在解决任务时能够交错地(interleaved)生成“推理轨迹(Thoughts)”和“任务相关动作(Actions)”,从而实现推理与行动的协同增效。

其工作原理可以分解为以下几个关键部分:

1. 扩展的动作空间 (Augmented Action Space)

ReAct 对传统智能体的动作空间进行了根本性的扩展。

  • 传统框架:智能体在时间步 tt 接收环境观察 oto_t,然后从动作空间 AA 中选择一个动作 ata_t 来执行。动作直接影响环境,环境会返回下一个观察 ot+1o_{t+1}

image.png

  • ReAct 框架:ReAct 将动作空间扩展为 A^=AL\hat{A} = A \cup L。其中:
    • AA 是原有的、能改变外部环境的动作空间(例如,在问答任务中是 Search[entity]Lookup[string]Finish[answer];在文本游戏中是 go to cabinet 1take apple 1)。
    • LL 是语言空间。在这个空间中生成的动作被称为 Thought(思考/推理轨迹)。Thought 不会改变外部环境,因此不会触发环境的观察反馈。它的作用是对当前上下文 ctc_t 进行推理,生成有用的信息,并将这些信息更新到上下文中,以支持未来的推理或行动。

image 1.png

2. 交错生成推理与动作 (Interleaved Generation of Thoughts and Actions)

这是 ReAct 的核心机制。模型被提示以特定的格式生成输出,这个格式强制或鼓励模型在生成动作之前或之后插入思考步骤。

  • 推理指导行动 (Reason to Act):Thoughts 用于:

    • 分解目标:将复杂任务拆解成子目标(如:“1. 我需要先找到胡椒瓶 2. 然后把它放进抽屉。”)。
    • 制定和调整计划:根据当前状态决定下一步该做什么(如:“现在胡椒瓶找到了,下一步是去抽屉。”)。
    • 处理异常:当行动失败或信息不符时,调整策略(如:“搜索‘iPhone17ProMax’ wiki 没找到,我应该转变思路通过 Google 搜索关键词”)。
    • 提取和总结信息:从环境观察中提炼关键事实(如:“之前有提到,当前最新的 iPhone 是 16”)。
    • 注入常识或进行计算:利用模型的内部知识辅助决策(如:“应该告知用户想要的东西并不存在”)。
  • 行动辅助推理 (Act to Reason):Actions 用于:

    • 与外部环境交互:通过执行动作(如搜索、点击、移动)从外部世界(如 Wikipedia API、模拟游戏环境、购物网站)获取新的、模型内部知识库可能没有或已过时的信息。
    • 验证或修正推理:获取到的新信息可以用来验证之前的假设,或修正错误的推理路径。

这种交错模式创造了一个动态的、闭环的决策过程:

Thought → Action → Observation → Thought → Action → ...


ReAct 提示词工程

ReAct 提示词是一种精心设计的输入模板,通过少样本学习教会大型语言模型遵循 Thought → Action → Observation 的循环模式。其核心由三个关键组件构成,共同构建了一个完整的推理-行动框架。

  • 前缀 (PREFIX):定义任务目标和可用工具集

    • 功能:清晰说明任务性质和模型可调用的工具

    • 典型内容

      Answer the following questions as best you can. You have access to the following tools:
      List <tool_name>:
      
      
  • 循环参考 (CONTEXT):定义以什么方式进行运行

    • 功能:明确循环的开头和边界

    • 典型内容

      Use the following format:
      
      Question: <Question>
      Thought: ...
      Action: <tool_name>
      Action Input: <tool_input>
      Observation: <result>
      
      
  • 后缀 (SUFFIX):整合当前问题与历史交互

    • 功能:让 LLM 能够沿着设定好的路线进行 Next Token Prediction

    • 典型内容

      Begin!
      
      Question: {input} + {agent_scratchpad}
      Thought:
      
      
    • 关键作用{agent_scratchpad} 动态包含之前的 Thought/Action/Action Input/Observation 历史,使模型能在完整上下文中进行决策。

  • 组合起来就是:强制执行思考-行动循环

    • 典型内容

      Answer the following questions as best you can. You have access to the following tools:
      Search: a tool for searching the web
      Calculator: a tool for performing calculations
      
      Use the following format:
      
      Question: the input question you must answer
      Thought: you should always think about what to do
      Action: the action to take, should be one of [Search, Calculator]
      Action Input: the input to the action
      Observation: the result of the action
      ... (this Thought/Action/Action Input/Observation can repeat N times)
      Thought: I now know the final answer
      Final Answer: the final answer to the original input question
      
      Begin!
      
      Question: What is the capital of France?
      Thought:
      
      
    • 关键作用:通过严格的格式要求,确保模型输出可被系统解析,并强制模型在行动前进行思考。

动态交互机制 (Dynamic Interaction Mechanism)

ReAct 提示词的精髓在于其动态构建机制,使模型能够通过多轮交互解决复杂任务。

  • agent_scratchpad 的核心作用
    • 初始状态:首次调用时为空,仅包含 Question: {input}\\nThought:
    • 迭代更新:每次交互后,系统将模型生成的 Thought/Action/Action Input 与真实 Observation 拼接到 agent_scratchpad
    • 关键价值:维持完整的决策历史,使后续思考基于先前的交互结果
  • 停止序列 (Stop Sequences) 的精细控制
    • 典型设置stop=["\\nObservation"]
    • 功能:在模型生成 "Action Input" 后停止,防止模型伪造观察结果
    • 关键作用:确保 Observation 部分由系统填充真实环境反馈,保持推理的“接地性”

这种设计使 ReAct 提示词成为连接模型内部推理能力与外部环境交互的桥梁,通过结构化但灵活的框架,实现了边想边做的人类式问题解决过程,同时保持了高度的可解释性和可控性。

LangChain ReAct 使用方法

以下是 ReAct 提示方法在实际应用中的高层级示例。我们将使用 LangChainlangchain-community,因为它已经内置了利用 ReAct 框架构建能够通过结合 LLM 的力量和不同工具来执行任务的代理的功能。

获取免费模型

登陆 modelscope.cn/ 并注册成功后,在该页面 modelscope.cn/my/myaccess…

获取 API 密钥后,配置环境即可使用任意兼容 OpenAI /v1 接口的模型。

1. 环境准备

首先,确保系统已安装 Python ≥ 3.10。推荐使用虚拟环境以隔离依赖:

python -m venv react-env
source react-env/bin/activate  # Linux/macOS
# 或 react-env\Scripts\activate  # Windows

随后安装必要依赖:

pip install --upgrade langchain langchain-community langchain-openai ddgs python-dotenv playwright pypdf requests
python -m playwright install chromium

说明:Playwright 用于无头浏览器渲染,确保能获取动态网页内容;ddgs 提供 DuckDuckGo 搜索能力;pypdf 支持 PDF 文本提取。

2. 配置模型接入(.env

在项目根目录创建 .env 文件:

OPENAI_API_KEY=your_api_key_here
OPENAI_API_BASE=https://your-llm-endpoint/v1
MODEL_ID=your-model-name

这里推荐 Qwen/Qwen3-Next-80B-A3B-Instruct 模型

3. 构建 ReAct 代理(react_agent.py

创建 react_agent.py,逐步构建代理逻辑:

(1) 基础脚手架与环境加载

from __future__ import annotations
import argparse, os
from dotenv import load_dotenv
load_dotenv()

def main() -> None:
    ap = argparse.ArgumentParser()
    ap.add_argument("--question", required=True)
    args = ap.parse_args()
    print("Question:", args.question)
    # 后续在此处插入 LLM 与代理逻辑

(2) 初始化 OpenAI 兼容 LLM

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model=os.getenv("MODEL_ID"),
    base_url=os.getenv("OPENAI_API_BASE"),
    api_key=os.getenv("OPENAI_API_KEY"),
    temperature=0,
    streaming=True,
)

(3) 定义外部工具集(Actions)

ReAct 的"行动"能力**依赖于工具**。我们定义四类工具,覆盖信息获取的主要路径:

# Web 搜索(DuckDuckGo)
from ddgs import DDGS

def ddgs_search(q: str) -> str:
    items = []
    with DDGS() as s:
        for it in s.text(q.strip(), max_results=6):
            items.append(f"{it['title']} :: {it['href']} :: {it['body']}")
    return "\n".join(items)[:2000] or "no results"

# 浏览器渲染(获取真实页面内容)
from playwright.sync_api import sync_playwright

def browser_render(url: str) -> str:
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        context = browser.new_context()
        page = context.new_page()
        page.goto(url.strip(), wait_until="domcontentloaded", timeout=30000)
        html = page.content()
        context.close(); browser.close()
    return html[:4000]

# HTTP 端点获取
import requests

def http_fetch(url: str) -> str:
    r = requests.get(url.strip(), timeout=20)
    r.raise_for_status()
    return r.text[:2000]

# PDF 文本提取(可选)
import tempfile
from pathlib import Path

def download_pdf_text(url: str) -> str:
    r = requests.get(url.strip(), timeout=30)
    r.raise_for_status()
    with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp:
        tmp.write(r.content)
        path = Path(tmp.name)
    try:
        from langchain_community.document_loaders.pdf import PyPDFLoader
        pages = PyPDFLoader(str(path)).load()
        return "\n".join(p.page_content for p in pages)[:4000]
    finally:
        path.unlink(missing_ok=True)

(4) 封装为 LangChain 工具

from langchain_core.tools import StructuredTool

tools = [
    StructuredTool.from_function(ddgs_search, name="ddgs_search", description="Perform web search via DuckDuckGo."),
    StructuredTool.from_function(browser_render, name="browser_render", description="Render a webpage using headless Chromium and return HTML content."),
    StructuredTool.from_function(http_fetch, name="http_fetch", description="Fetch plain text or JSON from HTTP endpoints."),
    StructuredTool.from_function(download_pdf_text, name="download_pdf_text", description="Download a PDF file and extract its textual content."),
]

(5) 初始化 ReAct 代理

from langchain.agents import AgentType, initialize_agent

agent = initialize_agent(
    tools=tools,
    llm=llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True,
    max_iterations=30,
    agent_kwargs={
        "system_message": (
            "You are a ReAct analyst. Solve the task by interleaving Thought, Action, and Observation. "
            "Do not treat search engine result pages (SERPs) as evidence. Always open and summarize at least one "
            "content page, PDF, or API response before concluding. If evidence is insufficient, state 'Insufficient Evidence' "
            "instead of hallucinating."
        )
    },
)

result = agent.invoke({"input": args.question})
print("\n[Final Answer]", result.get("output"))

4. 运行与验证

执行以下命令测试代理:

python react_agent.py --question "凹凸实验室 详情"

你将观察到完整的 ReAct 轨迹,例如:

Thought: 我需要先搜索"凹凸实验室"以获取基本信息。
Action: ddgs_search
Action Input: 凹凸实验室
Observation: [搜索结果摘要]
Thought: 搜索结果中包含官网链接,我应渲染该页面以获取详细内容。
Action: browser_render
Action Input: https://aotu.io/
Observation: [HTML 内容片段]
Thought: 页面显示凹凸实验室是京东的前端技术团队...
Final Answer: 凹凸实验室是京东集团旗下的前端技术团队...

若信息不足,代理将主动返回 "Insufficient Evidence",而非生成幻觉内容——这正是 ReAct 通过行动辅助推理克服 CoT 幻觉问题的体现。


结语:迈向更稳健、可解释、可协作的智能体

ReAct 不仅是一种提示工程技巧,更代表了一种认知架构的范式转变——将语言模型从“被动回答者”转变为“主动探索者”。通过强制模型在推理与行动之间建立反馈闭环,ReAct 有效弥合了纯内省式推理(如 CoT)与盲目试错式行动(如早期 WebAgent)之间的鸿沟。

正如人类在真实世界中解决问题时,既会思考“下一步该做什么”,也会动手“查资料、点链接、试操作”,ReAct 使 LLM 具备了类似的边想边做、以行促思的能力。这种能力带来了三重核心价值:

  1. 事实可靠性提升:通过与外部知识源交互,显著减少幻觉,尤其在开放域问答与事实核查任务中表现突出;
  2. 任务鲁棒性增强:面对信息缺失、环境异常或目标模糊时,模型可通过动态调整计划实现容错;
  3. 人机协同成为可能:清晰的推理轨迹(Thoughts)为人类干预提供了天然接口,使“人在回路”的调试、引导与监督变得直观可行。

未来,随着工具生态的丰富(如数据库查询、代码执行、多模态感知)与代理架构的演进(如记忆机制、多智能体协作),ReAct 所奠定的“推理-行动”协同框架,将持续作为构建可信、可控、可扩展人工智能系统的重要基石。

最终启示:真正的智能,不在于无所不知,而在于知道何时思考、何时行动,以及如何在未知中稳健前行。ReAct,正是朝这一方向迈出的关键一步。