Spring Ai超简单教程系列 - 07工具调用

在网上找了一些Spring AI相关的教程,因为官方API更新较快的原因,大部分教程的内容都已过时。所以在参照官方参考文档学习的同时,沉淀每篇文章,为同样热爱学习的你,提供参考。
本系列教程参考Spring AI官方1.1.x版本文档:https://docs.spring.io/spring-ai/reference/1.1/index.html

工具调用

Tool Calling(工具调用) 是指让大语言模型在对话过程中,根据用户问题自主决定是否调用应用程序提供的工具或函数,并由应用程序执行工具,最后将执行结果返回给模型生成最终答案。
简单来说:
    大模型负责“判断需要做什么”,应用程序负责“真正执行什么”。
例如,用户询问:
    “北京今天的天气怎么样?”
大模型本身通常没有实时天气数据,它可以判断需要调用一个天气查询工具:

模型:我要查询北京天气,需要调用 getWeather(city="北京")
应用:执行天气服务接口,返回 25℃,晴
模型:根据工具结果回答用户

Spring AI中,Tool Calling可以将Java方法、业务服务或外部 API 暴露给大模型使用。

简单示例

大模型无法获取实时信息。任何假设了解当前日期或天气预报等信息的问题,模型都无法回答。我们可以提供一个工具来获取这些信息,并在需要实时信息时让模型调用该工具。

定义获取当前日期的工具方法并添加相应描述。

static class DateTimeTools {

    @Tool(description = "获取当前日期和时间")
    String getCurrentDateTime() {
        log.info("调用了日期和时间工具");
        return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }

}

接下来,我们将工具提供给模型使用。

@GetMapping("/ai/call/tool/date")
String callDateTimeTools() {
    return ChatClient.create(this.chatModel)
            .prompt("明天日期是什么?")
            .tools(new DateTimeTools())
            .call()
            .content();
}

大模型输出效果:

明天是 **2026年9月10日**(星期四)。

工具上下文

Spring AI支持通过ToolContext API向工具方法传递额外的上下文信息。可以提供自定义的附加数据。下面已多租户的场景为例,在调用工具方法时,通过ToolContext传递租户信息。
工具方法定义:

static class OrderTools {

    @Tool(description = "根据订单Id查询当前订单状态")
    String getOrderStats(@ToolParam(description = "订单Id") String orderId, ToolContext toolContext) {
        log.info("调用订单查询工具,订单Id:[ {} ]", orderId);
        log.info("租户Id:[ {} ]", toolContext.getContext().get("tenantId"));
        return new String[]{"下单成功", "运输中", "已收货", "交易成功"}[RandomUtils.secure().randomInt(0, 4)];
    }

}

接口定义:

@GetMapping("/ai/call/tool/order")
String callOrderTools() {
    return ChatClient.create(this.chatModel)
            .prompt("我的订单Id是12345,当前订单状态是什么?")
            .tools(new OrderTools())
            .toolContext(Map.of("tenantId", "1"))
            .call()
            .content();
}

调用日志:

2026-09-09T17:25:44.537+08:00  INFO 30764 --- [ai-java-demo] [nio-8080-exec-6] c.c.a.web.ToolCallingController          : 调用订单查询工具,订单Id:[ 12345 ]
2026-09-09T17:25:44.540+08:00  INFO 30764 --- [ai-java-demo] [nio-8080-exec-6] c.c.a.web.ToolCallingController          : 租户Id:[ 1 ]

大模型输出效果:

您订单Id为12345的订单当前状态是:**已收货**。

实战场景

我们结合SpringBoot中的Bean,开发一个可以查询指定城市天气的接口,向大模型提供天气查询、日期查询两个工具方法,让大模型根据用户输入城市调用工具方法并返回响应内容。

定义天气查询Service类:

@Slf4j
@Service
public class WeatherService {

    private final WebClient webClient = WebClient.builder().baseUrl("https://uapis.cn").build();

    @Tool(
            description = "根据城市名称查询当前天气信息",
            resultConverter = WeatherToolCallResultConverter.class
    )
    public Optional<String> getCurrentWeather(@ToolParam(description = "需要查询的城市名") String city) {
        return webClient.get()
                .uri(
                        uriBuilder -> uriBuilder
                                .path("/api/v1/misc/weather")
                                .queryParam("city", city)
                                .build()
                )
                .retrieve()
                .bodyToMono(String.class)
                .blockOptional();
    }

    public static class WeatherToolCallResultConverter implements ToolCallResultConverter {

        private final ObjectMapper objectMapper = new ObjectMapper();

        @SneakyThrows
        @Override
        public String convert(@Nullable Object result, @Nullable Type returnType) {
            if (result instanceof Optional rop
                    && rop.isPresent()
                    && rop.get() instanceof String resultStr) {

                Map<String, String> json = objectMapper.readValue(resultStr, Map.class);

                return String.format(
                        "根据 %s 的天气信息,%s %s 今天的天气 %s,温度 %s 度, %s %s",
                        json.get("report_time"),
                        json.get("province"),
                        json.get("city"),
                        json.get("weather"),
                        json.get("temperature"),
                        json.get("wind_direction"),
                        json.get("wind_power")
                );
            }
            return "未查询到天气信息";
        }
    }

}

定义查询接口:

@GetMapping("/ai/call/tool/weather")
String callWeatherTools(@RequestParam("city") String city) {
    return ChatClient.create(this.chatModel)
            .prompt()
            .user(up -> up.text("查询{city}今天的天气信息").params(Map.of("city", city)))
            .system("用户查询天气信息时,按照今天的日期、天气信息发布时间、省份城市、天气、温度、风力返回结果信息,最后根据天气信息添加一句关怀提醒。")
            .tools(weatherService, new DateTimeTools())
            .call()
            .content();
}

大模型输出效果:

为您查询到深圳今天的天气信息如下: 📅 **日期**:2026年9月9日(今天) 🕒 **发布时间**:6分钟前发布 📍 **地点**:广东省 深圳市 🌤 **天气**:多云 🌡 **温度**:30度 💨 **风力**:东北风 3级 --- 💡 **温馨提示**:今天深圳天气多云,气温30度较为闷热,风力不大,体感偏热。建议您外出时注意防晒补水,穿着清凉透气的衣物,及时补充水分哦!午后若在户外活动,不妨携带遮阳伞或帽子。祝您拥有愉快的一天!😊
posted @ 2026-09-09 17:32  codest  阅读(12)  评论(0)    收藏  举报