
ReAct智能体实战:旅游规划多步推理与循环调参要点
单轮问答和真正的智能体之间差着一层"边想边做"的能力。查天气、荐活动、搜股价这类环环相扣的任务,用简单链式调用写死流程当然可行,但一旦中间某步失败,整条链就断了。ReAct 框架解决的就是这个问题:让模型在循环里自己决定下一步,失败了还能重新推理。
三步循环:推理、行动、观察
ReAct 的核心是把智能体行为压成一个固定循环:
- 推理(Thought)——分析当前状态,决定该调哪个工具还是直接回答;
- 行动(Action)——执行决策,带上参数调用工具;
- 观察(Observation)——读取工具返回,更新状态,判断是否进入下一轮。
思考过程有标准格式,一眼能读懂它的"心路":
Thought: 我需要先查北京的天气,才能推荐活动
Action: get_weather
Action Input: 北京
Observation: 晴,25℃
Thought: 天气是晴,适合推荐户外活动
Action: recommend_activity
Action Input: 晴,25℃
Observation: 推荐户外活动:公园骑行
这种显式思考链带来两个实际好处:调试时能看到模型"为什么这么做";某一步出错时,模型能在下一轮推理里自我修正,而不是从头再来。

增量点:三种创建方式怎么选
LangChain 里建智能体有三条路,选错路是新手最常见的翻车原因:
| 场景特征 | 推荐方法 | 原因 |
|---|---|---|
| 多步推理、需要自我修正 | create_react_agent | 显式思考链,可分步拆解 |
| 严格结构化参数(对接支付等API) | create_tool_calling_agent | 直接输出 JSON,解析错误率低 |
| 简单任务快速出活 | initialize_agent | 开箱即用,配置最少 |
判断口诀:参数格式要求严格就选 tool_calling,任务需要"看着结果改主意"就选 react。两者不是替代关系,是场景分工。
完整实现:旅游规划智能体
工具定义里最容易被忽视的是文档字符串——智能体全靠它判断什么时候用这个工具:
from langchain.tools import tool
@tool
def get_weather(city: str) -> str:
"""
获取指定城市的天气信息,用于旅游活动推荐。
参数:city - 城市名称(如北京、上海、广州)
"""
weather_data = {"北京": "晴,25℃", "上海": "雨,20℃"}
return weather_data.get(city, f"暂不支持查询{city}的天气")
@tool
def recommend_activity(weather: str) -> str:
"""
根据天气推荐活动,必须先调用 get_weather 获取天气。
参数:weather - get_weather 返回的天气字符串
"""
if "雨" in weather:
return "推荐室内活动:博物馆参观、美食探店"
return "推荐户外活动:公园骑行、徒步"
注意 recommend_activity 的文档里写了"必须先调用 get_weather"——这行字直接决定了调用顺序,模型会照做。
模型和模板部分:

from langchain_openai import ChatOpenAI
from langchain import hub
llm = ChatOpenAI(model_name="qwen-plus", temperature=0.3)
prompt = hub.pull("hwchase17/react") # 官方模板,别自己手写
from langchain.agents import create_react_agent, AgentExecutor
agent = create_react_agent(llm=llm, tools=tools, prompt=prompt)
executor = AgentExecutor(
agent=agent, tools=tools, verbose=True,
max_iterations=5,
handle_parsing_errors="请检查输入格式,确保问题清晰",
return_intermediate_steps=True
)
跑起来后,日志里能看到完整的三轮循环:查天气 → 荐活动 → 搜股价,最后汇成 Final Answer。
增量点:五个生产级调参细节
实战里真正决定成败的是参数,这几条是踩坑总结:
- max_iterations 建议设 3~5。设大了死循环烧钱,设小了复杂任务跑不完。观察目标任务的正常步数,上限设为它的 1.5~2 倍。
- handle_parsing_errors 必须配。模型偶发生成不符合 ReAct 格式的输出,直接抛异常会终止整个会话;配上错误提示语后,下一轮模型通常能自己修正。
- return_intermediate_steps 打开。中间步骤留痕是排查工具调用顺序问题的第一手证据,也方便事后统计每类任务的平均循环数。
- 温度给 0.2~0.4。太低的多步推理容易卡在同一轮重复,太高会偏离 ReAct 格式。
- 模型要支持格式遵循。旧版模型(如 gpt-3.5-turbo-0301 一类)经常不按模板输出,优先选指令遵循强的模型,格式崩了再好的框架也救不回来。
增量点:两个模板相关的坑
别手写 ReAct 模板。 官方模板里 tools、tool_names 两个变量必须被正确注入,手写漏一个变量,模型就不知道工具清单,开始幻觉工具名。用 hub.pull("hwchase17/react") 一行解决。
模板是英文的,观察结果最好是中文摘要。 工具返回原文直接进 Observation 会拉长上下文,也稀释模型注意力。在工具函数内部就把结果压缩成"结论 + 关键数字",循环轮数和 token 消耗都会明显下降。
收束
ReAct 的价值不在"更智能",而在可控:每一步有据可查、错了可以重推、调试有完整轨迹。旅游规划只是载体,任何"步骤取决于上一步结果"的任务——技术调研、故障排查、数据核对——都适用同一套骨架。把循环次数、错误处理、中间留痕三件事配好,它就能从演示走向生产。

评论0