AI能做到如今的“万能”,单靠它的文本输出可是不行的,我们要给他赋予使用工具的能力

首先我们先来了解

AI怎么做到工具调用(Tool Calling)?

我们要知道大模型还是那个只会输入和输出的大模型,我们听到的有工具调用能力的大模型是指:有结构化输出的功能

就是说大模型会输出:

好的,收到。。。

也会输出:

{ "tool": "searchWeb", "arguments": { "query": "上海" } }

就是靠这种输出来调用指定的工具,同时也有相关的参数,只要你把工具的描述先告诉AI就可以

(需要说明的是相关概念名词:F‏‏‏unction Calling(功‍‍‍能调用)和Tool Calling(工具调‏‏‏用)完全是同一概念,只是不同平台或⁡⁡⁡每个人习惯的叫法不同而已)

回到我们写的代码上,我们要怎么写出工具并告诉AI怎么使用呢?

Spring AI 工具开发

大概流程就是:

  1. 工具定义与注册:Spring AI 可以通过简洁的注解自动生成工具定义和 JSON Schema,让 Java 方法轻松转变为 AI 可调用的工具

  2. 工具调用请求:Spring AI 自动处理与 AI 模型的通信并解析工具调用请求,并且支持多个工具链式调用。

  3. 工具执行:Spring AI 提供统一的工具管理接口,自动根据 AI 返回的工具调用请求找到对应的工具并解析参数进行调用。

  4. 处理工具结果:Spring AI 内置结果转换和异常处理机制,支持各种复杂 Java 对象作为返回值。

  5. 返回结果给模型:Spring AI 封装响应结果并管理上下文,确保工具执行结果正确传递给模型或直接返回给用户。

  6. 生成最终响应:Spring AI 自动整合工具调用结果到对话上下文,支持多轮复杂交互。

我们可以看到其中好多都是Spring AI自动就给我们完成了,在写代码上面我要做到很简单:

首先我们用基于 Method‏‏‏s 方法用注解的方式定义工具
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();

可以在构建 ChatClien‎‎‎t 时注册默认工具,这样,这些工‏‏‏具将对从同一个 ChatClie⁡⁡⁡nt 发起的所有对话可用

你会注意到这种使用工具的方式都是专门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); } }

使用注解方‍式时‎指定‎ retur‏nD‎i‏rect ⁡参数为true即可

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐