跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaAIjava

Spring AI 工具调用(Tool Calling)实战

综述由AI生成介绍 Spring AI 中实现工具调用的两种主要方式:使用 @Tool 注解定义方法和使用 Function 接口定义服务。通过时间与闹钟、天气查询等代码示例,解析了工具调用的工作原理、多轮交互流程及类型限制。文章对比了两种方式的适用场景,并提供了最佳实践建议,帮助开发者将大模型与外部系统有效连接。

数字游民发布于 2026/3/25更新于 2026/5/2420K 浏览

在大模型应用开发中,一个核心挑战是如何让语言模型'走出'自身的知识边界,与外部系统进行交互。这就是 工具调用(Tool Calling) 的意义所在。

工具调用 是指语言模型根据用户输入判断是否需要调用某个外部 API 或执行某项操作,并生成结构化的调用请求(包含工具名和参数),由客户端应用程序负责执行该调用并将结果返回给模型,最终由模型整合信息并生成自然语言响应。

它主要应用于两大场景:

  1. 信息检索:从数据库、网络服务、文件系统等外部来源获取实时或私有数据,扩展模型的知识能力。
  2. 采取行动:触发系统内的具体操作,如发送邮件、设置提醒、创建任务等,实现自动化流程。

本文将结合完整的代码示例,带你深入掌握 Spring AI 中实现工具调用的两种方式 —— 方法作为工具 和 函数作为工具,并通过一个天气查询系统的实战案例,全面解析其工作原理与最佳实践。

虽然我们常说'模型调用了工具',但实际上,模型本身并不执行任何外部逻辑。真正的执行责任在于客户端应用程序。整个过程是一个循环的协作流程:

  1. 应用程序构建 ChatRequest,并将可用的 工具定义(Tool Definition) 注入其中;
  2. 请求被发送至大模型;
  3. 模型分析用户意图,若需调用工具,则返回一个结构化指令(含工具名称和参数);
  4. 客户端接收到响应后,解析出工具调用请求;
  5. 工具调度器根据工具名称查找对应的工具实现并执行;
  6. 执行结果被封装并再次发送回模型;
  7. 模型结合工具返回的结果生成最终的人类可读回复;
  8. 若模型仍需调用其他工具,则重复上述流程,直到完成所有步骤。

这个过程可能涉及多次往返通信(multi-turn),确保复杂任务的顺利完成。

方法一:使用 @Tool 注解定义工具

Spring AI 支持通过注解的方式将普通 Java 方法转化为可被模型识别的'工具'。

示例:时间与闹钟工具
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.context.i18n.LocaleContextHolder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class LocalDateTimeTool {
    @Tool(description = "Get the current date and time in the user's timezone")
    public String getCurrentDateTime() {
        System.out.println("Get the current date!");
        return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }

    @Tool(description = "Set a user alarm for the given time, provided in ISO-8601 format")
    public   {
           LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println( + alarmTime);
    }
}
void
setAlarm
(@ToolParam(description = "Time in ISO-8601 format") String time)
LocalDateTime
alarmTime
=
"Alarm set for "
注解说明:
注解参数说明
@Toolname工具名称,默认为方法名
description必须提供!帮助模型理解何时调用此工具
returnDirect是否直接返回结果给用户(默认 false)
resultConverter自定义结果转字符串逻辑
@ToolParamdescription参数描述,强烈建议填写
required是否必填
控制器调用示例:
@GetMapping("/annotate/setAlarm")
public String setAlarm(String userInput) {
    return chatClient.prompt().tools(new LocalDateTimeTool()) // 注册整个类中的 @Tool 方法.
        .user(userInput)
        .call()
        .content();
}

测试请求:

GET /tool/annotate/setAlarm?userInput=请帮我设置 10 分钟后的闹钟 

模型会自动提取时间并格式化为 ISO-8601 字符串传入 setAlarm() 方法。

使用限制

当使用方法作为工具时,以下类型不能用于参数或返回值:

  • Optional<T>
  • 异步类型(如 CompletableFuture, Future)
  • 响应式类型(如 Mono, Flux, Flow)
  • 函数式接口(如 Function, Supplier, Consumer)

方法二:使用函数式编程定义工具

Spring AI 还支持以 Function<I, O> 形式定义工具,更适合无状态的服务逻辑。

示例:天气查询服务
import org.springframework.ai.tool.annotation.Description;

public class WeatherService implements Function<WeatherService.WeatherRequest, WeatherService.WeatherResponse> {
    public record WeatherRequest(String location, Unit unit) {}
    public record WeatherResponse(double temp, Unit unit) {}
    public enum Unit { C, F }

    @Override
    public WeatherResponse apply(WeatherRequest request) {
        System.out.println("获取{" + request.location + "}的天气");
        double temperature = Math.random() * 50; // 模拟随机温度
        return new WeatherResponse(temperature, Unit.C);
    }
}
方式 A:手动构建 FunctionToolCallback

适用于灵活注册、动态管理工具场景。

@GetMapping("/method/getWeather")
public String getWeather(String userInput) {
    FunctionToolCallback<WeatherService.WeatherRequest, WeatherService.WeatherResponse> callback = FunctionToolCallback.builder("currentWeather", new WeatherService())
        .description("Get the weather in location")
        .inputType(WeatherService.WeatherRequest.class)
        .build();
    return chatClient.prompt().toolCallbacks(callback).user(userInput).call().content();
}
方式 B:通过 @Bean 注册工具(推荐)

利用 Spring IoC 容器统一管理工具实例,更符合我们的开发习惯。

@Configuration(proxyBeanMethods = false)
public class WeatherTools {
    public static final String CURRENT_WEATHER_TOOL = "currentWeather";

    @Bean(CURRENT_WEATHER_TOOL)
    @Description("Get the weather in location")
    public Function<WeatherRequest, WeatherResponse> currentWeather() {
        return new WeatherService();
    }
}

注意:@Description 注解用于提供工具描述,若不加则默认使用 Bean 名称作为描述。

调用控制器:
@GetMapping("/spring/getWeather")
public String getWeatherBySpring(String userInput) {
    return chatClient.prompt().toolNames(WeatherTools.CURRENT_WEATHER_TOOL) // 仅传入 Bean 名称.
        .user(userInput)
        .call()
        .content();
}

测试请求:

GET /tool/spring/getWeather?userInput=上海今天热吗? 

模型会正确解析出地点'上海',调用 currentWeather 工具,并结合返回温度生成人性化回答。

函数工具的类型限制

以下类型不支持作为函数工具的输入或输出:

  • 原始类型(primitive types,如 int, double)
  • Optional<T>
  • 集合类型(如 List, Map, Set, 数组)
  • 异步/响应式类型

✅正确做法是使用 Record 或 POJO 封装参数和返回值,如上文的 WeatherRequest 和 WeatherResponse。

总结对比

特性方法工具(@Tool)函数工具(Function)
定义方式类中带注解的方法Function<I, O> 实现
注册方式.tools(instance).toolCallbacks() 或 .toolNames(beanName)
适合场景多个相关功能组合(如时间处理)单一职责服务(如天气、翻译)
管理方式手动实例化可交由 Spring 容器管理(@Bean)
类型限制不支持异步/响应式等不支持原始类型、集合等

最佳实践建议

  1. 优先使用 @Bean + Function 模式:便于依赖注入、单元测试和统一管理;
  2. 务必填写 description:高质量的描述能显著提升模型选择工具的准确性;
  3. 合理命名工具和参数:语义清晰有助于模型理解和推理;
  4. 避免副作用过重的操作:工具应尽量保持幂等性和安全性;
  5. 记录日志便于调试:观察模型是否准确识别了工具调用时机;
  6. 考虑错误处理机制:工具执行失败时应有兜底策略。

结语

Spring AI 对工具调用的抽象极大简化了大模型与现实世界的连接。无论是将已有方法快速暴露为工具,还是构建新的函数式服务,Spring AI 都提供了简洁而强大的支持。

本文使用 @Tool 注解创建了时间工具和闹钟功能,利用 Function + @Bean 构建了可复用的天气查询服务,介绍了工具调用背后的多轮交互机制和常见类型限制陷阱。

目录

  1. 方法一:使用 @Tool 注解定义工具
  2. 示例:时间与闹钟工具
  3. 注解说明:
  4. 控制器调用示例:
  5. 使用限制
  6. 方法二:使用函数式编程定义工具
  7. 示例:天气查询服务
  8. 方式 A:手动构建 FunctionToolCallback
  9. 方式 B:通过 @Bean 注册工具(推荐)
  10. 调用控制器:
  11. 函数工具的类型限制
  12. 总结对比
  13. 最佳实践建议
  14. 结语
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • GPT-5 API 结合 RAG 知识库构建电商客服机器人实战
  • 骡子快跑 MuleRun:自进化 AI 数字员工开启 Agent 普及元年
  • C++未定义行为(UB)详解与解决方案
  • 基于 GPT-5 API 与 RAG 知识库构建智能客服机器人
  • Whisper-Large-V3-Turbo 模型部署与性能优化实战
  • 基于大模型 API 与 RAG 知识库构建智能客服机器人实战
  • Neo4j 图数据库安装与操作指南 (Mac 版)
  • 基于 S 函数和 Simulink 的 6 自由度无人机飞行模拟与控制
  • 前端数据库 IndexedDB 详解:构建离线 Web 应用
  • Stable Diffusion v1.5 风格化图像生成作品集与 Prompt 解析
  • ROG-Map:一种高效的大场景 LiDAR 机器人中心栅格地图
  • C# 实现文本框仅允许输入数字的键盘事件处理
  • 常见免费论文查重与 AI 写作工具功能对比
  • LTX-2.3:开源 AI 视频生成新标杆,支持音视频同步生成
  • 灵感画廊 AI 绘画工具安装与使用指南
  • 2026 主流 AI 编程助手深度评测:文心快码、Copilot 与 Cursor
  • Vheer:免费免登录 AI 绘画视频生成与智能编辑工具
  • Web 打印控件 Lodop 快速入门与使用指南
  • 通过 Vue 实例劫持突破 Web 编辑器的粘贴限制
  • Eino ADK 核心 Agent 详解:ChatModelAgent 机制与实战

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online