在 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 地址,输出结果如下:
查看后端打印的日志,如下图:
根据输出日志,可以确定,确实调用了我们自定义的工具。
你可以再次提出同样的问题。这一次,不要向模型提供工具(将 .tools(new DateTimeTools()) 语句注释掉)。输出结果如下:
如果没有这个工具,模型就不知道如何回答问题,因为它没有能力确定当前的日期和时间。
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 地址,输出结果如下:
查看后端打印的日志,如下图:
从上述日志可知,分别调用了 getCurrentDateTime() 和 setAlarm() 工具,将闹钟时间设置为“2025-08-05T20:51:17.234861900”。
更多关于工具调用的知识将在后续单独章节进行详细介绍,上面只是初步了解如何通过 Spring AI 进行工具调用。