Function Calling 与 MCP:从工具调用到标准化 Agent 扩展实践
摘要
本文从大模型工具调用闭环出发,分析 Function Calling 与 MCP 的职责边界,并以门票数据分析、高德旅行规划和本地 TXT 文件统计为例,说明应用内函数、远程服务与本地工具如何接入 Agent。重点讨论参数模式、工具调度、结果回填、能力发现、安全边界和工程选型。
Function Calling 与 MCP:从工具调用到标准化 Agent 扩展实践
写在前面
Large Language Model,大语言模型(LLM)擅长理解和生成文本,但它不会因为回答中出现一段 Structured Query Language,结构化查询语言(SQL),就自动连接数据库执行查询;也不会仅凭内部知识获得实时地图、网络搜索和本地文件信息。要让模型真正完成任务,应用必须把外部能力描述成工具,让模型决定是否调用,再由程序执行工具并把结果返回给模型。
这个项目围绕两种工具接入方式展开。第一种是 Function Calling,应用直接注册函数及其参数模式,模型生成结构化调用请求,应用负责执行。第二种是 Model Context Protocol,模型上下文协议(MCP),Agent Host 通过统一协议发现和调用外部工具、资源与提示模板。
二者不是替代关系。Function Calling 解决模型如何表达调用意图,MCP 解决工具如何被标准化暴露、发现和连接。实际 Agent 往往同时使用两者:MCP Client 先从 Server 获取工具定义,Host 再将这些定义交给模型;模型产生工具调用后,Host 通过 MCP 完成执行。
全文先解释共同的工具调用闭环,再用门票助手说明 Function Calling 的实现和演进;随后拆解 MCP 架构,并通过高德旅行规划和本地 TXT 文件统计说明远程服务与本地服务的接入方式;最后给出两类方案的选择条件和工程风险。
模块 | 解决的问题 | 项目中的实现 |
|---|---|---|
Function Calling | 模型如何选择应用内函数并生成参数 |
|
MCP Client | Host 如何连接并管理外部工具服务 | Qwen-Agent 中的 |
远程能力 | 如何复用地图和网络搜索能力 | 高德地图 MCP、Tavily MCP |
本地能力 | 如何将本地程序暴露给 Agent | FastMCP 桌面 TXT 文件统计器 |
工程控制 | 如何保证工具调用可控、可查、可验证 | 参数校验、权限隔离、日志与结果检查 |
一、整体架构:先建立共同的调用闭环

图 1:Function Calling 与 MCP 共用的工具调用闭环。Mermaid 源文件保存在同级 images 目录中(图由AI辅助绘制)。
这套架构包含六个连续步骤。
第一,Host 收到用户请求,并准备对话上下文。第二,Host 将可用工具的名称、用途和参数模式交给模型。第三,模型判断是否需要外部能力;如果需要,则生成包含工具名和参数的结构化请求。第四,Host 校验参数并选择执行路径:应用内函数由本地调度器直接执行,MCP 工具由 Client 转发到对应 Server。第五,执行结果回填到对话上下文。第六,模型基于工具结果生成最终回答、表格或图表。
模型在这个过程中只负责选择工具和生成参数,不直接执行函数。真正的数据库权限、文件权限、网络访问、超时和审计都属于 Host 或工具服务的职责。这个边界决定了系统能否从演示原型进入生产环境。
二、Function Calling 的本质
Function Calling 可以理解为模型与应用之间的一份结构化调用约定。应用把函数描述和参数模式传给模型,模型不返回自由文本指令,而是返回可解析的函数名和参数。应用根据名称找到真实函数,执行后再把结果交还给模型。
一次完整调用包含四类信息。
信息 | 作用 | 门票助手中的对应内容 |
|---|---|---|
函数名 | 唯一定位工具 |
|
函数描述 | 告诉模型何时使用 | 执行生成的 SQL,并返回查询结果 |
参数模式 | 约束参数名称、类型和必填项 |
|
工具结果 | 为模型提供真实外部信息 | Markdown 表格和图表路径 |
参数模式不是形式化装饰。描述过于宽泛时,模型可能选错工具;字段语义不清时,模型可能生成错误参数;可选项没有枚举时,同一概念可能出现多种写法。高质量工具定义应尽量做到单一职责、参数明确、返回值稳定和错误语义可区分。
Qwen-Agent 的实现将自定义工具注册为 BaseTool 子类,再把工具名传入 Assistant。官方项目同时提供 Function Calling、MCP、Code Interpreter 和 RAG 等 Agent 组件。[^6] 下面保留项目中的核心逻辑,并移除数据库凭据和界面代码。
模型侧只需要注册工具并运行对话。
代码很短,但运行质量取决于系统提示中是否给出了准确的表结构、业务口径和时间定义。模型只能依据提供的上下文生成 SQL,不会自动知道一日票、二日票分别对应哪些 Stock Keeping Unit,库存量单位(SKU),也不会自动统一周起始日和跨年周编号。
三、门票数据分析:从查询工具到连续分析
3.1 场景与数据
门票助手面向订单分析场景。核心表 tkt_orders 包含下单时间、用户、地区、SKU、销售渠道、订单状态、金额和数量等字段。系统需要处理三类问题:按周统计一日票与二日票销量、按省份统计入园人数、按渠道统计订单金额。
这类任务不只是自然语言转 SQL。模型还要理解业务分类、选择聚合口径、处理时间边界,并将结果转换为适合分析的表格和图表。项目因此分三版逐步实现。
版本 | 新增能力 | 解决的问题 | 仍然存在的限制 |
|---|---|---|---|
| 注册 | 打通模型生成 SQL、应用执行、结果回填 | 结果只有表格,不便观察趋势 |
| 查询后自动识别横轴和数值列并绘图 | 将数据查询扩展为可视化分析 | 多类别数据会被压缩到同一横轴 |
| 根据类别列构造透视表并绘制分组结果 | 展示日期、渠道、票种等多维关系 | 图表类型仍由数据类型启发式决定 |
3.2 第一版:让模型负责 SQL,让程序负责执行
系统提示中给出表结构、字段解释和票种映射。例如一日票通过 SKU LIKE 'Universal Studios Beijing One-Day%' 聚合,二日票通过 SKU LIKE 'USB%' 聚合。模型根据用户问题生成 SQL 后调用 exc_sql,工具通过 Pandas 执行查询并返回 Markdown 表格。
这个分工比让模型直接输出一段 SQL 更完整。用户得到的是数据库真实结果,不需要手动复制查询语句;模型也能基于执行结果继续解释。不过,原型直接执行模型生成的 SQL,只适合受控环境。生产环境至少需要只读账号、允许表清单、仅允许 SELECT、查询超时、结果行数上限和敏感字段屏蔽。
3.3 第二版:把查询和绘图放在同一个工具中
最初可以把 SQL 查询和绘图设计成两个工具,但这会产生一个新的状态问题:查询工具返回 Markdown 表格后,绘图工具还要重新解析文本、判断横纵轴,并在多轮调用中保持同一个 DataFrame。中间数据越大,模型上下文和序列化开销越高。
项目最终将查询与绘图放在同一个 exc_sql 工具中。工具执行 SQL 后直接取得 DataFrame,先返回表格,再根据列类型生成图表。这样避免了 DataFrame 在工具之间传递,也保证表格与图片来自同一次查询。
核心流程可以概括为:
3.4 第三版:用透视表表达多类别关系
简单数据通常只有一个类别列和多个数值列,例如周编号、一日票销量、二日票销量。第二版可以直接以周编号为横轴绘制两组柱形。
当查询结果同时包含日期和销售渠道时,同一天会出现多行记录。若仍把日期作为唯一横轴,不同渠道会使用重复标签,图表无法表达渠道差异。第三版先识别对象类型列和数值列,再通过 pivot_table 将渠道转为列层级,以日期作为索引,最后绘制多级分组或堆积图。
这里的关键不是 pivot_table 本身,而是明确图表语义:第一列表示观察维度,其他类别列表示分组维度,数值列表示度量。若应用场景固定,最好由工具参数显式传入 x、series、value 和图表类型,不应长期依赖数据类型自动推断。
3.5 结果与一次时间口径修正

图 2:门票助手调用 exc_sql 后同时返回周销量表格和柱形图。来源:项目运行结果。
结果显示,2023 年第 14 周到第 25 周的一日票销量大致稳定在 1.9 万至 2.0 万,二日票约为 1.4 万至 1.5 万;第 13 周和第 26 周明显偏低。这个现象不能直接解释为业务异常,因为查询区间是 4 月至 6 月,首尾周只覆盖了部分日期。
继续下钻第 13 周时,初始 SQL 使用了与业务口径不一致的周编号函数,只取到了 4 月 1 日的数据。修正后按 3 月 27 日至 4 月 2 日重新查询,才能得到完整周数据。这个过程说明,Function Calling 能执行 SQL,但不会自动消除统计口径歧义。周起始日、自然周与 ISO 周、跨月和跨年边界必须在系统提示或业务层固定。
四、MCP 为什么必要
应用内 Function Calling 适合少量、单一应用拥有的工具。随着工具数量和客户端数量增加,每个应用都要重复编写工具描述、进程启动、连接、权限和结果解析逻辑。MCP 将这些问题抽象成统一协议,使工具服务能够独立于具体模型和 Host 演进。
Anthropic 在 2024 年 11 月 25 日发布 MCP。当前官方架构将系统划分为 Host、Client 和 Server:Host 是承载模型和交互的 AI 应用;每个 Client 与一个 Server 维持独立连接;Server 提供上下文和可执行能力。MCP 只规定上下文交换协议,不规定 Host 使用哪一种模型,也不规定 Agent 如何管理记忆和规划。[^1][^2]
4.1 Host、Client 和 Server
组件 | 主要职责 | 项目中的对应对象 |
|---|---|---|
MCP Host | 管理模型、用户交互、权限和多个 Client | Qwen-Agent |
MCP Client | 建立连接、协商能力、发现工具并转发调用 | Qwen-Agent 内部 MCP 适配层 |
MCP Server | 暴露工具、资源和提示模板 | 高德地图、Tavily、TXT 统计服务 |
一个 Host 可以连接多个 Server,但通常会为每个 Server 创建一个独立 Client。这样可以隔离生命周期、权限和故障范围。高德 Server 不需要理解模型对话,TXT Server 也不需要知道地图工具是否存在;它们只需按协议声明能力并响应请求。
4.2 Tools、Resources 和 Prompts
MCP Server 可以暴露三类核心原语。Tools 是模型可调用的动作,例如查询地图、搜索网页或读取文件;Resources 是由应用选择并加入上下文的数据,例如文件内容、数据库记录和接口响应;Prompts 是可复用的交互模板。官方规范将三者分别概括为模型控制、应用控制和用户控制。[^3]
原语 | 主要用途 | 典型操作 |
|---|---|---|
Tools | 执行动作或获取动态结果 |
|
Resources | 提供可读取的上下文数据 |
|
Prompts | 提供参数化提示模板 |
|
项目主要使用 Tools。Client 连接 Server 后先发现工具列表,再把工具名称、描述和输入模式注册到 Host;模型产生调用后,Client 通过 tools/call 转发参数,并将响应交回 Host。
4.3 数据层与传输层
MCP 数据层基于 JavaScript Object Notation Remote Procedure Call 2.0,JSON 远程过程调用 2.0(JSON-RPC 2.0),负责初始化、能力协商、工具发现、调用和通知。传输层负责进程或网络通信。官方当前定义的主要传输方式是 standard input/output,标准输入输出(stdio)和 Streamable Hypertext Transfer Protocol,可流式超文本传输协议(Streamable HTTP)。本地工具通常使用 stdio,由 Host 启动子进程;远程服务通常使用 Streamable HTTP,并结合鉴权。[^2]
这两层分离后,同一组工具语义可以运行在本地进程,也可以部署为远程服务。Host 不需要针对每个工具重新设计通信格式。
五、高德旅行规划:通过 MCP 复用远程能力
5.1 场景与目标
旅行规划不是一次地点搜索。系统需要先查找候选景点,再获取地址、开放时间和门票信息,随后考虑景点间距离和交通方式,最后组织为可执行的日程。模型负责分解任务和组织结果,地图 Server 负责返回实时地理信息。
项目在 Qwen-Agent 中配置高德地图 MCP Server。Application Programming Interface,应用程序编程接口(API)密钥通过环境变量注入,不写入代码。
配置完成后,Host 启动 Server,Client 发现地图工具,并将其交给模型。模型面对上海一日游请求时,先调用文本搜索获取候选地点,再多次调用详情查询补充景点信息,最后根据位置和时间生成行程。整个过程不是模型凭记忆编写攻略,而是模型规划与地图工具返回结果的组合。

图 3:左侧为地图工具调用记录,右侧为基于查询结果整理的行程。来源:项目运行结果。
图中可以看到 maps_text_search 和 maps_search_detail 被连续调用,最终输出包含豫园、东方明珠、陆家嘴等地点的时间安排、地址和交通建议。这个案例体现了 MCP 的价值:地图能力由独立 Server 提供,Host 只负责连接与调度,模型负责决定查询顺序和组织答案。
结果仍需要人工核验。景点营业时间、票价、临时闭园和实时交通都可能变化;路线规划还应加入出发地点、预算、步行承受范围和必须到达时间等约束。涉及预订或支付时,工具必须要求用户确认,不能让模型直接完成不可逆操作。
六、本地 TXT 文件统计:实现最小 MCP Server
高德案例说明如何复用已有 Server,本地 TXT 文件统计器则说明如何把自己的 Python 函数变成 MCP 工具。项目使用官方 Python Software Development Kit,软件开发工具包(SDK)中的 FastMCP,注册了统计文件数量、列出文件名和读取指定文件三个工具。
下面是最小实现。
@mcp.tool() 会依据函数签名和文档字符串生成工具模式。Server 启动后,Client 可以通过 tools/list 发现工具,再通过 tools/call 执行。项目还使用 MCP Inspector 检查请求参数、返回内容和错误状态。

图 4:Inspector 调用本地工具后统计到 2 个 TXT 文件,并在历史记录中显示 tools/call 请求和 isError: false 响应。来源:项目运行结果。
这个最小案例验证了三件事:函数可以被自动描述为工具,Client 可以发现并执行工具,调用结果遵循统一响应结构。它也暴露了本地工具最需要注意的权限问题。文件工具不应默认访问整个用户目录;读取文件时要对路径做规范化,确认最终路径仍位于允许目录内,并限制扩展名、文件大小和编码。Tool 能运行不等于 Tool 可以获得无限权限。
项目依赖中固定了 mcp==1.7.1。MCP Python SDK 仍在演进,部署时应锁定 SDK 版本并针对该版本编写配置和测试,不能把不同版本的启动命令、传输参数和内部属性直接混用。官方 SDK 同时提供 FastMCP 和 Inspector,适合完成工具定义、连接与协议级调试。[^4]
七、Tavily 搜索:同一种接入方式扩展另一类能力
网络搜索与地图查询的业务逻辑不同,但 MCP 接入结构相同。项目通过 tavily-mcp@0.1.4 启动搜索 Server,将 TAVILY_API_KEY 作为环境变量传入,再把 Server 配置交给 Qwen-Agent。
模型可以据此完成新闻搜索、资料检索和网页内容提取。与地图案例相比,搜索结果更容易包含不可信网页内容,因此 Host 需要保留来源链接、限制返回长度、区分网页文本与系统指令,并防止工具返回内容通过提示注入改变 Agent 的权限和目标。
这个扩展示例说明,新增外部能力时,应用不必再为每种服务重写一套模型适配代码。只要 Server 遵循 MCP,Host 就能复用连接、发现和调用流程。
八、Function Calling 与 MCP 如何选择
维度 | Function Calling | MCP |
|---|---|---|
主要解决的问题 | 模型如何表达函数调用 | 工具、资源和提示如何标准化暴露与连接 |
工具位置 | 通常位于应用内部 | 本地进程或远程服务 |
工具发现 | 应用启动时手动注册 | Client 通过协议动态发现 |
通信与生命周期 | 由应用自行实现 | 协议定义初始化、能力协商和调用 |
复用范围 | 更适合单个应用 | 更适合多个 Host 或独立工具团队 |
实现成本 | 少量工具时较低 | 初始接入更复杂,但规模化后更统一 |
典型场景 | 计算、格式转换、应用内数据库查询 | 文件系统、代码仓库、地图、搜索和企业服务 |
选择时可以遵循三个判断。
工具数量少、逻辑归当前应用所有、调用链简单时,直接 Function Calling 更合适。工具需要跨多个 Agent 或编辑器复用,或需要独立部署、独立权限和动态发现时,使用 MCP 更合适。大多数复杂系统不需要二选一:MCP 负责连接工具生态,模型原生 Function Calling 负责产生结构化工具调用。
九、从原型到可用系统的工程控制
9.1 参数与返回值必须可验证
模型生成的参数只能视为不可信输入。Host 应按模式验证类型、范围、枚举和必填项,工具返回值也应有稳定结构。查询结果最好返回字段含义、单位、时间范围和数据来源,而不是只返回一段自然语言。
门票助手当前通过列类型推断图表。更稳妥的做法是让工具显式接收图表模式,或由业务规则决定维度和度量。结构明确后,系统才能对生成结果编写自动检查。
9.2 权限要放在工具侧,而不是提示词中
提示模型不要执行危险 SQL 不是安全边界。数据库需要只读账号和网络隔离,SQL 需要语法解析和允许表检查;文件工具需要允许目录;地图和搜索密钥需要最小权限;有副作用的操作需要用户确认和幂等设计。
MCP Server 应按能力拆分,避免一个 Server 同时拥有不相关的高权限。Host 还应允许用户查看即将调用的工具和关键参数,对写文件、发消息、提交订单等操作设置确认步骤。
9.3 工具链需要可观测
至少记录请求标识、工具名、参数摘要、Server、开始时间、耗时、结果大小、错误类型和模型最终结论。敏感参数不写入日志。连续工具调用出现问题时,需要区分模型选错工具、参数不合法、Server 连接失败、外部 API 失败和结果解释错误。
MCP Inspector 适合验证协议层和单个工具,完整 Agent 还需要端到端任务集。测试问题应覆盖正常输入、边界日期、空结果、超大结果、权限拒绝、超时和恶意输入。
9.4 控制工具数量和上下文开销
Host 将大量工具定义一次性传给模型,会增加上下文长度,也可能降低工具选择准确率。工具较多时,应按任务、权限或领域筛选工具,只向模型暴露当前需要的子集。多步调用还会增加模型往返和工具结果回填成本,应压缩中间结果,并避免把无关原始数据全部送回模型。官方 MCP Client 最佳实践同样强调工具筛选、结果大小和执行资源限制。[^5]
十、项目结果与局限
项目完成了三类验证。
门票助手打通了自然语言问题、SQL 生成、数据库执行、表格回填和自动可视化,并通过三次迭代支持多类别数据。高德地图 MCP 完成了工具发现、多次地点查询和一日游行程生成。FastMCP 本地服务成功暴露 TXT 统计工具,并通过 Inspector 验证 tools/call 的请求与响应。
这些结果证明工具链路能够工作,但不等于已经达到生产标准。当前门票助手没有给出查询正确率、工具选择准确率、执行延迟和并发性能的量化评估;SQL 安全和图表语义仍需加强。旅行规划依赖外部数据质量,且没有覆盖预订确认和实时交通。TXT 工具验证了协议流程,但权限范围和路径校验仍需收紧。
后续改进应优先建立一套可复现任务集,对每个问题同时检查工具选择、参数、执行结果和最终答案;随后再补充只读权限、结构化返回、审计日志和用户确认机制。工具越强,验证和权限控制越不能省略。
小结
Function Calling 让模型从生成文本扩展为生成结构化调用意图,MCP 则让外部能力从应用内私有实现扩展为可发现、可连接、可复用的标准服务。
门票助手说明了应用内工具如何从 SQL 查询演进到连续分析和自动可视化;高德旅行规划说明了 Agent 如何组合多个远程工具结果;TXT 统计器说明了本地函数如何通过 FastMCP 变成标准工具。三者共同指向同一个工程结论:模型负责理解、选择和组织,程序负责权限、执行和验证。
