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

张高兴的大模型开发实战:(六)在 LangGraph 中使用 MCP 协议配 TaoToken

发布时间:2026/9/29 9:03:58

资讯中心
01
ARTICLE

张高兴的大模型开发实战:(六)在 LangGraph 中使用 MCP 协议配 TaoToken

张高兴的大模型开发实战:(六)在 LangGraph 中使用 MCP 协议配 TaoToken
1. 为什么要在 LangGraph 里接 MCP而不是继续手写工具函数如果你已经用 LangGraph 搭过一两个 Agent大概率经历过这个阶段一开始图里只有一两个节点工具函数直接写在tools.py里bind_tools一绑就完事。等到工具数量涨到七八个、又要跨进程复用的时候问题就来了——工具定义散落在各个文件本地调试要手动起服务换台机器路径全废。MCPModel Context Protocol解决的正是这件事。它把「模型能调用什么」抽象成一套标准协议工具不再是你代码里的一个 Python 函数而是一个可以被发现、被描述、被远程调用的服务。LangGraph 负责编排节点和状态流转MCP 负责把外部能力以统一格式喂给模型两者分工很清楚。这篇要讲的是这条链路里最容易被忽略、也最容易卡住的一环模型通道怎么配。LangGraph 的图跑起来了MCP 工具也加载出来了但节点里的 LLM 到底走哪个 API、Key 填在哪、config.toml和settings.json各自管什么很多人是照着别人的仓库抄一遍报错了再回头猜。我试过把本地 Ollama、直连官方 API、统一网关三种方式混着用最后稳定下来的方案是用 TaoToken 做统一模型通道一个 Key 覆盖多个模型LangGraph 节点里只改base_url和model两个字段MCP 工具层完全不用动。下面把配置骨架、验证动作和踩过的坑一次讲清楚。适合谁看已经在写 LangGraph 多工具 Agent、准备把 MCP 接进工作流、但被模型通道配置卡住的开发者。你需要有基本的 Python 异步编程概念知道asyncio和async with大概在干什么就够了。2. TaoToken 前置统一 Key 与 API 通道要填在哪先说清楚 TaoToken 在这套架构里的位置。它不是替代 LangGraph也不是替代 MCP Server而是夹在「LangGraph 节点里的 LLM 调用」和「真实模型服务」之间的一层通道。你的图结构、工具节点、状态定义全都不变唯一变的是构造 ChatModel 时传的参数。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。注意 API 地址不带查询参数配置里填的就是这个纯地址。需要准备的东西只有两样一是 API Key。登录后在控制台的 API Keys 页面创建格式通常是一串以固定前缀开头的字符串。这个 Key 就是你在config.toml或环境变量里要填的值。创建入口在 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keys_ctautm_campaignrewrite 建议创建后立刻复制保存页面刷新后不再完整显示。二是模型名。TaoToken 的模型列表里每个模型有对应的标识符比如常见的对话模型、代码模型各有各的名字。你在 LangGraph 节点里model填的就是这个标识符不是 OpenAI 官方的名字也不是 Ollama 的本地 tag。具体可用模型可以在模型对话页面先试一下确认能正常返回再写进配置https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodels_ctautm_campaignrewrite 。这里有个概念要区分清楚MCP 工具的连接配置和模型通道的配置是两套东西不要混在一个文件里。MCP 的command/args/url描述的是工具服务怎么起、怎么连模型通道的base_url/api_key/model描述的是 LLM 请求发到哪。前者写在settings.json或代码里的MultiServerMCPClient字典后者写在config.toml或环境变量。混在一起是后面报错排查困难的主要根源。3. 可复制配置config.toml 与 settings.json 骨架先给目录结构和常见的 LangGraph MCP 项目保持一致. ├── config.toml # 模型通道配置 ├── settings.json # MCP 服务连接配置 ├── mcp_servers/ │ ├── math.py # stdio 方式 │ └── weather.py # sse 方式 └── main.py # LangGraph 主程序3.1 config.toml模型通道[llm] base_url https://taotoken.net/api api_key sk-你的Key model 你的模型标识符 temperature 0.2 timeout 60 [llm.retry] max_attempts 3 backoff_seconds 2base_url填 API 入口地址不要带末尾斜杠也不要带任何查询参数。api_key建议不要硬编码在文件里提交到仓库下面会给环境变量方案。model填你在模型列表里确认过的标识符。temperature对工具调用场景建议压低0.1 到 0.3 之间太高会导致模型在「该调工具」和「直接回答」之间摇摆。更稳妥的做法是用环境变量覆盖export TAOTOKEN_API_KEYsk-你的Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_MODEL你的模型标识符然后在代码里读取config.toml只留非敏感项。这样本地开发和 CI 环境可以用不同的 Key不用改文件。3.2 settings.jsonMCP 服务连接{ mcpServers: { math: { command: python, args: [mcp_servers/math.py], transport: stdio }, weather: { url: http://localhost:8001/sse, transport: sse } } }这个文件描述的是工具服务和模型通道无关。stdio方式下command和args决定怎么把本地脚本拉起来sse方式下url指向已经跑起来的服务地址。注意weather这个 SSE 服务需要你先手动启动python mcp_servers/weather.py否则连接会超时。3.3 main.py把两者接起来import asyncio import json import os import tomllib from contextlib import asynccontextmanager from typing import Annotated, TypedDict from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_mcp_adapters.client import MultiServerMCPClient from langgraph.graph import END, START, StateGraph from langgraph.graph.message import add_messages from langgraph.prebuilt import ToolNode, tools_condition def load_llm_config(): with open(config.toml, rb) as f: cfg tomllib.load(f)[llm] return { base_url: os.getenv(TAOTOKEN_BASE_URL, cfg[base_url]), api_key: os.getenv(TAOTOKEN_API_KEY, cfg[api_key]), model: os.getenv(TAOTOKEN_MODEL, cfg[model]), temperature: cfg.get(temperature, 0.2), timeout: cfg.get(timeout, 60), } def load_mcp_config(): with open(settings.json, r, encodingutf-8) as f: return json.load(f)[mcpServers] class State(TypedDict): messages: Annotated[list, add_messages] asynccontextmanager async def create_graph(): llm_cfg load_llm_config() model ChatOpenAI( base_urlllm_cfg[base_url], api_keyllm_cfg[api_key], modelllm_cfg[model], temperaturellm_cfg[temperature], timeoutllm_cfg[timeout], ) prompt ChatPromptTemplate.from_template( 你是一个可以调用外部工具的助手。需要计算或查询时调用工具 否则直接回答。用中文回复。\n\n问题{question} ) async with MultiServerMCPClient(load_mcp_config()) as client: tools client.get_tools() print(f已加载 MCP 工具{[t.name for t in tools]}) llm_with_tools prompt | model.bind_tools(tools) def agent(state: State): state[messages] llm_with_tools.invoke(state[messages]) return state builder StateGraph(State) builder.add_node(agent, agent) builder.add_node(tool, ToolNode(tools)) builder.add_edge(START, agent) builder.add_conditional_edges( agent, tools_condition, {tools: tool, END: END}, ) builder.add_edge(tool, agent) yield builder.compile() async def main(): async with create_graph() as graph: for q in [徐州天气怎么样, 现在几点了, (35)*12 等于多少]: result await graph.ainvoke({messages: q}) print(f[{q}] - {result[messages][-1].content}) if __name__ __main__: asyncio.run(main())关键点在于ChatOpenAI的base_url指向 TaoToken 的 API 入口api_key用统一 Keymodel用平台上的标识符。MCP 工具通过MultiServerMCPClient加载后bind_tools绑到同一个模型实例上工具调用和模型推理走的是同一条通道不需要为工具单独配 Key。4. 验证请求确认 LangGraph 节点路由到目标模型配置写完不能直接跑主程序要分层验证。我习惯按「通道 → 工具 → 图」三步走哪层出问题一目了然。4.1 第一步单独验证模型通道先不碰 MCP写个最小脚本确认 Key 和 base_url 能通import os from langchain_openai import ChatOpenAI model ChatOpenAI( base_urlos.environ[TAOTOKEN_BASE_URL], api_keyos.environ[TAOTOKEN_API_KEY], modelos.environ[TAOTOKEN_MODEL], temperature0, ) resp model.invoke(只回复两个字通了) print(resp.content)如果这一步报 401说明 Key 不对或没生效报 404说明base_url或model写错报超时检查网络和timeout设置。这一步过了模型通道就没问题后面所有报错都和通道无关。4.2 第二步验证 MCP 工具加载单独跑工具加载不接模型import asyncio from langchain_mcp_adapters.client import MultiServerMCPClient from main import load_mcp_config async def check(): async with MultiServerMCPClient(load_mcp_config()) as client: tools client.get_tools() for t in tools: print(t.name, |, t.description[:40]) asyncio.run(check())预期输出里应该能看到add、multiply、get_weather、get_time四个工具。如果weather相关工具缺失多半是 SSE 服务没启动如果math缺失检查args里的路径是不是相对当前工作目录。4.3 第三步跑完整图看工具调用链前两步都过了再跑main.py。正常输出类似已加载 MCP 工具[add, multiply, get_weather, get_time] [徐州天气怎么样] - 徐州现在是晴天。 [现在几点了] - 当前时间是 2025-01-15 17:22:15。 [(35)*12 等于多少] - (35)×12 96。判断「节点是否真的路由到目标模型」有个简单方法在agent函数里打印state[messages][-1].response_metadata里面会带模型名和 token 用量。如果模型名和你配置的标识符一致说明请求确实走了 TaoToken 通道而不是被某个本地默认值兜底了。def agent(state: State): msg llm_with_tools.invoke(state[messages]) meta getattr(msg, response_metadata, {}) print(model:, meta.get(model_name), | usage:, meta.get(token_usage)) state[messages] msg return state这一步能确认三件事模型标识符正确、请求经过统一通道、工具调用后模型能拿到结果继续推理。5. 本篇常见错排查5.1 报错Connection error或APIConnectionError先看base_url是不是写成了带路径的形式。TaoToken 的 API 入口就是https://taotoken.net/api不要自己拼/v1/chat/completionsSDK 会自动补。如果填了完整路径会出现双重路径导致 404。另一个常见原因是环境变量没生效。os.getenv读不到时如果代码里没有 fallbackapi_key会是NoneSDK 直接抛连接错误。建议在load_llm_config里加一句断言assert llm_cfg[api_key], TAOTOKEN_API_KEY 未设置5.2 工具加载为空tools_condition永远走 ENDMultiServerMCPClient的配置字典键名必须是command/args/transport或url/transport写错一个字母就静默失败。另外stdio方式下command用python还是python3取决于系统Windows 上有时要用完整路径。建议先用第 4.2 步的脚本单独验证确认工具列表非空再进图。5.3 模型不调工具直接编答案这是temperature太高或提示词太弱的典型表现。把temperature降到 0.1提示词里明确写「需要计算或查询时必须调用工具不要凭记忆回答」。另外确认bind_tools是在prompt | model之后调的顺序反了工具不会生效。5.4 SSE 服务连不上报ReadTimeoutweather.py里的port8001要和settings.json里的url端口一致。SSE 服务必须先启动再跑主程序顺序反了会一直重试直到超时。如果端口被占用换一个端口两处同步改。5.5 模型名报model not foundTaoToken 的模型标识符和 OpenAI 官方、Ollama 本地 tag 都不一样。不要凭印象填gpt-4或qwen2.5:7b去模型列表页面复制准确的标识符。填错时通常返回 404 或明确的 model 不存在提示。6. 把通道固定下来后面只动图结构走到这里你的 LangGraph 图应该能稳定跑通「模型推理 → 工具调用 → 结果回填 → 再推理」的完整链路而且模型通道是统一的一个 Key、一个 base_url、一个模型标识符改模型只改一个字段。后续要加新工具只需要在mcp_servers/下新增脚本、在settings.json里加一段配置main.py和图结构完全不用动。要换模型做对比测试改config.toml里的model就行工具层零改动。这种「通道和编排解耦」的结构是 MCP 接入 LangGraph 最实际的价值。如果你还在本地模型和远程通道之间来回切建议先把通道固定成 TaoToken 这一条把config.toml和settings.json的职责分清楚。需要长期跑编码类 Agent、频繁调用工具的可以看下 Coding Plan 的额度方案https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_plan_ctautm_campaignrewrite 。接入过程中遇到 Key 或模型标识符的问题直接去 API Keys 页面重新确认https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keys_ctautm_campaignrewrite 文档里也有各语言 SDK 的接入示例https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdoc_ctautm_campaignrewrite 。
02
RELATED NEWS

相关资讯

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

03
WHY YAOTU

想打造同款高转化官网?

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

◈

场景化定制

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

◐

营销型架构

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

▲

全周期服务

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

免费获取你的建站方案

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