Tool Calling 工具调用 目录一、概述二、工具定义与使用工具定义工具使用三、Tool Calling 使用案例1) 创建SpringBoot项目命名为“SpringAIToolCalling”2) 配置项目pom.xml3) 配置resources/application.properties4) 创建tools包并创建MyTools.java类5) 创建controller包并创建ToolUseController.java文件6) 启动项目并测试一、概述Tool Calling工具调用也称为函数调用是让大语言模型LLM在对话中“调用”外部定义的工具或 API 的机制通过这个机制模型可以在生成回答前提出需要执行的操作如获取实时天气、设置数据库记录、触发业务流程等然后由应用端执行工具结果再反馈回模型最终给用户完整回复。Tool Calling主要应用场景如下信息检索从外部源如数据库、Web 服务、文件系统或 Web 搜索引擎检索信息增强模型的知识使其能够回答其他方式无法回答的问题。执行操作在软件系统中执行特定操作如发送电子邮件、在数据库中创建新记录、提交表单或触发工作流。目标是自动执行原本需要人工干预或显式编程的任务。Spring AI 提供了方便的 API 来定义工具、解析来自模型的工具调用请求以及执行工具调用。二、工具定义与使用Spring AI中工具调用流程示意图如下开发者定义工具并将其注册到 Spring 容器中。模型在生成响应时识别到需要调用工具会生成包含工具调用信息的响应。应用程序接收到模型的响应后解析其中的工具调用信息执行相应的工具。工具执行完成后将结果返回给应用程序。应用程序将工具执行结果作为上下文信息传递给模型。模型使用工具执行结果生成最终的响应。工具定义开发者可以通过在方法上添加Tool注解定义工具该注解允许提供工具的名称、描述和输入参数等信息模型在调用工具时会根据这些信息生成相应的调用请求。定义工具示例如下Component public class Tools { Tool(description 获取当前日期和时间) public String getCurrentDateTime() { return 当前日期...; } Tool(description 设置闹钟) public void setAlarm(ToolParam(description 闹钟时间) String alarmTime) { // 设置闹钟的逻辑 } }以上注意点a. Component 加到类中表示是一个组件关键是将工具类让Spring容器管理起来也可以使用Configuration、Service标记类只要Spring 能扫描到并将其实例管理起来就可以。b. 工具方法使用Tool标注工具名称默认就是方法本身也可以通过Tool(nametool name)方式来指定。c. Tool(description...)中这里的description是工具描述大模型根据该描述决定要不要调用该工具。d. 工具方法中需要传入参数的通过使用ToolParam标注大模型自动决定调用时机和自动根据语义传入参数调用完成后生成最终对话。e. 工具不支持如下类型作为参数或返回值:Optional、异步类型如 CompletableFuture、Future、响应式类型如 Flow、Mono、Flux、函数式类型如 Function、Supplier、Consumer。工具使用//注册多个工具 ChatClient chatClient ChatClient.builder(chatModel) .defaultSystem(你是一个非常有帮助的助手你可以使用工具来帮助回答问题) .defaultTools(new ATools(),new BTools,new CTools ...) .build(); //与模型进行对话 String result chatClient.prompt() .user(给我设置10分钟后的闹钟) .call() .content();三、Tool Calling 使用案例如下创建SpringBoot项目在该项目中定义多个工具演示Spring AI中工具使用按照如下步骤实现即可。1) 创建SpringBoot项目命名为“SpringAIToolCalling”2) 配置项目pom.xml?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.5.3/version relativePath/ !-- lookup parent from repository -- /parent groupIdcom.example/groupId artifactIdSpringAIToolCalling/artifactId version0.0.1-SNAPSHOT/version nameSpringAIToolCalling/name descriptionSpringAIToolCalling/description properties java.version17/java.version /properties !-- 导入 Spring AI BOM用于统一管理 Spring AI 依赖的版本 引用每个 Spring AI 模块时不用再写 version只要依赖什么模块 Mavens 自动使用 BOM 推荐的版本 -- dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version1.0.0-SNAPSHOT/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-deepseek/artifactId /dependency /dependencies !-- 声明仓库 用于获取 Spring AI 以及相关预发布版本-- repositories repository idspring-snapshots/id nameSpring Snapshots/name urlhttps://repo.spring.io/snapshot/url releases enabledfalse/enabled /releases /repository repository nameCentral Portal Snapshots/name idcentral-portal-snapshots/id urlhttps://central.sonatype.com/repository/maven-snapshots//url releases enabledfalse/enabled /releases snapshots enabledtrue/enabled /snapshots /repository /repositories /project以上pom.xml中引入了“spring-ai-starter-model-deepseek”依赖包。3) 配置resources/application.propertiesspring.application.nameSpringAIToolCalling server.port8080 #配置 Deepseek的基础URL、密钥和使用模型 spring.ai.deepseek.base-urlhttps://api.deepseek.com spring.ai.deepseek.api-keysk-...21 spring.ai.deepseek.chat.options.modeldeepseek-chat4) 创建tools包并创建MyTools.java类package com.example.springaitoolcalling.tools; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; Component public class MyTools { Logger log LoggerFactory.getLogger(MyTools.class); Tool(description 返回当前系统时间) public String getCurrentTime() { log.info(调用 getCurrentTime 工具当前时间java.time.LocalDateTime.now().toString()); return java.time.LocalDateTime.now().toString(); } Tool(description 对两个数字执行加、减、乘、除运算) public double calculate( ToolParam(description 第一个数字) double a, ToolParam(description 第二个数字) double b, ToolParam(description 运算类型) String operation) { log.info(调用 calculate 工具第一个数字a,第二个数字b,运算类型operation); double result 0; switch (operation) { case add: result a b; break; case subtract: result a - b; break; case multiply: result a * b; break; case divide: if (b ! 0) { result a / b; } } return result; } private RestTemplate restTemplate new RestTemplate(); private String baseUrl http://shanhe.kim/api/youjia/youjia.php; Tool(description 查询指定省份的油价直接返回完整 JSON 字符串) public String getOilPriceJson(ToolParam(description 省份名称) String province) { log.info(调用 getOilPriceJson 工具查询省份province); String url String.format(%s?province%s, baseUrl, province); return restTemplate.getForObject(url, String.class); } }在MyTools.java类中我们定义了三个工具每个方法中进行了log日志输出getCurrentTime返回当前系统时间。calculate:对两个数字执行加、减、乘、除运算。getOilPriceJson:查询指定省份的油价直接返回完整 JSON 字符串。5) 创建controller包并创建ToolUseController.java文件package com.example.springaitoolcalling.controller; import com.example.springaitoolcalling.tools.MyTools; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.model.ChatModel; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; RestController RequestMapping(/ai) public class ToolUseController { private final ChatClient chatClient; public ToolUseController(ChatModel chatModel, MyTools tools) { this.chatClient ChatClient.builder(chatModel) .defaultSystem(你是一个非常有帮助的助手你可以使用工具来帮助回答问题) .defaultTools(tools) .build(); } GetMapping(/chat) public String chat(RequestParam(message) String message) { return chatClient.prompt() .user(message) .call() .content(); } }6) 启动项目并测试启动项目后浏览器输入如下内容进行测试# http://localhost:8080/ai/chat?message今天是什么日期 今天是xxx年xx月xx日 # http://localhost:8080/ai/chat?message123乘以200是多少 123乘以200等于24600。 # http://localhost:8080/ai/chat?message北京油价是多少 北京的油价如下 - 92号汽油7.17 元/升 - 95号汽油7.64 元/升 - 98号汽油9.14 元/升 - 0号柴油6.86 元/升 数据更新时间xxx xxx # http://localhost:8080/ai/chat?message今天天气如何 我无法直接获取天气信息但您可以告诉我您所在的城市或地区我可以尝试为您提供相关的天气查询建议或链接。特别提示以上代码运行后与工具调用相关的提问可以看到后台打印的日志会调用到工具对应的方法。我们也可以在“ToolUseController.java”中设置不使用工具将“defaultToolsnew MyTools”注释掉再进行测试会发现以上访问不会调用工具都由大模型根据已有知识进行回复可能存在不精准情况。