Spring AI 入门级学习 4:工具调用
AI能做到如今的“万能”,单靠它的文本输出可是不行的,我们要给他赋予使用工具的能力
首先我们先来了解
AI怎么做到工具调用(Tool Calling)?
我们要知道大模型还是那个只会输入和输出的大模型,我们听到的有工具调用能力的大模型是指:有结构化输出的功能
就是说大模型会输出:
好的,收到。。。
也会输出:
{ "tool": "searchWeb", "arguments": { "query": "上海" } }
就是靠这种输出来调用指定的工具,同时也有相关的参数,只要你把工具的描述先告诉AI就可以
(需要说明的是相关概念名词:Function Calling(功能调用)和Tool Calling(工具调用)完全是同一概念,只是不同平台或每个人习惯的叫法不同而已)
回到我们写的代码上,我们要怎么写出工具并告诉AI怎么使用呢?
Spring AI 工具开发
大概流程就是:
-
工具定义与注册:Spring AI 可以通过简洁的注解自动生成工具定义和 JSON Schema,让 Java 方法轻松转变为 AI 可调用的工具
-
工具调用请求:Spring AI 自动处理与 AI 模型的通信并解析工具调用请求,并且支持多个工具链式调用。
-
工具执行:Spring AI 提供统一的工具管理接口,自动根据 AI 返回的工具调用请求找到对应的工具并解析参数进行调用。
-
处理工具结果:Spring AI 内置结果转换和异常处理机制,支持各种复杂 Java 对象作为返回值。
-
返回结果给模型:Spring AI 封装响应结果并管理上下文,确保工具执行结果正确传递给模型或直接返回给用户。
-
生成最终响应:Spring AI 自动整合工具调用结果到对话上下文,支持多轮复杂交互。
我们可以看到其中好多都是Spring AI自动就给我们完成了,在写代码上面我要做到很简单:
首先我们用基于 Methods 方法用注解的方式定义工具
class WeatherTools {
@Tool(description = "Get current weather for a location")
public String getWeather(@ToolParam(description = "The city name") String city) {
return "Current weather in " + city + ": Sunny, 25°C";
}
}
// 使用方式
ChatClient.create(chatModel)
.prompt("What's the weather in Beijing?")
.tools(new WeatherTools())
.call();
可以看到使用了@Tool(description="工具描述")、@ToolParam(description = "工具参数描述")、.tools(创建工具类对象),这样Spring AI就可以帮我们让大模型完成工具的调用
(这里要说明工具方法定义的参数和返回类型有一些是不支持的: 异步类型(如 CompletableFuture, Future) 响应式类型(如 Flow, Mono, Flux) 函数式类型(如 Function, Supplier, Consumer) )
再给大家举一个文件操作工具的例子
public class FileOperationTool {
// 文件保存目录
private final String FILE_DIR = FileConstant.FILE_SAVE_DIR + "/file";
@Tool(description = "从一个文件中读内容")
public String readFile(@ToolParam(description = "要读取文件的名字") String fileName) {
String filePath = FILE_DIR + "/" + fileName;
try {
return FileUtil.readUtf8String(filePath);
} catch (Exception e) {
return "Error reading file: " + e.getMessage();
}
}
@Tool(description = "给一个文件写内容")
public String writeFile(
@ToolParam(description = "要写的文件的名字") String fileName,
@ToolParam(description = "要写的内容") String content) {
String filePath = FILE_DIR + "/" + fileName;
try {
// 创建目录
FileUtil.mkdir(FILE_DIR);
FileUtil.writeUtf8String(content, filePath);
return "File written successfully to: " + filePath;
} catch (Exception e) {
return "Error writing to file: " + e.getMessage();
}
}
}
接着我们再重点说说工具的使用和注册
除了.tools(new创建工具类对象)在一次对话中使用外,还有个全局使用
ChatClient chatClient = ChatClient.builder(chatModel) .defaultTools(new WeatherTools(), new TimeTools()) // 注册默认工具 .build();
可以在构建 ChatClient 时注册默认工具,这样,这些工具将对从同一个 ChatClient 发起的所有对话可用
你会注意到这种使用工具的方式都是专门new出来一个,有点不符合Spring的控制反转理念啊,所以我们可以用ToolCallback创建一个Spring可以管理的工具注册类
@Configuration public class ToolRegistration {
@Bean
public ToolCallback[] allTools() {
FileOperationTool fileOperationTool = new FileOperationTool();
WebSearchTool webSearchTool = new WebSearchTool(searchApiKey);
return ToolCallbacks.from(
fileOperationTool,
webSearchTool,
);
}
}
这样可以将所有的工具统一管理,使用时注入
@Resource private ToolCallback[] allTools;
public String doChatWithTools(String message, String chatId) { ChatResponse response = chatClient .prompt() .user(message)
.tools(allTools)
.call()
.chatResponse();
String content = response.getResult().getOutput().getText();
return content;
}
接下来我们再来说一些其他
补充知识
工具上下文
AI需要知道每一个参数才能调用工具方法,但有时候我们不想让AI知道一些参数的值,而怎么办呢,那就需要工具上下文(其实就是个Map)作参数了
String response = chatClient .prompt("帮我查询用户信息") .tools(new CustomerTools()) .toolContext(Map.of("userName", "kui")) // 在工具方法中可以使用 .call() .content();
class CustomerTools {
@Tool(description = "")
Customer getCustomerInfo(Long id, ToolContext toolContext) {
return customerRepository.findById(id, toolContext.getContext().get("userName"));
}
}
立即返回功能
有时候,工具执行的结果不需要再经过 AI 模型处理,而是希望直接返回给用户(比如生成 PDF 文档)。Spring AI 通过 returnDirect 属性支持这一功能
class CustomerTools { @Tool(description = "", returnDirect = true) Customer getCustomerInfo(Long id) { return customerRepository.findById(id); } }
使用注解方式时指定 returnDirect 参数为true即可
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)