3. 使用ReAct框架的Agent

使用ReAct框架的Agent 学习卡片

任务目标

构建一个基于ReAct(Reasoning + Acting)框架的Agent,使其能够通过Thought → Action → Observation的循环,自主解决数学问题。Agent需要具备推理能力(决定下一步做什么)和行动能力(调用工具执行计算),并在多轮循环后得出最终答案。

核心实现

本案例使用LangChain的create_react_agent方法,配合一个数学计算工具。Agent通过ReAct提示模板驱动,在循环中交替输出思考过程和工具调用,直到获得最终答案。核心依赖为langchain、langchain-和langchain-community。

# requirements.txt
# langchain>=0.2.0
# langchain->=0.1.0
# langchain-community>=0.2.0

import os
from langchain_ import ChatOpenAI
from langchain.agents import create_react_agent, AgentExecutor
from langchain.agents import Tool
from langchain import hub
from langchain_community.utilities import SerpAPIWrapper

# 1. 设置环境变量(请替换为你的真实)
os.environ["_"] = "your--"
# 如果使用SerpAPI搜索工具,需要设置;本案例仅用数学工具,可注释掉
# os.environ["SERPAPI_"] = "your-serpapi-key"

# 2. 定义数学计算工具(本案例核心工具)
def math_calculator(expression: str) -> str:
    """
    安全地计算数学表达式。
    仅支持基本四则运算、幂、括号,不支持变量赋值。
    """
    # 移除潜在的危险字符(仅允许数字、运算符、括号、小数点)
    allowed_chars = set("0123456789+-*/(). ")
    if not all(c in allowed_chars for c in expression):
        return "错误:表达式包含非法字符"
    try:
        # 使用eval但限制命名空间为空,仅允许数学运算
        result = eval(expression, {"__builtins__": {}}, {})
        return str(result)
    except ZeroDivisionError:
        return "错误:除零"
    except Exception as e:
        return f"错误:{str(e)}"

# 3. 创建工具列表
tools = [
    Tool(
        name="math_calculator",
        func=math_calculator,
        description="用于计算数学表达式。输入应为合法的数学表达式,如 '3*5+2' 或 '(4+5)*6'。返回计算结果。"
    )
]

# 4. 初始化语言模型(使用支持工具调用的模型)
llm = ChatOpenAI(model="-mini", temperature=0)

# 5. 获取ReAct提示模板(LangChain官方hub中的标准模板)
prompt = hub.pull("hwchase17/react")

# 6. 创建ReAct Agent
agent = create_react_agent(llm=llm, tools=tools, prompt=prompt)

# 7. 创建Agent执行器,设置最大迭代次数防止死循环
agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    verbose=True,          # 打印Thought/Action/Observation过程
    max_iterations=5,      # 最多5轮思考-行动循环
    handle_parsing_errors=True
)

# 8. 运行Agent解决数学问题
if __name__ == "__main__":
    # 测试问题1:需要多步计算的表达式
    question1 = "计算 (15 + 3) * 4 - 20 / 5 的结果"
    print("="*50)
    print(f"问题: {question1}")
    result1 = agent_executor.invoke({"input": question1})
    print(f"最终答案: {result1['output']}")
    
    # 测试问题2:需要验证中间结果的表达式
    question2 = "如果 x = 7,计算 3*x^2 + 2*x - 5 的值"
    print("="*50)
    print(f"问题: {question2}")
    result2 = agent_executor.invoke({"input": question2})
    print(f"最终答案: {result2['output']}")

运行与验证

运行方式:

  1. 安装依赖:pip install langchain langchain- langchain-community
  2. 将代码中的your--替换为真实有效的
  3. 直接运行脚本:python react_agent.py

验证方法与通过条件:

  • 观察执行过程:设置verbose=True后,控制台会打印完整的ReAct循环。应能看到模型依次输出Thought(推理)、Action(选择工具)、Action Input(传给工具的具体表达式)、Observation(工具返回结果),最后以Final Answer结束。
  • 验证结果正确性:问题1的正确答案为68((15+3)*4=72,20/5=4,72-4=68)。问题2的正确答案为156(3*49+14-5=156)。Agent最终输出的答案应与这两个数值一致。
  • 多轮循环验证:问题1需要Agent先计算括号内加法,再计算乘法和除法,最后做减法,至少需要2次工具调用,可验证Agent具备多步推理能力。
ReAct Agent 工作流程 用户问题 Thought(推理) 分析问题,决定下一步行动 Action(行动) 选择工具并传入参数 工具(Tool) math_calculator → 执行计算并返回结果 Observation(观察) 获取工具执行结果 循环直到得到最终答案 Final Answer

常见问题

  • 无效:确保环境变量已正确设置,且账户有可用额度。
  • 工具调用格式错误:如果模型输出的Action格式不符合规范,handle_parsing_errors=True会自动重试,但会消耗额外调用次数。
  • 死循环:max_iterations=5限制了最大循环次数,防止模型陷入无限推理。若问题过于复杂,可适当增大该值。
  • eval安全性:本案例的math_calculator通过白名单字符过滤和空命名空间限制,仅允许纯数学运算,不执行任意代码。实际生产环境建议使用ast模块或专用数学解析库(如sympy)替代。