跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonAI

基于 LangChain 的 ReAct AI Agent 搭建实战

大语言模型存在知识滞后与幻觉问题,引入 Agent 机制可借助外部工具解决。以 LangChain 框架为例,详解 ReAct(推理 + 行动)模式的实现原理。通过定义查询与购票工具,构建具备记忆与规划能力的智能体,完成火车票预订任务的全流程代码演示与执行日志分析。

灰度发布发布于 2026/4/9更新于 2026/5/2312 浏览
基于 LangChain 的 ReAct AI Agent 搭建实战

LLM 为什么需要 Agent 化

虽然大语言模型(LLM)能力强大,但受限于训练数据的时间范围,它们存在知识滞后、幻觉以及难以处理复杂推理等问题。例如在查询实时信息时,模型无法获取当前的列车时刻表或用户位置。

在这里插入图片描述

基于大模型的 Agent 可以通过调用外部工具来弥补这些短板,实现更复杂的任务闭环。

ReAct Agent 核心概念

ReAct 是 Reasoning(推理)与 Action(行动)的结合。Agent 的发展路径通常是从直接回答(Standard IO),演进到思维链(CoT),再到函数调用(Function Calling),最终形成推理与行动并重的模式。

组成部分

使用 LangChain 构建 ReAct Agent 主要包含以下组件:

  • Models:负责生成文本的 LLM。
  • Prompts:定义 Agent 的行为指令和约束。
  • Memory:记录执行状态及缓存已知信息。
  • Indexes:结构化文档以便模型检索。
  • Chains:LangChain 的核心逻辑链。
  • Agent:协调上述组件的智能体。

Prompt 模板示例

Prompt 需要明确告诉模型如何思考、何时行动以及如何输出结果。一个典型的 ReAct 格式如下:

from langchain_core.prompts import PromptTemplate

template = '''Answer the following questions as best you can. You have access to the following tools: {tools}
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Begin!
Question: {input}
Thought:{agent_scratchpad}'''

prompt = PromptTemplate.from_template(template)

代码实战:火车票助手

下面我们通过手写一个能帮忙买火车票的智能 Agent 来演示完整流程。注:火车票相关 API 均为 Mock 模拟。

依赖安装

首先确保安装了必要的库:

pip install langchain
pip install uuid
pip install pydantic

导入模块

我们需要引入 LangChain 的核心类以及 Python 标准库来处理数据结构。

import json
import sys
 typing  , , , , , 
 uuid  UUID

 langchain.memory  ConversationTokenBufferMemory
 langchain.tools.render  render_text_description
 langchain_core.callbacks  BaseCallbackHandler
 langchain_core.language_models  BaseChatModel
 langchain_core.output_parsers  PydanticOutputParser, StrOutputParser
 langchain_core.outputs  GenerationChunk, ChatGenerationChunk, LLMResult
 langchain_core.prompts  PromptTemplate
 langchain_core.tools  StructuredTool
 langchain_openai  ChatOpenAI
 pydantic  BaseModel, Field, ValidationError
from
import
List
Optional
Dict
Any
Tuple
Union
from
import
from
import
from
import
from
import
from
import
from
import
from
import
from
import
from
import
from
import
from
import

定义工具(Tools)

工具是 Agent 与外部世界交互的桥梁。这里我们定义两个核心工具:查询车票和购买车票。

from typing import List
from langchain_core.tools import StructuredTool

def search_train_ticket(
    origin: str,
    destination: str,
    date: str,
    departure_time_start: str,
    departure_time_end: str
) -> List[dict[str, str]]:
    """按指定条件查询火车票"""
    # mock train list
    return [
        {
            "train_number": "G1234",
            "origin": "北京",
            "destination": "上海",
            "departure_time": "2024-06-01 8:00",
            "arrival_time": "2024-06-01 12:00",
            "price": "100.00",
            "seat_type": "商务座",
        },
        {
            "train_number": "G5678",
            "origin": "北京",
            "destination": "上海",
            "departure_time": "2024-06-01 18:30",
            "arrival_time": "2024-06-01 22:30",
            "price": "100.00",
            "seat_type": "商务座",
        },
        {
            "train_number": "G9012",
            "origin": "北京",
            "destination": "上海",
            "departure_time": "2024-06-01 19:00",
            "arrival_time": "2024-06-01 23:00",
            "price": "100.00",
            "seat_type": "商务座",
        }
    ]

def purchase_train_ticket(train_number: str) -> dict:
    """购买火车票"""
    return {
        "result": "success",
        "message": "购买成功",
        "data": {
            "train_number": "G1234",
            "seat_type": "商务座",
            "seat_number": "7-17A"
        }
    }

search_train_ticket_tool = StructuredTool.from_function(
    func=search_train_ticket,
    name="查询火车票",
    description="查询指定日期可用的火车票。",
)
purchase_train_ticket_tool = StructuredTool.from_function(
    func=purchase_train_ticket,
    name="购买火车票",
    description="购买火车票。会返回购买结果 (result), 和座位号 (seat_number)",
)
finish_placeholder = StructuredTool.from_function(
    func=lambda: None,
    name="FINISH",
    description="用于表示任务完成的占位符工具"
)

tools = [search_train_ticket_tool, purchase_train_ticket_tool, finish_placeholder]

Prompt 设计

我们需要两个关键的 Prompt:一个是引导 Agent 进行思考和调用的主 Prompt,另一个是生成最终回复的结束 Prompt。

主要任务 Prompt
prompt_text = """ 你是强大的 AI 火车票助手,可以使用工具与指令查询并购买火车票 
你的任务是:{task_description}
你可以使用以下工具或指令,它们又称为动作或 actions: {tools}
当前的任务执行记录:{memory}
按照以下格式输出:
任务:你收到的需要执行的任务
思考:观察你的任务和执行记录,并思考你下一步应该采取的行动
然后,根据以下格式说明,输出你选择执行的动作/工具:{format_instructions}
"""
最终回复 Prompt
final_prompt = """ 你的任务是:{task_description}
以下是你的思考过程和使用工具与外部资源交互的结果。
{memory}
你已经完成任务。
现在请根据上述结果简要总结出你的最终答案。
直接给出答案。不用再解释或分析你的思考过程。
"""

辅助工具类

为了调试方便,我们自定义了一个 CallbackHandler 来打印 LLM 的思考过程,同时定义了结构化的 Action 类。

class Action(BaseModel):
    """结构化定义工具的属性"""
    name: str = Field(description="工具或指令名称")
    args: Optional[Dict[str, Any]] = Field(description="工具或指令参数,由参数名称和参数值组成")

class MyPrintHandler(BaseCallbackHandler):
    """自定义 LLM CallbackHandler,用于打印大模型返回的思考过程"""
    def __init__(self):
        super().__init__()

    def on_llm_new_token(
        self,
        token: str,
        *,
        chunk: Optional[Union[GenerationChunk, ChatGenerationChunk]] = None,
        run_id: UUID,
        parent_run_id: Optional[UUID] = None,
        **kwargs: Any,
    ) -> Any:
        end = ""
        content = token + end
        sys.stdout.write(content)
        sys.stdout.flush()
        return token

    def on_llm_end(self, response: LLMResult, **kwargs: Any) -> Any:
        end = ""
        content = "\n" + end
        sys.stdout.write(content)
        sys.stdout.flush()
        return response

定义 Agent 类

这是核心部分,封装了记忆管理、循环推理和执行逻辑。

class MyAgent:
    def __init__(
        self,
        llm: BaseChatModel = ChatOpenAI(model="gpt-4-turbo", temperature=0, model_kwargs={"seed": 42}),
        tools=None,
        prompt: str = "",
        final_prompt: str = "",
        max_thought_steps: Optional[int] = 10,
    ):
        if tools is None:
            tools = []
        self.llm = llm
        self.tools = tools
        self.final_prompt = PromptTemplate.from_template(final_prompt)
        self.max_thought_steps = max_thought_steps
        self.output_parser = PydanticOutputParser(pydantic_object=Action)
        self.prompt = self.__init_prompt(prompt)
        self.llm_chain = self.prompt | self.llm | StrOutputParser()
        self.verbose_printer = MyPrintHandler()

    def __init_prompt(self, prompt):
        return PromptTemplate.from_template(prompt).partial(
            tools=render_text_description(self.tools),
            format_instructions=self.__chinese_friendly(self.output_parser.get_format_instructions()),
        )

    def run(self, task_description):
        """Agent 主流程"""
        thought_step_count = 0
        agent_memory = ConversationTokenBufferMemory(
            llm=self.llm,
            max_token_limit=4000,
        )
        agent_memory.save_context({"input": "\ninit"}, {"output": "\n开始"})

        while thought_step_count < self.max_thought_steps:
            print(f">>>>Round: {thought_step_count}<<<<")
            action, response = self.__step(task_description=task_description, memory=agent_memory)

            if action.name == "FINISH":
                break

            observation = self.__exec_action(action)
            print(f"----\nObservation:\n{observation}")

            self.__update_memory(agent_memory, response, observation)
            thought_step_count += 1

        if thought_step_count >= self.max_thought_steps:
            reply = "抱歉,我没能完成您的任务。"
        else:
            final_chain = self.final_prompt | self.llm | StrOutputParser()
            reply = final_chain.invoke({"task_description": task_description, "memory": agent_memory})
        return reply

    def __step(self, task_description, memory) -> Tuple[Action, str]:
        """执行一步思考"""
        response = ""
        for s in self.llm_chain.stream(
            {"task_description": task_description, "memory": memory},
            config={"callbacks": [self.verbose_printer]}
        ):
            response += s
        action = self.output_parser.parse(response)
        return action, response

    def __exec_action(self, action: Action) -> str:
        observation = "没有找到工具"
        for tool in self.tools:
            if tool.name == action.name:
                try:
                    observation = tool.run(action.args)
                except ValidationError as e:
                    observation = f"Validation Error in args: {str(e)}, args: {action.args}"
                except Exception as e:
                    observation = f"Error: {str(e)}, {type(e).__name__}, args: {action.args}"
        return observation

    @staticmethod
    def __update_memory(agent_memory, response, observation):
        agent_memory.save_context({"input": response}, {"output": "\n返回结果:\n" + str(observation)})

    @staticmethod
    def __chinese_friendly(string) -> str:
        lines = string.split('\n')
        for i, line in enumerate(lines):
            if line.startswith('{') and line.endswith('}'):
                try:
                    lines[i] = json.dumps(json.loads(line), ensure_ascii=False)
                except:
                    pass
        return '\n'.join(lines)

测试运行

if __name__ == "__main__":
    my_agent = MyAgent(tools=tools, prompt=prompt_text, final_prompt=final_prompt)
    task = "帮我买 24 年 6 月 1 日早上去上海的火车票"
    reply = my_agent.run(task)
    print(reply)

执行结果分析

第一轮思考

Agent 识别到任务需求,决定先查询可用车次。它会组装参数调用 search_train_ticket 工具。

>>>>Round: 0<<<<
任务:帮我买 24 年 6 月 1 日早上去上海的火车票
思考:根据任务需求,首先需要查询 2024 年 6 月 1 日早上从当前位置到上海的火车票。这需要使用'查询火车票'工具,指定出发地、目的地、日期以及早上的时间范围。
动作/工具:{"name":"查询火车票", "args":{"origin":"当前位置", "destination":"上海", "date":"2024-06-01", "departure_time_start":"00:00", "departure_time_end":"12:00"}}
----
Observation:
[{'train_number':'G1234', 'origin':'北京', 'destination':'上海', 'departure_time':'2024-06-01 8:00', 'arrival_time':'2024-06-01 12:00', 'price':'100.00', 'seat_type':'商务座'}, ...]
第二轮思考

根据返回的车次列表,Agent 筛选出符合早上出发条件的 G1234 次列车,并调用购票工具。

>>>>Round: 1<<<<
任务:帮我买 24 年 6 月 1 日早上去上海的火车票
思考:根据查询结果,有三个车次可供选择,但只有车次 G1234 符合早上出发的要求,因此应选择购买这个车次的票。
动作/工具:{"name":"购买火车票", "args":{"train_number":"G1234"}}
----
Observation:
{'result':'success', 'message':'购买成功', 'data':{'train_number':'G1234', 'seat_type':'商务座', 'seat_number':'7-17A'}}
第三轮思考

任务已完成,Agent 触发 FINISH 工具并生成自然语言回复。

>>>>Round: 2<<<<
任务:帮我买 24 年 6 月 1 日早上去上海的火车票
思考:根据执行记录,已经成功购买了 2024 年 6 月 1 日早上从北京到上海的火车票(车次 G1234)。因此,接下来的任务是完成这个购票任务。
动作/工具:{"name":"FINISH"}
购买成功。您已成功购买 2024 年 6 月 1 日早上从北京出发前往上海的火车票,车次为 G1234,座位类型为商务座,座位号为 7-17A。

通过这种方式,我们可以灵活扩展更多工具(如获取地理位置、当前日期等),让 Agent 具备更强的自主决策能力。

目录

  1. LLM 为什么需要 Agent 化
  2. ReAct Agent 核心概念
  3. 组成部分
  4. Prompt 模板示例
  5. 代码实战:火车票助手
  6. 依赖安装
  7. 导入模块
  8. 定义工具(Tools)
  9. Prompt 设计
  10. 主要任务 Prompt
  11. 最终回复 Prompt
  12. 辅助工具类
  13. 定义 Agent 类
  14. 测试运行
  15. 执行结果分析
  16. 第一轮思考
  17. 第二轮思考
  18. 第三轮思考
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • JiuwenClaw AI 智能体安装、任务管理与上下文控制实践
  • WebGIS 开发实战:坐标系转换与 JavaScript 应用
  • AI Agent:大模型时代的应用交互变革
  • Office 区域不支持 Copilot 的解决方法
  • 通义万相 2.1 视频生成模型技术特性与应用场景
VSCode Copilot 配置文件提示“未知工具”警告排查与解决
  • GitHub Trending 日榜 - 2026-01-11
  • Spring AI Alibaba 快速入门指南
  • 13 个实用的 Python 自动化脚本示例
  • 基于 Trae Solo 与豆包大模型实现 AI 菜单识别应用
  • GitHub Copilot CLI 斜杠命令速查表
  • 奇偶链表 JavaScript 实现
  • 基于 AI 辅助快速构建 CRM 系统原型的技术实践
  • Go 与 Python 技术选型及职业发展方向对比
  • OpenCode 搭配 GitHub Copilot:低成本调用 Claude 等顶级模型
  • OpenClaw 安全最佳实践:保护 AI 与数据
  • FPGA 实现 OV5640 摄像头视频图像显示
  • 基于 FastGPT 与 MCP 协议构建工具增强型智能体
  • Python 类方法、实例方法与静态方法深度解析
  • OpenClaw 自托管 AI 网关安装部署指南
  • 相关免费在线工具

    • RSA密钥对生成器

      生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

    • Mermaid 预览与可视化编辑

      基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

    • 随机西班牙地址生成器

      随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

    • curl 转代码

      解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

    • Base64 字符串编码/解码

      将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

    • Base64 文件转换器

      将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online