Spring AI 工具调用(ToolCalling)完整使用教程

| 🔍 开发者资源导航 🔍 |
|---|
| 🏷️ 博客主页: 个人主页 |
| 📚 专栏订阅: JavaEE全栈专栏 |
一、前言
工具调用 (也称为函数调用 )是 AI 应用中的常见模式,它允许模型与一组 API 或工具进行交互,从而增强其功能。
ToolCalling = 让 AI 模型能主动调用你写的 Java / 代码函数,去查数据、执行操作,再把结果返回给用户。
整理成流程就是:
- 你给 AI 注册几个工具(就是你的方法:查天气、查订单、查数据库…)
- 用户问:今天北京天气?
- AI 发现自己不知道,主动决定调用哪个工具
- AI 返回给你:我要调用 xxx 工具,参数是 xx
- Spring AI 自动执行你的方法
- 把结果再丢给 AI,AI 整理成人话回答用户
二、快速开始
1. 导包,这里使用的是Spring AI ablibaba
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<dependency>
<groupId>com.github.victools</groupId>
<artifactId>jsonschema-generator</artifactId>
<!-- 可根据实际情况使用最新稳定版本 -->
<version>4.37.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-bom</artifactId>
<version>1.0.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2. 配置apikey
spring:
ai:
dashscope:
api-key: 你的apikey
申请百炼平台的apikey可参考此文档:https://help.aliyun.com/zh/model-studio/get-api-key
3. 创建工具方法
public class DateTimeTool {
@Tool(description = "获取当前时间")
String getCurrentTime() {
LocalDateTime now = LocalDateTime.now();
System.out.println(now.toString());
return now.toString();
}
}
4.创建controller层
@RequestMapping("/ali")
@RestController
public class TestController {
private ChatClient chatClient;
public TestController(DashScopeChatModel chatModel) {
this.chatClient = ChatClient.builder(chatModel)
//设置默认工具
.defaultTools(new DateTimeTool())
.build();
}
@RequestMapping(value = "/tool", produces = "text/html;charset=utf-8")
private Flux<String> toolChat(String message) {
return chatClient.prompt(message).stream().content();
}
}
5.运行


此时我们可以发现ai是已经调用过我们这个函数了,如果我们没写这个方法,ai因为是已经训练好的原因,是不能读取到外界的时间的。
三、原理

1.当我们想让模型可以使用某个工具时,我们会将其定义包含在聊天请求中。每个工具定义都包含名称、描述和输入参数的模式。
2.当模型决定调用某个工具时,它会发送一个响应,其中包含工具名称和根据已定义模式建模的输入参数。
3.使用工具名称来识别和执行该工具,并根据提供的输入参数进行操作。
4.返回工具调用的结果
5.将工具调用结果发送回模型
6.将结果交给模型进行润色,最后返回结果。
四、声明式定义
4.1 参数讲解
声明式定义是指使用注解的方式来定义工具,可参考快速开始的代码。
该注解具有以下参数:
public @interface Tool {
String name() default "";
String description() default "";
boolean returnDirect() default false;
Class<? extends ToolCallResultConverter> resultConverter() default DefaultToolCallResultConverter.class;
}
- name:name是一个工具的唯一字段,不设置的时候默认使用方法名称来定义,该字段不能重复,一旦重复调用的时候就会报错。
- description:是指这个工具方法的描述,模型会通过该参数判断是否要调用该方法,因此这个参数务必要清晰精准。
- returnDirect:默认为false,如果returnDirect为true,那么调用的结果就会直接返回,不会经过ai的润色。
下述代码将展示returnDirect为true的样例:
@Tool(description = "获取当前时间", returnDirect = true)
String getCurrentTime() {
LocalDateTime now = LocalDateTime.now();
System.out.println(now.toString());
return now.toString();
}

也就是说,即使你问的问题可能和它不相关,但是涉及到了这个工具的调用,它也会直接返回这个结果。
4.2 传参
使用@ToolParam对参数进行声明,声明后ai会自动根据场景进行传参,和@Tool一样它也需要写入一个描述的参数。
@Tool(description = "设置闹钟")
void alertTime(@ToolParam(description = "设置的时间,格式为ISO-8601") String time){
System.out.println(time);
}
(调用了时间工具,和闹钟工具⬇️)

因为AI具有一定的随机性,因此每次回答都可能产生不同的结果。
五、编程式定义
编程式比声明式的定义写法要麻烦很多,但是相对会更灵活一些。
首先定义一个工具方法:
public class DateTimeTool {
String getCurrentTime1() {
LocalDateTime now = LocalDateTime.now();
System.out.println(now.toString());
return now.toString();
}
}
再定义其配置类
public class ToolConfig {
@Bean
public ToolCallback toolCallback(){
//通过反射获取方法
Method method = ReflectionUtils.findMethod(DateTimeTool.class, "getCurrentTime1");
//创建一个toolCallback
ToolCallback dateTimeToolCallback = MethodToolCallback.builder()
.toolDefinition(ToolDefinitions.builder(method)
//写描述
.description("获取当前的时间")
.build())
.toolMethod(method)
.toolObject(new DateTimeTool())
.build();
return dateTimeToolCallback;
}
}
最后再配置到ChatClient里面
@RequestMapping("/ali")
@RestController
public class TestController {
private ChatClient chatClient;
//当前类的初始方法
public TestController(DashScopeChatModel chatModel, ToolCallback toolCallback) {
this.chatClient = ChatClient.builder(chatModel)
.defaultToolCallbacks(toolCallback)
.build();
}
@RequestMapping(value = "/tool1", produces = "text/html;charset=utf-8")
private Flux<String> toolChat1(String message) {
return chatClient
.prompt(message)
.stream()
.content();
}
}

编程式定义的传参和声明式是一样的,也是使用@ToolParam来定义:
void alertTime(@ToolParam(description = "设置的时间,格式为ISO-8601") String time){
System.out.println(time);
}
因为方式一样,这里就不多赘述。
更多内容可以参考Spring AI的官方文档
Spring AI官方文档
https://docs.spring.io/spring-ai/reference/api/tools.html#_tool_context
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)