前言
随着人工智能技术的快速发展,越来越多的企业开始尝试将 AI 能力集成到自己的系统中。Spring AI 作为一个面向 Java 开发者的 AI 框架,提供了强大的工具调用(Tool Calling)机制,帮助开发者更高效地构建和扩展 AI 应用。
在本文中,我们将围绕 Spring AI 中的工具调用功能展开讨论。通过实际的例子和通俗易懂的解释,我们将带你一步步了解如何在 Spring AI 中定义、使用和管理工具,并探索其背后的设计理念和最佳实践。
先决条件
在阅读本文之前,建议你已经对以下 Spring AI 基础概念有一定的了解:
-
Chat Model(聊天模型):
理解 Spring AI 中如何与 AI 模型进行交互是使用工具调用功能的前提。你可以参考官方文档或相关博客,学习如何配置和使用 ChatClient、Prompt 和 AiResponse 等核心类。 -
Chat Memory(聊天记忆):
工具调用通常发生在多轮对话中,因此理解如何管理对话历史和上下文信息(如 ChatMemory 和 ConversationContext)将有助于更好地掌握工具调用的使用场景。
如果你还不熟悉这些内容,建议先学习 Spring AI 中的 Chat Model 和 Chat Memory 相关知识,这将帮助你更顺利地理解和应用本文介绍的工具调用机制。
本文基于 Spring AI v1.0.0版本编写。由于该框架仍在持续演进中,后续版本可能会对 API 或功能做出调整。因此,文中所述内容可能不适用于未来版本,请以Spring AI 官方文档为准。
本栏目其他有关 Spring AI 的其他博客链接:
1.Spring AI Chat Client API 指南
2.Spring AI Chat Memory 指南
一、方法作为工具(Methods as Tools)
1. 声明式定义:@Tool 注解
在 Spring AI 中,我们可以通过 @Tool
注解来标记一个方法为“可被 AI 调用的工具”。这意味着当 AI 模型需要执行某个任务时,它可以直接调用这些方法。这种方式非常适合结构清晰、逻辑明确的功能。
public class WeatherTools {@Tool(description = "获取指定城市的天气信息")public String getWeather(String location) {// 模拟调用天气APIreturn "晴天,在" + location;}
}
小贴士:
你可以给 @Tool
添加描述信息,这样 AI 更容易理解这个工具的作用(例如 (description = "获取天气")
)。
2. 编程式定义:MethodToolCallback 接口
如果你希望在运行时动态决定调用哪个方法,可以使用 MethodToolCallback
接口。它允许你根据方法名和参数灵活地实现工具调用逻辑。
public class DynamicToolProvider implements MethodToolCallback {@Overridepublic Object invoke(Method method, Object[] args) {if (method.getName().equals("getWeather")) {String location = (String) args[0];return "晴天,在" + location;}return null;}
}
为什么有用?
当你不确定具体的方法结构或希望统一处理多个方法时,这种模式非常实用。
3. 方法工具的限制
并不是所有的方法都可以直接作为工具使用。它们必须是 public
的,不能是 static
,并且返回类型要能被 Spring AI 识别和处理。
// 错误示例:私有方法无法被识别为工具
private String getWeather(String location) {return "晴天,在" + location;
}
建议:
尽量保持方法签名简单清晰,避免使用复杂的泛型或自定义类型。
二、函数作为工具(Functions as Tools)
4. 编程式定义:FunctionToolCallback 接口
除了传统的 Java 方法,Spring AI 也支持使用函数式编程的方式定义工具。这特别适合那些需要高度灵活性和组合性的场景。
public class FunctionToolProvider implements FunctionToolCallback {@Overridepublic Object apply(Map<String, Object> arguments) {String location = (String) arguments.get("location");return "晴天,在" + location;}
}
好处:
函数形式更加简洁,适合处理动态参数和复杂逻辑。
5. 动态定义:@Bean + @Tool
你也可以通过 Spring 的 @Bean
注解配合 @Tool
来注册一个函数作为工具。这种方式便于在配置类中集中管理工具。
@Configuration
public class ToolConfig {@Bean@Tool(description = "获取天气信息")public Function<Map<String, Object>, String> getWeather() {return args -> {String location = (String) args.get("location");return "晴天,在" + location;};}
}
提示:
这种方式适合与 Spring 容器集成,方便进行依赖注入和生命周期管理。
6. 函数工具的限制
函数工具要求输入参数是一个 Map<String, Object>
类型,输出结果也需要能够被转换成 JSON 等格式供 AI 模型使用。
@Bean
@Tool
public String getWeather(String location) { // 参数不是Map,无法正确解析return "晴天,在" + location;
}
解决方案:
始终使用 Map<String, Object>
作为函数参数类型,确保兼容性。
三、工具的定义与规范(Tool Specification)
7. 工具回调(Tool Callback)
你可以通过实现 ToolCallback
接口,在工具执行前后插入自定义逻辑,比如日志记录、权限检查等。
public class LoggingToolCallback implements ToolCallback {@Overridepublic void beforeInvoke(ToolInvocationContext context) {System.out.println("即将调用工具:" + context.getMethod().getName());}@Overridepublic void afterInvoke(ToolInvocationContext context, Object result) {System.out.println("工具调用完成:" + context.getMethod().getName() + ",结果:" + result);}
}
应用场景:
调试、性能监控、安全审计等。
8. 工具定义(Tool Definition)
每个工具都应该有一个清晰的定义,包括名称、描述、参数等。这有助于 AI 模型更好地理解和使用它。
例子(工具定义文件):
{"name": "getWeather","description": "获取指定地点的天气信息","parameters": [{"name": "location","type": "string","description": "要查询天气的城市或地区"}]
}
作用:
帮助 AI 生成更准确的请求,并提升工具的可维护性。
9. JSON Schema 定义参数格式
为了确保工具的参数结构一致且可验证,我们可以使用 JSON Schema 来定义参数格式。
{"type": "object","properties": {"location": {"type": "string"}},"required": ["location"]
}
优势:
防止传入错误类型的参数,提高系统的健壮性。
10. 结果转换(Result Conversion)
工具返回的结果可能需要进一步处理才能被 AI 模型使用。我们可以使用 ResultConverter
来统一转换格式。
public class WeatherResultConverter implements ResultConverter {@Overridepublic Object convert(Object result) {if (result instanceof String) {return new WeatherResponse((String) result);}return result;}
}
适用场景:
标准化返回值、添加额外字段、封装错误信息等。
11. 工具上下文(Tool Context)
工具上下文包含了调用时的环境信息,如参数、用户身份、调用链等,可以在工具内部访问这些信息以增强逻辑。
public class MyTool {@Toolpublic String getWeather(ToolContext context) {String location = (String) context.getArguments().get("location");return "晴天,在" + location;}
}
用途:
用于日志、权限控制、多租户等高级功能。
12. 直接返回(Return Direct)
有时候我们希望工具直接返回结果而不经过任何转换,这时可以设置 returnDirect = true
。
@Tool(returnDirect = true)
public String getWeather(String location) {return "晴天,在" + location;
}
适用情况:
返回值已经是标准格式,无需再做处理。
四、工具执行(Tool Execution)
13. 框架控制的执行(Framework-Controlled)
Spring AI 默认会自动管理工具的调用流程,你只需要定义好工具即可,无需关心底层细节。
@Tool
public String getWeather(String location) {return "晴天,在" + location;
}
优点:
开箱即用,适合大多数场景。
14. 用户控制的执行(User-Controlled)
如果你希望手动控制工具的调用流程,可以使用 ToolRegistry
和 ToolExecutor
来实现。
public class CustomToolExecutor {private final ToolRegistry registry;public CustomToolExecutor(ToolRegistry registry) {this.registry = registry;}public void executeTool(String toolName, Map<String, Object> args) {Tool tool = registry.getTool(toolName);tool.invoke(args);}
}
适用场景:
需要深度定制调用逻辑、实现插件化架构等。
五、异常处理(Exception Handling)
工具在执行过程中可能会抛出异常,Spring AI 提供了统一的异常处理机制,确保整个流程不会中断。
@Tool
public String getWeather(String location) throws Exception {if (location == null || location.isEmpty()) {throw new IllegalArgumentException("地点不能为空");}return "晴天,在" + location;
}
建议:
使用统一的异常处理器,返回友好的错误信息给 AI 模型。
六、工具解析(Tool Resolution)
工具解析器负责根据名称和参数找到对应的工具实现。你可以自定义解析逻辑,以支持不同的工具来源(如数据库、远程服务等)。
public class CustomToolResolver implements ToolResolver {@Overridepublic Tool resolve(String toolName) {if ("getWeather".equals(toolName)) {return new WeatherTool();}return null;}
}
用途:
实现插件系统、多版本工具共存、按需加载等高级功能。
七、可观测性(Observability)
为了更好地监控和调试工具的执行过程,Spring AI 支持将调用信息记录下来,供后续分析使用。
public class ToolLogger {public void logExecution(ToolInvocationContext context, Object result) {System.out.println("调用工具:" + context.getMethod().getName() +",参数:" + context.getArguments() +",结果:" + result);}
}
作用:
帮助定位问题、优化性能、提供运维支持。
结语
通过本文的介绍,我们了解了 Spring AI 中关于工具调用的完整体系,包括如何定义工具、如何传递参数、如何处理结果以及如何进行异常处理和监控。
无论是使用简单的 @Tool
注解还是复杂的 FunctionToolCallback
,Spring AI 都为我们提供了丰富的选项来满足不同场景的需求。希望这篇文章能帮助你更好地掌握 Spring AI 的工具调用机制,并在实际项目中灵活运用。
如果你正在构建一个 AI 驱动的应用程序,Spring AI 的工具调用功能无疑是一个强大而实用的利器!
上一部分: Spring AI Chat Memory 指南