Spring AI Alibaba学习记录(函数/方法调用)
在刚接触时我会搞混 MCP 和 Function Calling (函数调用)。因为两者本质都是“让 AI 自主调用某项工具/功能”,但在架构和使用场景上是有区别的。下面先简单辨析一下,等有时间了会专门了解 MCP:
-
MCP (Model Context Protocol):
- 通常分为 客户端 (Client) 和 服务端 (Server)。
- Agent 使用 MCP 本质上是跨进程甚至跨网络调用另一个项目或服务提供的能力。
- 服务端通常 是一个独立的项目,负责提供具体的功能实现。
- 你想的没错,OpenClaw 就是深度集成 MCP,想了解的话建议直接去学习 Python 的 LangChain。
-
Function Calling (函数调用):
- 通常是 内嵌 在当前项目中的。
- Agent 调用的是当前项目中的 Java 方法 (Function),操作仅仅在一个应用进程内进行。
- 原理: 让 Agent (LLM) 分析用户输入的 关键词,然后在你提供的工具列表中 自主决策 使用哪个函数,并提取参数。Agent 返回决策结果(要调用的函数名和参数),框架执行该函数,并将结果返回给 Agent 进行最终回复。
2. 快速入门:使用注解定义工具
秉承面向注解开发的理念,我们直接通过官方提供的 @Tool 注解,将 Java 方法变成 AI 可调用的工具。(其实是因为通过编程方式,使用底层 MethodToolCallback 实现我看不懂)
2.1 定义工具类
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.context.i18n.LocaleContextHolder;
import java.time.LocalDateTime;
public class DateTimeTools {
@Tool(description = "获取用户当前时区的日期和时间。当用户问'现在几点了'或'今天几号'时使用。")
public String getCurrentDateTime() {
return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
}
}
2.2 将工具提供给模型
在 Controller 中,通过 .tools() 方法将工具实例注册给 ChatClient。
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AIController {
private final ChatClient chatClient;
public AIController(ChatClient.Builder builder, ChatMemory chatMemory) {
// 初始化 ChatClient,挂载记忆功能
this.chatClient = builder
.defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory))
.build();
}
@GetMapping("/ai")
public String generation(@RequestParam String userInput,
@RequestParam String conversationId) {
return this.chatClient.prompt()
.user(userInput)
//直接实例化并注册工具!!!!!!!!!!!!
.tools(new DateTimeTools())
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
.call()
.content();
}
}
3. 进阶:使用 @ToolParam 增强参数描述
在 Spring AI 中,@ToolParam 的核心作用是为 AI 提供参数的上下文描述。
由于 AI 本质上是根据语义(语义理解)来决定给你的函数传什么值,如果你的参数名不够直白(比如叫 id 而不是 orderId),AI 可能会传错值。@ToolParam 就是为了解决这个“沟通障碍”。
3.1 情景一:传参内容“缺斤少两”
当你的方法参数名比较通用,或者需要特定格式时,必须通过描述告诉 AI 到底要传什么。
@Service
public class WeatherService {
@Tool(description = "获取指定城市的天气预报")
public String getWeather(
@ToolParam(description = "城市的中文全称,例如:北京市、上海市") String city,
@ToolParam(description = "预报天数,最多支持7天") int days
) {
return "查询中...";
}
}
- 问题: “帮我查找一下北京近几天的天气”
- 期望结果: 北京最近 7 天的天气情况
- 出现的问题: 由于没有指定查询几天的规定,AI 则会出现幻觉可能查询 8 天?15 天?反正有概率不是 7 天,但是数据库最多只有 7 天的记录,所以会出现查询异常。
(我知道有人可能会想:让 Agent 再反问回去确定查询几天不就行了?token 消耗警告!!!)
3.2 情景二:处理“隐晦”的业务逻辑
有时候参数是一个代码或缩写,人类开发者懂,但 AI 可能拿不准。
@Service
public class OrderService {
@Tool(description = "修改订单状态")
public void updateOrderStatus(
@ToolParam(description = "订单的唯一序列号") String sn,
@ToolParam(description = "状态码:1代表待发货,2代表已发货,3代表已签收") int status
) {
// 业务代码
}
}
- 痛点: AI 看到
int status时,不知道该传 1 还是传 2。 - 解决: 在注解里直接告诉 AI 状态码的映射关系。
3.3 情景三:控制参数是否可选
在最新的 Spring AI 版本中,@ToolParam 还可以用来显式标记某个参数是否是必填的。
@Tool(description = "搜索图书")
public List<Book> searchBooks(
@ToolParam(description = "书名关键字") String keyword,
@ToolParam(description = "作者姓名", required = false) String author
) {
// 如果用户没提作者,AI 就会只传 keyword
return database.find(keyword, author);
}
- 问题: “帮我查找有关《三体》的书籍”
- 期望结果: 返回刘慈欣的三体书籍信息
- 出现的问题: 因为没有指定作者,AI 可能会自动填充为其他作者(有概率不是刘慈欣,
咱就说有没有可能嘛),由此给函数的参数为:keyword= “三体”author= “张三”- 这就导致了查询异常,因为数据库中没有“张三”的书籍。
如果你不写
@ToolParam,Spring AI 会默认尝试使用 Java 的参数名作为描述,但如果你的代码被混淆 (Confuse) 或者编译时没开启-parameters参数,AI 拿到的描述就会是空,极易出错。
4. 方法作为工具的限制
虽然 Spring AI 支持将大多数 Java 方法转换为工具,但也存在一些限制,主要体现在不支持的类型和命名规范上。
4.1 不支持的类型
以下类型目前不支持作为 @Tool 注解方法的参数或返回值:
- 异步类型 (Asynchronous types): 如
CompletableFuture,Future。 - 响应式类型 (Reactive types): 如
Flow,Mono,Flux。 - 函数式类型 (Functional types): 如
Function,Supplier,Consumer。- 注:函数式类型可以通过
FunctionCallback编程式注册,但不支持直接用@Tool注解。
- 注:函数式类型可以通过
注意: 方法的返回值必须是可序列化的,因为结果需要被序列化成 JSON 文本传回给 AI 模型。
4.2 命名唯一性
- 工具名称必须唯一: 在同一个
ChatClient请求上下文中,不能存在两个同名的工具。 - 如果不指定
@Tool(name = "..."),默认使用方法名作为工具名。因此,避免在不同类中使用相同的方法名注册为工具,或者显式指定不同的name。
该文章内容还有好多东西并没有写出来比如工具回调(FunctionToolCallback),Agent返回数据结构化(JSON)等等建议想深入了解的去官网
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)