Spring AI:让大模型住进 Spring 生态(七)

📅 2026/7/12 18:55:58
Spring AI:让大模型住进 Spring 生态(七)
专栏Spring AI 探索手札个人主页手握风云目录一、Tool Calling 工具调用1.1. 基础概念与定位1.2. 快速开发声明式注解方案1.3. Tool Calling 标准 6 步执行流程1.4. 两种工具定义开发方式1. 声明式Tool 注解实现2. 编程式MethodToolCallback 底层手动构建工具1.5. 底层核心组件规范1. ToolCallback工具回调顶层接口2. MethodToolCallback方法工具回调官方核心实现类3. ToolDefinition工具元定义接口4. ToolContext工具上下文1.6. 工具执行一、Tool Calling 工具调用1.1. 基础概念与定位Tool Calling 是 AI 通用技术模式允许 LLM 根据用户需求自动选择、调用外部函数 / API / 服务打破大模型仅能生成文本的局限实现与真实系统交互。Function Calling 属于早期出现的狭义概念最初仅指代调用开发者预先定义的 Java 方法而 Tool Calling 是范围更广的上层抽象概念能够覆盖自定义函数、接口、数据库、第三方服务等全部类型的外部工具。二者存在明确的从属关系Function Calling 是 Tool Calling 的一种具体实现方式在日常 AI 开发工作中这两个名词也常常被混合使用。工具调用主要分为两类核心落地场景第一类是实时信息检索场景由于大模型原生不具备获取实时在线数据的能力可通过工具调用完成天气、当前时间、各类联网动态数据的查询第二类为业务动作执行场景依托工具调用可完成订购车票、发送邮件、读写操作数据库、操控硬件设备等具备实际操作属性的业务行为。1.2. 快速开发声明式注解方案首先需要引入 jsonschema-generator 依赖该依赖可自动生成工具参数对应的 JSON Schema供大模型识别规范的参数格式。dependency groupIdcom.github.victools/groupId artifactIdjsonschema-generator/artifactId version4.38.0/version scopecompile/scope /dependency方案包含两组核心注解分别承担不同作用Tool 用于标记目标方法为 AI 可调用工具核心配置属性有 name工具名称、description核心属性直接决定模型是否会调用该工具、returnDirect、resultConverterToolParam 则用来自定义方法参数的说明信息关键属性为 required设置参数是否必填默认值 true与 description参数描述文本。注解作用关键属性Tool标记方法为 AI 可调用工具name (工具名)、description (核心决定模型是否调用)、returnDirect、resultConverterToolParam自定义方法参数说明required (是否必填默认 true)、description (参数描述)package com.yang.alibaba.tool; import org.springframework.ai.tool.annotation.Tool; import org.springframework.context.i18n.LocaleContextHolder; import java.time.LocalDateTime; public class DateTimeTools { Tool(description Get the current date and time in the users timezone) String getCurrentDateTime() { return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString(); } }完成工具方法定义后有两种途径将工具注入 ChatClient第一种是配置全局默认工具调用 defaultTools() 即可生效第二种是为单次对话设置临时工具使用 .tools() 方法配置临时工具会覆盖全局默认工具。package com.yang.alibaba.controller; import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel; import com.yang.alibaba.tool.DateTimeTools; 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 ChatClient chatClient; public ChatController(DashScopeChatModel chatModel) { this.chatClient ChatClient.builder(chatModel).build(); } RequestMapping(/call1) public String call1(String message) { return chatClient.prompt() .user(message) .tools(new DateTimeTools()) // 声明式 .call() .content(); } }// 全局默认工具 private ChatClient chatClient; public ChatController(DashScopeChatModel chatModel) { this.chatClient ChatClient.builder(chatModel) .defaultTools(new DateTimeTools()) .build(); } RequestMapping(/call1) public String call1(String message) { return chatClient.prompt() .user(message) .call() .content(); }启用工具时模型可自动匹配并执行对应工具方法返回真实业务数据若移除全部工具模型无法执行实际操作仅能输出文字类指引无法落地真实业务任务。1.3. Tool Calling 标准 6 步执行流程Tool Calling 具备一套标准化的六步闭环执行流程完整实现大模型联动外部工具处理实际业务需求的全链路逻辑。流程第一步为注册工具系统会预先向大模型下发全部可用工具的名称、功能描述以及入参对应的 JSON Schema 规范让模型提前掌握所有工具的能力边界与参数填写规则进入第二步模型决策阶段当用户输入提问后大模型会自主解析用户诉求判断当前问题是否需要调用外部工具补充信息若判定存在工具调用需求则输出标准化的工具调用请求第三步交由本地应用程序处理程序会根据请求中携带的工具标识精准匹配对应工具并完整运行工具内部的业务逻辑第四步应用程序接收工具运行完成后输出的真实业务结果第五步系统将工具返回的数据回传给大模型把这份数据追加至对话上下文当中最后第六步大模型结合用户原始提问与工具返回的真实业务数据整合信息生成流畅易懂的自然语言作为面向用户的最终回复至此一轮完整的 Tool Calling 调用流程全部完成。1.4. 两种工具定义开发方式Spring AI 封装 ToolCallback 作为工具统一接口提供两种创建工具的内置方案声明式Tool 注解开发简单日常业务首选编程式底层 MethodToolCallback 手动构建灵活自定义工具元信息适合动态工具场景。1. 声明式Tool 注解实现Tool Calling 源码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工具唯一标识模型调用时匹配工具不填则默认使用方法名同一类不能重名description工具功能描述模型判断是否调用工具的核心依据必须清晰详细模糊描述会导致调用失败returnDirect工具执行结果处理模式开关false结果传回大模型二次生成话术默认true直接返回原始结果给调用方跳过模型resultConverter工具返回值转换器默认内置DefaultToolCallResultConverter自动转字符串支持自定义转换类Spring AI 针对被 Tool 注解标注的工具方法会自动基于方法入参生成标准 JSON Schema 并提供给大模型这份 Schema 相当于工具专属的参数说明书能够让大模型清晰识别参数的数据类型、必填项与各类格式约束。该自动生成机制的核心作用是规范大模型调用工具时传入参数的整体结构从源头避免参数格式错误若需要丰富参数释义、补充取值范围等细节信息还可搭配 ToolParam 注解对参数描述做增强补充优化大模型的参数识别与传参准确性。ToolParam 参数注解用于给工具方法的入参添加结构化描述控制必填性Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) Retention(RetentionPolicy.RUNTIME) Documented public interface ToolParam { boolean required() default true; // 是否必填默认true参数加Nullable会自动变为可选 String description() default ; // 参数含义、格式、取值范围说明辅助模型传参 }Tool(description Set a user alarm for the given time) void setAlarm(ToolParam(description Time in ISO-8601 format) String time) { System.out.println(Alarm set for time); }测试接口http://127.0.0.1:8080/chat/call1?message为我设置下午 3 点的闹钟。绑定 ChatModel 底层通过 ToolCallingChatOptions 传入工具底层原生调用模型时生效。package com.yang.alibaba.controller; import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel; import com.yang.alibaba.tool.DateTimeTools; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.prompt.ChatOptions; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.model.tool.ToolCallingChatOptions; import org.springframework.ai.support.ToolCallbacks; import org.springframework.ai.tool.ToolCallback; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; RestController RequestMapping(/chatModel) public class ChatModelController { private ChatModel chatModel; public ChatModelController(DashScopeChatModel chatModel) { this.chatModel chatModel; } RequestMapping(/call) public String call(String message) { return chatModel.call(message); } RequestMapping(/callByTool) public String callByTool(String message) { ToolCallback[] dateTimeTool ToolCallbacks.from(new DateTimeTools()); ChatOptions chatOptions ToolCallingChatOptions.builder() .toolCallbacks(dateTimeTool) .build(); Prompt prompt new Prompt(message, chatOptions); return chatModel.call(prompt).getResult().getOutput().getText(); } }测试接口http://127.0.0.1:8080/chatModel/call?message告诉我当前的时间。http://127.0.0.1:8080/chatModel/callByTool?message告诉我当前的时间。2. 编程式MethodToolCallback 底层手动构建工具该方法适用于无法使用注解、需要动态自定义工具名称 / 描述 / 参数 Schema 的场景手动将普通 Java 方法封装为 ToolCallback。定义工具类package com.yang.alibaba.tool; public class WeatherTools { public String getCurrentWeatherByCityName(String cityName) { switch (cityName){ case 北京: return 北京今天天气: 晴空万里; case 上海: return 上海今天天气: 电闪雷鸣; case 广州: return 广州今天天气: 细雨蒙蒙; case 深圳: return 深圳今天天气: 乌云密布; default: return 没有该城市的天气信息; } } }整套 MethodToolCallback 的构建与注册流程遵循从业务方法提取、工具元数据封装、回调载体组装到模型注入的完整链路首先需要通过Java反射机制定位并获取业务能力对应的目标业务Method方法对象这是整个工具调用链路的底层业务逻辑载体拿到目标Method后调用 ToolDefinitions.builder(method) 工具元数据构造器基于当前业务方法实例构建 ToolDefinition 工具元数据对象在构造阶段可自定义配置工具对外调用标识 name、工具功能说明 description同时定义方法入参对应的输入 schema 参数规范为大模型提供识别工具入参格式的标准描述完成工具元数据封装后进入 MethodToolCallback 的组装环节组装时需要完成三组核心绑定分别绑定第一步反射获取的业务Method、该方法所属的业务实例对象用于反射执行实例方法、以及上一步构建完成的 ToolDefinition 工具元数据让MethodToolCallback同时承载工具对外描述信息与真实可执行的业务逻辑最后将组装完毕、具备完整调用能力的ToolCallbackMethodToolCallback实例注入 ChatClient 或 ChatModel 对话模型客户端完成工具注册大模型后续推理过程中判定需要调用对应工具时便可通过该回调载体执行底层业务方法。// 注入 ChatClient设置临时工具 RequestMapping(/call2) public String call2(String message) { Method method ReflectionUtils.findMethod(WeatherTools.class, getCurrentWeatherByCityName, String.class); ToolCallback toolCallback MethodToolCallback.builder() .toolDefinition(ToolDefinitions .builder(method) .description(根据给定的城市名称, 获取城市当前的天气) .build()) .toolMethod(method) .toolObject(new WeatherTools()) .build(); return chatClient.prompt() .user(message) .toolCallbacks(toolCallback) .call() .content(); }测试接口http://127.0.0.1:8080/chat/call2?message告诉我上海的天气情况。// 设置全局默认工具 Autowired public ChatController(DashScopeChatModel chatModel, ToolCallback weatherTool) { this.chatClient ChatClient.builder(chatModel) .defaultTools(new DateTimeTools()) .defaultToolCallbacks(weatherTool) .build(); }package com.yang.alibaba.config; import com.yang.alibaba.tool.WeatherTools; import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.method.MethodToolCallback; import org.springframework.ai.tool.support.ToolDefinitions; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; Configuration public class ToolConfig { Bean public ToolCallback weatherTool() { Method method ReflectionUtils.findMethod(WeatherTools.class, getCurrentWeatherByCityName, String.class); ToolCallback toolCallback MethodToolCallback.builder() .toolDefinition(ToolDefinitions .builder(method) .description(根据给定的城市名称, 获取城市当前的天气) .build()) .toolMethod(method) .toolObject(new WeatherTools()) .build(); return toolCallback; } }测试接口http://127.0.0.1:8080/chat/call?message告诉我深圳的天气情况。// 底层 ChatModel 绑定 RequestMapping(/callByTool2) public String callByTool2(String message) { Method method ReflectionUtils.findMethod(WeatherTools.class, getCurrentWeatherByCityName, String.class); ToolCallback toolCallback MethodToolCallback.builder() .toolDefinition(ToolDefinitions .builder(method) .description(根据给定的城市名称, 获取城市当前的天气) .build()) .toolMethod(method) .toolObject(new WeatherTools()) .build(); ChatOptions chatOptions ToolCallingChatOptions.builder() .toolCallbacks(toolCallback) .build(); Prompt prompt new Prompt(message, chatOptions); return chatModel.call(prompt).getResult().getOutput().getText(); }测试接口http://127.0.0.1:8080/chatModel/callByTool2?message告诉我广州的天气情况并给出出行建议。1.5. 底层核心组件规范1. ToolCallback工具回调顶层接口ToolCallback 是 Spring AI 里用于与 AI 模型交互的回调接口核心作用是允许开发者定义可被大模型调用的外部工具以此在 AI 应用中集成各类外部功能支撑大语言模型按需调用外部业务能力。public interface ToolCallback { Logger logger LoggerFactory.getLogger(ToolCallback.class); ToolDefinition getToolDefinition(); default ToolMetadata getToolMetadata() { return ToolMetadata.builder().build(); } String call(String toolInput); default String call(String toolInput, Nullable ToolContext toolContext) { if (toolContext ! null !toolContext.getContext().isEmpty()) { logger.info(By default the tool context is not used, override the method call(String toolInput, ToolContext toolcontext) to support the use of tool context.Review the ToolCallback implementation for {}, this.getToolDefinition().name()); } return this.call(toolInput); } }getToolDefinition()强制实现返回工具结构化元信息 ToolDefinition包含工具名、功能描述、入参格式是大模型判断是否调用工具的核心依据。getToolMetadata()默认空实现可选重写提供扩展非业务元数据权限、分类标签等仅用于框架扩展不影响工具核心调用逻辑。call(String toolInput)强制实现接收模型传入的 JSON 格式参数执行工具业务逻辑返回字符串格式执行结果结果会回传给大模型做后续处理。重载方法 call(String toolInput, ToolContext toolContext)默认抛异常支持携带上下文执行工具默认不支持上下文子类可重写开启上下文传递能力。2. MethodToolCallback方法工具回调官方核心实现类MethodToolCallback 是 Spring AI 框架中实现 Tool Calling 的核心机制该类为 final 类型且实现了 ToolCallback 顶层接口核心作用是将普通 Java 方法包装成 AI 模型能够识别、调用的标准化工具。public final class MethodToolCallback implements ToolCallback { private static final Logger logger LoggerFactory.getLogger(MethodToolCallback.class); private static final ToolCallResultConverter DEFAULT_RESULT_CONVERTER new DefaultToolCallResultConverter(); private static final ToolMetadata DEFAULT_TOOL_METADATA ToolMetadata.builder().build(); private final ToolDefinition toolDefinition; private final ToolMetadata toolMetadata; private final Method toolMethod; Nullable private final Object toolObject; private final ToolCallResultConverter toolCallResultConverter; }全局默认静态常量默认结果转换器、空元数据对象toolDefinition工具元定义存储工具名称、描述、入参 JSON SchematoolMetadata扩展元数据toolMethod通过反射获取的目标 Java 方法toolObject方法所属实例对象静态方法可传 nulltoolCallResultConverter自定义返回值转换器将方法返回值转为字符串传给大模型。该实现类支撑 Spring AI 两种工具开发方式既可以配合 Tool、ToolParam 注解实现声明式工具定义也支持通过 Builder 构建器完成编程式工具创建能够自动扫描解析方法上的注解信息、自动生成入参对应的 JSON Schema最终依靠反射执行目标业务方法完整完成普通 Java 方法到 AI 可调用工具的整套封装逻辑。3. ToolDefinition工具元定义接口ToolDefinition 是用于向大模型展示工具能力的标准化元数据载体每一个 ToolCallback 实例都必须持有一个 ToolDefinition 对象其作用是向模型清晰说明工具具备什么功能、调用时需要传入哪些参数。该接口规定了三个必须实现的抽象方法public interface ToolDefinition { String name(); String description(); String inputSchema(); static DefaultToolDefinition.Builder builder() { return DefaultToolDefinition.builder(); } }方法作用说明name()工具唯一标识名称同一会话内不可重名模型调用时靠名称匹配工具description()工具功能描述核心关键描述清晰度直接决定模型是否正确选择调用该工具inputSchema()JSON Schema 字符串规范工具入参参数类型、必填项、取值约束、字段说明创建 ToolDefinition 主要有两种途径第一种为自动构建通过 ToolDefinition.from (method) 方式程序会自动扫描方法上的 Tool 与 ToolParam 注解自动生成配套元数据第二种是手动自定义构建借助 ToolDefinition.Builder 构造器手动设置工具名称、功能描述与自定义 JSON Schema能够覆盖自动解析生成的默认元数据内容。4. ToolContext工具上下文ToolContext 是用于给工具传递私有业务上下文数据的载体这类上下文数据仅服务端可见不会发送给大模型能够实现不同会话、不同用户之间的数据隔离适合存放租户 ID、登录用户标识、企业权限标签、环境区分参数等隐私或业务隔离类信息。public final class ToolContext { public static final String TOOL_CALL_HISTORY TOOL_CALL_HISTORY; private final MapString, Object context; public ToolContext(MapString, Object context) { this.context Collections.unmodifiableMap(context); } public MapString, Object getContext() { return this.context; } public ListMessage getToolCallHistory() { return (List)this.context.get(TOOL_CALL_HISTORY); } }ChatClient 会话层调用 .toolContext(Map) 传入上下文ChatModel 底层通过 ToolCallingChatOptions 绑定上下文封装进 Prompt 对象发起请求。使用时只需在自定义工具方法中增加 ToolContext 类型入参工具执行阶段便可读取上下文内携带的业务标识完成数据库查询等操作全程上下文数据不会流入大模型保障敏感业务信息安全。1.6. 工具执行工具执行指使用模型传入的参数调用对应工具、执行业务逻辑并返回结果的完整流程ToolCallingManager 是 Spring AI 中管控工具调用全生命周期的核心顶层接口全权负责两件核心事识别可用工具、执行模型发起的工具调用。public interface ToolCallingManager { ListToolDefinition resolveToolDefinitions(ToolCallingChatOptions chatOptions); ToolExecutionResult executeToolCalls(Prompt prompt, ChatResponse chatResponse); static DefaultToolCallingManager.Builder builder() { return DefaultToolCallingManager.builder(); } }resolveToolDefinitions(ToolCallingChatOptions chatOptions)解析聊天配置中的全部工具定义整理出可用工具清单告知 AI 模型当前可调用哪些工具。executeToolCalls(Prompt prompt, ChatResponse chatResponse)接收模型下发的工具调用请求完成工具匹配、参数传入、方法执行并返回工具执行结果。应用将工具定义封装进聊天请求 Prompt调用 ChatModel API 发送给大模型大模型判断需要调用工具返回携带工具名称、入参的 ChatResponseChatModel 将工具调用请求转发给 ToolCallingManagerToolCallingManager 根据工具名匹配对应工具使用参数执行工具逻辑工具执行完成将原始结果返回给 ToolCallingManager管理器把工具结果封装为 ToolResponseMessage回传给 ChatModelChatModel 将工具执行结果提交给 AI 模型AI 模型结合工具返回的真实数据推理生成最终回答经由 ChatClient 返回给前端调用方。