模型三剑客:工具、函数调用与MCP协同之道
这三个概念不在同一个层级是配合起来用的Function Calling 是模型“决定调用哪个工具”的能力Tool 是具体可执行的功能MCP 是统一连接工具和模型的标准协议。可以把模型想象成一个聪明的助理Function Calling助理的“决策和表达”听懂需求后判断该用哪个工具、需要什么参数并生成结构化指令比如{name: getWeather, arguments: {city: 成都}}。它本身不执行只负责“说清楚要干什么”。Tool工具助理实际能用的“家伙什”比如查天气的接口、发邮件的功能、计算器。开发者把工具定义好告诉模型“你有这些可以用”。MCP连接助理和工具的“标准插座”像 USB-C。以前每家模型对接工具的方式都不一样MCP 统一了接口标准让同一个工具能被不同模型直接使用不用反复适配。它们怎么配合工作注册工具开发者定义好工具Tool比如getWeather用 JSON 描述它的功能和参数。模型决策你问“成都明天天气”模型通过 Function Calling 判断需要调用天气工具并生成指令{name: getWeather, arguments: {city: 成都, date: 明天}}。执行与返回你的程序或 MCP Client收到指令真正去执行工具拿到天气数据后再交给模型由模型整理成自然语言回复你。关键点模型不直接执行代码它只负责“发号施令”真正的执行由后端完成。Function Calling 和 MCP 的核心区别对比维度Function CallingMCP本质模型的输出能力连接工具与应用的协议作用层模型层传输/协议层解决的问题模型怎么表达调用意图应用怎么发现和连接工具工具发现开发者写死工具列表运行时动态发现跨平台各家格式不兼容统一标准一次接入到处可用简单说Function Calling 是“大脑”的决策MCP 是让决策能落地的“高速公路”两者互补不是替代关系。什么时候用哪个只服务单一模型直接用 Function Calling 就够了更简单直接。小项目、仅需3-5个固定工具直接用Function Calling对接Tool即可代码量小、链路简单完全不需要引入MCP要支持多个模型、工具会动态增减或涉及数据库、支付等敏感操作建议上 MCP协议层有更好的标准化和安全机制。实际项目里两者通常结合使用模型用 Function Calling 表达意图MCP 负责把意图路由到正确的工具并执行。企业级多Agent系统、需要对接十几个内部业务系统用MCP统一封装所有Tool再通过Function Calling触发调用能减少60%以上的重复开发代码工具支持热插拔迭代效率大幅提升。各自的核心定位Tool工具是最底层的“执行单元”就是一个个能完成具体任务的功能比如查天气的接口、发邮件的函数、查询数据库的能力本身是一段可执行的代码或API不直接和模型交互。Function Calling是大模型的原生输出能力它的核心作用是让模型在生成文本时能输出结构化的JSON调用指令明确告诉应用“我要调用哪个工具、传什么参数”解决的是“单次调用怎么准确表达意图”的问题。MCP模型上下文协议是Anthropic推出的标准化中间层协议相当于工具调用领域的“USB-C通用接口”它不替代任何一方而是把所有外部工具统一封装成可被自动发现、连接的标准服务解决的是“工具怎么跨应用复用、统一治理”的问题。三者的完整协作链路在实际生产系统中三者会按固定流程配合工作完全不存在谁替代谁的情况工具标准化封装开发者把所有Tool天气查询、数据库操作、文件读取等封装成独立的MCP Server通过统一的JSON-RPC协议暴露工具清单、参数规则。工具自动发现AI应用作为MCP Client连接各个MCP Server自动拉取所有可用工具的完整描述不需要开发者手动为每个工具写重复的Schema定义。模型生成调用指令用户发起请求后大模型通过Function Calling能力判断需要调用的工具输出标准的结构化调用JSON明确工具名和入参。协议层路由执行应用侧把模型输出的Function Calling指令转发给对应的MCP Server由MCP Server完成参数校验、实际Tool执行再把结果格式化返回给模型。结果整合输出大模型拿到工具返回的结果整理成自然语言回复给用户MCP还会自动维护多轮调用的上下文状态不需要开发者手动传递参数。核心差异对比维度ToolFunction CallingMCP所处层级最底层执行层模型侧交互层中间协议层核心目标完成具体业务动作让模型准确表达调用意图统一工具接入标准实现跨应用复用核心能力执行具体逻辑输出结构化调用JSON工具自动发现、状态自动维护、跨模型兼容复用范围仅在当前代码库可用绑定特定大模型的输出格式支持所有兼容MCP的AI应用/模型直接复用适用场景所有需要外部操作的场景工具少、单应用的轻量场景多Agent协作、大量工具需要统一治理的复杂场景简单总结Tool是“干活的手”Function Calling是“大脑发出的动作指令”MCP是连接大脑和手的标准化“神经通路”三者配合才能让大模型真正安全、高效地和真实业务系统交互。生活场景智能家居管家Tool家里的空调、灯、扫地机器人——具体能执行动作的设备。Function Calling管家模型的能力你说有点热他能判断出该开除湿还是制冷、定几度输出明确指令。MCP家里的智能中控网关。以前小米、海尔、格力的设备协议各不相同管家得分别学着控制有了统一网关管家只要对着网关说把客厅降温网关自动翻译成各品牌设备听得懂的信号。于是流程变成你说到家了有点热 → 管家模型判断要开空调开灯 → 通过网关MCP分别下发指令 → 空调、灯Tool各自执行 → 管家告诉你已开空调 26 度和客厅灯模型整合结果回复你如果哪天你新买了一台新品牌的风扇只要它接入了这个网关管家自动就能控制它你什么都不用改——这就是 MCP 带来的热插拔代码示例一、假设有一个订单服务正常运行二、搭建一个MCP Server 去调用订单服务查询订单详情1、引入依赖!--引入依赖 spring-ai-mcp-server-webflux-spring-boot-starter-- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-mcp-server-webflux-spring-boot-starter/artifactId /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency2、配置文件#配置服务端口 server: port: 8084 spring: application: name: order-mcp-server #配置mcp的服务 ai: mcp: server: name: my-order-server version: 1.0.03、实现往Spring 注册Bean(ToolCallbackProvider)Data public class Order implements Serializable { private String orderId; private String userId; JsonFormat(pattern yyyy-MM-dd HH:mm:ss, timezone GMT8) private Date orderTime; private BigDecimal totalAmount; /** * 订单状态 * 0:待付款 * 1:已付款 * 2:已发货 * 3:已完成 * 4:已取消 */ private Integer orderStatus; private String paymentMethod; private String shippingAddress; private String contactPhone; private ListOrderDetail orderDetails; }Data public class OrderDetail { private Integer detailId; private String orderId; private String productId; private String productName; private Integer quantity; private BigDecimal unitPrice; private BigDecimal totalPrice; private String specification; }public enum OrderStatus { /** * 待付款 (0) */ PENDING(0, 待付款), /** * 已付款 (1) */ PAID(1, 已付款), /** * 已发货 (2) */ SHIPPED(2, 已发货), /** * 已完成 (3) */ COMPLETED(3, 已完成), /** * 已取消 (4) */ CANCELLED(4, 已取消); private final int code; private final String description; /** * 构造函数 * param code 状态码 * param description 状态描述 */ OrderStatus(int code, String description) { this.code code; this.description description; } /** * 获取状态码 * return 状态码 */ public int getCode() { return code; } /** * 获取状态描述 * return 状态描述 */ public String getDescription() { return description; } /** * 根据状态码获取枚举实例 * param code 状态码 * return 对应的枚举实例 * throws IllegalArgumentException 如果找不到对应的枚举值 */ public static OrderStatus fromCode(int code) { for (OrderStatus status : values()) { if (status.code code) { return status; } } throw new IllegalArgumentException(无效的订单状态码: code); } /** * 检查当前状态是否允许取消订单 * return 是否允许取消 */ public boolean canBeCancelled() { return this PENDING || this PAID; } /** * 检查当前状态是否已完成包括已完成和已取消 * return 是否已完成 */ public boolean isFinalStatus() { return this COMPLETED || this CANCELLED; } }Service public class OpenOrderService { //订单服务访问地址 private static final String BASE_URL http://localhost:8083/orders; private final RestTemplate restTemplate; public OpenOrderService() { this.restTemplate new RestTemplate(); } Tool(description 获取所有订单信息 ) public ListOrder getOrders() { // 尝试远程调用 String url BASE_URL/list; return restTemplate.getForObject(url, List.class); } Tool(description 根据用户ID获取用户订单列表信息 ) public ListOrder getOrdersByUserId(String userId) { // 尝试远程调用 String url BASE_URL/user/ userId; return restTemplate.getForObject(url, List.class); } Tool(description 根据订单ID获取订单详情 ) public Order getOrderById(String orderId) { String url BASE_URL/{orderId}; return restTemplate.getForObject(url, Order.class, orderId); } Tool(description 根据订单ID取消订单 ) public boolean cancelOrder(String orderId) { String url BASE_URL/cancel/{orderId}; return restTemplate.postForObject(url, null, Boolean.class, orderId); } }SpringBootApplication public class OMSApplication { public static void main(String[] args) { SpringApplication.run(OMSApplication.class,args); } //通过ToolCallbackProvider 提供远程服务调用mcp client Bean public ToolCallbackProvider orderTools(OpenOrderService openOrderService) { return MethodToolCallbackProvider.builder().toolObjects(openOrderService).build(); } }三、搭建一个MCP Client 去获取订单服务详情数据1、引入依赖dependencies !--引入依赖 spring-ai-mcp-client-webflux-spring-boot-starter-- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-mcp-client-webflux-spring-boot-starter/artifactId /dependency !--引入依赖 sspring-ai-alibaba-starter-- dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter/artifactId /dependency /dependencies2、配置mcp的服务spring: application: name: order-mcp-client main: web-application-type: none ai: ollama: base-url: http://localhost:11434 #本地ollama服务地址 chat: model: deepseek-r1:1.5b #本地大模型 #ai: #dashscope: #api-key: ${AI_DASHSCOPE_API_KEY} mcp: client: sse: connections: server1: url: http://localhost:8084 #连接服务 mandatory-file-encoding: UTF-8 # 调试日志 logging: level: io: modelcontextprotocol: client: DEBUG spec: DEBUG ai: user: input: 查询订单ID为ORD20250414001的订单详情3、实现通过ToolCallbackProvider 调用远程的服务SpringBootApplication(exclude { org.springframework.ai.autoconfigure.mcp.client.SseHttpClientTransportAutoConfiguration.class }) public class OMCApplication { public static void main(String[] args) { SpringApplication.run(OMCApplication.class,args); } private String userInput 查询订单ID为ORD20250414001的订单详情; /** * param chatClientBuilder * param tools 通过ToolCallbackProvider 调用远程的服务 * param context * return */ Bean public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder, ToolCallbackProvider tools, ConfigurableApplicationContext context) { return args - { var chatClient chatClientBuilder //通过tool方式接入 .defaultTools(tools) .build(); System.out.println(\n QUESTION: userInput); System.out.println(\n ASSISTANT: chatClient.prompt(userInput).call().content()); context.close(); }; } }启动服务数据库服务本地大模型服务应用服务启动应用服务顺序1、订单服务 2、MCP Server 3、 MCP ClientMCP Client 端执行结果执行查询命令 QUESTION: 查询订单ID为ORD20250414001的订单详情返回查询结果大模型整合返回结果 ASSISTANT: 订单ID为 ORD20250414001 的订单详情如下