SpringAI Tool Calling(工具调用)

发布时间:2026/6/28 15:16:28

SpringAI Tool Calling(工具调用) 一.Tool Calling概述随着大语言模型(LLM)能力的飞速发展我们不再满足于仅仅让它们生成文本或回答问题。我们期望它们能成为真正的智能助手能够与外部世界交互执行具体任务比如查询数据库、发送邮件或分析数据。为了解决这一挑战工具调用 (Tool Calling)应运而生。Tool Calling (工具调用)是 AI 应用程序中的一种常见模式允许大语言模型(LLM)根据用户请求智能地选择、调用外部工具如函数、API、服务并获取结果的技术流程从而增强其功能。可以把 LLM 想象成为一个知识渊博、无所不知的博士不论你问他什么理论问题他都可以对答如流。但如果你问他 “帮我预订一下今晚公司附近那家最热门的意大利餐厅”他就会束手无策 —— 因为他虽然能计算出公司附近最热门的意大利餐厅但他没有连接订座系统无法订座。Tool Calling 就是解决这个问题的它就像给这个博士配备了一个万能遥控器这个遥控器有很多按钮这些按钮可以执行一些具体任务比如博士思考餐厅名称按钮来执行订座。Tool Calling 让 LLM 从一个 “无所不知的学者” 变成了一个 “无所不能的指挥家”它负责思考和规划而具体的工作则由外部工具执行。二.和Function Calling 什么关系?官方介绍如下:Tool calling (also known as function calling) is a common pattern in AI applications allowing a model to interact with a set of APIs, or tools, augmenting its capabilities.摘自 Tool Calling :: Spring AI ReferenceFunction Calling 是 Tool Calling 早期更为流行的术语。它是指 LLM 请求调用一个开发者预定义的函数 (Function)这里的 函数 就是你代码中的一个方法。Tool Calling 是一个更通用、更广泛的概念不仅包含了 Function Calling还涵盖了调用其他类型的工具。Function Calling 好比是万能遥控器上的一个具体的按钮比如 开机 按钮它非常具体按下去就直接执行开机这个单一操作。Tool Calling 则是整个万能遥控器的概念这个遥控器上不仅有 开机 按钮还有 调音量、换台、投屏 等按钮。它是一个更上层、更通用的抽象涵盖了函数、API、查询等各种工具。简单来说在 Spring AI 里定义一个Tool(工具)它通常就是一个Function(函数)我们可以认为 Function Calling 是实现 Tool Calling 的具体技术方式。两者在日常讨论中经常混用但 Tool Calling 这个词更全面。三.应用场景1. 信息检索大模型可以借助 Tool 从外部资源如数据库、Web 服务、文件系统或者 WEB 搜索引擎检索信息。如人工智能模型无法访问实时信息任何假设了解当前日期或天气预报等信息的问题都无法由模型回答。但是我们可以提供一个可以检索此信息的工具并让模型在需要访问实时信息时调用此工具。2. 采取行动大模型可以借助 Tool 完成一些执行操作如发送电子邮件、在数据库中创建新记录、提交表单或触发工作流如模型可以生成预订北京旅行的计划。但是该模型不具备执行计划的能力。这就是工具的用武之地。它们可用于执行模型生成的计划。四.快速应用1.添加依赖dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter-dashscope/artifactId /dependency dependency groupIdorg.springframework/groupId artifactIdspring-webflux/artifactId /dependency !-- tool calling -- dependency groupIdcom.github.victools/groupId artifactIdjsonschema-generator/artifactId !-- 可根据实际情况使用最新稳定版本 -- version4.37.0/version /dependency /dependencies dependencyManagement dependencies dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-bom/artifactId version1.0.0.2/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement2.配置文件spring: ai: dashscope: api-key: ${DASH_SCOPE_API_KEY} #阿里百炼平台申请的api-key3.调用工具代码与结果演示import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel; import org.springframework.ai.chat.client.ChatClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; RestController RequestMapping(/chat) public class ChatController { private final ChatClient client; public ChatController(DashScopeChatModel dashScopeChatModel) { this.client ChatClient.builder(dashScopeChatModel).build(); } RequestMapping(/call) public String chat(String message) { return client.prompt() .user(message) .call() .content(); } }4.定义工具tool calling依赖上面已经添加import org.springframework.ai.tool.annotation.Tool; import java.time.LocalDateTime; public class DateTimeTools { Tool(description A tool to get the current date and time) public String getCurrentDateTime() { return LocalDateTime.now().atZone(java.time.ZoneId.systemDefault()).toString(); } }5.应用工具RequestMapping(/call) public String chat(String message) { return client.prompt() .user(message) .tools(new DateTimeTools()) //添加工具 .call() .content(); }6.运行结果五.Tool Calling 原理1.Tool Calling 请求响应流程a) 注册工具: 在向 AI 模型发送请求时应用程序需要提前告诉模型有哪些工具可用包括工具的名称 (name)、描述 (description) 和参数格式 (input schema)描述 (Description) 是灵魂这是模型决定是否调用工具的核心依据描述必须清晰准确。一个模糊的描述 (如 处理数据) 会导致模型无法正确调用。一个清晰的描述 (如 根据城市名称查询该城市的当前天气温度) 则能极大提高调用的准确率b) 模型决策: AI 模型根据对话内容判断是否需要调用工具当模型决定调用工具时它会发送一个工具调用请求其中包含工具名称和符合预定义的输入参数。c) 查找并执行: 应用程序接收到这个 工具调用请求 后会根据工具名称找到对应的工具并用模型提供的参数来执行它。d) 获取结果: 工具执行后会产生一个结果 (比如查询到了今天的温度是 25 度)应用程序会处理返回的结果。e) 返回结果: 应用程序将这个工具执行的结果再次发送给 AI 模型。f) 生成最终回复: AI 模型结合工具返回的结果组织语言生成最终的用户回复。2.Tool Calling 部分源码解释Spring AI 为方法转工具即ToolCallback提供了两种内置方式声明式通过Tool注解实现编程式通过底层的MethodToolCallback实现a) 声明式定义工具Tool注解Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) Retention(RetentionPolicy.RUNTIME) Documented public interface Tool { String name() default ; String description() default ; boolean returnDirect() default false; Class? extends ToolCallResultConverter resultConverter() default DefaultToolCallResultConverter.class; }Name指定工具的名称如果不指定则默认使用方法名称。AI 模型在调用工具时使用此名称来标识工具。因此不允许在同一类中有两个同名的工具。Description工具的描述模型可以使用它来了解何时以及如何调用工具如果不指定则使用方法名。建议详细清晰地描述工具的功能这对于工具的使用至关重要直接影响大模型的使用效果。returnDirect指定工具执行的结果是直接返回还是要发给大模型默认发送给大模型。如果为true 上述流程直接从4--6不会在发给大模型处理之后返回用户了。resultConverter指定工具执行结果转换器。Spring AI 内置了一个默认将工具调用结果转换为 String如果有特殊业务需求可以自行实现。input schema是什么?JSON Schema 是一种用于描述和验证 JSON 数据结构的规范。它定义了 JSON 数据应具备的格式、类型、字段、约束条件等就像是一份数据模板或数据说明书用来确保 JSON 数据符合预期的结构。我们可以把 JSON Schema 想象成一个「表格填写指南」表格 要接收的 JSON 数据填写指南 JSON Schema说明哪些项必填、是什么类型、有什么限制例如{ name: Alice, age: 28, email: aliceexample.com, hobbies: [reading, swimming] } { name: Alice, age: 28, email: aliceexample.com, hobbies: [reading, swimming] }对应的 JSON Schema{ $schema: https://json-schema.org/draft/2020-12/schema, $id: https://example.com/user.schema.json, title: User, type: object, properties: { name: { type: string, description: 用户姓名 }, age: { type: integer, minimum: 0, description: 用户年龄 }, email: { type: string, format: email, description: 电子邮箱地址 }, hobbies: { type: array, items: { type: string }, optional: true } }, required: [name, age, email] }在工具调用流程中JSON Schema 用于定义工具的输入参数格式。开发人员可以通过ToolParam注解为输入参数提供额外信息如描述、是否必需等默认情况下所有输入参数均为必需参数。import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; class DateTimeTools { Tool(description Set a user alarm for the given time) void setAlarm(ToolParam(description Time in ISO-8601 format) String time) { LocalDateTime alarmTime LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME); System.out.println(Alarm set for alarmTime); } }ToolParam 注解源码定义Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) Retention(RetentionPolicy.RUNTIME) Documented public interface ToolParam { /** * 指定参数是否为必填默认必填。如果参数被标记为Nullable则该参数将被视为可选 * 除非使用ToolParam注解显式标记为必需 */ boolean required() default true; /** * 工具参数的描述模型通过描述可以更好的理解如何使用它例如参数应采用什么格式 * 允许使用哪些值等。 */ String description() default ; }工具分类工具分为运行时工具(特定接口调用时加载)和默认工具(所有请求都会加载的)可以在创建chatclient的时候加上defaultToolsprivate final ChatClient client; public ChatController(DashScopeChatModel dashScopeChatModel) { this.client ChatClient.builder(dashScopeChatModel) .defaultTools(new DateTimeTools()) .build(); }b) 编程式定义工具定义工具public class WeatherTools { String getCurrentWeatherByCityName(String cityName) { switch (cityName) { case 北京: return 北京今天天气晴空万里; case 上海: return 上海今天天气电闪雷鸣; case 广州: return 广州今天天气细雨蒙蒙; default: return 没有该城市的天气信息; } } }上述这个还只是一个方法 还不是工具在代码中将该方法转化为可调用的工具RequestMapping(/call2) public String chat2(String message) { //获取天气工具方法 Method method ReflectionUtils.findMethod(WeatherTools.class, getCurrentWeatherByCityName, String.class); //创建工具回调 ToolCallback toolCallback MethodToolCallback.builder() .toolDefinition(ToolDefinitions.builder(method) .description(Get current weather by city name) .build()) .toolMethod(method) .toolObject(new WeatherTools()) .build(); return client.prompt() .user(message) .toolCallbacks(toolCallback) //添加工具 .call() .content(); }.测试结果MethodToolCallback和ToolDefinitions介绍一下内容截取自spring ai官方 链接: https://springdoc.cn/spring-ai/api/tools.html添加默认工具直接在构造方法初始化client的时候添加public ChatController(DashScopeChatModel dashScopeChatModel) { //获取天气工具方法 Method method ReflectionUtils.findMethod(WeatherTools.class, getCurrentWeatherByCityName, String.class); //创建工具回调 ToolCallback toolCallback MethodToolCallback.builder() .toolDefinition(ToolDefinitions.builder(method) .description(Get current weather by city name) .build()) .toolMethod(method) .toolObject(new WeatherTools()) .build(); this.client ChatClient.builder(dashScopeChatModel) .defaultToolCallbacks(toolCallback) //添加默认工具 .build(); }如果臃肿不美观 可以运用IOC思想提取创建ToolCallBack类的方法 交给spring容器管理 然后再构造方法注入3.工具规范a) ToolCallbackToolCallback 是一个用于与 AI 模型交互的回调接口允许开发者定义可被 AI 调用的外部工具在 AI 应用比如大语言模型中集成工具(Tools)让 AI 模型可以在需要时调用外部功能。public interface ToolCallback { /** * 返回该工具的元信息描述 * ToolDefinition 包含工具名称、描述、参数列表等结构化信息供 AI 模型理解“什么情况下该调用这个工具”以及“需要传什么参数”。 * 必须实现是函数调用机制的核心部分 * return */ ToolDefinition getToolDefinition(); /** * 提供额外的非功能性元数据主要用于框架层面的扩展性支持不影响核心逻辑。 * 使用了 default 方法意味着子类可以不重写默认返回空的元数据对象。 * return */ default ToolMetadata getToolMetadata() { return ToolMetadata.builder().build(); } /** * 抽象方法必须由实现类提供具体逻辑。 * 接收一个字符串输入通常是 JSON 格式的参数执行业务逻辑并返回结果字符串。 * 结果会传回给 AI 模型供其继续推理或生成回复。 */ String call(String toolInput); /** * 带上下文的调用方法也是默认实现。 * 如果toolContext有值则不支持主要用于被子类重写支持上下文功能 */ default String call(String toolInput, Nullable ToolContext toolContext) { if (toolContext ! null !toolContext.getContext().isEmpty()) { throw new UnsupportedOperationException(Tool context is not supported!); } else { return this.call(toolInput); } } }b) MethodToolCallbackMethodToolCallback 是 Spring AI 框架中实现 Tool Calling的核心机制之一。它用于将普通 Java 方法包装成 AI 模型可调用的“工具”Tool。public final class MethodToolCallback implements ToolCallback { //工具默认执行的转换器 private static final ToolCallResultConverter DEFAULT_RESULT_CONVERTER new DefaultToolCallResultConverter(); //工具默认元数据 private static final ToolMetadata DEFAULT_TOOL_METADATA ToolMetadata.builder().build(); //工具定义也称为工具的元信息名字、描述、参数列表等告诉 AI“我能干啥” private final ToolDefinition toolDefinition; //工具额外元数据(如权限分类) private final ToolMetadata toolMetadata; //真正要执行的那个 Java 方法对象通过反射获取 private final Method toolMethod; //工具对象如果方法不是静态的需要这个对象来调用即 object.method() Nullable private final Object toolObject; //工具转换器:把方法返回值转成字符串返回给 AI默认用 JSON private final ToolCallResultConverter toolCallResultConverter; }c) ToolDefinitionpublic interface ToolDefinition { /** * 工具名称。在提供给模型的工具集中是唯一的 */ String name(); /** * AI模型使用工具描述来确定工具的功能 */ String description(); /** * 用于调用工具的参数的模式 */ String inputSchema(); }ToolDefinition 实例ToolDefinition toolDefinition ToolDefinition.builder() .name(currentWeather) .description(Get the weather in location) .inputSchema( { type: object, properties: { location: { type: string }, unit: { type: string, enum: [C, F] } }, required: [location, unit] } ) .build();d) ToolContextSpring AI 支持通过ToolContext API向工具传递额外的上下文信息。此功能允许开发人员提供用户自定义的额外数据这些数据可与 AI 模型传递的工具参数一起在工具执行过程中使用。工具添加上下文 还是以获取当前时间为例Tool(description A tool to get the current date and time) public String getCurrentDateTime(ToolContext context) { System.out.println(userID: context.getContext().get(userID)); return LocalDateTime.now().atZone(java.time.ZoneId.systemDefault()).toString(); }RequestMapping(/call) public String chat(String message) { return client.prompt() .user(message) .tools(new DateTimeTools()) //添加工具 .toolContext(Map.of(userID, 12345)) //调用时给工具传入上下文信息 .call() .content(); }测试结果e) Return Direct默认情况下工具调用结果将作为响应返回模型随后模型可利用该结果继续对话。某些场景下开发人员可能希望将结果直接返回调用方而非传回模型。例如当构建依赖 RAG 工具的代理时开发人员可能希望直接将检索结果返回调用方而非传回模型进行不必要的后处理默认值为false二者对比4.工具的执行工具执行是指使用提供的输入参数调用工具并返回结果的过程。这个过程由ToolCallingManager接口处理该接口是 Spring AI 中负责管理 AI 调用工具 全过程的核心组件负责管理工具执行的完整生命周期。它主要管控以下核心问题哪些工具可用AI 请求调用工具时怎么执行执行结果如何返回给 AI 继续对话public interface ToolCallingManager { /** * 从模型的工具调用选项中解析工具定义告诉模型我能用哪些工具 */ ListToolDefinition resolveToolDefinitions(ToolCallingChatOptions chatOptions); /** * 执行模型所要求的工具调用也就是真正的去调工具 */ ToolExecutionResult executeToolCalls(Prompt prompt, ChatResponse chatResponse); }流程图流程图文字解释当需要向模型提供工具时我们将其定义包含在聊天请求Prompt中并调用ChatModelAPI 将请求发送至 AI 模型。当模型决定调用工具时它会发送包含工具名称及符合定义模式的输入参数的响应ChatResponse。ChatModel将工具调用请求发送至ToolCallingManagerAPI。ToolCallingManager负责识别需调用的工具并使用提供的输入参数执行该工具。工具调用结果返回至ToolCallingManager。ToolCallingManager将工具执行结果返回给ChatModel。ChatModel将工具执行结果返回 AI 模型ToolResponseMessage。AI 模型利用工具调用结果作为附加上下文生成最终响应并通过ChatClient将其返回调用方ChatResponse默认情况下Spring AI 在每个ChatModel实现中透明地管理工具执行生命周期。但开发人员可选择退出此行为自行控制工具执行。

相关新闻