尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

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

发布时间:2026/9/28 19:08:29

资讯中心
01
ARTICLE

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

学习 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 和工具设计收益会比一开始就纠结架构大得多。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。