前言:在最近发布的 Spring AI 1.0.0.M6 版本中,其中一个重大变化是 Function Calling 被废弃,被 Tool Calling 取代。Tool Calling工具调用(也称为函数调用)是AI应用中的常见模式,允许模型通过一组API或工具进行交互,从而增强其能力
1、Tool Calling 工具调用 简介
Spring AI 中的工具调用使 AI 模型能够与外部工具和服务交互,从而增强其功能。Tool Calling 工具调用允许 AI 模型执行外部函数、访问外部服务、执行复杂操作和与现有系统集成
主要使用的场景:
-
信息检索(Information Retrieval)。
此类工具可用于从外部资源(如数据库、Web服务、文件系统或者 WEB 搜索引擎)检索信息。
目标:增强模型的知识,使其能够回答其其它方式不能回答的问题。例如,工具用于检索给定的位置天气、检索最新的新闻文章或者查询数据库。
-
采取行动(Taking Action)
此类工具可用于在软件系统中的执行操作(如发送电子邮件、在数据库中创建新记录、提交表单或触发工作流),自动执行原本需要人工干预或者显式编程的任务。例如,与机器人交互生成待办事项、自动填写网页表单、聊天机器人预订机票、创建会议安排等。
注意: 通常我们认为工具调用是模型功能,但实际上由客户端应用程序提供工具调用逻辑,模型只能请求工具调用并提供输入参数,模型本身不执行工具调用。
2、为什么废弃 Function Calling?
-
更好的改进和扩展 Spring AI 中工具调用功能。
-
新的 API 从 functions 改为 tools 术语,与行业术语保持一致性。
除以上两点之外,在设计上也做了一定的优化,主要体现在;
-
新的 API 在工具的定义和实现之间提供了更好的分离
-
工具定义可以在不同的实现中重复使用
-
在使用上,简化了构造器模式,更好的支持基于方法的工具,并改进了错误处理。
两者在本质上概念上没有区别,都是为增强大模型的能力,在底层的实现原理上也是一致的,只是对外提供的概念稍微变动一下。官方建议尽快将 Function Calling 相关使用的 API 迁移到 Tool Calling API。Function Calling API 在后续的版本中会被移除。基本上是将原API 中的Function 替换为 Tool,再者就是为了方便方法的使用做了一些优化。
3、Tool Calling 主要操作流程和源代码
(1)主要操作流程
定义工具 :当需要向模型提供工具时,需在聊天请求中包含其定义。每个工具定义包含名称、描述及输入参数的模式(schema)。
模型发起调用 :当模型决定调用工具时,会返回包含工具名称和符合预定义模式的输入参数的响应。
应用执行工具 :应用程序负责根据工具名称识别并执行对应工具,传入提供的输入参数。
处理结果 :工具调用的结果由应用程序处理。
返回结果至模型 :应用程序将工具调用结果返回给模型。
生成最终响应 :模型结合工具调用结果作为上下文生成最终响应
(2)源码
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Tool {/*** 指定工具的名称,如果不指定则默认使用方法名称。* 注意:方法名称的唯一性*/String name() default "";/*** 工具的描述,模型可以使用它来了解何时以及如何调用工具,如果不指定则使用方法名。* 强烈建议:详细,清晰的描述工具的功能,这对于工具的使用至关重要,直接影响大模型的* 使用效果。*/String description() default "";/*** 指定工具执行的结果是直接返回,还是要发给大模型,默认发送给大模型*/boolean returnDirect() default false;/*** 指定工具执行结果转换器。Spring AI 内置一个默认转换为String,如果有特殊业务* 需求可自行实现。*/Class<? extends ToolCallResultConverter> resultConverter() default DefaultToolCallResultConverter.class;}
4、Tool Calling 快速入门
让我们通过一个示例了解如何在Spring AI中使用工具调用。我们将实现两个简单工具:一个用于信息检索,另一个用于执行操作。信息检索工具用于获取用户时区的当前日期和时间,操作工具用于设置指定时间的闹钟。
(1)信息检索
AI模型无法访问实时信息。任何涉及当前日期、天气预报等实时信息的问题,模型都无法直接回答。但我们可以提供能够检索此类信息的工具,并让模型在需要实时数据时调用这些工具。
首先在DateTimeTools类中实现一个获取用户时区当前日期时间的工具。该工具不需要参数,通过Spring框架的LocaleContextHolder获取用户时区。工具方法使用@Tool注解,并添加详细描述帮助模型理解调用时机。
package com.hs.demo.tool;import org.springframework.ai.tool.annotation.Tool;
import org.springframework.context.i18n.LocaleContextHolder;import java.time.LocalDateTime;public class DateTimeTools {@Tool(description = "获取用户时区的当前日期和时间")String getCurrentDateTime() {return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();}}
接下来将工具提供给模型,本例使用ChatClient与模型交互,通过tools()方法传入DateTimeTools实例。当模型需要实时时间信息时,会自动请求调用该工具。ChatClient会执行工具调用并将结果返回给模型,模型结合结果生成最终响应。
输出示例:
明天是2025-05-30。
如果直接提问但不提供工具,模型将返回:
我无法访问实时信息,请提供当前日期以便计算明天的日期。
这证明模型在缺乏工具时无法自主获取实时数据
(2) 执行操作
AI模型可以生成实现目标的计划(如制定瑞士旅行计划),但无法直接执行。此时需要工具来落实模型生成的计划。
我们将定义第二个工具,用于在特定时间设置闹钟。在第一个工具的基础上,先获取当前时间,在当前时间的基础上设置闹钟。在现有DateTimeTools类中新增设置闹钟的工具。该工具接收ISO-8601格式的时间参数,向控制台输出闹钟设置信息。同样使用@Tool注解并添加详细描述
class DateTimeTools {@Tool(description = "获取用户时区的当前日期和时间")String getCurrentDateTime() {return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();}@Tool(description = "为指定ISO-8601时间设置用户闹钟")void setAlarm(String time) {LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);System.out.println("闹钟已设置为 " + alarmTime);}
}
通过ChatClient同时提供两个工具。当请求"10分钟后设置闹钟"时,模型会先调用getCurrentDateTime获取当前时间,计算目标时间后调用setAlarm工具。ChatClient自动处理工具调用请求并返回结果,模型最终生成响应
ChatModel chatModel = ...String response = ChatClient.create(chatModel).prompt("能设置10分钟后的闹钟吗?").tools(new DateTimeTools()).call().content();System.out.println(response);
应用日志将显示正确设置的闹钟时间,验证工具调用流程
参考链接:
Spring AI 框架在升级,Function Calling 废弃,被 Tool Calling 取代
Spring AI之工具调用_springai-CSDN博客