新闻详情

新闻详情

首页 / 资讯中心 / 详情

学习 agent 开发:用 LangGraph + Tool Calling 搭一个带 Persistence 的 MCP Server 骨架

发布时间:2026/9/28 19:08:29来源:尧图网络
学习 agent 开发:用 LangGraph + Tool Calling 搭一个带 Persistence 的 MCP Server 骨架
1. 从一次「Agent 失忆」说起为什么需要 LangGraph Persistence如果你正在学 agent 开发大概率踩过这个坑写了个能调用工具的对话循环第一轮问「帮我查下北京天气」模型乖乖调了天气工具第二轮接着问「那明天呢」它却像失忆一样反问「你指的是哪个城市」。这不是模型笨而是你的 agent 没有状态记忆——每一轮请求都是独立的上一轮的上下文、工具调用结果、中间推理步骤全丢了。LangGraph 解决的正是这类问题。它把 agent 的执行流程建模成一张有向图节点是「模型推理」「工具执行」这类动作边是流转条件而 Persistence 层负责把整张图在每个步骤后的状态快照存下来。这样 agent 就能在长任务、多轮对话里持续工作而不是每次从零开始。MCP Server 则是把这套能力包装成标准服务让外部客户端通过统一协议调用你的工具和状态。这篇面向正在跑通最小链路的开发者我会给出可复制的 LangGraph 节点配置、Tool Calling 定义、Persistence 存储骨架以及 MCP Server 的启动与验证动作。模型调用通道我用 TaoToken 统一管理 Key省去多平台切换的麻烦。整套代码你可以在本地直接跑起来。2. TaoToken 前置统一 Key 与 API 通道在写 LangGraph 之前先把模型调用通道理顺。Agent 开发里最烦的往往不是逻辑而是不同模型、不同工具背后各有一套 Key 和 endpoint。TaoToken 的思路是提供一个统一的 API 入口你用同一个 Key 就能访问多种模型LangGraph 里的ChatOpenAI或兼容 OpenAI 协议的客户端只需改base_url和api_key两个参数。具体操作登录官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后进入控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 创建 API Key。这个 Key 就是后面所有代码里用的凭证。API 的基础地址是 https://taotoken.net/api注意这个地址不加 UTM 参数直接用于代码配置。注意Key 只创建一次并妥善保存页面刷新后不再完整显示。建议放进环境变量不要硬编码进代码提交到仓库。如果你只是想先验证模型能不能通可以打开模型对话页面 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 直接发一条消息测试。确认通道正常后再进入下面的代码环节。对于长期做编码和 Agent 任务的场景Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 会更划算这个后面排障部分再展开。3. 可复制配置LangGraph 节点 Tool Calling Persistence 骨架这一节是全文核心我按「定义工具 → 绑定模型 → 构建图 → 接入持久化」的顺序给完整代码。环境依赖先装好pip install langgraph langchain-openai langchain-core3.1 定义 Tool Calling 的工具函数Tool Calling 的本质是你用结构化描述告诉模型「有哪些工具可用」模型决定调哪个、传什么参数你的代码执行后把结果回传。先定义两个简单工具from langchain_core.tools import tool tool def get_weather(city: str) - str: 查询指定城市的当前天气。参数 city 为城市名例如 北京。 fake_db {北京: 晴12℃, 上海: 多云18℃} return fake_db.get(city, f{city}暂无数据) tool def calc(expression: str) - str: 计算一个数学表达式例如 23*4。 try: return str(eval(expression, {__builtins__: {}})) except Exception as e: return f计算失败{e} tools [get_weather, calc]每个工具的 docstring 很关键模型靠它判断何时调用。参数类型用类型注解声明LangGraph 会自动转成 JSON Schema 传给模型。3.2 绑定模型并构建 LangGraph 图这里用 TaoToken 的统一通道初始化模型把工具绑定上去然后定义「模型节点」和「工具节点」import os from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph, MessagesState, START, END from langgraph.prebuilt import ToolNode llm ChatOpenAI( modelgpt-4o-mini, api_keyos.environ[TAOTOKEN_API_KEY], base_urlhttps://taotoken.net/api, temperature0, ) llm_with_tools llm.bind_tools(tools) def call_model(state: MessagesState): response llm_with_tools.invoke(state[messages]) return {messages: [response]} def should_continue(state: MessagesState): last state[messages][-1] if getattr(last, tool_calls, None): return tools return END builder StateGraph(MessagesState) builder.add_node(agent, call_model) builder.add_node(tools, ToolNode(tools)) builder.add_edge(START, agent) builder.add_conditional_edges(agent, should_continue, {tools: tools, END: END}) builder.add_edge(tools, agent)MessagesState是 LangGraph 内置的消息状态结构add_messagesreducer 会自动把新消息追加进列表而不是覆盖。should_continue判断模型是否发起了工具调用有就转到 tools 节点执行没有就结束。3.3 接入 Persistence让状态可保存可恢复Persistence 是这套骨架的灵魂。LangGraph 提供 checkpointer 机制把每个步骤后的图状态按thread_id存起来。开发阶段用内存版生产可换 SQLite 或 Postgresfrom langgraph.checkpoint.memory import MemorySaver memory MemorySaver() graph builder.compile(checkpointermemory) config {configurable: {thread_id: user-001}}thread_id就是会话标识。同一个thread_id下的多轮调用共享状态换一个 id 就是全新会话。这就是「记忆」的实现方式——不是模型记住了而是你把历史状态喂回给它。4. 验证请求跑通多轮对话与工具调用代码写完直接验证。下面这段连续发两轮消息观察第二轮是否记得第一轮的城市def run(): r1 graph.invoke( {messages: [{role: user, content: 北京天气怎么样}]}, configconfig, ) print(第一轮, r1[messages][-1].content) r2 graph.invoke( {messages: [{role: user, content: 那明天适合出门吗}]}, configconfig, ) print(第二轮, r2[messages][-1].content) if __name__ __main__: run()预期结果第一轮模型调用get_weather返回「北京晴12℃」并组织成自然语言第二轮因为thread_id相同历史消息都在状态里模型知道「那」指的是北京会基于天气给出建议而不是反问城市。再验证工具调用是否真的发生。打印中间消息for m in r1[messages]: print(type(m).__name__, getattr(m, tool_calls, None))你会看到AIMessage里带着tool_calls字段ToolMessage里是工具返回值。这说明 Tool Calling 链路完整走通了。4.1 把骨架包装成 MCP ServerMCP Server 的作用是把上面的工具和状态能力暴露成标准服务。最小骨架用官方 SDKfrom mcp.server.fastmcp import FastMCP mcp FastMCP(agent-tools) mcp.tool() def get_weather(city: str) - str: 查询指定城市的当前天气。 fake_db {北京: 晴12℃, 上海: 多云18℃} return fake_db.get(city, f{city}暂无数据) if __name__ __main__: mcp.run(transportstdio)启动后客户端通过 stdio 协议连接就能发现并调用get_weather。如果你想让 MCP Server 也带状态记忆可以在工具内部接入 LangGraph 的 checkpointer把thread_id作为参数传入这样每次工具调用都能读写同一份会话状态。5. 本篇常见错排查报错一openai.AuthenticationError或 401。检查TAOTOKEN_API_KEY环境变量是否设置正确base_url是否写成https://taotoken.net/api。注意 base_url 末尾不要多加/v1客户端会自动拼接。如果还是 401去 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 重新生成一个 Key 试试。报错二模型不调用工具直接编答案。通常是工具 docstring 太模糊或者temperature太高。把 docstring 写清楚「什么时候用、参数是什么」temperature设 0。另外确认bind_tools真的绑上了打印llm_with_tools看有没有工具列表。报错三第二轮对话丢失上下文。九成是thread_id变了或者graph.invoke时没传config。Persistence 靠thread_id索引状态每次调用必须带同一个 config。如果你换了MemorySaver实例之前的状态也会丢因为内存版不跨进程。报错四ToolNode执行报参数错误。检查工具函数的参数名和类型注解是否和模型生成的 JSON 对得上。模型有时会传多余字段可以在工具函数里加**kwargs兜底或者用 Pydantic 模型严格校验。报错五MCP Server 启动后客户端连不上。stdio 模式下Server 不能往 stdout 打印调试信息否则会污染协议流。所有日志走 stderr。另外确认客户端配置的启动命令路径正确。如果你在接入过程中反复卡在通道配置上建议直接用 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 把 Key 和额度一次配好省得在多个平台间来回折腾。接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里有各语言客户端的完整示例遇到参数不确定时对照着看最快。6. 继续往下走从骨架到可用 Agent跑通这个骨架后你手里其实已经有了一套可扩展的底座。接下来可以做的几件事把MemorySaver换成SqliteSaver让状态跨进程持久在图上加一个human-in-the-loop节点工具执行前先让人确认把多个工具拆成子图用 supervisor 模式做多 agent 路由。这些能力 LangGraph 都有现成组件官方文档的 persistence 和 multi-agent 章节讲得很细。我自己的习惯是每加一个新工具就先单独测 Tool Calling 是否稳定再挂到图上。工具一多模型选错工具的概率会上升这时候要么精简工具描述要么在 prompt 里加路由规则。另外thread_id的命名最好带业务前缀比如chat-{user_id}-{session}方便排查和清理。模型通道这边TaoToken 的模型对话页面 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 可以快速对比不同模型在你工具集上的调用表现换模型只改一个字符串不用动其他代码。等你把骨架跑顺了再回头优化 prompt 和工具设计收益会比一开始就纠结架构大得多。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

STM32 Model Zoo 够用吗?嵌入式AI模型选型与自定义设计实战 2026/9/29 3:29:55

STM32 Model Zoo 够用吗?嵌入式AI模型选型与自定义设计实战

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

阅读更多 →
HarmonyOS 7端侧视觉控件实测:从名片识别到系统级AI能力接入 2026/9/29 3:29:48

HarmonyOS 7端侧视觉控件实测:从名片识别到系统级AI能力接入

HarmonyOS 7把一批视觉AI能力直接做成了系统级场景化控件,端侧视觉能力的接入门槛,第一次被打到“拖控件、写回调”这种程度。上周朋友找我评估需求:他们那款工具类App想加拍名片、自动提取姓名电话存进通讯录。换两年前,我大概会…

阅读更多 →
Model-Optimizer:AI模型推理优化的工程方法论与实战路径 2026/9/29 3:29:48

Model-Optimizer:AI模型推理优化的工程方法论与实战路径

1. 项目概述:Model-Optimizer不是工具名,而是一类工程实践的统称“Model-Optimizer”这个词在当前AI工程落地场景中,已经悄然脱离了单纯软件名称的范畴,演变为一个高度凝练的技术动作集合体——它指代的是在模型训练完成之后、部署…

阅读更多 →
App云测试平台实战指南:从兼容性测试到性能优化的完整方案 2026/9/29 3:29:36

App云测试平台实战指南:从兼容性测试到性能优化的完整方案

1. 先聊聊:为什么我得用云测试平台,而不是自己养一屋子真机前阵子团队上线一款新App,安卓、iOS双端同步发版,光是兼容性测试就差点把人逼疯。公司测试机就那七八台,还都是近两年的主流机型,可线上用户手里的…

阅读更多 →
vibe-coding进阶:让AI自测自修,跑通再汇报的闭环方法 2026/9/29 3:29:36

vibe-coding进阶:让AI自测自修,跑通再汇报的闭环方法

最近圈子里聊得最多的,除了 vibe-coding 还能不能继续写大项目,就是怎么让 AI 从"写完就交差"变成"写完了自己测、自己修、跑通了再汇报"。我把它叫做 vibe-coding 的九阳神功之测——听起来有点江湖,其实就是一套把 AI …

阅读更多 →
Node.js彻底卸载指南:Windows/macOS/Linux全平台残留清理与验证 2026/9/29 3:29:35

Node.js彻底卸载指南:Windows/macOS/Linux全平台残留清理与验证

卸载Node.js这件事,听起来不就是打开控制面板点两下吗?但你真的做过一次就会发现,事情远没那么简单。特别是那种装了又卸、卸了又装的环境,各种残留文件、环境变量、缓存在背后疯狂搞事,等你重装完发现node命令还是“不…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉