ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

python+fastmcp+豆包 Doubao-1.5-lite-32k 实现一个完整的mcp服务,客户端调用

python+fastmcp+豆包 Doubao-1.5-lite-32k 实现一个完整的mcp服务,客户端调用 1. 为什么要把豆包 Doubao-1.5-lite-32k 包成 MCP 服务如果你最近在折腾 Agent 或者本地工具调用大概率听过 MCPModel Context Protocol这个词。简单说它是一套让大模型能看见并调用你本地函数的协议你写好一个工具函数注册到 MCP 服务端模型就能根据用户问题自动决定调哪个函数、传什么参数。而 fastmcp 是 Python 里把这件事做得最省心的库之一几行装饰器就能把普通函数变成模型可调用的工具。这篇要解决的核心问题是用 python fastmcp 把豆包 Doubao-1.5-lite-32k 封装成一个完整的 MCP 服务并让客户端真正调用起来。适合谁适合已经会一点 Python、想让自己的小工具算数、查天气、查数据库被大模型自动调度但又被各种 SDK 文档绕晕的人。Doubao-1.5-lite-32k 这个模型本身便宜、上下文够长32k做工具调用的意图识别完全够用拿它当大脑来指挥本地工具是很划算的组合。整个链路是这样的客户端拿到用户问题 → 把问题连同 MCP 服务端暴露的工具列表一起发给豆包 → 豆包返回我要调用 add 工具参数是 a1,b1 → 客户端去 MCP 服务端执行这个工具 → 把结果再喂回豆包 → 豆包生成最终自然语言回答。听起来绕但拆开就是两次模型调用加一次工具执行代码量并不大。我实测下来最容易卡住的不是模型调用本身而是三件事工具 schema 的格式转换、SSE 传输的连接地址、以及 API Key 和 Base URL 的配置。下面我会把这三块都摊开讲配置片段可以直接复制。在开始写代码前先说一下统一入口的问题。豆包官方 SDK 需要你去火山引擎控制台注册、开通模型、拿 Key流程不算复杂但每个项目都要重复一遍。如果你同时还在用 Claude Code、Cline 这类工具Key 管理会很乱。我现在的做法是通过 TaoToken 统一管理 API 通道官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 一个 Key 走多个模型省得来回切换。下面配置里我会同时给出官方 SDK 和统一通道两种写法你按自己的情况选。2. 前置准备装依赖、拿 Key、确认模型 ID2.1 安装依赖库fastmcp 负责服务端和客户端volcengine-python-sdk 是豆包官方 SDKarkitect 是配套的类型支持。三条命令依次执行pip install fastmcp pip install --upgrade volcengine-python-sdk[ark] pip install --upgrade arkitect装完之后建议验证一下版本fastmcp 迭代很快老版本的部分 API 名字不一样python -c import fastmcp; print(fastmcp.__version__)如果报ModuleNotFoundError多半是 pip 装到了别的 Python 环境用python -m pip install再装一次。2.2 拿到 API Key 和模型 ID走官方路线的话去火山引擎控制台在模型广场找到 Doubao-1.5-lite-32k点立即体验再点右上角API 接入按引导开通就能拿到 Key新用户一般有免费额度可以先跑通。这里要注意一个坑控制台里显示的模型名和代码里写的 model ID 经常不是一回事。Doubao-1.5-lite-32k 对应的调用 ID 通常带日期后缀比如doubao-1-5-lite-32k-250115这种格式具体以你控制台API 接入页面显示的为准直接复制过来别自己拼。如果你用 TaoToken 统一通道就不用单独去火山引擎开通了在控制台生成一个 KeyBase URL 填https://taotoken.net/api模型 ID 还是填豆包对应的那个。这样你后面换模型比如换成别的厂商只需要改 model 字段客户端代码不用动。2.3 环境变量配置不要把 Key 硬编码进代码用环境变量。Linux/macOSexport ARK_API_KEY你的key export ARK_BASE_URLhttps://taotoken.net/apiWindows PowerShell$env:ARK_API_KEY你的key $env:ARK_BASE_URLhttps://taotoken.net/api如果你用 TaoToken 的 Coding Plan 做长期编码类任务Key 和额度是打通的配置一次就行入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。3. 可复制配置服务端工具注册与客户端接入3.1 服务端用 fastmcp 注册工具服务端的核心就是把普通函数用mcp.tool()装饰一下。fastmcp 会自动读取函数的类型注解和 docstring生成模型能理解的 JSON Schema。所以类型注解一定要写全docstring 一定要写清楚参数含义模型判断调不调这个工具全靠这些描述。from fastmcp import FastMCP mcp FastMCP(nameMyAssistantServer) mcp.tool() def add(a: float, b: float) - float: 加法运算 参数: a: 第一个数字 b: 第二个数字 返回: 两数之和 return a b mcp.tool() def divide(a: float, b: float) - float: 除法运算 参数: a: 被除数 b: 除数 返回: 两数之商 异常: 除数为零时抛出 ValueError if b 0: raise ValueError(除数不能为零) return a / b mcp.tool() def get_weather(city: str, unit: str 摄氏度) - str: 查询城市天气 参数: city: 城市名称 unit: 温度单位默认摄氏度 返回: 城市加温度的描述 # 真实场景这里换成天气 API 调用 return f今天 {city} 的温度是 25{unit} if __name__ __main__: mcp.run(transportsse, host127.0.0.1, port8001)注意mcp.run的transport参数sse走 HTTP 长连接适合跨进程、跨机器stdio走标准输入输出适合被编辑器比如 Claude Code、Cline直接拉起。本地调试客户端用 sse 更直观因为你能看到端口。3.2 客户端连接 MCP 服务并调用豆包客户端要做两件事连上 MCP 服务端拿工具列表把工具列表转成豆包能识别的 function 格式然后走模型判断 → 执行工具 → 模型总结的循环。import asyncio import os import json from typing import List, Dict, Any from fastmcp import Client from fastmcp.client import SSETransport from volcenginesdkarkruntime import Ark class ToolExecutor: def __init__(self, server_url: str http://127.0.0.1:8001/sse): self.local_client Client(SSETransport(server_url)) self.ark Ark( api_keyos.getenv(ARK_API_KEY), base_urlos.getenv(ARK_BASE_URL, https://taotoken.net/api), ) self.model_name doubao-1-5-lite-32k-250115 staticmethod def convert_to_function_format(tools: List[Any]) - List[Dict[str, Any]]: function_list [] for tool in tools: function { type: function, function: { name: tool.name, description: tool.description.strip(), parameters: { type: object, properties: {}, required: tool.inputSchema.get(required, []), }, }, } for pname, pinfo in tool.inputSchema.get(properties, {}).items(): spec { type: pinfo.get(type), description: pinfo.get(title, ), } if enum in pinfo: spec[enum] pinfo[enum] function[function][parameters][properties][pname] spec function_list.append(function) return function_list async def run(self, question: str) - str: async with self.local_client: tools await self.local_client.list_tools() print(可用工具:, [t.name for t in tools]) messages [{role: user, content: question}] completion self.ark.chat.completions.create( modelself.model_name, messagesmessages, toolsself.convert_to_function_format(tools), ) resp completion.choices[0].message messages.append(resp.model_dump()) if resp.tool_calls: for call in resp.tool_calls: name call.function.name args json.loads(call.function.arguments) result await self.local_client.call_tool(name, args) messages.append({ tool_call_id: call.id, role: tool, name: name, content: str(result.data), }) second self.ark.chat.completions.create( modelself.model_name, messagesmessages ) return second.choices[0].message.content return resp.content async def main(): executor ToolExecutor() answer await executor.run(11等于几顺便看下惠州天气) print(最终答案:, answer) if __name__ __main__: asyncio.run(main())这里有个关键点base_url参数。官方 SDK 默认指向火山引擎的地址如果你走 TaoToken 统一通道就把它改成https://taotoken.net/apiKey 也换成 TaoToken 的 Key。这样模型 ID 还是豆包的但请求走的是统一入口后面想换模型只改model_name一行。3.3 如果你用 Claude Code 或 Cline 接入有些同学不想自己写客户端而是想让 Claude Code、Cline 这类工具直接连你的 MCP 服务。这时候服务端用 stdio 传输更合适配置写进对应的 settings 文件。以 Cline 的 MCP 配置为例三件套是 Base URL、Key、Model ID{ mcpServers: { my-assistant: { command: python, args: [server.py], env: { ARK_API_KEY: 你的key, ARK_BASE_URL: https://taotoken.net/api } } } }Claude Code 的配置类似写在~/.claude/settings.json或者项目级的.mcp.json里。Codex 的话看auth.json把 base_url 和 api_key 填对就行。这三个工具的共同点是Base URL 决定请求发到哪Key 决定身份Model ID 决定用哪个模型缺一个都会报错。4. 验证请求跑一次真实调用看返回配置写完先启动服务端python server.py看到类似Uvicorn running on http://127.0.0.1:8001的输出就说明 SSE 服务起来了。然后另开一个终端跑客户端python client.py正常的话你会看到这样的输出可用工具: [add, divide, get_weather] 最终答案: 11等于2。惠州今天的温度是25摄氏度。这个结果说明整条链路通了豆包识别出问题里有两个意图算数和查天气分别调用了add和get_weather拿到结果后组织成了自然语言。你可以故意问一个不需要工具的问题比如你好看它是不是直接回答而不调工具——这能验证模型判断逻辑是否正常。想单独验证模型通道是否通可以打开模型对话页面直接测https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 输入同样的问题看返回能快速区分是模型问题还是 MCP 连接问题。5. 常见报错排查401、连接失败、choices 为空5.1 401 Unauthorized最常见。原因通常是 Key 没读到或者 Base URL 和 Key 不匹配。检查两点一是环境变量有没有在当前终端生效echo $ARK_API_KEY看有没有值二是如果你用 TaoToken 的 KeyBase URL 必须是https://taotoken.net/api用官方 Key 则要指向火山引擎地址两者混用必报 401。5.2 local proxy failed / connection refused客户端连不上服务端。先确认服务端真的在跑再确认端口对得上。SSETransport的地址结尾要带/sse写成http://127.0.0.1:8001会连不上。如果服务端和客户端不在同一台机器host要改成0.0.0.0客户端地址换成实际 IP。5.3 reading choices of undefined这个报错说明模型返回体里没有choices字段通常是请求根本没成功返回的是错误 JSON。打印完整的completion对象看error字段八成还是 Key 或模型 ID 的问题。模型 ID 写错比如漏了日期后缀也会走到这里。5.4 OAuth / 鉴权相关报错如果你在 Claude Code 里接入报 OAuth 相关错误多半是 settings 里的鉴权字段格式不对。Claude Code 走的是它自己的鉴权体系MCP 服务端的 Key 要放在env里传不要和 Claude Code 本身的登录态混在一起。5.5 工具调用参数解析失败json.loads(call.function.arguments)报错一般是模型返回的 arguments 不是合法 JSON。这种情况在模型能力较弱时偶发可以在解析前加个 try失败就跳过这个工具调用并把错误信息喂回模型让它重试。6. 继续往下走把 MCP 服务接到更多场景跑通这个最小闭环之后能扩展的方向很多。比如把get_weather换成真实的天气 API把add换成查数据库、发邮件、调内部系统。MCP 的价值就在于你只需要写普通 Python 函数模型负责决定什么时候调、传什么参数不用为每个工具单独写意图识别逻辑。如果你打算长期做这类 Agent 项目建议把 Key 和通道统一管理起来别每个项目散落一份。TaoToken 的 API Keys 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 遇到配置问题先翻文档比瞎试快。长期跑编码类 Agent 任务的话Coding Plan 的额度比按量付费划算入口前面给过了。最后留一个我踩过的坑fastmcp 的call_tool返回的是个对象结果在.data里直接str(result)会带一堆元信息喂给模型前记得取.data。这个细节文档里不显眼但会让你的工具返回结果多出一堆噪音影响模型理解。
返回列表