【Agent】手把手开发一个旅行助手Agent(附源码)(纯干货)
Agent概念
Agent = LLM + Planning + Memory + Tool
-
Planning: 规划
-
Memory:上下文管理
-
Tool:大模型自主决定调用哪些工具
reAct范式
分成三部分
reasoning:模型根据当前问题和之前的观察历史,推理下一步该做什么
act:决定调用哪个工具,生成调用该工具所需的参数
observation: 系统执行模型所选的行动(如调用搜索引擎)并将执行结果返回给模型

旅行助手Agent实践
需求
旅行 Agent Demo 功能:
-
根据城市查询天气(函数1)
-
根据天气给出旅游方案(函数2)
技术栈
框架:langchain
llm:采用心流网页api模式 qwen2-32b
Agent代码
运行的时候记得修改api-key为自己的,如果没有就去注册个心流
# -*- coding: utf-8 -*-
"""
旅行 Agent Demo
功能:
1. 根据城市查询天气(函数1)
2. 根据天气给出旅游方案(函数2)
使用 LangChain ReAct + 心流 Qwen3-32B
"""
import os
from langchain.agents import AgentExecutor, create_react_agent
from langchain_core.prompts import PromptTemplate
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
# ======================
# Tools:旅行功能
# ======================
@tool
def query_weather(city: str) -> str:
"""根据城市名查询当前天气"""
# 这里只是 mock 数据,真实场景可调用天气 API
weather_map = {
"北京": "晴",
"上海": "雨",
"广州": "多云",
"深圳": "晴",
"成都": "阴"
}
weather = weather_map.get(city, "未知")
return f"{city}当前天气:{weather}"
@tool
def travel_plan(weather: str) -> str:
"""根据天气给出旅游方案"""
plan_map = {
"晴": "推荐户外徒步、城市骑行、野餐拍照。",
"多云": "适合逛博物馆、老街、拍照打卡。",
"阴": "可以去咖啡馆、书店、室内乐园。",
"雨": "推荐室内景点:科技馆、商场、温泉。"
}
return plan_map.get(weather, "暂无对应方案,请自行探索~")
tools = [query_weather, travel_plan]
# ======================
# ReAct Prompt 模板
# ======================
REACT_PROMPT_TEMPLATE = """你是旅行小助手(Travel Assistant)。
根据用户需求,使用工具给出天气与旅游建议。
可用工具:
{tools}
工具名称(用逗号分隔):
{tool_names}
使用以下格式:
Thought: 思考下一步
Action: 工具名称
Action Input: 工具输入
Observation: 工具返回
...(可重复)
Thought: 已得到最终答案
Final Answer: 返回给用户的完整建议
开始!
Question: {input}
{agent_scratchpad}
"""
# ⚠️⚠️⚠️⚠️注意 {agent_scratchpad}这是 LangChain 自动填充的“思考记录”,记录了之前的 Thought/Action/Observation,让模型能记住上下文。
prompt = PromptTemplate.from_template(REACT_PROMPT_TEMPLATE)
# ======================
# 创建 Agent
# ======================
llm = ChatOpenAI(
model="qwen3-32b",
base_url="https://apis.iflow.cn/v1",
api_key=os.getenv("IFLOW_API_KEY", "sk-xxx"), #改成自己的心流token
temperature=0,
verbose=True
)
agent = create_react_agent(llm=llm, tools=tools, prompt=prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
handle_parsing_errors=True
)
# ======================
# 执行测试
# ======================
if __name__ == "__main__":
print("\n" + "="*50)
print("🚀 旅行 Agent 启动(使用心流 Qwen3-32B)")
print("="*50)
# 测试请求
request = "我想去北京旅行给出建议"
result = agent_executor.invoke({"input": request})
print("\n" + "="*50)
print("🎉 最终建议:")
print(result["output"])
print("="*50)
运行结果

原理
时序图

用户输入
↓
LLM 生成第一个 Thought + Action
↓
AgentExecutor 解析 Action和ActionInput
↓
AgentExecutor 解析在 tools 列表中查找对应工具
↓
AgentExecutor 解析调用 tool.invoke(input) 执行函数
↓
AgentExecutor 解析拿到 Observation(结果)
↓
AgentExecutor 解析拼回 prompt,继续给 LLM
↓
循环直到 Final Answer
↓
返回最终结果给用户
深入LangChain源码
实现reAct Agent,使用了框架中的create_react_agent和AgentExecutor
agent = create_react_agent(llm=llm, tools=tools, prompt=prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
handle_parsing_errors=True
)
这两个函数分别啥作用?
create_react_agent可以解析LLM输出的参数,组织成Action结构,交给AgentExecutor去执行
可以把AgentExecutor理解为身体,create_react_agent理解成大脑。身体要做啥,需要问大脑,大脑给出答案后身体执行,之后再去问大脑...直到输出最终结果
create_react_agent 到底做了什么?
它创建了一个 遵循 ReAct 范式的 Agent 可运行对象(Runnable)
这个对象的本质是一个 “提示词 + LLM + 输出解析器” 的组合,它的任务是:
接收当前状态(用户问题 + 历史思考),输出下一步的 Thought/Action/Input
我们来看它的内部结构:
agent = create_react_agent(llm=llm, tools=tools, prompt=prompt)
它实际上构建了一个这样的流程:
Input (用户问题 + 历史记录)
↓
[ReAct Prompt Template] → 拼成完整提示词
↓
LLM(Qwen3)→ 输出文本:"Thought: ...\nAction: ...\nAction Input: ..."
↓
[ReAct Parser] → 解析出 Action 和 Input(如:query_weather, "北京")
↓
输出一个 { 'actions': [...], 'intermediate_steps': ... } 结构⚠️
关键产出:一个能输出 Action 的 Runnable
这个 agent 对象本身不会去调用工具,它只负责:
-
生成符合 ReAct 格式的文本
-
解析出结构化的
Action和Action Input
它就像是一个“战略指挥官”,只下命令:“下一步该查天气了”,但不亲自去查。
AgentExecutor 做了什么?
它是“战术执行官” + “流程控制器”。
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
它负责:
|
功能 |
说明 |
|
循环执行 |
不断调用 |
|
执行工具 |
拿到 |
|
维护状态 |
把每次的 |
|
拼接上下文 |
把历史记录填入 |
|
错误处理 |
工具失败、解析失败时如何应对(如重试或提示模型) |
总结:框架做了什么
本质上还是把reAct步骤翻译成了Prompt,通过解析LLM输出结果,来得到哪些工具使用以及如何使用
局限性
LLM必须够大够好:否则不能很好理解并返回Action ActionInput,对格式和内容要求高。
耗时长
langchain靠prompt执行reAct,会有幻觉以及返回格式不满足要求情况出现,包装比较深,难以排查
更多推荐



所有评论(0)