Spring AI Chat Tool Calling 指南
前言
随着人工智能技术的快速发展,越来越多的企业开始尝试将 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 指南