ARTICLE DETAIL

资讯详情

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

第七章:工具增强型智能体实战:用 Qwen-Agent 打通 Function Calling 到 MCP 的配置链路

第七章:工具增强型智能体实战:用 Qwen-Agent 打通 Function Calling 到 MCP 的配置链路 1. 为什么工具增强型智能体总在“最后一公里”翻车Function Calling 和 MCPModel Context Protocol这两个词最近在智能体圈子里出现频率极高。简单说Function Calling 是让模型知道“该用哪个工具”MCP 是让所有工具遵循“同一套交互语言”。前者解决单次调用后者解决跨应用、跨平台的工具复用。适合谁适合已经跑通 Qwen-Agent 基础对话、想让智能体真正“动手做事”的开发者也适合被各种工具接入配置折磨过的工程同学。我见过太多项目卡在同一个地方模型能正确输出函数名和参数但工具执行结果回传后模型不认或者本地 stdio 跑得好好的一换到 HTTP/SSE 传输就超时。问题往往不在模型本身而在配置链路——API Key 通道、工具描述格式、传输层参数三者没对齐。这篇就聚焦 Qwen-Agent 框架下从 Function Calling 到 MCP 的配置演进给出可复制的 settings.json 与 config.toml 骨架并用 TaoToken 统一 Key/API 通道接入最后附验证动作确认工具调用链路真的生效。2. TaoToken 前置统一 Key 与 API 通道在动手写工具之前先把模型通道固定下来。Qwen-Agent 默认走 DashScope 的兼容接口但如果你同时要接多个模型、或者想让 MCP Server 和 Agent 共用一套凭证用 TaoToken 做统一入口会省掉很多重复配置。TaoToken 的定位是模型 API 聚合通道官网在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 。注意 API 地址不带 UTM 参数直接写进配置即可。你需要先拿到一个 Key。登录后进入控制台在 API Keys 页面创建一个新 Key复制出来。这个 Key 同时用于 Qwen-Agent 的 LLM 调用和后续 MCP Server 里可能用到的模型请求避免每个组件单独配一套凭证。注意Key 只显示一次建议创建后立刻写入本地配置文件不要硬编码在代码里提交到仓库。配置时有两个关键参数要对齐model字段填你实际要用的模型名api_key填 TaoToken 的 Keybase_url填https://taotoken.net/api。Qwen-Agent 的Assistant类接受一个llm字典把这三项塞进去就行。3. 可复制配置settings.json 与 config.toml 骨架3.1 settings.jsonQwen-Agent 侧配置Qwen-Agent 本身没有强制的 settings.json 规范但工程上建议把 LLM 配置和工具配置分离。下面这个骨架可以直接用{ llm: { model: qwen-max, api_key: sk-your-taotoken-key, base_url: https://taotoken.net/api, timeout: 60, max_retries: 2 }, agent: { system_message: 你是一个工具增强型助手优先调用可用工具获取实时信息。, function_list: [search_tickets, book_ticket], max_tool_calls: 5 }, mcp: { enabled: true, servers: [ { name: travel-assistant, transport: stdio, command: python, args: [mcp_travel_server.py] } ] } }这里function_list里写的是工具名实际注册时用BaseTool子类实例。mcp.servers数组是给支持 MCP 的客户端用的Qwen-Agent 原生不直接读这个字段但你可以自己写一层适配把 MCP Server 暴露的工具转成BaseTool注册进去。3.2 config.tomlMCP Server 侧配置MCP Server 如果用 Python SDK 写建议把传输方式和工具开关放在 config.toml 里避免每次改代码[server] name travel-assistant version 1.0.0 [transport] type stdio [llm] api_key sk-your-taotoken-key base_url https://taotoken.net/api model qwen-max [tools.search_attractions] enabled true max_results 10 [tools.generate_itinerary] enabled true max_days 10读取时用tomllibPython 3.11或tomliimport tomllib with open(config.toml, rb) as f: config tomllib.load(f) api_key config[llm][api_key] base_url config[llm][base_url]这样 MCP Server 内部如果要调模型做摘要或规划也能复用同一套 TaoToken 通道不用再单独配环境变量。3.3 工具定义与注册Function Calling 的核心是工具描述要准确。以门票助手为例两个工具的定义如下from qwen_agent.tools import BaseTool class SearchTickets(BaseTool): description 搜索指定景区在指定日期的可用门票 parameters { type: object, properties: { scenic_spot: {type: string, description: 景区名称}, date: {type: string, description: 游玩日期格式YYYY-MM-DD} }, required: [scenic_spot] } def call(self, params: dict, **kwargs): spot params.get(scenic_spot) date params.get(date, 任意日期) mock {故宫: {成人: 60, 学生: 30}, 长城: {成人: 40, 学生: 20}} if spot in mock: return f{spot}门票{mock[spot]}日期{date}余票充足 return f未找到{spot}的门票信息注册时把实例放进function_listfrom qwen_agent.agents import Assistant bot Assistant( llm{ model: qwen-max, api_key: sk-your-taotoken-key, base_url: https://taotoken.net/api }, function_list[SearchTickets()], system_message你是门票助手帮助用户查询和预订门票。 )跑起来后用户问“故宫明天有票吗”模型会输出search_tickets调用请求Qwen-Agent 自动执行call方法并把结果回传模型再生成最终回答。4. 验证请求确认工具调用链路生效配置写完不代表链路通了。你需要一个可观测的验证动作确认三件事模型确实发起了函数调用、工具确实被执行、结果确实回传给了模型。4.1 打印中间消息Qwen-Agent 的run方法返回的是消息列表流。把每一步都打出来messages [{role: user, content: 故宫明天有票吗}] for response in bot.run(messages): for msg in response: print(f[{msg.get(role)}] {msg.get(content, )[:200]}) if msg.get(function_call): print(f - 函数调用: {msg[function_call][name]}) print(f - 参数: {msg[function_call][arguments]})如果链路正常你会看到类似输出[user] 故宫明天有票吗 [assistant] - 函数调用: search_tickets - 参数: {scenic_spot: 故宫, date: 2025-01-16} [function] 故宫门票{成人: 60, 学生: 30}日期2025-01-16余票充足 [assistant] 故宫明天有票成人票60元学生票30元余票充足。4.2 用 curl 直接验证 TaoToken 通道如果模型侧没反应先排除通道问题。用 curl 打一次 TaoToken 的 APIcurl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-your-taotoken-key \ -H Content-Type: application/json \ -d { model: qwen-max, messages: [{role: user, content: 你好}] }返回里有choices[0].message.content就说明 Key 和通道没问题。如果返回 401检查 Key 是否复制完整返回 404检查 base_url 是否写成了带路径的形式。4.3 MCP Server 单独启动验证MCP Server 用 stdio 传输时可以先用命令行手动喂一条 JSON-RPC 请求echo {jsonrpc:2.0,id:1,method:tools/list,params:{}} | python mcp_travel_server.py正常会返回工具列表的 JSON。如果卡住不动多半是stdio_server没正确进入事件循环检查asyncio.run(main())是否在__main__里调用。5. 本篇常见错排查5.1 模型不调用工具只输出文本最常见的原因是工具描述不够具体。description要写清楚“什么时候用”而不是“这是什么”。比如搜索指定景区在指定日期的可用门票比门票搜索工具好得多。另外parameters里的required字段要准确缺了必填参数模型可能直接放弃调用。5.2 函数调用参数解析失败Qwen-Agent 内部用 JSON 解析arguments。如果模型输出的参数里带了中文引号或多余空格解析会报错。可以在call方法里加一层容错import json def call(self, params: dict, **kwargs): if isinstance(params, str): params json.loads(params) # 后续逻辑5.3 MCP Server 启动后客户端连不上stdio 传输要求 Server 进程和 Client 进程在同一台机器上且 Server 不能往 stdout 打非 JSON-RPC 的日志。如果你在代码里用了print调试会污染协议流。把调试信息写到 stderrimport sys print(debug info, filesys.stderr)5.4 TaoToken 返回 429并发请求过多会触发限流。在llm配置里加max_retries和退避策略或者降低 Agent 的max_tool_calls避免一次对话里连续打太多请求。5.5 工具执行结果回传后模型“失忆”有些模型对function角色的消息支持不完整。确认你用的模型在 TaoToken 通道上支持 function role。如果不支持可以把工具结果包装成user消息追加到对话里并在 system message 里说明“工具结果会以 user 消息形式返回”。6. 从 Function Calling 到 MCP 的下一步Function Calling 适合单一 Agent 内部的轻量工具调用5 到 20 个工具规模下开发复杂度低、上手快。MCP 适合构建可复用的工具生态一次开发多端使用但需要理解协议规范和传输层配置。实际项目里两者不冲突应用内专用工具用 Function Calling 快速集成跨应用复用的工具封装成 MCP ServerAgent 通过 MCP Client 连多个 Server 实现能力组合。如果你已经跑通了上面的门票助手下一步可以把SearchTickets和BookTicket抽出来做成独立的 MCP Server然后在 Qwen-Agent 里写一个适配层把 MCP 的tools/list结果转成BaseTool子类动态注册。这样你的工具库就能同时被 Claude Desktop、Cursor 和其他支持 MCP 的客户端复用。需要长期跑编码类 Agent 的话可以了解下 Coding Plan 的额度方案只是想先验证模型对话和工具调用是否通直接开模型对话页面试几条请求最快。接入文档里有完整的参数说明和错误码对照排障时对着查比盲猜省时间。
返回列表