AI agent cover2

【核心概念速览 / TL;DR】
什么是 ReAct 模式? ReAct(Reasoning and Acting,推理与行动)是一种赋予大语言模型(LLM)使用外部工具能力的经典范式。它通过强制 LLM 交替进行“思考(Thought)”和“行动(Action)”,并结合环境的“观察反馈(Observation)”,从而解决复杂的多步问题。ReAct 模式完全依靠精心设计的提示词模板和解析逻辑实现,而不是 LLM 内置的魔法。

欢迎来到《从0开始开发 AI Agent》系列第二篇。在上一篇文章中,我们探讨了 Agent 的核心循环。今天,我们将暂时抛开 LangChain、CrewAI 等热门框架,用最基础的 Python 代码,手把手带你搭建一个真正的 ReAct Agent。

1. 为什么先不学框架?

如今,AI Agent 框架层出不穷,但为什么我们建议你从“纯手搓(No Framework)”开始?

  • 剥离魔法,看清底层 I/O 逻辑:高层框架(如 CrewAI)虽然封装了 ReAct 范式,但往往隐藏了底层逻辑。如果直接使用框架,当 Agent 出现死循环或无法正确调用工具时,你将很难排查问题。
  • 极致的调试能力与低成本:不依赖框架意味着你可以精确知道哪一步失败了。此外,纯代码实现避免了框架默认使用的冗余 Context 和昂贵的大模型,让你的 Agent 运行更便宜、更快速。

2. ReAct 模式解析:大模型如何“思考”与“行动”

ReAct 模式的核心在于一个结构化的提示词循环。人类解决问题时,通常是“思考 -> 采取行动 -> 观察结果 -> 继续思考”。ReAct 正是让 LLM 遵循这个过程。

在 ReAct 中,我们将 LLM 的输出严格限制为以下格式:

  1. Thought(思考):大模型表达它的内部推理过程(例如:“我需要计算总和”)。
  2. Action(行动):大模型决定调用的外部工具名称(例如:Calculator)。
  3. Action Input(行动输入):传递给工具的参数,通常是严格的 JSON 格式。
  4. Observation(观察)(这步由我们的代码返回) 工具执行后的结果反馈给大模型。
  5. Final Answer(最终答案):当大模型收集到足够信息后,输出最终结果。

通过这种结构化的自我对话,大模型不再局限于其静态的训练数据,而是可以动态地向互联网、数据库或本地函数寻求帮助。

3. 动手实战:用纯 Python 构建 ReAct Agent

我们将编写一个拥有“计算器”和“天气查询”能力的智能体。

第一步:编写 System Prompt(系统提示词)
这是 Agent 的灵魂。我们需要通过提示词强制 LLM 遵循 ReAct 格式。

SYSTEM_PROMPT = """
你是一个可以解答问题的智能助手。你可以使用以下工具:
1. calculator: 执行数学计算,参数为 {"expression": "数学表达式"}

你必须严格遵循以下格式进行交互:
Thought: 思考你需要做什么
Action: 选择你要使用的工具名称
Action Input: 传递给工具的 JSON 格式参数
Observation: 工具返回的结果(你不要生成这部分,这是由系统提供的)
... (Thought/Action/Action Input/Observation 可以重复多次)
Thought: 我现在知道最终答案了
Final Answer: 回答用户的最终答案
"""

第二步:定义原子工具(Tools)
我们将工具定义为普通的 Python 函数,并用一个字典做路由映射。

def calculator(args):
    # 模拟计算器工具
    return str(eval(args.get("expression")))

# 工具路由映射
tools_mapping = {
    "calculator": calculator
}

第三步:编写 While 循环(Agent Loop)

这是架构的核心:一个不断迭代的控制流。在循环中,大模型生成操作,我们解析并执行操作,将结果(Observation)拼接到上下文中,直到触发 Final Answer

def run_react_agent(query):
    messages = [{"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": query}]

    while True: # Agent Loop
        # 1. 调用大模型 (Perceive & Reason)
        response = call_llm(messages)
        messages.append({"role": "assistant", "content": response})

        # 2. 如果包含 Final Answer,则结束循环
        if "Final Answer:" in response:
            print("任务完成!\n", response)
            break

        # 3. 解析 Action 和 Action Input (Plan)
        action_name = extract_action(response)
        action_input = extract_action_input(response)

        # 4. 执行工具 (Act)
        if action_name in tools_mapping:
            tool_func = tools_mapping[action_name]
            observation = tool_func(action_input)
            print(f"[执行工具]: {action_name}({action_input}) -> 结果: {observation}")

            # 5. 将观察结果返回给大模型 (Observe)
            messages.append({"role": "user", "content": f"Observation: {observation}"})
        else:
            messages.append({"role": "user", "content": "Observation: 工具不存在,请重试。"})

当你运行 run_react_agent("35乘以2是多少?") 时,你将亲眼见证大模型逐步推理、调用天气函数、调用计算器函数,最终得出答案的完整过程。

ReAct Agent in Pure Python


常问问题解答(FAQ)

Q: 为什么纯代码编写的 Agent 比使用框架更好调试?
A: 当你使用纯 Python 编写 while 循环时,你可以清楚地记录每一次大模型调用的确切输入和输出(Thoughts 和 Observations)。而高度封装的框架如果发生工具解析错误,往往只会抛出深层的堆栈异常,难以定位。

Q: ReAct 模式是如何解决 LLM 幻觉问题的?
A: 通过交替进行“推理(Reasoning)”和“行动(Acting)”,LLM 不再需要凭空捏造事实,而是通过调用外部搜索引擎或数据库工具,获取真实的 Observation 作为下一步推理的依据,显著降低了事实性幻觉。

📢 下一篇预告:
在理解了底层的 ReAct I/O 逻辑后,我们将在**《第三篇:利器选择 —— 主流 Agent 框架大比拼与 LangGraph 实战》**中探讨如何为生产环境引入状态管理,并使用现代框架重构我们的智能体。

📦 代码资源

完整代码实现:
🔗 *easyagent

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐