Spring AI 工具(Tool)调用

在 AI 大模型的能力体系中,工具调用是一项关键功能,它让模型突破了自身知识库和计算能力的局限,能够与外部系统、工具或服务交互,从而更高效地解决复杂问题。

工具调用(也称函数调用)是 AI 应用的常见模式,允许模型通过与一组 API(即工具)交互来扩展其能力。

工具调用的核心概念:

  • 工具:指能被模型调用以完成特定任务的外部资源,涵盖 API 接口(如天气查询、支付接口)、数据库查询语句、代码解释器、文件处理工具、搜索引擎等。这些工具为模型提供了实时数据获取、复杂计算、特定功能实现等能力。

  • 工具调用:是 AI 大模型根据用户需求或任务目标,自主决定调用合适的工具,并通过特定格式将请求参数传递给工具,再接收工具返回结果,最终整合结果生成回答的过程。注意:AI 大模型不执行具体工具调用,仅仅给出要使用哪些参数调用哪个工具的描述信息。

  • 客户端应用程序:在工具调用流程中扮演着 “中介” 和 “执行者” 的角色。它负责提供工具调用的核心逻辑,接收模型的工具调用请求,执行具体的工具调用操作,然后将工具返回的结果传递回模型。

工具主要应用于以下场景:

  • 信息检索:此类工具可用于从外部源检索信息,例如数据库、网络服务、文件系统或网络搜索引擎。其目的是增强模型的知识,使其能够回答原本无法回答的问题。因此,它们可用于检索增强生成(RAG)场景。例如,可以使用工具检索给定位置的当前天气、检索最新新闻文章或查询数据库中的特定记录。

  • 执行操作:此类工具可用于在软件系统中执行操作,例如发送电子邮件、在数据库中创建新记录、提交表单或触发工作流。其目的是自动化那些原本需要人工干预或显式编程的任务。例如,可以使用工具为与聊天机器人交互的客户预订航班、填写网页上的表单,或在代码生成场景中基于自动化测试(TDD)实现 Java 类。

尽管我们常将工具调用归为模型的能力范畴,但实际上,工具调用的核心逻辑是由客户端应用程序承载的。模型仅能发起工具调用请求并提供所需的输入参数,而具体的工具调用执行过程及结果返回,则由应用程序全权负责。值得强调的是,模型始终无法直接访问任何作为工具存在的API接口——这一点正是保障系统安全的关键设计考量。

Spring AI 提供了简洁易用的 API,用于工具定义、模型工具调用请求的解析以及工具调用的执行流程。下文将简单介绍两个例子,快速对 Spring AI 中的工具调用功能有个简单认识,后续将详细介绍工具调用。

  

入门示例

下面我们来看看如何在 Spring AI 中使用工具调用功能。我们将实现两个简单的工具:一个用于信息检索,另一个用于执行操作。信息检索工具将用于获取用户所在时区的当前日期和时间,而操作工具将用于设置指定时间的闹钟。

信息检索

AI 模型无法获取实时信息。任何需要知晓当前日期或天气预报等实时信息的问题,模型都无法直接回答。但我们可以提供能够检索这类信息的工具,当需要访问实时数据时,让模型调用这些工具。

下面我们在 DateTimeTools 类中实现一个获取用户所在时区当前日期时间的工具。该工具将不接收任何参数,通过 Spring Framework 的 LocaleContextHolder 获取用户时区信息。我们将使用 @Tool 注解来定义这个工具方法,并通过详细的工具描述帮助模型理解是否及何时调用该工具。

在 Spring AI 中,@Tool 是核心注解之一,用于将普通 Java 方法标记为可被 AI 模型调用的工具(Tool),是实现 “模型-工具交互” 的关键机制。通过 @Tool 注解,开发者可以快速定义工具能力,让 AI 模型根据用户需求自动触发对应的方法调用,从而拓展模型的功能边界(如调用外部 API、执行数据处理等)。

示例代码如下:

(1)编写一个简单的工具:

package com.hxstrive.springai.springai_openai.tools1;

import java.time.LocalDateTime;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.context.i18n.LocaleContextHolder;

public class DateTimeTools {

    // 定义一个工具,和普通方法没有什么区别,仅多了一个 @Tool 注解
    // 注意,description 是工具的描述信息,要编写准确清晰,便于AI准确发现
    @Tool(description = "获取用户所在时区的当前日期和时间")
    public String getCurrentDateTime() {
        System.out.println("->> getCurrentDateTime() 获取用户所在时区的当前日期和时间");
        return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }

}

(2)接下来我们将上述工具(DateTimeTools)提供给模型使用。在本例中,我们将使用 ChatClient 与模型交互。我们将通过 tools() 方法传递 DateTimeTools 实例来向模型提供工具。当模型需要知道当前日期和时间时,它将请求调用该工具。在内部,ChatClient 将调用该工具并将结果返回给模型,模型随后将使用工具调用结果生成对原始问题的最终响应。代码如下:

package com.hxstrive.springai.springai_openai.tools1.controller;

import com.hxstrive.springai.springai_openai.tools1.DateTimeTools;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
class MyController {

    @Autowired
    private ChatModel chatModel;

    // 模型使用 gpt-4-turbo
    // GPT-4 全面支持工具调用功能,且在处理复杂度、准确性和灵活性上显著优于 GPT-3.5-turbo
    // http://localhost:8080/ai?topic=海盗&adjective=幽默
    @GetMapping(value = "/ai",produces = "text/html; charset=UTF-8")
    public String ai() {
        ChatClient chatClient = ChatClient.builder(chatModel)
                .defaultSystem("你是AI助手小粒,所有回复均使用中文。")
                .defaultAdvisors(
                        new SimpleLoggerAdvisor() // 输出聊天日志
                )
                .build();

        return chatClient
                // 提示词
                .prompt("明天是星期几?")
                // 设置可用的工具给大模型,让大模型知道有哪些工具可以使用
                .tools(new DateTimeTools())
                .call().content();
    }

}

运行示例,使用浏览器访问 http://localhost:8080/ai 地址,输出结果如下:

image.png

查看后端打印的日志,如下图:

image.png

根据输出日志,可以确定,确实调用了我们自定义的工具。

你可以再次提出同样的问题。这一次,不要向模型提供工具(将 .tools(new DateTimeTools()) 语句注释掉)。输出结果如下:

image.png

image.png

如果没有这个工具,模型就不知道如何回答问题,因为它没有能力确定当前的日期和时间。

  

执行操作

AI 模型可用于生成实现特定目标的计划。例如,模型可以生成一个前往丹麦旅行的预订计划。但模型本身不具备执行计划的能力,这正是工具的用武之地:它们能执行模型生成的计划。

在前面的例子中,我们使用工具来确定当前的日期和时间。在本例中,我们将定义第二个工具,用于在特定时间设置闹钟。我们的目标是设置一个从现在开始 10 分钟的闹钟,因此需要向模型同时提供这两个工具来完成此任务。

我们将在之前的 DateTimeTools 类中添加这个新工具。该工具将接收一个 ISO-8601 格式的时间参数,并在控制台打印消息,提示已为指定时间设置闹钟。与之前一样,这个工具通过 @Tool 注解的方法定义,我们同样会提供详细描述,帮助模型理解何时及如何使用该工具。

ISO 8601 是由国际标准化组织(ISO)制定的日期和时间表示法国际标准,旨在统一全球日期时间的书写格式,避免歧义。其核心原则是 “年在前,月在中,日在后,时间按小时、分钟、秒顺序排列”,并支持从简单日期到复杂时间间隔的多种场景。

示例代码如下:

(1)定义工具

package com.hxstrive.springai.springai_openai.tools2;

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.context.i18n.LocaleContextHolder;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class DateTimeTools {

    @Tool(description = "获取用户所在时区的当前日期和时间")
    public String getCurrentDateTime() {
        System.out.println("->> getCurrentDateTime() 获取用户所在时区的当前日期和时间");
        return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }

    @Tool(description = "根据 ISO-8601 格式设置用户在指定时间的闹钟")
    public void setAlarm(String time) {
        System.out.println("->> setAlarm() 根据 ISO-8601 格式设置用户在指定时间的闹钟, time=" + time);
        LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println("->> 闹钟设置为 " + alarmTime);
    }

}

(2)接下来我们将这两个工具都提供给模型使用。我们将使用 ChatClient 与模型交互,通过 tools() 方法传入 DateTimeTools 实例来提供工具。当我们要求设置一个 10 分钟后的闹钟时,模型首先需要知道当前日期和时间,然后利用当前时间计算闹钟时间,最后使用闹钟工具设置闹钟。在内部,ChatClient 将处理模型发出的所有工具调用请求,并将工具执行结果返回给模型,使模型能够生成最终响应。代码如下:

package com.hxstrive.springai.springai_openai.tools2.controller;

import com.hxstrive.springai.springai_openai.tools2.DateTimeTools;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
class MyController {

    @Autowired
    private ChatModel chatModel;

    // 模型使用 gpt-4-turbo
    // GPT-4 全面支持工具调用功能,且在处理复杂度、准确性和灵活性上显著优于 GPT-3.5-turbo
    // http://localhost:8080/ai?topic=海盗&adjective=幽默
    @GetMapping(value = "/ai",produces = "text/html; charset=UTF-8")
    public String ai() {
        ChatClient chatClient = ChatClient.builder(chatModel)
                .defaultSystem("你是AI助手小粒,所有回复均使用中文。")
                .defaultAdvisors(
                        new SimpleLoggerAdvisor() // 输出聊天日志
                )
                .build();

        return chatClient
                // 提示词
                .prompt("你能设置一个从现在起10分钟后的闹钟吗?")
                // 设置可用的工具给大模型,让大模型知道有哪些工具可以使用
                .tools(new DateTimeTools())
                .call().content();
    }

}

运行示例,使用浏览器访问 http://localhost:8080/ai 地址,输出结果如下:

Spring AI 工具(Tool)调用

查看后端打印的日志,如下图:

image.png

从上述日志可知,分别调用了 getCurrentDateTime() 和 setAlarm() 工具,将闹钟时间设置为“2025-08-05T20:51:17.234861900”。

更多关于工具调用的知识将在后续单独章节进行详细介绍,上面只是初步了解如何通过 Spring AI 进行工具调用。

  

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号