ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

大模型探秘–AI 感知世界:用 FunctionCall 与 MCP 打通交互链路

2026/9/27 18:56:47 拓冰建站 浏览量
大模型探秘–AI 感知世界:用 FunctionCall 与 MCP 打通交互链路 1. 从“只会聊天”到“能动手干活”中间缺了什么大模型刚火那阵我身边不少朋友的第一反应是这不就是个高级版聊天框吗问它天气它给你一段文字让它订机票它只能回你“抱歉我无法访问实时信息”。问题不在于模型不够聪明而在于它被关在一个纯文本的盒子里——能理解世界却碰不到世界。FunctionCall 和 MCP 就是打开这个盒子的两把钥匙。FunctionCall 让模型学会“我要调用哪个函数、传什么参数”MCP 则把这种调用能力标准化让不同工具、不同模型之间用同一套协议对话。打个比方FunctionCall 像是教会一个人“看到红灯要踩刹车”MCP 则是把刹车、油门、方向盘统一成标准接口换任何一辆车都能开。这篇文章面向的是已经用过大模型 API、想进一步做工具调用的开发者。我会先讲清楚 FunctionCall 和 MCP 各自解决什么问题然后给出一份可复制的 MCP 服务端配置骨架再配一个 FunctionCall 参数示例最后走一遍从对话到实际调用的完整验证流程。全程用 TaoToken 作为模型接入层因为它同时支持标准 OpenAI 格式的 FunctionCall 和 MCP 协议接入省去自己搭转发层的麻烦。2. 前置准备TaoToken 接入层与 MCP 环境2.1 为什么需要接入层直接调各家模型的原生接口做 FunctionCall最头疼的是格式不统一。OpenAI 的 tools 参数、Claude 的 tool_use 块、国内模型的 function_call 字段写法各有差异。TaoToken 的价值在于它把这些差异抹平了——你按 OpenAI 的 FunctionCall 格式写一次背后路由到不同模型时由接入层做转换。官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI 基础地址https://taotoken.net/api2.2 获取 API Key登录后进入控制台在 API Keys 页面创建一个新 Key。建议按用途分 Key比如“functioncall-test”单独一个方便排查问题时定位。API Keys 管理页https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite创建后复制保存Key 只显示一次。环境变量里这样设置export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api2.3 MCP 服务端运行环境MCP 服务端本质是一个遵循 JSON-RPC 2.0 的进程通过 stdio 或 SSE 与客户端通信。本地调试用 stdio 最省事不需要开端口。你需要Python 3.10 以上官方 SDK 要求Node.js 18 以上如果要用现成的 TypeScript 服务端一个能跑命令的终端安装 Python SDKpip install mcp装完后可以用python -c import mcp; print(mcp.__version__)确认版本。3. 可复制配置MCP 服务端骨架与 FunctionCall 参数3.1 MCP 服务端最小骨架下面这个服务端暴露一个get_weather工具接收城市名返回模拟天气。代码可以直接存成weather_server.py运行。from mcp.server import Server from mcp.server.stdio import stdio_server from mcp.types import Tool, TextContent app Server(weather-server) app.list_tools() async def list_tools(): return [ Tool( nameget_weather, description查询指定城市的当前天气, inputSchema{ type: object, properties: { city: { type: string, description: 城市名称如北京、上海 } }, required: [city] } ) ] app.call_tool() async def call_tool(name: str, arguments: dict): if name get_weather: city arguments.get(city, 未知) # 实际项目这里换成真实天气 API 调用 return [TextContent( typetext, textf{city}当前晴气温 22 摄氏度湿度 45% )] raise ValueError(f未知工具: {name}) async def main(): async with stdio_server() as (read, write): await app.run(read, write, app.create_initialization_options()) if __name__ __main__: import asyncio asyncio.run(main())关键点list_tools返回工具清单call_tool处理实际调用。inputSchema用 JSON Schema 描述参数模型就是靠这个生成正确参数的。3.2 客户端连接配置在支持 MCP 的客户端比如 Claude Desktop 或自己写的 Agent里配置这样写{ mcpServers: { weather: { command: python, args: [/绝对路径/weather_server.py], env: { TAOTOKEN_API_KEY: sk-你的key } } } }注意args里用绝对路径相对路径在不同工作目录下会找不到文件。3.3 FunctionCall 参数示例如果你不走 MCP直接用 OpenAI 格式的 FunctionCall请求体长这样{ model: gpt-4o, messages: [ {role: user, content: 北京今天天气怎么样} ], tools: [ { type: function, function: { name: get_weather, description: 查询指定城市的当前天气, parameters: { type: object, properties: { city: { type: string, description: 城市名称 } }, required: [city] } } } ], tool_choice: auto }模型返回的tool_calls字段里会带上function.name和function.arguments你解析后执行本地函数再把结果以role: tool的消息塞回去模型就能生成最终回答。3.4 两种方式怎么选维度FunctionCallMCP标准化程度各家格式有差异统一协议工具发现每次请求手动传 tools服务端自动暴露适用场景单次、简单调用多工具、长期运行调试难度低直接看请求响应中需要看服务端日志简单任务用 FunctionCall 就够了工具多了、要跨会话复用时上 MCP。4. 验证请求从对话到实际调用的完整流程4.1 用 curl 验证 FunctionCall先确认接入层能正常返回 tool_callscurl https://taotoken.net/api/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: gpt-4o, messages: [{role: user, content: 上海天气如何}], tools: [{ type: function, function: { name: get_weather, description: 查询城市天气, parameters: { type: object, properties: {city: {type: string}}, required: [city] } } }] }预期返回里choices[0].message.tool_calls不为空arguments里是{city: 上海}。如果返回的是普通文本回答说明模型没触发工具调用检查tool_choice是否设成了auto或具体函数名。4.2 用 MCP Inspector 验证服务端MCP 官方提供了 Inspector 工具可以可视化调试服务端npx modelcontextprotocol/inspector python weather_server.py启动后浏览器打开提示的地址在 Tools 标签页能看到get_weather点进去填{city: 北京}执行右侧会返回天气文本。这一步通了说明服务端本身没问题。4.3 端到端串联把 MCP 服务端接到 Agent 里用户说“帮我查下北京天气”流程是Agent 把用户输入和 MCP 暴露的工具列表一起发给模型模型返回 tool_call指定get_weather和参数{city: 北京}Agent 通过 MCP 客户端调用服务端拿到天气文本Agent 把结果回传模型模型生成“北京当前晴22 度”这样的自然语言回答实测下来从发起到拿到最终回答本地 stdio 方式延迟在 200ms 以内主要耗时在模型推理那一步。5. 本篇常见错排查5.1 模型不调用工具只回文本最常见的原因是工具描述写得太模糊。description要写清楚“什么时候用这个工具”而不是只写“查询天气”。改成“当用户询问某城市实时天气、温度、湿度时调用”会明显提升触发率。另外确认tool_choice不是none。5.2 MCP 服务端启动报 ModuleNotFoundError多半是 Python 环境不对。pip install mcp装到了系统 Python但客户端配置里用的python指向了虚拟环境。解决办法是在配置里写虚拟环境解释器的绝对路径比如/Users/you/venv/bin/python。5.3 tool_calls 的 arguments 解析失败模型返回的arguments是 JSON 字符串不是对象。直接arguments.city会报错要先json.loads(arguments)。有些模型会返回带换行或多余空格的 JSON解析前先strip()一下。5.4 调用结果回传后模型重复调用这是消息历史没拼对。回传工具结果时role必须是tool并且带上tool_call_id和模型返回的id对应。漏了tool_call_id模型会以为工具没执行再次发起调用。5.5 接入层返回 401检查 Key 是否复制完整有没有多余空格。如果 Key 没问题确认请求头是Authorization: Bearer sk-xxx不是x-api-key。TaoToken 走的是标准 OpenAI 鉴权格式。6. 继续深入把工具调用接进日常开发流FunctionCall 和 MCP 打通之后能做的事情比想象中多。比如把本地文件操作、数据库查询、内部 API 都封装成 MCP 服务端模型就能在对话里直接读写文件、查数据。我试过把项目里的日志查询封装成工具排查线上问题时直接问模型“最近一小时有没有 500 错误”它自己调工具拿数据再总结比手动 grep 快不少。如果你主要做长期编码和 Agent 开发建议直接上 Coding Plan工具调用次数和并发都更充裕https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite想先快速验证模型对 FunctionCall 的支持情况用模型对话页测几轮最直接https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite接入文档里有完整的 FunctionCall 和 MCP 配置说明遇到协议细节问题可以对照查https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite最后提醒一句MCP 服务端暴露的工具权限要收窄别把生产数据库的写权限直接开出去。本地调试先用只读接口确认调用链路通了再逐步放开。