从 Tool Calling 到 MCP:让 AI 调用真实世界能力的入门实践
很多人第一次接触大模型时,会以为它只会聊天:输入一段文字,输出一段文字。但在真实业务中,我们希望 AI 能做更多事情:查询订单、获取天气、检索公司知识库、创建工单、生成图片,甚至调用地图服务规划路线。
这些能力不是模型“天生就会”,而是通过 Tool Calling(工具调用)连接到你的程序和外部系统。
本文以 Java 和 Spring AI 为例,系统说明 Tool Calling 是什么、普通 Tool 如何实现、它与 MCP 的区别,以及上线时需要注意的安全边界。
一、为什么大模型需要工具?
大模型擅长理解自然语言、总结内容、生成文本和进行推理,但它也有明显边界:
- 不一定知道今天的实时天气、股价或新闻;
- 不能直接访问你的订单系统、CRM 或公司数据库;
- 不应直接拥有发邮件、退款、删除数据等执行权限;
- 在精确计算、实时查询和业务操作上,不能只依赖模型猜测。
例如用户问:
我的订单什么时候送到?
模型自己无法知道订单物流状态。正确做法是让模型识别出“需要查询订单”,再由后端调用真实订单服务,最后把查询结果交给模型组织成自然语言回复。
这就是 Tool Calling 的核心价值:
模型负责理解、选择和表达;程序负责权限、执行与真实结果。
二、Tool Calling 不是让模型直接运行代码
Tool Calling 的名称容易让人误会。模型并不会直接运行 Java 方法,也不会直接访问数据库或互联网。
模型实际做的是返回一个结构化的“调用请求”。假设后端告诉模型有一个天气工具:
{
"name": "get_weather",
"description": "查询指定城市的实时天气",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
}
}
用户问“杭州天气怎么样”时,模型可能返回:
{
"name": "get_weather",
"arguments": {
"city": "杭州"
}
}
随后由你的应用执行真实逻辑:
模型提出调用请求
↓
后端校验参数和用户权限
↓
后端调用天气 API
↓
后端把天气结果返回给模型
↓
模型生成最终回复
因此,Tool Calling 可以看成一种“模型与程序之间的结构化协作协议”。
三、普通 Tool 最常见的实现方式
在 Spring AI 中,一个 Tool 通常就是一个带 @Tool 注解的 Java 方法。方法内部可以调用任何受控的业务能力。
1. 封装本项目的业务 Service
例如,让 AI 查询当前用户的订单:
@Component
public class OrderTools {
private final OrderService orderService;
public OrderTools(OrderService orderService) {
this.orderService = orderService;
}
@Tool(description = "查询指定订单的详情和物流状态,只允许查询当前登录用户自己的订单")
public OrderInfo getOrderDetail(
@ToolParam(description = "订单 ID") Long orderId,
@ToolContext UserContext userContext
) {
return orderService.findForUser(orderId, userContext.userId());
}
}
真正处理订单业务的仍是 OrderService。Tool 的职责是提供一个参数明确、权限可控、可被模型理解的入口。
2. 封装第三方 HTTP API
天气、地图、快递、汇率等能力通常来自第三方服务:
@Tool(description = "查询指定城市的实时天气")
public WeatherResult getWeather(
@ToolParam(description = "城市名称,例如杭州") String city
) {
return weatherClient.getCurrentWeather(city);
}
调用关系为:
LLM → Spring AI Tool → weatherClient → 第三方天气 API
3. 查询数据库或知识库
例如查询当前用户最近的订单:
@Tool(description = "查询当前用户最近五条订单记录")
public List<OrderSummary> getRecentOrders(
@ToolContext UserContext userContext
) {
return orderRepository.findTop5ByUserIdOrderByCreatedAtDesc(
userContext.userId()
);
}
不要把“执行任意 SQL”暴露给模型。应该将查询封装成明确的业务操作,例如“查询当前用户订单”“查询商品库存”。
4. 执行有副作用的操作
创建工单、取消订单、发邮件、发消息等操作,也可以做成 Tool:
@Tool(description = "为当前用户创建售后工单,需要订单号和问题描述")
public TicketResult createAfterSaleTicket(
@ToolParam(description = "订单号") Long orderId,
@ToolParam(description = "售后原因") String reason,
@ToolContext UserContext userContext
) {
return ticketService.create(userContext.userId(), orderId, reason);
}
但这类工具不能因为模型想调用就立刻执行。更稳妥的流程是:模型先生成操作草稿,用户确认后,再允许后端真正调用工具。
5. 创建异步任务
文生图、文生音频、文生视频、批量报表等操作可能耗时很长,不适合让请求一直等待。
@Tool(description = "根据文字描述创建视频生成任务,返回任务 ID,不等待视频生成完成")
public VideoTask createVideoTask(
@ToolParam(description = "视频画面描述") String prompt
) {
return videoService.submit(prompt);
}
工具先返回:
{
"taskId": "video_001",
"status": "processing"
}
之后再通过“查询任务状态”的 Tool 获取最终视频地址。
四、Spring AI 中如何注册和使用 Tool?
以“当前时间”和“天气查询”为例:
public class DateTimeTools {
@Tool(description = "获取服务器当前的中国标准时间")
public String getCurrentDateTime() {
return LocalDateTime.now(ZoneId.of("Asia/Shanghai")).toString();
}
}
调用聊天模型时注册工具:
return chatClient.prompt()
.tools(new DateTimeTools(), new WeatherTools())
.user(message)
.stream()
.content();
当模型发现问题需要实时信息时,会请求调用对应工具;Spring AI 会根据工具名称匹配 Java 方法、传入参数、接收返回值,并将结果再次交给模型生成最终回答。
要注意,工具名称、描述和参数定义非常重要。模型不知道你的业务代码,只能根据这些信息判断是否应该调用工具。
不清晰的描述:
@Tool(description = "订单工具")
更好的描述:
@Tool(description = "查询指定订单的物流状态,只读操作,不修改订单")
五、Tool Calling、Function Calling 和 Agent 的关系
不同框架有时会使用不同名称:
| 名称 | 含义 |
|---|---|
| Function Calling | 较早、较常见的称呼,强调调用函数 |
| Tool Calling | 更宽泛的称呼,工具不一定只是本地函数 |
| Agent | 在多轮中规划、选择工具、执行并根据结果继续决策的系统 |
Tool Calling 是 Agent 的基础能力,但单次 Tool Calling 不等于完整 Agent。
例如用户说:
查北京明天是否下雨;如果下雨,推荐室内活动并给我发邮件。
一个 Agent 可能经历:
- 调用天气 Tool;
- 判断是否下雨;
- 调用知识库或搜索 Tool 获取室内活动;
- 生成邮件草稿;
- 获得用户确认;
- 调用邮件 Tool 执行发送。
其中每一次“调用天气”“查询知识库”“发送邮件”都是 Tool Calling;Agent 则负责整个任务的编排与决策。
六、MCP 和普通 Tool 有什么区别?
普通 Tool 常常直接写在当前项目中:
Spring Boot 应用
├── OrderTools
├── WeatherTools
└── ImageGenerationTools
而 MCP(Model Context Protocol)是一套让外部系统以统一方式提供能力的协议。典型结构如下:
AI 应用(MCP Client)
↓
MCP Server
↓
地图、Git 仓库、知识库、数据库或企业系统
MCP Server 可以向 AI 应用提供:
- Tools:可执行操作,例如查询地图、创建工单;
- Resources:可读取资源,例如文档、配置和数据;
- Prompts:可复用的提示模板。
普通 Tool 与 MCP 并不是对立关系。MCP Server 暴露的 Tool,最终也会成为模型可以选择的工具。
更准确的理解是:
普通 Tool 是当前应用内直接注册的工具;MCP 是跨进程、跨服务、跨团队暴露和发现工具的标准协议。
如果只是让 AI 查询当前项目订单,直接写本地 Tool 往往最简单;如果地图、知识库、代码仓库等能力需要被多个应用复用,把它做成 MCP Server 会更合适。
七、工具设计的五条原则
1. 一个 Tool 只做一件事
推荐:
get_order_detail(orderId)
cancel_pending_order(orderId)
get_current_weather(city)
不推荐:
manage_order(action, arbitraryData)
工具职责越单一,模型越容易正确选择,权限控制也越清晰。
2. 参数要少且语义明确
不要让模型猜复杂对象的格式。为每个参数写清楚用途、格式和示例。
3. 返回结构化数据,而不是长篇文案
例如:
public record WeatherResult(
String city,
String condition,
Integer temperature
) {}
模型可以基于结构化结果组织不同风格的回答,前端也能直接展示数据。
4. 工具内部必须完成鉴权和校验
模型的参数不是可信输入。工具必须验证:
- 用户是否登录;
- 是否有操作权限;
- 参数是否为空、越界或格式错误;
- 操作对象是否属于当前用户;
- 是否命中限流、风控或业务规则。
5. 有副作用的操作应当可审计、可确认、可重试
对于发送邮件、退款、下单、删除数据等操作,至少需要:
- 用户确认;
- 审计日志;
- 幂等键,避免重复执行;
- 超时和失败处理;
- 清晰的错误返回。
八、常见风险与错误做法
直接信任模型参数
错误做法是将模型生成的 userId、金额、订单号直接用于数据库操作。模型可能理解错上下文,也可能受到恶意提示词影响。
正确做法是从登录态或服务端上下文中获取真实用户身份,而不是相信模型传来的身份字段。
暴露万能高危工具
下面这类工具风险极高:
execute_any_sql(sql)
run_shell_command(command)
send_email(to, body)
应改为面向业务的受限能力,例如:
get_user_orders()
create_support_ticket()
draft_email()
把 Tool 当作 RAG
RAG 的重点是检索资料,为模型补充知识;Tool 的重点是获得实时结果或执行操作。
| 技术 | 解决的问题 |
|---|---|
| RAG | 企业制度、产品文档、历史资料等知识检索 |
| Tool Calling | 查订单、查天气、生成文件、执行业务动作 |
| Agent | 多步骤规划和工具编排 |
| MCP | 标准化连接外部工具、资源和提示模板 |
九、总结
Tool Calling 的本质不是“让 AI 随意操作系统”,而是让 AI 在受控范围内调用程序提供的能力。
一个完整的职责分工可以这样记:
用户:提出自然语言需求
模型:理解需求,决定是否调用工具,生成参数与最终回答
应用:鉴权、参数校验、执行业务逻辑、记录审计日志
Tool:受控地封装查询、计算或操作能力
MCP:让不同服务以统一协议提供和发现这些能力
从一个“查询当前时间”的本地 Tool 开始,是理解 Tool Calling 最好的方式。之后再接入订单、天气、知识库、地图等真实业务能力,最后使用 MCP 将可复用能力独立为标准化服务,就能逐步构建出可靠的 AI 应用与 Agent 系统。