🚀 欢迎来到我的CSDN博客:Optimistic _ chen
一名热爱技术与分享的全栈开发者,在这里记录成长,专注分享编程技术与实战经验,助力你的技术成长之路,与你共同进步!


🚀我的专栏推荐

专栏 内容特色 适合人群
🔥C语言从入门到精通 系统讲解基础语法、指针、内存管理、项目实战 零基础新手、考研党、复习
🔥Java基础语法 系统解释了基础语法、类与对象、继承 Java初学者
🔥Java核心技术 面向对象、集合框架、多线程、网络编程、新特性解析 有一定语法基础的开发者
🔥Java EE 进阶实战 Servlet、JSP、SpringBoot、MyBatis、项目案例拆解 想快速入门Java Web开发的同学
🔥Java数据结构与算法 图解数据结构、LeetCode刷题解析、大厂面试算法题 面试备战、算法爱好者、计算机专业学生
🔥Redis系列 从数据类型到核心特性解析 项目必备

🚀我的承诺:
✅ 文章配套代码:每篇技术文章都提供完整的可运行代码示例

✅ 持续更新:专栏内容定期更新,紧跟技术趋势

✅ 答疑交流:欢迎在文章评论区留言讨论,我会及时回复(支持互粉)


🚀 关注我,解锁更多技术干货!
⏳ 每天进步一点点,未来惊艳所有人!✍️ 持续更新中,记得⭐收藏关注⭐不迷路 ✨

📌 标签:#技术博客#编程学习#Java#C语言#算法#程序员

什么是Tool Calling

  随着大模型的发展,我们不再满足于仅仅让它们生成文本或回答问题。我们希望它可以成为真正的智能助手,能够实现与外部世界交互,代替人类执行任务,解放人的双手。为了解决这个挑战,Tool Calling应运而生。

  Tool Calling是AI应用程序中的一种常见模式,允许大语言模型根据用户需求,智能的选择、调用外部工具,并获取结果,从而增强其功能。实现了应用程序与外部世界的交互。

正常的大模型,只能应用在对话文本的场景下,但是如果添加Tool Calling,比如添加一个订餐系统,大模型就能帮我在我想要的餐厅订餐,实现外部交互。

快速上手

首先在代码中,我们使用Tool Calling需要添加它的依赖

<dependency>
     <groupId>com.github.victools</groupId>
     <artifactId>jsonschema-generator</artifactId>
     <!-- 可根据实际情况使⽤最新稳定版本 --> 
     <version>4.37.0</version>
</dependency>

其次,通过 @Tool注解来定义工具,为了帮助模型了解如何调用此工具,工具的描述非常重要,需要我们提供工具的详细说明。

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

public class DateTimeTools {

    @Tool(description = "获取用户时区的当前日期和时间")
    public String getCurrentDateTime() {
        // 从 LocaleContextHolder 获取上下文用户时区,如果为空则使用系统默认时区
        ZoneId zoneId = LocaleContextHolder.getTimeZone() != null 
                ? LocaleContextHolder.getTimeZone().toZoneId() //将 TimeZone 转换为 ZoneId
                : ZoneId.systemDefault();//如果上下文为空,则获取 JVM 默认时区
        
        //根据确定的时区获取当前日期时间
        LocalDateTime now = LocalDateTime.now(zoneId);
        //定义日期时间输出格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        
        //格式化并返回结果
        return now.format(formatter);
    }
}

@Tool 注解的作用:让方法成为 AI 的"工具箱",模型可以决定何时调用
description:模型通过描述判断工具的用途,描述越清晰,调用越准确

调用工具

为了将工具提供给模型使用,将定义好的工具注册到 ChatClient 中:

@Autowired
private ChatModel chatModel;

public String chatWithTime(String userInput) {
    return ChatClient.create(chatModel)
            .prompt(userInput)
            .tools(new DateTimeTools())   // 注册工具
            .call()
            .content();
}

当用户问“今天是几号?”“明天是星期几?”等问题时,模型会自动判断需要获取当前时间,并调用此工具。

Tool Calling原理

Spring AI 通过一组灵活的抽象机制支持工具调用功能,这些抽象允许你以统一的方式定义、解析和执行工具。(类似于函数调用)
在这里插入图片描述
这幅图直观的展示了工具调用的一系列流程:

  1. 当我们想让模型使用某个工具时,我们会在聊天请求中包含该工具的定义,包括名称、描述和输入参数的格式
  2. 模型调用工具时,它会发送包含工具名称以及符合工具预定义的参数
  3. 应用程序负责根据工具名称识别对应工具,并使用提供的输入参数执行该工具
  4. 工具返回的结果由应用程序进行处理
  5. 应用程序将工具调用结果返回至模型
  6. 模型最终利用工具调用结果作为附加上下文生成响应

方法即工具

Spring AI 为方法转工具(即 ToolCallback)提供两种内置支持方式:

  • 声明式:通过@Tool注解实现
  • 编程式:通过底层的MethodToolCallBack实现

声明式定义工具

源码:
在这里插入图片描述
在"⼯具调⽤"流程中,JSON Schema⽤于定义⼯具的输⼊参数格式,Spring AI 将自动为 @Tool 注解方法的输入参数生成 JSON Schema。

但是,这里我有一个疑问,为什么方法的参数不直接传给工具,而是先通过JSON Schema模型再传给工具本身??
注意:JSON Schema 不是传给工具的,而是传给 AI 模型的。回忆Tool Calling的原理图,JSON Schema 供模型理解如何调用工具及准备工具请求.

同时可使用 @ToolParam 注解为输入参数提供额外信息,若参数标注了 @Nullable 注解,则该参数将被视为可选参数。

为ChatModel添加工具

  当使用声明式方案时,你可以通过调用 ChatModel 时使用的 ToolCallingChatOptions 中的 toolCallbacks() 方法传入工具类实例。注意:此类工具仅在添加它们的特定聊天请求中可用。

ChatModel chatModel = ...
ToolCallback[] dateTimeTools = ToolCallbacks.from(new DateTimeTools());
ChatOptions chatOptions = ToolCallingChatOptions.builder()
    .toolCallbacks(dateTimeTools)
    .build();
Prompt prompt = new Prompt("What day is tomorrow?", chatOptions);
chatModel.call(prompt);

为ChatClient添加工具

  当使用声明式配置方案时,你可以在调用 ChatClient 时通过 tools() 方法传入工具类实例。此类工具仅在添加它们的特定聊天请求中可用。

ChatClient.create(chatModel)
    .prompt("What day is tomorrow?")
    .tools(new DateTimeTools())
    .call()
    .content();

编程式定义工具

我们也可以通过编程式构建MethodToolCallback将⽅法转为⼯具底层实现。

//通过反射获取方法对象
Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
//构建工具回调
ToolCallback toolCallback = MethodToolCallback.builder()
    .toolDefinition(ToolDefinition.builder(method)//构建工具定义
            .description("Get the current date and time in the user's timezone")
            .build())//定义工具信息
    .toolMethod(method)//指定方法
    .toolObject(new DateTimeTools())//创建方法的实例
    .build();

为ChatClient添加工具

通过toolCallbacks为ChatClient添加工具

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.model.tool.ToolCallback;
import org.springframework.ai.tool.MethodToolCallback;
import org.springframework.ai.tool.definition.ToolDefinition;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;

@Configuration
public class ChatClientConfig {

    @Bean
    public ChatClient chatClient(ChatModel chatModel) {
        
        // 1. 通过反射获取方法
        Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
        
        // 2. 手动构建 ToolDefinition
        ToolDefinition toolDefinition = ToolDefinition.builder(method)
                .description("Get the current date and time in the user's timezone")
                .name("getCurrentDateTime")  // 可选,默认使用方法名
                .build();
        
        // 3. 手动构建 ToolCallback
        ToolCallback toolCallback = MethodToolCallback.builder()
                .toolDefinition(toolDefinition)
                .toolMethod(method)
                .toolObject(new DateTimeTools())
                .build();
        
        // 4. 将 ToolCallback 注册到 ChatClient
        return ChatClient.builder(chatModel)
                .defaultTools(toolCallback)  // 单个工具
                // .defaultTools(toolCallback1, toolCallback2)  // 多个工具
                .build();
    }
}

工具执行

工具执行指使⽤提供的输⼊参数调⽤⼯具并返回结果的过程。
在这里插入图片描述

  1. 当需要向模型提供工具时,我们将其定义包含在聊天请求(Prompt)中,并调用 ChatModel API 将请求发送至 AI 模型。

  2. 当模型决定调用工具时,它会发送包含工具名称及符合定义模式的输入参数的响应(ChatResponse)。

  3. ChatModel 将工具调用请求发送至 ToolCallingManager API。

  4. ToolCallingManager 负责识别需调用的工具并使用提供的输入参数执行该工具。

  5. 工具调用结果返回至 ToolCallingManager。

  6. ToolCallingManager 将工具执行结果返回给 ChatModel。

  7. ChatModel 将工具执行结果返回AI模型(ToolResponseMessage)。

  8. AI 模型利用工具调用结果作为附加上下文生成最终响应,并通过 ChatClient 将其返回调用方(ChatResponse)。

完结撒花!🎉

如果这篇博客对你有帮助,不妨点个赞支持一下吧!👍
你的鼓励是我创作的最大动力~

想获取更多干货? 欢迎关注我的专栏 → optimistic_chen
📌 收藏本文,下次需要时不迷路!

我们下期再见!💫 持续更新中……


悄悄说:点击主页有更多精彩内容哦~ 😊
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7471a32ba1fc4954b6ae528ef5b66475.png

Logo

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

更多推荐