Tools、MCP 和 Function Calling 详细对比文档
基于 Lynxe 项目的实际实现分析
概述
在 AI Agent 开发中,Tools 、MCP 和 Function Calling 是三种不同的工具调用机制,它们各有特点和应用场景。本文档是基于 Lynxe 项目的实际实现,详细说明三者的区别、关系和使用方式。
核心概念速览
| 特性 | Tools (Spring AI) | MCP | Function Calling |
|---|---|---|---|
| 定位 | 框架层面的工具抽象 | 协议标准 | 模型层面的能力 |
| 实现层级 | 应用框架层 | 协议层 | 模型 API 层 |
| 标准化程度 | Spring AI 框架标准 | 行业协议标准 | 模型厂商标准 |
| 集成方式 | 直接集成 | 通过协议集成 | 通过 API 集成 |
| 扩展性 | 框架内扩展 | 跨平台扩展 | 模型能力限制 |
Tools (Spring AI Tools)
定义
Tools 是 Spring AI 框架提供的统一工具调用机制,它是框架层面的抽象,用于将各种功能封装成可被 LLM 调用的工具。
核心特点
- 框架级抽象:不依赖特定模型,是 Spring AI 框架的统一接口
- 类型安全:使用 Java 泛型,提供类型安全的工具定义
- 统一管理 :通过
ToolCallingManager统一管理所有工具 - 灵活扩展:可以轻松添加自定义工具
在 Lynxe 中的实现
1. 工具定义接口
所有工具都实现 ToolCallBiFunctionDef 接口:
java
// ToolCallBiFunctionDef.java
public interface ToolCallBiFunctionDef<I>
extends BiFunction<I, ToolContext, ToolExecuteResult> {
String getServiceGroup(); // 工具分组
String getName(); // 工具名称
String getDescription(); // 工具描述
String getParameters(); // 参数定义(JSON Schema)
Class<I> getInputType(); // 输入类型
boolean isReturnDirect(); // 是否直接返回结果
boolean isSelectable(); // 是否可选
}
2. 工具注册流程
在 PlanningFactory.toolCallbackMap() 方法中:
java
// 1. 创建工具定义列表
List<ToolCallBiFunctionDef<?>> toolDefinitions = new ArrayList<>();
// 2. 添加内置工具(例如:浏览器工具、数据库工具等)
toolDefinitions.add(BrowserUseTool.getInstance(...));
toolDefinitions.add(DatabaseReadTool.getInstance(...));
toolDefinitions.add(new Bash(...));
// ... 更多工具
// 3. 将工具定义包装成 FunctionToolCallback
for (ToolCallBiFunctionDef<?> toolDefinition : toolDefinitions) {
FunctionToolCallback<?, ToolExecuteResult> functionToolCallback =
FunctionToolCallback
.builder(qualifiedKey, toolDefinition)
.description(toolDefinition.getDescriptionWithServiceGroup())
.inputSchema(toolDefinition.getParameters())
.inputType(toolDefinition.getInputType())
.toolMetadata(ToolMetadata.builder()
.returnDirect(toolDefinition.isReturnDirect())
.build())
.build();
// 4. 注册到工具回调映射
toolCallbackMap.put(qualifiedKey, functionToolCallback);
}
3. 工具调用流程
在 DynamicAgent 中调用 LLM:
java
// 1. 获取工具回调列表
List<ToolCallback> callbacks = getToolCallList();
// 2. 通过 ChatClient 调用,传递工具
Flux<ChatResponse> responseFlux = chatClient.prompt(userPrompt)
.toolCallbacks(callbacks) // 关键:传递工具列表
.stream()
.chatResponse();
// 3. LLM 返回工具调用请求
List<ToolCall> toolCalls = streamResult.getEffectiveToolCalls();
// 4. 通过 ToolCallingManager 执行工具
ToolExecutionResult result = toolCallingManager.executeToolCalls(
userPrompt, response);
典型工具示例
浏览器工具 (BrowserUseTool)
java
public class BrowserUseTool extends AbstractBaseTool<BrowserInput> {
@Override
public ToolExecuteResult run(BrowserInput input) {
// 执行浏览器操作
// 返回结果
}
}
数据库工具 (DatabaseReadTool)
java
public class DatabaseReadTool extends AbstractBaseTool<DatabaseQueryInput> {
@Override
public ToolExecuteResult run(DatabaseQueryInput input) {
// 执行数据库查询
// 返回查询结果
}
}
Tools 的优势
✅ 统一接口 :所有工具使用相同的接口,易于管理
✅ 类型安全 :编译时类型检查,减少运行时错误
✅ 框架集成 :与 Spring AI 深度集成,开箱即用
✅ 易于扩展 :实现接口即可添加新工具
✅ 统一管理:通过 ToolCallingManager 统一管理执行流程
Tools 的局限性
❌ 框架绑定 :依赖 Spring AI 框架
❌ 平台限制:主要在 Java/Spring 生态中使用
MCP (Model Context Protocol)
定义
MCP (Model Context Protocol) 是由 Anthropic 提出的一个开放协议标准,用于在 AI 应用和外部服务之间建立标准化的通信协议。它允许 AI 应用通过标准化的方式访问外部工具、资源和上下文。
核心特点
- 协议标准:跨平台、跨语言的协议标准
- 标准化通信:定义标准的消息格式和通信流程
- 外部服务集成:可以集成任何支持 MCP 的外部服务
- 资源访问:不仅支持工具调用,还支持资源访问和提示词模板
MCP 协议架构
┌─────────────┐ MCP Protocol ┌─────────────┐
│ AI Client │ ◄─────────────────────────► │ MCP Server │
│ (Lynxe) │ (JSON-RPC over │ (External) │
│ │ stdio/HTTP/SSE) │ │
└─────────────┘ └─────────────┘
AI 客户端如: Lynxe 可以通过 MCP 协议(JSON-RPC)和外部 MCP 服务器通信,通信方式可以是标准输入输出、HTTP 请求或者 SSE 推送。
在 Lynxe 中的实现
1. MCP 服务管理
McpService 负责管理 MCP 服务器连接:
java
@Component
public class McpService {
// 获取 MCP 服务器的工具回调
public List<McpServiceEntity> getFunctionCallbacks(String planId) {
// 1. 从数据库加载 MCP 配置
// 2. 建立 MCP 连接
// 3. 获取工具列表
// 4. 返回工具实体
}
}
2. MCP 工具包装
MCP 工具通过 McpTool 包装成 Spring AI Tools:
java
public class McpTool extends AbstractBaseTool<Map<String, Object>> {
private final ToolCallback toolCallback; // MCP 协议返回的 ToolCallback
@Override
public ToolExecuteResult run(Map<String, Object> inputMap) {
// 1. 将输入转换为 JSON
String jsonInput = objectMapper.writeValueAsString(inputMap);
// 2. 通过 MCP 协议调用外部服务
String result = toolCallback.call(jsonInput, null);
// 3. 处理结果并返回
return new ToolExecuteResult(result);
}
}
3. MCP 工具注册
在 PlanningFactory 中,MCP 工具被统一注册:
java
// 获取 MCP 服务的工具回调
List<McpServiceEntity> functionCallbacks = mcpService.getFunctionCallbacks(planId);
for (McpServiceEntity toolCallback : functionCallbacks) {
String serviceGroup = toolCallback.getServiceGroup();
ToolCallback[] tCallbacks = toolCallback.getAsyncMcpToolCallbackProvider()
.getToolCallbacks();
for (ToolCallback tCallback : tCallbacks) {
// 将 MCP ToolCallback 包装成 McpTool
toolDefinitions.add(new McpTool(
tCallback,
serviceGroup,
planId,
innerStorageService,
objectMapper
));
}
}
// 最终,MCP 工具也会被包装成 FunctionToolCallback
// 与内置工具一起注册到 toolCallbackMap
MCP 工具示例
假设有一个外部的文件系统 MCP 服务器:
json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"]
}
}
}
这个 MCP 服务器提供的工具会被自动注册到 Lynxe 中,就像内置工具一样使用。
MCP 的优势
✅ 标准化 :遵循行业标准协议,易于集成
✅ 跨平台 :不依赖特定框架或语言
✅ 外部服务 :可以集成任何支持 MCP 的外部服务
✅ 资源访问 :不仅支持工具,还支持资源和提示词
✅ 解耦:AI 应用与外部服务解耦,通过协议通信
MCP 的局限性
❌ 协议开销 :需要额外的协议转换层
❌ 外部依赖 :依赖外部 MCP 服务器的可用性
❌ 配置复杂:需要配置 MCP 服务器连接
Function Calling
定义
Function Calling 是 LLM 模型原生支持的能力,允许模型在生成响应时,输出特定格式的函数调用请求。这些请求通常以 JSON 格式表示,包含函数名称和参数。
核心特点
- 模型原生能力:是 LLM 模型(如 GPT-4、Claude 等)的内置功能
- 标准化格式:模型输出标准化的函数调用 JSON
- 直接调用:应用层直接解析和执行函数调用
- 模型依赖:依赖模型是否支持 Function Calling
Function Calling 流程

LLM Function Calling 流程步骤
第 1 步:接收函数定义
- 应用程序将可调用函数列表发送给 LLM API
- 包含函数名、描述、参数定义(JSON Schema)
- LLM 了解可用的外部能力
第 2 步:生成函数调用(JSON)
- LLM 根据用户输入和函数定义,决定调用哪个函数
- 生成 JSON 格式的函数调用请求
- 包含函数名和参数值
第 3 步:解析调用
- 应用程序接收 LLM 返回的函数调用 JSON
- 解析函数名和参数
- 准备执行对应函数
第 4 步:执行函数
- 应用程序执行被调用的函数
- 使用解析出的参数
- 完成实际业务逻辑(如查询数据库、调用 API 等)
第 5 步:接收结果
- 应用程序将函数执行结果返回给 LLM API
- LLM 接收结果后继续生成响应
- 可能基于结果进行后续处理或生成最终回答
Function Calling 示例
OpenAI Function Calling 格式
1. 定义函数
json
{
"functions": [
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"]
}
}
]
}
2. 模型返回函数调用
json
{
"role": "assistant",
"content": null,
"function_call": {
"name": "get_weather",
"arguments": "{\"location\": \"San Francisco, CA\", \"unit\": \"celsius\"}"
}
}
3. 应用执行函数并返回结果
json
{
"role": "function",
"name": "get_weather",
"content": "{\"temperature\": 22, \"unit\": \"celsius\", \"description\": \"Sunny\"}"
}
在 Lynxe 中的处理
虽然 Lynxe 使用 Spring AI Tools 机制,但底层模型(如 OpenAI)仍然使用 Function Calling。Spring AI 框架会自动处理转换:
java
// Spring AI 内部处理流程:
// 1. Tools → Function Calling 格式转换
// 2. 调用模型 API(使用 Function Calling)
// 3. 解析模型返回的函数调用
// 4. 执行对应的工具
// 5. 将结果转换回 Tools 格式
Function Calling 的优势
✅ 模型原生 :模型直接支持,无需额外框架
✅ 标准化 :遵循模型厂商的标准格式
✅ 直接通信 :与模型 API 直接通信,延迟低
✅ 广泛支持:主流模型都支持 Function Calling
Function Calling 的局限性
❌ 模型依赖 :依赖模型是否支持
❌ 格式固定 :需要遵循模型厂商的格式
❌ 平台绑定 :不同模型的格式可能不同
❌ 功能有限:主要是函数调用,不支持资源访问等
三者关系与区别
关系图

第一层:框架抽象层(Framework Abstraction Layer)
核心组件:Spring AI Tools
-
作用:提供统一的工具接口,屏蔽底层差异
-
特点:
-
内置工具(Built-in Tools):框架内定义的工具,如数据库工具、文件工具等
-
MCP 工具包装(MCP Tools):将外部 MCP 服务包装成统一格式
为什么需要这一层?
-
统一管理:所有工具使用相同接口
-
类型安全:Java 强类型,编译时检查
-
易于扩展:实现接口即可添加新工具
第二层:标准化协议层(Standardization Protocol)
核心组件:MCP Protocol
-
作用:跨平台、跨语言的标准化通信协议
-
特点:
-
外部服务 1、外部服务 2:支持多个 MCP 服务器
-
标准化通信:定义统一的消息格式和通信流程
为什么需要这一层?
-
解耦:应用与外部服务通过协议通信
-
标准化:遵循行业标准,易于集成
-
跨平台:不依赖特定框架或语言
第三层:模型原生能力层(Model Native Capability)
核心组件:Function Calling
-
作用:LLM 模型原生支持的函数调用能力
-
特点:
-
OpenAI API:支持 Function Calling
-
Claude API:支持 Function Calling
-
模型原生:模型直接支持,无需额外框架
详细对比表
| 维度 | Tools (Spring AI) | MCP | Function Calling |
|---|---|---|---|
| 定位层级 | 应用框架层 | 协议层 | 模型 API 层 |
| 标准化 | Spring AI 框架标准 | 行业协议标准 | 模型厂商标准 |
| 实现方式 | Java 接口实现 | 协议通信 | API 调用 |
| 工具来源 | 框架内定义 | 外部 MCP 服务器 | 应用层定义 |
| 集成方式 | 直接集成 | 通过协议集成 | 通过 API 集成 |
| 类型安全 | ✅ 强类型(Java) | ⚠️ 弱类型(JSON) | ⚠️ 弱类型(JSON) |
| 跨平台 | ❌ Java/Spring 生态 | ✅ 跨平台 | ⚠️ 模型依赖 |
| 扩展性 | ✅ 框架内扩展 | ✅ 外部服务扩展 | ⚠️ 模型能力限制 |
| 资源访问 | ✅ 支持 | ✅ 支持 | ❌ 仅函数调用 |
| 配置复杂度 | 低 | 中 | 低 |
| 性能开销 | 低 | 中(协议转换) | 低 |
| 学习曲线 | 中(需了解框架) | 中(需了解协议) | 低(直接 API) |
核心区别总结
1. 抽象层级不同
- Tools:应用框架层的抽象,提供统一的工具接口
- MCP:协议层的抽象,定义标准化的通信协议
- Function Calling:模型 API 层的抽象,模型原生能力
2. 实现方式不同
- Tools:通过 Java 接口实现,编译时类型检查
- MCP:通过 JSON-RPC 协议通信,运行时动态调用
- Function Calling:通过模型 API 调用,返回 JSON 格式
3. 工具来源不同
- Tools:框架内定义的工具(如 BrowserUseTool、DatabaseReadTool)
- MCP:外部 MCP 服务器提供的工具
- Function Calling:应用层定义的函数
4. 集成方式不同
- Tools:直接实现接口,框架自动管理
- MCP:配置 MCP 服务器,通过协议获取工具
- Function Calling:定义函数列表,模型返回调用请求
在 Lynxe 项目中的实现
关键代码位置
1. 工具注册:PlanningFactory.toolCallbackMap()
文件 :src/main/java/com/alibaba/cloud/ai/lynxe/planning/PlanningFactory.java
关键代码:
java
// 内置工具
toolDefinitions.add(BrowserUseTool.getInstance(...));
toolDefinitions.add(DatabaseReadTool.getInstance(...));
// MCP 工具
List<McpServiceEntity> functionCallbacks = mcpService.getFunctionCallbacks(planId);
for (McpServiceEntity toolCallback : functionCallbacks) {
toolDefinitions.add(new McpTool(...));
}
// 统一包装
FunctionToolCallback<?, ToolExecuteResult> functionToolCallback =
FunctionToolCallback.builder(...).build();
2. 工具调用:DynamicAgent.think()
文件 :src/main/java/com/alibaba/cloud/ai/lynxe/agent/DynamicAgent.java
关键代码:
java
List<ToolCallback> callbacks = getToolCallList();
Flux<ChatResponse> responseFlux = chatClient.prompt(userPrompt)
.toolCallbacks(callbacks)
.stream()
.chatResponse();
3. MCP 工具包装:McpTool
文件 :src/main/java/com/alibaba/cloud/ai/lynxe/mcp/model/vo/McpTool.java
关键代码:
java
public class McpTool extends AbstractBaseTool<Map<String, Object>> {
private final ToolCallback toolCallback; // MCP 协议返回
@Override
public ToolExecuteResult run(Map<String, Object> inputMap) {
String result = toolCallback.call(jsonInput, null);
return new ToolExecuteResult(result);
}
}
数据流转示例
场景:调用 MCP 文件系统工具
1. 用户请求:读取文件 /path/to/file.txt
2. PlanningFactory.toolCallbackMap()
├─ 获取 MCP 工具列表
├─ 创建 McpTool 实例
└─ 包装成 FunctionToolCallback
└─ 注册到 toolCallbackMap
3. DynamicAgent.think()
├─ 获取工具列表(包含 MCP 工具)
├─ 调用 ChatClient
│ └─ Spring AI 转换为 Function Calling 格式
│ └─ 发送到模型 API
4. 模型返回函数调用
└─ {"name": "filesystem_read_file", "arguments": {...}}
5. ToolCallingManager.executeToolCalls()
├─ 查找对应的工具(McpTool)
├─ 调用 McpTool.run()
│ └─ 通过 MCP 协议调用外部服务
│ └─ 返回文件内容
└─ 返回结果给模型
6. 模型生成最终响应
└─ 包含文件内容
使用场景建议
何时使用 Tools (Spring AI Tools)
✅ 适用场景:
- 开发框架内的核心功能工具
- 需要类型安全和编译时检查
- 工具逻辑与业务紧密相关
- 需要高性能和低延迟
示例:
- 数据库操作工具
- 文件系统操作工具
- 浏览器自动化工具
- 业务逻辑工具
何时使用 MCP
✅ 适用场景:
- 集成外部标准化服务
- 需要跨平台、跨语言集成
- 工具由第三方提供
- 需要动态加载工具
示例:
- 集成 GitHub MCP 服务器
- 集成文件系统 MCP 服务器
- 集成数据库 MCP 服务器
- 集成第三方 API 服务
何时使用 Function Calling
✅ 适用场景:
- 直接调用模型 API,不使用框架
- 简单的函数调用场景
- 不需要复杂的工具管理
- 快速原型开发
示例:
- 简单的天气查询
- 简单的计算函数
- 简单的数据转换
混合使用策略
在 Lynxe 项目中,推荐使用 Tools + MCP 的组合:
- 核心功能使用 Tools:框架内定义,类型安全,性能好
- 外部服务使用 MCP:标准化集成,易于扩展
- 统一管理:通过 Spring AI Tools 机制统一管理
总结
核心要点
- Tools (Spring AI) 是应用框架层的抽象,提供统一的工具接口和管理机制
- MCP 是协议层的标准,用于集成外部服务,最终也会被包装成 Tools
- Function Calling 是模型 API 层的能力,Spring AI 会自动处理转换
在 Lynxe 中的实际应用
- ✅ 主要使用 Tools 机制:所有工具(包括 MCP 工具)都通过 Tools 机制统一管理
- ✅ MCP 作为扩展 :MCP 工具通过
McpTool包装,无缝集成到 Tools 机制中 - ✅ Function Calling 透明:Spring AI 框架自动处理 Tools 与 Function Calling 的转换
选择建议
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 开发核心业务工具 | Tools | 类型安全、性能好、易维护 |
| 集成外部标准化服务 | MCP | 标准化、易扩展、解耦 |
| 简单快速原型 | Function Calling | 直接、简单、快速 |
| 企业级应用 | Tools + MCP | 兼顾性能和扩展性 |