一、Tool Calling

1.1、为什么要学Tool Calling

在传统的 Java 开发中,我们擅长处理确定性的逻辑(如数据库 CRUD、事务控制、微服务调用)。但在 AI 时代,大模型(LLM)虽然聪明,却有两个致命弱点:‌它不知道实时数据‌(如今天的股价、你的订单状态),也‌无法直接执行操作‌(如发邮件、改数据库)。

Spring AI 的“工具调用”(Function Calling(函数调用) / Tool Calling)正是为了解决这个问题而存在的。

1.2、Tool Calling能做什么

赋予 AI “手脚”,从“聊天机器人”升级为“智能代理”

没有函数调用,AI 只是一个会说话的百科全书,面对“帮我查一下成都现在实时天气”或“取消我的订单”这类请求,它只能回答“我无法访问实时数据”。
通过 Spring AI 的函数调用,你可以将 Java 方法注册为“工具”。当用户提问时,AI 会自动判断:“这个问题我需要调用 createOrder(自定义) 方法”,然后 Spring AI 帮你执行这个 Java 方法,拿到结果后再让 AI 组织语言回答用户。
价值点‌:你不需要写复杂的正则表达式或意图识别代码来解析用户指令,AI 自己会决定何时调用你的代码。

1.3、Tool Calling定义

让  大语言模型(LLM)在对话中,主动决定调用你提前注册的 Java 方法 / 外部 API接口,拿到结果后再整理成自然语言回答Spring 框架。

  • LLM 不直接执行代码,只输出 “调用哪个工具、传什么参数” 的 JSON 意图Spring 框架。
  • Spring AI负责解析意图、执行 Java 函数、返回结果给 LLM,完成闭环。
  • 核心价值:把 LLM 从 “只会聊天” 升级为 “能办事、能查数据、能控系统”

工作流程(5 步闭环)

用户提问 → 2. LLM 判断需调用工具 → 3. Spring AI 执行 Java 函数 → 4. 结果回传给 LLM → 5. LLM 生成最终回答。

二、Spring AI 函数调用几种方式

三种方式:

@Tool 注解式(最简单)、Function 函数式(轻量)、MethodToolCallback 编程式(灵活)。

2.1、前置环境搭建

2.1.1、技术栈介绍

JDK17+、SpringBoot.3.3.10、‌智谱AI GLM系列模型(glm-4glm-4-flash)‌

2.1.2、创建SpringBoot项目,导入如下依赖

​
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.10</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wn</groupId>
    <artifactId>boot-ai-zhipu</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>boot-ai-zhipu</name>
    <description>boot-ai-zhipu</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-zhipuai</artifactId>
            <version>1.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

​

2.1.3、配置应用环境

需通过环境变量读取,禁止在代码、配置文件中明文硬编码,防止密钥泄露。

2.1.4、application.yml

​
spring:
  ai:
    zhipuai:
      # 智谱AI的API密钥,通过系统环境变量ZHIPUAI_API_KEY动态注入,避免硬编码泄露密钥
      api-key: ${ZHIPU_API_KEY}
      # 智谱AI聊天服务的配置选项
      chat:
        options:
          model: glm-4 # 指定调用的智谱大模型版本,此处为glm-4,可根据需求更换为glm-3等其他支持的模型

​

2.1.5、新建聊天控制器

​
/**
 * 聊天控制器
 * 负责处理前端发起的聊天请求,集成 Spring AI 与智谱大模型
 */
@RestController
@RequestMapping("/chat")
public class ChatController {

    // 声明 ChatClient 实例,用于构建提示词并与大模型交互
    private ChatClient chatClient;

    /**
     * 构造函数注入
     * Spring 容器会自动注入 ChatModel Bean
     * 在此处通过 Builder 模式创建 ChatClient 实例
     * @param chatModel 由 Spring AI 自动配置的底层聊天模型实现
     */
    public ChatController(ChatModel chatModel) {
        // 使用 ChatModel 构建 ChatClient
        // 注意:原代码中 builder(chatModel).build() 没有赋值给成员变量,此处已修正为赋值操作
        this.chatClient = ChatClient.builder(chatModel).build();
    }

    /**
     * 同步聊天接口
     * 接收用户消息,调用大模型生成回复,并返回完整结果
     *
     * @param message 用户输入的文本消息,默认值为“你好!请介绍一下自己”
     * @return 大模型生成的完整文本回复
     */
    @GetMapping("sync")
    public String syncChat(@RequestParam(value = "message", defaultValue = "你好!请介绍一下自己") String message) {
        // 1. prompt(): 创建一个新的提示词构建器
        // 2. user(message): 设置用户角色的消息内容
        // 3. call(): 执行同步阻塞调用,等待模型返回完整结果
        // 4. content(): 从响应结果中提取纯文本内容
        return chatClient.prompt()
                .user(message)
                .call()
                .content();
    }
}

​

2.2、注解式(@Tool)—— 最简单、企业最常用

2.2.1、新建天气查询工具类

直接在 Spring Bean 的普通方法上加 **@Tool** 注解,Spring AI 自动生成工具定义与 JSON Schema。

/**
 * 天气查询工具类
 * 该类被注册为 Spring Bean,并暴露给 AI 模型作为可调用的工具(Function Calling)。
 * AI 可以根据用户意图自动调用此方法来获取实时天气信息。
 */
@Component
public class WeatherTools {

    /**
     * 根据城市名称查询实时天气
     * @param city 城市名称,例如:成都、杭州、北京等
     * @return 包含温度、天气状况和湿度的格式化字符串
     */
    @Tool(description = "根据城市名查询实时天气,返回温度、湿度、天气状况")
    public String getWeather(
            // @ToolParam 用于向 AI 描述参数的具体含义和格式要求,提高参数提取的准确率
            @ToolParam(description = "城市名称,如:成都、杭州") String city) {

        // TODO: 在实际生产中,此处应注入 WeatherService 并调用第三方天气 API
        // 示例逻辑:模拟返回指定城市的天气数据
        return "成都:28℃,晴,湿度40%";
    }
}

2.2.2、修改聊天控制器

/**
 * 聊天控制器
 * 负责处理前端发起的聊天请求,集成 Spring AI 与智谱大模型
 */
@RestController
@RequestMapping("/chat")
public class ChatController {

    // 声明 ChatClient 实例,用于构建提示词并与大模型交互
    private ChatClient chatClient;
    // 注入天气工具类,使其能够被大模型在需要时调用
    @Autowired
    private WeatherTools weatherTools;

    /**
     * 构造函数注入
     * Spring 容器会自动注入 ChatModel Bean
     * 在此处通过 Builder 模式创建 ChatClient 实例
     * @param chatModel 由 Spring AI 自动配置的底层聊天模型实现
     */
    public ChatController(ChatModel chatModel) {
        // 使用 ChatModel 构建 ChatClient
        // 注意:原代码中 builder(chatModel).build() 没有赋值给成员变量,此处已修正为赋值操作
        this.chatClient = ChatClient.builder(chatModel).build();
    }

    /**
     * 同步聊天接口
     * 接收用户消息,调用大模型生成回复,并返回完整结果
     *
     * @param message 用户输入的文本消息,默认值为“你好!请介绍一下自己”
     * @return 大模型生成的完整文本回复
     */
    @GetMapping("sync")
    public String syncChat(@RequestParam(value = "message", defaultValue = "你好!请介绍一下自己") String message) {
        // 1. prompt(): 创建一个新的提示词构建器
        // 2. tools(weatherTools): 注册可用工具,允许大模型在必要时调用 WeatherTools 获取实时数据
        // 3. user(message): 设置用户角色的消息内容
        // 4. call(): 执行同步阻塞调用,等待模型返回完整结果
        // 5. content(): 从响应结果中提取纯文本内容
        return chatClient.prompt()
                .tools(weatherTools)
                .user(message)
                .call()
                .content();
    }
}

2.3、函数式(Function/ BiFunction)

注:官方推荐、轻量

2.3.1、创建函数

/**
 * 汽车信息查询函数实现类
 * 实现了 Java 标准的 Function 接口,用于将 AI 模型的请求转换为具体的业务查询结果。
 * 该类的实例通常会被 Spring AI 包装为 ToolCallback,供大语言模型调用。
 */
public class CarFunction implements Function<CarFunction.CarRequest, String> {

    /**
     * 核心业务逻辑方法
     * 接收包含汽车ID的请求对象,执行查询逻辑并返回结果字符串。
     *
     * @param request 包含查询参数(如汽车ID)的请求对象
     * @return 查询结果的 JSON 格式字符串
     */
    @Override
    public String apply(CarRequest request) {
        // 1. 参数校验(建议在实际生产环境中添加)
        if (request == null || request.getCarId() == null) {
            return "{\"error\": \"Invalid request: carId is missing\"}";
        }

        // 2. 根据查询调用第三方API获取汽车信息
        // 此处省略一万字....
        // 实际开发中,这里通常会注入 RestTemplate 或 WebClient 来调用外部微服务或数据库

        // 3. 构建并返回结果
        // 注意:手动拼接 JSON 字符串容易出错且不安全,生产环境建议使用 Jackson 或 Gson 库进行序列化
        return "{'carid':" + request.getCarId() + ",'type':'SUV','color':'白色'}";
    }

    /**
     * 内部静态类:定义工具调用的输入参数结构
     * Spring AI 会利用反射分析此类,自动生成 JSON Schema,从而告诉大模型需要传入什么参数。
     */
    public static class CarRequest {
        
        /**
        表示汽车编号
         * 大模型在调用此工具时,会将提取到的 carId 值映射到此字段
         */
        private Integer carId;

        /**
         * 获取汽车编号
         * @return 汽车ID
         */
        public Integer getCarId() {
            return carId;
        }

        /**
         * 设置汽车编号
         * @param carId 汽车ID
         */
        public void setCarId(Integer carId) {
            this.carId = carId;
        }
    }
}

2.3.2、创建FunctionConfig配置类

/**
 * Spring AI 工具函数配置类
 * 用于将自定义的业务逻辑注册为 AI 模型可调用的工具(Tool/Function)
 */
@Configuration
public class FunctionConfig {

    /**
     * 注册汽车信息查询工具
     * 
     * @return 实现了 Function 接口的 CarFunction 实例
     * 
     * 注意:
     * 1. @Description 注解用于向大语言模型描述该工具的功能,
     *    模型会根据此描述判断何时调用该工具。
     * 2. 返回类型 Function<CarRequest, String> 定义了工具的输入参数结构
     *    和输出结果格式(通常为 JSON 字符串)。
     * 3. 在较新版本的 Spring AI 中,推荐使用 ToolCallback 或 @Tool 注解,
     *    但此写法在兼容旧版 API 时依然有效。
     */
    @Bean
    @Description("查询指定车辆(汽车)的信息,需提供汽车ID")
    public Function<CarFunction.CarRequest, String> carFunction() {
        // 实例化并返回具体的函数实现类
        return new CarFunction();
    }
}

2.3.3、ChatController使用函数调用

    /**
     * 同步聊天接口:处理用户消息并返回 AI 回复
     * 支持工具调用(Function Calling),模型可根据语境自动选择调用天气或汽车查询工具
     *
     * @param message 用户输入的聊天消息,默认为“你好!请介绍一下自己”
     * @return AI 生成的最终回复文本
     */
    @GetMapping("sync")
    public String syncChat(@RequestParam(value = "message", defaultValue = "你好!请介绍一下自己") String message) {
        
        // 构建并执行聊天请求链式调用
        return chatClient.prompt()
                
                // 1. 注册汽车信息查询工具
                // 通过 Bean 名称 "carFunction" 引用之前配置的工具,使模型具备查询车辆信息的能力
                .tools("carFunction")
                
                // 2. 设置用户消息内容
                // 将前端传入的 message 作为用户角色的输入发送给大模型
                .user(message)
                
                // 3. 执行同步阻塞调用
                // 发送请求至大模型,并等待模型完成推理及可能的工具调用流程,返回完整响应对象
                .call()
                
                // 4. 提取响应内容
                // 从模型返回的结果对象中解析出最终的纯文本回复内容
                .content();
    }

2.4、MethodToolCallback 编程式(灵活)

略....

Logo

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

更多推荐