[LangChain智能体本质论-01]两种视角看待Agent和ReAct循环

news2026/4/1 18:16:54
作为LangChain智能体的Agent采用一种被称为ReAct循环的执行流程如下图所示这是一种结合了“推理”Reasoning与“行动”Acting的交互模式旨在让Agent能像人类一样通过逻辑思考来解决复杂问题。但是从底层的执行方式来看Agent本质上是一个Pregel对象(我的系列文章“拆解LangChain执行引擎”对Pregel具有系统的介绍)是一个通过节点和通道构建的Actor模型那么两者是如何结合在一起的我希望通过这个系列文章回答这个问题。除此之外这个序列还将深入介绍Agent状态读写、结构化输出、工具和中间的设计和实现。1. 从create_agent工厂函数说起LangChain提供了不同的编程模式创建Agent其中最简单的莫过于直接使用create_agent函数所以我们不妨先来看看该函数的定义。如下面的代码片段所示这个工厂函数创建的Agent体现为一个CompiledStateGraph对象它本质上是一个Pregel对象所以此函数提供的很多参数旨在初始化这个Pregel对象。defcreate_agent(model:str|BaseChatModel,tools:Sequence[BaseTool|Callable[...,Any]|dict[str,Any]]|NoneNone,*,system_prompt:str|SystemMessage|NoneNone,middleware:Sequence[AgentMiddleware[StateT_co,ContextT]](),response_format:ResponseFormat[ResponseT]|type[ResponseT]|dict[str,Any]|NoneNone,state_schema:type[AgentState[ResponseT]]|NoneNone,context_schema:type[ContextT]|NoneNone,checkpointer:Checkpointer|NoneNone,store:BaseStore|NoneNone,interrupt_before:list[str]|NoneNone,interrupt_after:list[str]|NoneNone,debug:boolFalse,name:str|NoneNone,cache:BaseCache[Any]|NoneNone,)-CompiledStateGraph[AgentState[ResponseT],ContextT,_InputAgentState,_OutputAgentState[ResponseT]]我们有必要逐个介绍一下每个参数model智能体的“大脑”。可以传模型名称字符串需环境配置或已实例化的 BaseChatModel如 ChatOpenAI。tools赋予Agent的“工具箱”。支持 BaseTool对象、普通Python函数会自动转为工具或描述工具JSON Schema的字典。system_prompt: 定义Agent的角色、行为准则和背景知识。支持纯字符串或预定义的SystemMessage对象。response_format: 强制结构化输出。可以传入Pydantic模型、JSON Schema 或 ResponseFormat对象确保Agent返回的数据符合特定格式常用于数据提取或接口调用。state_schema: 定义Agent的内部状态结构继承自 AgentState。它决定了Agent运行过程中能“记住”哪些信息如历史对话、工具执行中间结果。context_schema: 定义外部上下文结构。与状态不同上下文通常是运行时传入的只读配置或全局信息如 user_id, session_id。middleware: 插件系统。允许在 Agent 运行前后插入自定义逻辑如日志记录、输入过滤、耗时统计。checkpointer: 持久化层。用于保存图的状态快照实现断点续传、多轮对话记忆以及“时间旅行”回溯到某一步骤。store: 长效存储。用于在不同线程或用户之间共享信息如存储用户的长期偏好不随单次对话结束而消失。cache: 缓存机制。减少模型重复调用的开销提高响应速度并节省 Token。interrupt_before/interrupt_after: 人机交互点。在进入或退出指定节点前挂起执行。这通常用于“人在回路Human-in-the-loop”场景需用户审批后再继续。debug: 开启后会打印每一轮迭代的详细状态变化和节点执行信息。name: 为生成的 Agent 图命名方便在多 Agent 协同系统Multi-agent system中进行追踪和引用。一个Agent由最为核心的Model和Tool组成所以这三个对象交互的视角来看待Agent基于ReAct循环的执行流程是最直接的。2. 以Agent、Mode和Tool三者交互视角看待ReAct循环ReAct是一个循环往复的过程直到模型得出最终答案或达到最大尝试次数。其核心逻辑可拆解为以下四个步骤Thought推理LLM 接收到用户问题及当前上下文分析当前所处的阶段并决定下一步需要采取什么行动。Action行动模型根据推理结果发出指令调用特定的工具。这包括从工具库中提取参数并向外部环境发送请求。Observation观察LangChain 接收工具返回的真实数据如网页搜索结果、数据库查询值或代码运行输出并将其反馈给模型。Loop循环模型根据新的“观察”结果再次进行“推理”。如果信息足够则输出最终答案如果信息仍不足则继续开启下一轮 Thought - Action - Observation。我们可以从一个简单的实例来体验一下LangChain的ReAct循环。这是一个经典的利用Agent获取天气信息的例子如代码片段所示我们定义了一个get_weather函数作为Agent的工具该函数根据指定的城市通过city参数表示得到以文本表示的天气信息。函数的docstring给出了基本的描述Agent将会提取此信息作为工具描述。我们创建一个Agent并初始化了通过model、tools和system_prompt字段表示的模型、注册的工具列表和系统提示符。fromlangchain.agentsimportcreate_agentfromdotenvimportload_dotenvfromlangchain_openaiimportChatOpenAIfromlangchain_core.messagesimportHumanMessage load_dotenv()defget_weather(city:str)-str:Get weather for a given city.returnfIts always sunny in{city}!agentcreate_agent(modelChatOpenAI(modelgpt-5.2-chat),tools[get_weather],system_promptYou are a helpful assistant,)messageHumanMessage(contentWhat is the weather in Suzhou?)forstepinagent.stream(input{messages:[message]},stream_modevalues):step[messages][-1].pretty_print()具体的模型是基于“gpt-5.2-chat”创建的ChatOpenAI相关的设置比如api-key和base-url等定义在.env文件通过dotenv.load_dotenv写入环境变量。我们直接将函数get_weather作为工具添加到注册的列表中。通过create_agent函数创建的Agent默认以表示状态的AgentState作为输入这是一个TypedDict其核心成员“messages”用于存储整个Agent执行过程中生成的消息。所以我们创建了这样的字典作为调用Agent的输入并在其messages列表中添加了一个用于查询天气的HumanMessage对象。我们调用Agent的stream方法并将流模式设置为“values”执行流程中的每个步骤对于Pregel的Superstep结束之后会以流的形式输出所有的状态这里我们将每个步骤维护的消息列表中的最后一条消息的内容打印出来。 Human Message What is the weather in Suzhou? Ai Message Tool Calls: get_weather (call_aCcssiCPOFyJa6dfu2dSltqD) Call ID: call_aCcssiCPOFyJa6dfu2dSltqD Args: city: Suzhou Tool Message Name: get_weather Its always sunny in Suzhou! Ai Message Right now, the weather in **Suzhou** is reported as **sunny** ☀️. If you’d like, I can also help with things like the temperature, forecast for the next few days, or weather in a specific Suzhou (there’s one in Jiangsu, China, and another in Anhui).这个例子涉及的ReAct循环体现在如上的输出中首先我们以HumanMessage的形式向模型提供查询模型经过推理确定这是“天气查询”并且自身绑定的工具列表具有一个与之匹配的工具get_weather所以模型认为完成当前任务需要先调用get_weather工具。模型不会自行调用工具服务端工具除外但是它需要将工具调用意图封装成一个TooCall对象该对象承载的信息包括包括工具的名称get_weather、标识工具调用的IDcall_aCcssiCPOFyJa6dfu2dSltqD参数列表city: Suzhou。这样一个ToolCall对象被封装成AIMessage返回给Agent。Agent接收到AIMessage之后从中提取出ToolCall提供的参数对目标工具发起调用并将结果“It’s always sunny in Suzhou!”封装成ToolMessage再次发送给模型。模型经过推理确定能够对查询做出最终的答复了于是组织文本并组织文本并以AIMessage的形式予以回复。messageHumanMessage(contentWhat is the weather in Suzhou?)resultagent.invoke(input{messages:[message]})formessageinresult[messages]:message.pretty_print()如果不使用流式输出我们也可用按照如上方式调用Agent的invoke方法并从作为结果的字典中利用“messages”作为Key得到整个“交谈”过程中生成的消息。上面这段程序也可以得到类似的输出: Human Message What is the weather in Suzhou? Ai Message Tool Calls: get_weather (call_CIUcZcYEGEbI0IJlDs19RhTd) Call ID: call_CIUcZcYEGEbI0IJlDs19RhTd Args: city: Suzhou Tool Message Name: get_weather Its always sunny in Suzhou! Ai Message The weather in Suzhou is sunny ☀️3. 以Pregel的视角看到Agent和ReAct循环既然Agent是一个Pregel对象这是一个由节点和通道构建的Actor模型我们不免会好奇它由哪些节点和通道构成呢每个通道采用何种类型通道和节点之间的订阅和读写关系是什么样子我们为此编写了如下的演示程序将上面创建的Agent作为一个Pregel对象将其所有的通道及其类型、节点包括名称、输入和驱动Channel以及Pregel对象自身的输入/输出通道以及驱动通道与对应节点的映射关系打印出来。fromlangchain.agentsimportcreate_agentfromdotenvimportload_dotenvfromlangchain_openaiimportChatOpenAIfromPILimportImageasPILImageimportio load_dotenv()defget_weather(city:str)-str:Get weather for a given city.returnfIts always sunny in{city}!agentcreate_agent(modelChatOpenAI(modelgpt-5.2-chat),tools[get_weather],system_promptYou are a helpful assistant,)print(channels:)for(name,chan)inagent.channels.items():print(f\t[{chan.__class__.__name__}]{name})print(nodes:)for(name,node)inagent.nodes.items():print(f\tname:{name})print(f\tchannels:{node.channels})print(f\ttriggers:{node.triggers}\n)print(finput_channels:{agent.input_channels})print(foutput_channels{agent.output_channels})print(trigger_to_nodes)for(name,nodes)inagent.trigger_to_nodes.items():print(f\t{name}:{nodes})payloadagent.get_graph(xrayTrue).draw_mermaid_png()PILImage.open(io.BytesIO(payload)).show()从如下的输出可以看出通过create_agent函数创建的Agent有且只有三个节点前提是没有注册中间件分别是作为启动节点的节点“start”、封装模型和工具的节点model和节点tools。也就是说注册的所有工具都封装在同一个节点tools中并由它管理并选择执行。channels: [BinaryOperatorAggregate]messages [EphemeralValue]jump_to [LastValue]structured_response [EphemeralValue]__start__ [Topic]__pregel_tasks [EphemeralValue]branch:to:model [EphemeralValue]branch:to:tools nodes: name: __start__ channels: __start__ triggers: [__start__] name: model channels: [messages, jump_to, structured_response] triggers: [branch:to:model] name: tools channels: [messages, jump_to, structured_response] triggers: [branch:to:tools] input_channels:__start__ output_channels[messages, structured_response] trigger_to_nodes __start__: [__start__] branch:to:model: [model] branch:to:tools: [tools]再来看看Agent的通道列表。三个节点具有对应的触发通道它们的名称分别是“start”、“branch:to:model”和“branch:to:tools”对应的类型均为EphemeralValue。针对Agent的调用实际上就是通过写入“start”驱动Agent从“start”节点开始执行。model节点完成模型调用后如果需要调用工具就写入“branch:to:tools”工具调用之后通过写入“branch:to:model”将工具执行的结果反馈给模型并驱动模型节点执行。model和tools节点具有相同的输入通道分别是承载消息列表的messages、用于跳转的jump_to和表示结构化输出的structured_response。messages通道的类型为BinaryOperatorAggregate其operator用于执行列表添加操作这意味着针对此通道的更新总是在做“消息追加”操作这样会将所有的消息历史保存下来上面演示的实例也证明了这一点。工具或者中间件可以通过写入jump_to通道实现“跳转”。该通道支持三个选项“model”、“tools”和“end”前两个选项实现针对model和tools节点的跳转“end”用于终止整个处理流程。结构化输出最终写入通道structured_response。演示程序的最后两行代码会将Agent的结构以可视化的形式展现出来具体呈现的结构如下所示。如果我们站在Pregel的视角审视ReAct循环将会更加接近真实的执行流程当我们调用Agent对象时指定的HumanMessage会写入messages通道中;作为入口节点model节点将其读取出来之后与绑定的系统消息通过system_prompt参数指定的系统提示词创建和工具列表一并发送给语言模型。对于我们的例子来说就是调用OpenAI API具体的请求如下所示。{messages:[{content:You are a helpful assistant,role:system},{content:What is the weather in Suzhou?,role:user}],model:gpt-5.2-chat,stream:false,tools:[{type:function,function:{name:get_weather,description:Get weather for a given city.,parameters:{properties:{city:{type:string}},required:[city],type:object}}}]}LLM经过推理决定需要调用工具并将针对工具调用的描述置于响应中。从如下所示的响应内容可以看出针对工具get_weather的调用被置于响应的choicestool_calls节点(包括调用工具的名称标识工具调用的ID和参数列表。model节点将接收到的响应内容封装成AIMessage并写入messages通道。通过分析内容确定下一步需要调用工具于是通过写入“branch:to:tools”通道驱动执行tools节点。{choices:[{content_filter_results:{},finish_reason:tool_calls,index:0,logprobs:null,message:{annotations:[],content:null,refusal:null,role:assistant,tool_calls:[{function:{arguments:{\city\:\Suzhou\},name:get_weather},id:call_cK9LgQ76xAalnjxUH1q945CM,type:function}]}}],created:1772717196,id:chatcmpl-DG30m9xH7c6ujOxbuMIJ2cid9mU30,model:gpt-5.2-chat-2025-12-11,object:chat.completion,prompt_filter_results:[...],system_fingerprint:null,usage:{...}}当tools节点开始执行的时候它从messages通道中读取最后一条AIMessage在将工具调用部分的内容读取出来后对涉及的工具实施调用并发调用。对于每个成功完成的工具调用tools节点都会根据指定的结果创建一个ToolMessage并写入messages通道。待所有工具调用完成之后它通过写入“branch:to:model”通道驱动执行model节点。model节点和之前一样从messages通道提取写入的三条消息并附加上一条系统消息和工具列表生成如下的请求第二次对作为LLM的OpenAI API发起调用。{messages:[{content:You are a helpful assistant,role:system},{content:What is the weather in Suzhou?,role:user},{content:null,role:assistant,tool_calls:[{type:function,id:call_cK9LgQ76xAalnjxUH1q945CM,function:{name:get_weather,arguments:{\city\: \Suzhou\}}}]},{content:Its always sunny in Suzhou!,role:tool,tool_call_id:call_cK9LgQ76xAalnjxUH1q945CM}],model:gpt-5.2-chat,stream:false,tools:[{type:function,function:{name:get_weather,description:Get weather for a given city.,parameters:{properties:{city:{type:string}},required:[city],type:object}}}]}经过LLM的分析此时能够对用于的查询做出答复于是它充分利用现有的语料组织文本对请求予以响应。model节点依然将响应内容封装成AIMessage写入messages通道。由于messages作为Agent的两个输出通道之一所以我们能从调用结果中的messages成员提取完整的消息历史。{choices:[{content_filter_results:{...},finish_reason:stop,index:0,logprobs:null,message:{annotations:[],content:The weather in **Suzhou** is currently **sunny** ☀️.\n\nIf you’d like more details—such as temperature, humidity, orr a multi-day forecast—just let me know!,refusal:null,role:assistant}}],created:1772719213,id:chatcmpl-DG3XJbOOkM3usPXR56MEVrlRrthMO,model:gpt-5.2-chat-2025-12-11,object:chat.completion,prompt_filter_results:[...],system_fingerprint:null,usage:{...}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2472794.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…