第二阶段(核心攻坚):死磕 LangGraph + ReAct 架构 + 工具调用,手撕一个带记忆的多工具 Agent
1. 为什么「带记忆的多工具 Agent」是面试硬通货大模型应用开发已经过了“会调 API 就能写简历”的阶段。现在面试官真正想考察的是你能否让模型在真实任务中自主决策、调用外部工具、并且记住上下文持续工作。这三点分别对应三个核心技术ReAct 架构Reasoning Acting 的循环让模型在“思考”和“行动”之间交替而不是一次性输出答案。LangGraph把 Agent 的决策流程建模成状态图比传统的 AgentExecutor 更灵活、更可控。工具调用Tool Calling让模型能查天气、搜网页、执行代码、读写数据库突破纯文本生成的边界。再加一层记忆——多轮对话里模型要记住用户之前说过什么、执行过什么这就是“带记忆的多工具 Agent”。这套组合拳在面试里几乎必考而且通常要求现场手撕代码。本文会用一段可以复制运行的 Python 代码完整实现一个带记忆的多工具 Agent。读完你就能直接拿去面试。核心概念在正式进入代码之前先建立三个关键概念的共识它们是理解后文所有示例的基础Agent智能体以大模型为决策中枢能够根据目标自主规划步骤、调用外部工具并持续迭代执行的应用形态。它不是简单的“问答机器人”而是一个会“干活”的执行体。ReAct 架构Reasoning Acting 的缩写让模型在“推理”与“行动”之间交替循环。模型先思考下一步再决定是调用工具还是输出最终答案直到任务完成。工具调用Tool Calling模型输出结构化指令、由程序实际执行外部工具并返回结果的能力。它让 Agent 从“只能生成文本”扩展为“能查数据、能计算、能操作外部系统”。这三个概念叠加起来再加上贯穿多轮对话的记忆就构成了本文要手撕的完整 Agent。2. ReAct 架构模型为什么要「边想边做」2.1 传统方式的问题如果只用一个简单的提示词让模型回答问题模型遇到“北京明天天气怎么样”这种需要实时数据的问题时只能凭训练数据编一个答案。这不是能力问题而是它没有获得外部信息的手段。2.2 ReAct 的核心循环ReAct 的核心是一个循环需要不需要接收用户问题模型思考需要工具吗输出工具调用指令执行工具拿到结果把结果喂回模型输出最终答案每一轮循环包含两个动作Reasoning推理模型分析当前状态决定下一步是调用工具还是直接回答。Acting行动模型生成一个结构化的工具调用由程序真正执行工具再把结果拼回上下文。这个循环会一直持续直到模型认为信息足够、输出最终答案为止。2.3 一个最小的 ReAct 提示词REACT_PROMPT你是一个智能助手可以使用以下工具 {tools} 请按照以下格式回答 Thought: 你的思考过程 Action: 要调用的工具名 Action Input: 工具的输入参数 Observation: 工具执行结果 ...Thought/Action/Action Input/Observation 可以重复多次 Thought: 我现在知道最终答案了 Final Answer: 给用户的最终回答 用户问题{question} 这个提示词就是 ReAct 的“灵魂”。它强制模型按照固定的节奏输出程序再解析Action和Action Input真正调用工具。现在很多框架已经把这个过程封装好了但面试官问你 ReAct 原理时你要能讲清楚这个循环。3. LangGraph 核心概念把 Agent 画成一张图3.1 为什么不用 LangChain 的 AgentExecutor早期 LangChain 的AgentExecutor是一个黑盒循环流程写死在框架里。想加记忆、加人工确认、加条件分支都很别扭。LangGraph 的思路完全不同把 Agent 的每个环节都拆成一个节点Node用边Edge连接起来形成一个显式的状态图。好处有三个流程可视化Agent 的每一步都看得见出问题好排查。高度可控可以随时在图里插入人工审批、重试、超时等节点。状态可持久化图的状态就是记忆的载体天然支持多轮对话。3.2 三个核心概念概念作用类比State在节点之间传递的数据结构流水线上的工件Node一个处理函数接收 State 并返回更新流水线上的工位Edge决定下一个节点是谁可以带条件流水线上的传送带一个最简单的图长这样fromtypingimportTypedDict,Annotatedfromlanggraph.graphimportStateGraph,START,ENDclassAgentState(TypedDict):messages:Annotated[list,messages]defnode_a(state:AgentState):# 处理逻辑返回要更新的字段return{messages:state[messages][A 处理完成]}graphStateGraph(AgentState)graph.add_node(a,node_a)graph.add_edge(START,a)graph.add_edge(a,END)appgraph.compile()3.3 条件边ReAct 循环的图表达ReAct 里“要不要继续调工具”是一个判断这在 LangGraph 里用条件边表达defshould_continue(state:AgentState)-str:last_messagestate[messages][-1]# 如果最后一条消息包含工具调用就回到工具节点ifgetattr(last_message,tool_calls,None):returntools# 否则结束returnEND graph.add_conditional_edges(agent,should_continue,{tools:tools,END:END})这就是 LangGraph 表达 ReAct 循环的完整方式agent节点负责推理tools节点负责执行工具条件边决定“继续做”还是“收工”。整个循环在图的状态里自动运行直到走出END。4. 实战手撕一个带记忆的多工具 Agent下面是一段完整可运行的代码。我们用langchain-openai作为模型层工具是两个常用场景查询天气和执行简单计算。整个 Agent 有完整的四轮对话记忆并且每轮都能调用不同工具。4.1 安装依赖pipinstalllanggraph langchain-openai langchain-core4.2 定义工具fromlangchain_core.toolsimporttooltooldefget_weather(city:str)-str:查询指定城市的天气。 参数: city: 城市名称例如北京 weather_data{北京:晴28°C空气质量优,上海:多云26°C,广州:雷阵雨32°C,深圳:晴30°C,}returnweather_data.get(city,f暂无{city}的天气数据)tooldefcalculate(expression:str)-str:执行一个数学表达式计算。 参数: expression: 数学表达式例如 123 * 45 67 try:resulteval(expression,{__builtins__:{}},{})returnf计算结果为{result}exceptExceptionase:returnf计算失败{e}说明示例中eval使用了受限的命名空间仅用于教学演示。生产环境请替换为ast解析或专用计算库避免任意代码执行风险。4.3 定义带记忆的 State记忆的本质是把历史消息保存在 State 里并且使用add_messages归并器来追加而不是覆盖fromtypingimportTypedDict,Annotatedfromlangchain_core.messagesimportBaseMessagefromlanggraph.graph.messageimportadd_messagesclassAgentState(TypedDict):# add_messages 保证了每轮消息会追加到列表末尾而不是覆盖messages:Annotated[list[BaseMessage],add_messages]4.4 绑定工具并构建图importosfromlangchain_openaiimportChatOpenAIfromlanggraph.graphimportStateGraph,START,ENDfromlanggraph.prebuiltimportToolNode# 初始化模型modelChatOpenAI(modelgpt-4o-mini,temperature0,api_keyos.getenv(OPENAI_API_KEY),)# 把工具列表绑定到模型tools[get_weather,calculate]model_with_toolsmodel.bind_tools(tools)defagent_node(state:AgentState):agent 节点模型根据当前消息决定调用工具还是直接回答。responsemodel_with_tools.invoke(state[messages])return{messages:[response]}# 构建图defbuild_agent():graphStateGraph(AgentState)graph.add_node(agent,agent_node)# ToolNode 会自动解析最后一条消息里的 tool_calls 并执行工具graph.add_node(tools,ToolNode(tools))defshould_continue(state:AgentState)-str:last_messagestate[messages][-1]ifgetattr(last_message,tool_calls,None):returntoolsreturnEND graph.add_edge(START,agent)graph.add_conditional_edges(agent,should_continue,{tools:tools,END:END})graph.add_edge(tools,agent)returngraph.compile()appbuild_agent()4.5 四轮对话验证记忆与工具切换fromlangchain_core.messagesimportHumanMessage,AIMessage# 记忆列表会贯穿所有轮次memory:list[BaseMessage][]# 第一轮查天气memory.append(HumanMessage(content北京今天天气怎么样))resultapp.invoke({messages:memory})memoryresult[messages]print(第一轮,memory[-1].content)# 第二轮计算题验证工具切换memory.append(HumanMessage(content请帮我算一下 1024 * 768 等于多少))resultapp.invoke({messages:memory})memoryresult[messages]print(第二轮,memory[-1].content)# 第三轮追问天气验证多轮记忆memory.append(HumanMessage(content那上海呢))resultapp.invoke({messages:memory})memoryresult[messages]print(第三轮,memory[-1].content)# 第四轮验证模型记得上下文memory.append(HumanMessage(content我刚才问了哪几个城市))resultapp.invoke({messages:memory})memoryresult[messages]print(第四轮,memory[-1].content)第三轮的“那上海呢”最能体现记忆的价值模型必须回顾前文才知道用户是在问天气而不是问别的。第四轮则直接考验模型对整段对话的回忆能力。5. 面试高频追问这样回答才加分5.1 “ReAct 和 Function Calling 是什么关系”参考答案Function Calling 是模型层的能力指模型可以输出结构化的工具调用请求ReAct 是应用层的循环架构它利用 Function Calling 来驱动“思考—行动—观察”的循环。两者不在一个层面Function Calling 是“手”ReAct 是“怎么用手”。5.2 “为什么用 LangGraph 而不是直接写 while 循环”参考答案while 循环也能实现 ReAct但 LangGraph 提供了三样东西一是状态管理图的 State 天然支持持久化、断点恢复和回溯二是可视化与可观测性每个节点的输入输出都能追踪三是可扩展性加人工审批、并行分支、超时重试都只需要改图结构不需要改动核心循环代码。5.3 “记忆存在哪怎么持久化”参考答案短期记忆存在 State 的messages列表里进程内就能跑持久化需要给graph.compile()传入checkpointer比如MemorySaver内存或SqliteSaver磁盘这样每次invoke都传入thread_id就能恢复对应会话的完整状态。跨会话的长期记忆还可以单独挂一个向量库把历史对话存成 embedding检索后拼进提示词。5.4 “工具调用失败了怎么办”参考答案分两层处理。第一层是模型层面在工具描述里写清楚异常返回格式模型拿到错误信息后会自己调整策略第二层是图层面用ToolNode的异常捕获或者自定义 try/except 包裹节点把工具异常转成一条普通消息返回给模型让它继续决策避免整个 Agent 崩溃。5.5 “怎么控制 Agent 不无限循环”参考答案三个手段一是设定max_iterations超过就强制结束并返回中间结果二是在should_continue里加判断连续 N 次调用同一个工具且输入没变化就终止三是给模型绑定max_tokens和时间预算。这些控制逻辑在图的条件边里实现非常自然。6. 总结这一阶段的目标不是“会用 LangGraph”而是能从零手写出一个带记忆的多工具 Agent并讲清楚每一层为什么这样设计。梳理一下核心链路ReAct 循环LangGraph 状态图Tool Calling记忆 State可运行的多工具 Agent面试时如果被要求手撕就按本文的节奏来先定义工具再定义带add_messages的 State然后构建agenttools两个节点最后用条件边串成循环。逻辑清晰、结构完整就是硬通货该有的样子。

相关新闻

GEO测试数据怎么存?从 Query、Run、Entity 到 Citation 的数据库建模

GEO测试数据怎么存?从 Query、Run、Entity 到 Citation 的数据库建模

企业开始长期做 GEO(Generative Engine Optimization,生成式引擎优化)测试后,真正棘手的问题往往不是: 怎么再多测几个AI平台? 而是: 测完以后,这些数据到底应该怎么存? …

2026/10/9 7:18:00 阅读更多 →
知漫剧小说转漫剧教程:从原文导入到视频成片

知漫剧小说转漫剧教程:从原文导入到视频成片

写了一堆小说没人看?试试把它变成漫剧视频。知漫剧(zz.jiaxunai.cn)价格实惠,零基础一键生成,平台有全流程教学,角色、声音、场景一致性全搞定,小白也能轻松出片。这篇讲讲怎么把小说原文导入知…

2026/9/27 13:04:44 阅读更多 →
不写代码,用公众号智能回复+ima 做 24h 智能体 !

不写代码,用公众号智能回复+ima 做 24h 智能体 !

很多号主都被私信淹过:“那篇讲 XX 的文章在哪”“手册发我下”“这个怎么落地”。 雇客服不划算,自己回又没时间。 其实微信现在给了两套免费能力,拼起来用,个人号也能有 724 小时“数字分身 资料室”。 一、谁该用这套组合 …

2026/10/14 11:10:31 阅读更多 →

最新新闻

跨界资源整合:内容与资本的战略合作模式

跨界资源整合:内容与资本的战略合作模式

1. 战略合作背景解析启明社与安盛投资的这次战略合作,本质上是一次典型的跨界资源整合案例。启明社作为内容创作领域的头部机构,拥有强大的IP孵化能力和粉丝基础;而安盛投资则是金融投资领域的专业机构,在资本运作和商业资源方面具…

2026/10/14 14:27:40 阅读更多 →
SpringBoot+Vue3疾病防控系统开发实战

SpringBoot+Vue3疾病防控系统开发实战

1. 项目概述与核心价值这个基于SpringBoot2Vue3MyBatis-PlusMySQL8.0技术栈的疾病防控综合系统,是我去年带队为某三甲医院开发的实战项目。系统上线后日均处理2000条疫情数据,成功将基层医疗机构的数据上报效率提升47%。不同于简单的CRUD管理系统&#x…

2026/10/14 14:27:40 阅读更多 →
贪心算法实战:跳跃游戏问题解析与优化

贪心算法实战:跳跃游戏问题解析与优化

1. 问题背景与核心挑战跳跃游戏是算法面试中的经典题型,考察对贪心算法的理解和应用能力。题目描述如下:给定一个非负整数数组nums,数组中的每个元素代表在该位置可以跳跃的最大长度。初始位于数组的第一个位置,判断是否能够到达最…

2026/10/14 14:27:40 阅读更多 →
IP102害虫数据集转YOLO格式:4400张子集训练实践

IP102害虫数据集转YOLO格式:4400张子集训练实践

做智慧农业害虫检测的朋友,应该都绕不开IP102这个数据集——102类农作物害虫、数万张图片,光看规模确实诱人。但真正下载下来用过的人都知道,原始标注格式是XML/JSON结构,直接扔给YOLO训练是不可能的,还得自己写脚本做…

2026/10/14 14:27:40 阅读更多 →
SpringBoot+Vue3全栈图书管理系统开发实战

SpringBoot+Vue3全栈图书管理系统开发实战

1. 项目概述:全栈图书管理系统的技术选型与价值 这套基于SpringBoot2Vue3MyBatis-PlusMySQL8.0的图书管理系统源码,是当前企业级应用开发的典型技术组合方案。作为前后端分离架构的实战案例,它完整实现了图书的增删改查、分类管理、借阅归还等…

2026/10/14 14:27:40 阅读更多 →
Vue3图片查看器:鼠标为中心缩放与拖拽实现详解

Vue3图片查看器:鼠标为中心缩放与拖拽实现详解

图片查看功能在后台系统、编辑器、图库工具里太常用了,但很多人做的时候都栽在同一个坑上:缩放是缩了,但中心点永远在左上角,鼠标滚轮一滚,图片直接跑偏;想拖拽吧,又和文字选中等浏览器默认行为…

2026/10/14 14:26:39 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →