基于 LangChain 搭建 ReAct Agent:从原理到火车票购票任务实操指南
引言
随着大语言模型(LLM)在各领域的应用普及,其局限性逐渐凸显——无法实时获取信息、易产生虚假内容、复杂推理能力不足等问题,导致LLM难以独立完成“购票”“数据分析”等现实任务。而LLM-based Agent(基于LLM的智能体) 通过“推理+外部工具调用”的模式,成为解决这些痛点的核心方案。本文AI铺子将以ReAct Agent(Reasoning+Action) 为核心,结合LangChain框架,手把手教你搭建一个能完成“火车票购票”任务的AI Agent,同时详解原理、实操步骤与测试结果,助力开发者快速掌握生成式AI工具开发技能。
一、核心背景:LLM的局限性与Agent化的必要性
LLM虽具备强大的自然语言理解与生成能力,但在落地到实际任务时,存在四大关键局限性,这些问题直接制约了其应用场景:
存在幻觉:LLM可能生成与事实不符的内容(如虚构不存在的火车车次),无法保证信息真实性;
结果不真实:即使无明显幻觉,输出内容也可能因训练数据滞后或逻辑偏差,与现实情况脱节;
对时事了解有限:LLM的知识范围限于训练数据集(如GPT-4训练截止到2023年),无法获取实时动态信息(如当日火车余票、车次变动);
难以应对复杂推理和计算:对于“确定出发地→查询车次→筛选符合条件车次→完成购票”的多步骤任务,LLM无法自主拆解流程并执行。
而Agent化的核心价值,正是通过集成外部工具(如实时查询接口、计算工具)与推理逻辑,让LLM从“被动回答”升级为“主动完成任务”,彻底弥补上述局限性。

二、ReAct Agent:原理与LangChain核心组成
2.1 ReAct Agent的定义与优势
ReAct Agent 是LLM Agent的进阶形态,其核心逻辑是“Reasoning(推理)+ Action(行动) ”的循环:通过“分析任务→确定下一步动作→调用工具执行→获取结果→再推理”的流程,逐步推进任务完成。与仅依赖思维链(COT)的“纯推理”模式、仅调用函数的“纯行动”模式相比,ReAct Agent兼具“逻辑拆解能力”与“现实交互能力”,更适配复杂现实任务。
2.2 LLM Agent的发展路径
从技术演进来看,LLM Agent经历了四个关键阶段,ReAct是当前兼顾效果与实用性的主流方案:Standard IO(直接回答) → COT(Chain-of-Thought,思维链推理) → Action-Only(仅函数调用) → ReAct(推理+行动协同)
2.3 基于LangChain的ReAct Agent核心组成
LangChain是开发LLM Agent的主流框架,其提供的模块化组件可快速搭建ReAct Agent。本文搭建的火车票AI Agent,核心依赖以下6大组件,各组件功能与实操细节如下表所示:
| 组件名称 | 核心功能 | 本文实操细节 |
|---|---|---|
| Models | 提供推理核心能力 |
使用GPT-4 Turbo(推理精度高),配置temperature=0(减少随机性)、seed=42(保证结果可复现) |
| Prompts | 约束Agent行为与输出格式 | 设计两类Prompt:①任务执行Prompt(明确“思考→行动→观察”循环格式);②最终回复Prompt(总结任务结果) |
| Memory | 记录任务执行状态与历史信息 | 采用ConversationTokenBufferMemory,设置最大Token限制4000,实时保存每轮思考与工具返回结果 |
| Tools | 实现Agent与外部的交互 |
定义3个工具:查询火车票、购买火车票、FINISH(任务结束占位符),通过StructuredTool封装Python函数 |
| Chains | 串联“Prompt→LLM→解析”流程 | 基于LCEL(LangChain Expression Language) 构建链式逻辑,确保推理与工具调用的连贯性 |
| Agent | 统筹任务执行的核心单元 | 自定义MyAgent类,实现“初始化→循环思考→工具调用→记忆更新→任务终止”全流程控制 |

三、手把手搭建火车票AI Agent(LangChain实操)
本节将以“购买2024年6月1日早上去上海的火车票”为目标任务,分6步完成ReAct Agent的搭建,所有代码与逻辑均基于真实可执行的技术方案。
3.1 环境准备:安装依赖与导入模块
3.1.1 安装核心依赖
首先通过pip安装LangChain及相关工具包,执行以下命令:
pip install langchain # LangChain核心框架 pip install uuid # 生成唯一标识(可选) pip install pydantic # 数据验证(工具参数校验) pip install openai # 调用GPT-4 Turbo(需配置API密钥)
3.1.2 导入关键模块
在Python脚本中导入所需组件,包括LangChain工具、模型、记忆模块等:
import json import sys from typing import List, Dict, Optional from langchain.chat_models import ChatOpenAI from langchain.tools import StructuredTool from langchain.prompts import PromptTemplate from langchain.memory import ConversationTokenBufferMemory from langchain.schema import BaseMessage, HumanMessage from langchain.callbacks.base import BaseCallbackHandler from pydantic import BaseModel, Field
3.2 工具定义:Agent的“手脚”
工具是Agent与外部世界交互的核心载体。本文需实现3个工具,分别对应“查询车次”“购买车票”“任务终止”,具体定义如下:
3.2.1 查询火车票工具
功能:根据出发地、目的地、日期等参数,返回符合条件的mock车次列表(实际应用中可对接12306实时接口)。
def query_train_tickets(
origin: str = Field(..., description="出发地,如北京"),
destination: str = Field(..., description="目的地,如上海"),
date: str = Field(..., description="日期,格式YYYY-MM-DD"),
departure_time_start: str = Field(..., description="出发时间段起始,格式HH:MM"),
departure_time_end: str = Field(..., description="出发时间段结束,格式HH:MM")
) -> Dict:
# mock数据:模拟返回3个车次,仅G1234符合“早上出发”条件
return {
"status": "success",
"tickets": [
{"train_number": "G1234", "origin": origin, "destination": destination, "departure_time": "08:00", "seat_type": "商务座", "price": 1200},
{"train_number": "G5678", "origin": origin, "destination": destination, "departure_time": "14:30", "seat_type": "二等座", "price": 550},
{"train_number": "D9012", "origin": origin, "destination": destination, "departure_time": "20:15", "seat_type": "一等座", "price": 800}
]
}
# 封装为LangChain工具
query_tool = StructuredTool.from_function(
func=query_train_tickets,
name="查询火车票",
description="根据出发地、目的地、日期和出发时间段,查询可用火车车次信息"
)3.2.2 购买火车票工具
功能:根据车次号,返回mock购票结果(含座位号等信息)。
def buy_train_ticket(
train_number: str = Field(..., description="要购买的车次号,如G1234")
) -> Dict:
# mock数据:模拟购票成功,返回座位信息
return {
"status": "success",
"result": "购票成功",
"train_info": {
"train_number": train_number,
"origin": "北京",
"destination": "上海",
"departure_time": "08:00",
"seat_type": "商务座",
"seat_number": "7-17A"
}
}
# 封装为LangChain工具
buy_tool = StructuredTool.from_function(
func=buy_train_ticket,
name="购买火车票",
description="根据车次号,购买对应车次的火车票"
)3.2.3 FINISH工具(占位符)
功能:标识任务完成,无实际执行逻辑,仅用于Agent终止流程。
def finish_task() -> None: return None finish_tool = StructuredTool.from_function( func=finish_task, name="FINISH", description="当任务已完成(如已成功购买火车票),调用此工具终止流程" ) # 工具列表:Agent可调用的所有工具 tools = [query_tool, buy_tool, finish_tool]

3.3 Prompt设计:Agent的“指令手册”
Prompt是控制Agent行为的关键,需明确任务目标、工具列表与输出格式,避免Agent产生无效推理。本文设计两类Prompt:
3.3.1 任务执行Prompt
用于指导Agent在任务过程中进行“思考→行动→观察”循环,模板如下:
task_prompt_template = """
你是一个强大的AI火车票助手,负责帮用户完成火车票购买任务。
可用工具列表:
{tools}
工具调用格式要求:
1. 先思考:分析当前任务进度,确定是否需要调用工具、调用哪个工具;
2. 再行动:若需调用工具,按以下格式输出(仅JSON,无其他内容):
{{"Thought": "你的思考过程", "Action": "工具名称", "Action Input": {{工具参数}}}}
3. 观察结果:工具返回结果后,基于结果继续思考下一步。
当前任务:{task_description}
历史执行记录:{memory}
请输出你的思考与行动。
"""
task_prompt = PromptTemplate(
template=task_prompt_template,
input_variables=["tools", "task_description", "memory"],
partial_variables={"tools": "\n".join([f"- {tool.name}:{tool.description}" for tool in tools])}
)3.3.2 最终回复Prompt
用于任务完成后,基于历史记录生成简洁易懂的结果总结:
final_prompt_template = """
根据以下任务描述和执行记录,总结最终结果,直接给出答案,不解释思考过程。
任务描述:{task_description}
执行记录:{memory}
最终结果:
"""
final_prompt = PromptTemplate(
template=final_prompt_template,
input_variables=["task_description", "memory"]
)3.4 工具类实现:辅助Agent运行
3.4.1 Action类(数据验证)
通过Pydantic定义Action结构,确保Agent输出的工具调用参数符合规范:
class Action(BaseModel): Thought: str = Field(..., description="Agent的思考过程") Action: str = Field(..., description="调用的工具名称") Action Input: Dict = Field(..., description="工具的输入参数,需与工具要求匹配")
3.4.2 MyPrintHandler类(日志回调)
自定义回调类,实时打印Agent的思考与工具调用过程,便于调试:
class MyPrintHandler(BaseCallbackHandler):
def on_llm_new_token(self, token: str, **kwargs) -> None:
# 实时打印LLM生成的内容(思考过程)
sys.stdout.write(token)
sys.stdout.flush()
def on_llm_end(self, response, **kwargs) -> None:
# LLM生成结束后换行
print("\n")3.5 Agent定义:核心执行逻辑(MyAgent类)
自定义MyAgent类,实现“初始化→循环思考→工具调用→记忆更新→任务终止”的全流程控制,核心方法如下:
3.5.1 初始化方法(init)
配置模型、工具、Prompt、记忆模块与最大思考步数(避免死循环):
class MyAgent:
def __init__(
self,
llm: ChatOpenAI,
tools: List[StructuredTool],
task_prompt: PromptTemplate,
final_prompt: PromptTemplate,
max_thought_steps: int = 10
):
self.llm = llm
self.tools = {tool.name: tool for tool in tools} # 工具字典,便于快速匹配
self.task_prompt = task_prompt
self.final_prompt = final_prompt
self.max_thought_steps = max_thought_steps
# 初始化记忆模块:保存历史执行记录
self.memory = ConversationTokenBufferMemory(
llm=llm,
max_token_limit=4000,
return_messages=True
)
# 回调函数:打印思考过程
self.callbacks = [MyPrintHandler()]3.5.2 单步思考与工具调用(__step、__exec_action)
__step:调用LLM生成思考与Action;__exec_action:根据Action调用对应工具,返回观察结果。
def __step(self, task_description: str) -> tuple[Action, Dict]:
# 1. 拼接Prompt:任务描述 + 记忆
memory_messages = self.memory.load_memory_variables({})["history"]
memory_str = "\n".join([f"{msg.type}: {msg.content}" for msg in memory_messages])
prompt = self.task_prompt.format(
task_description=task_description,
memory=memory_str
)
# 2. 调用LLM生成Action
response = self.llm([HumanMessage(content=prompt)], callbacks=self.callbacks)
action = Action(**json.loads(response.content))
# 3. 执行工具,获取观察结果
observation = self.__exec_action(action.Action, action.Action Input)
return action, observation
def __exec_action(self, tool_name: str, tool_input: Dict) -> Dict:
# 匹配工具并执行
if tool_name not in self.tools:
return {"status": "error", "message": f"工具不存在:{tool_name}"}
tool = self.tools[tool_name]
try:
result = tool.run(tool_input)
return {"status": "success", "result": result}
except Exception as e:
return {"status": "error", "message": str(e)}3.5.3 记忆更新与主流程(__update_memory、run)
__update_memory:将“思考→Action→观察结果”存入记忆;run:循环执行思考-行动,直至任务完成或达到最大步数。
def __update_memory(self, action: Action, observation: Dict) -> None:
# 格式化记忆内容
action_str = json.dumps(action.dict(), ensure_ascii=False)
observation_str = json.dumps(observation, ensure_ascii=False)
memory_content = f"思考与行动:{action_str}\n观察结果:{observation_str}"
# 存入记忆
self.memory.save_context(
inputs={"input": memory_content},
outputs={"output": ""}
)
def run(self, task_description: str) -> str:
print(f"任务开始:{task_description}\n")
for step in range(self.max_thought_steps):
print(f"=== 第{step}轮思考 ===")
# 1. 单步思考与工具调用
action, observation = self.__step(task_description)
# 2. 更新记忆
self.__update_memory(action, observation)
# 3. 检查是否任务完成(调用FINISH工具)
if action.Action == "FINISH":
print("=== 任务完成 ===")
return self.__generate_final_response(task_description)
# 达到最大步数仍未完成
return f"任务未完成:已达到最大思考步数({self.max_thought_steps}轮)"
def __generate_final_response(self, task_description: str) -> str:
# 生成最终总结
memory_messages = self.memory.load_memory_variables({})["history"]
memory_str = "\n".join([f"{msg.type}: {msg.content}" for msg in memory_messages])
prompt = self.final_prompt.format(
task_description=task_description,
memory=memory_str
)
response = self.llm([HumanMessage(content=prompt)])
return response.content3.6 测试结果:验证Agent功能
3.6.1 初始化Agent并执行任务
配置GPT-4 Turbo模型,初始化MyAgent,执行“购买2024年6月1日早上去上海的火车票”任务:
# 初始化LLM:GPT-4 Turbo
llm = ChatOpenAI(
model_name="gpt-4-turbo-preview",
temperature=0,
seed=42,
openai_api_key="你的API密钥" # 需替换为实际密钥
)
# 初始化Agent
agent = MyAgent(
llm=llm,
tools=tools,
task_prompt=task_prompt,
final_prompt=final_prompt,
max_thought_steps=10
)
# 执行任务
task = "帮我买2024年6月1日早上去上海的火车票"
result = agent.run(task)
print("最终结果:", result)3.6.2 任务执行过程(3轮思考完成)
Agent通过3轮思考完成任务,每轮逻辑清晰,步骤如下:
第0轮思考:需先查询符合条件的车次
思考:用户需要2024-06-01早上去上海的火车票,需先调用“查询火车票”工具,确定出发地为当前城市(默认北京),时间段为00:00-12:00。
行动:调用“查询火车票”,参数为
{"origin":"北京","destination":"上海","date":"2024-06-01","departure_time_start":"00:00","departure_time_end":"12:00"}。观察结果:返回3个车次,仅G1234(08:00出发,商务座) 符合“早上”要求。
第1轮思考:购买符合条件的G1234车次
思考:已查询到G1234符合需求,无需进一步查询,直接调用“购买火车票”工具。
行动:调用“购买火车票”,参数为
{"train_number":"G1234"}。观察结果:购票成功,座位号为7-17A,车次信息与查询结果一致。
第2轮思考:任务完成,终止流程
思考:已成功购买G1234车次的火车票,任务目标达成,调用“FINISH”工具终止。
行动:调用“FINISH”,无参数。
观察结果:流程终止,触发最终结果总结。
3.6.3 最终结果
最终结果:已成功为你购买2024年6月1日从北京出发前往上海的火车票,具体信息如下: - 车次:G1234 - 出发时间:08:00 - 座位类型:商务座 - 座位号:7-17A

四、总结
本文从LLM的局限性出发,详解了ReAct Agent的原理与LangChain核心组成,并通过“火车票购票任务”完成了Agent的全流程搭建。通过实操可知,ReAct Agent通过“推理+工具调用”的模式,能有效解决LLM的幻觉、实时性差、复杂推理弱等问题,是落地生成式AI任务的关键方案。
对于开发者而言,掌握LangChain框架与ReAct模式后,可快速扩展至其他场景(如酒店预订、数据分析、智能客服),真正实现“让AI自主完成现实任务”。
版权及免责申明:本文由@AI工具箱原创发布。该文章观点仅代表作者本人,不代表本站立场。本站不承担任何相关法律责任。
如若转载,请注明出处:https://www.aipuzi.cn/ai-tutorial/325.html

