Spring AI Alibaba 的 ChatClient 工具注册与 Function Calling 实践总结
在实际使用 Spring AI 进行聊天应用开发时,碰到工具(Tool)注册、函数调用(Function Calling)以及
ChatClient 配置的问题。本文将总结从源码到实践的一些经验和知识点,帮助你更高效地集成 AI 聊天功能。
1. ChatClient Builder 的核心方法
Spring AI 提供了 ChatClient.Builder,用于构建一个可用的 AI 聊天客户端。常用方法包括:
- 默认系统提示
java
.defaultSystem(AiPrompts.GENERAL_ASSISTANT)
- 默认会话记忆顾问
java
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(
MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.build())
.build()
)
- 工具注册
java
.defaultTools(...) // 注册对象实例
.defaultToolNames(...) // 注册 Spring Bean 名称对应的工具
.tool(...) // 注册 @Tool 注解方法
注意:
.defaultTools()与.defaultToolNames()的作用不同,稍后详细说明。
2. Function Calling 与工具注册
Spring AI 支持把 Spring Bean 自动注册为 AI 可调用的函数(function calling)。常用方式有两种:
2.1 Bean + Supplier / Function
java
@Bean
@Description("查询所有学生信息")
public Supplier<List<Student>> getAllStudents() {
return () -> studentInfoService.selectStudentInfoList(new Student());
}
@Bean
@Description("根据学生ID查询学生信息")
public Function<Long, Student> getStudentById() {
return studentId -> studentInfoService.selectStudentInfoByStudentId(studentId);
}
Supplier:无入参,返回值为工具输出。Function<T, R>:有入参T,返回值为工具输出R。- 通过
.defaultToolNames("getAllStudents")自动注册,AI 可以直接调用。
2.2 @Tool 注解方法
java
@Tool(name = "getAllStudents", description = "查询所有学生信息")
public List<Student> getAllStudents() {
return studentInfoService.selectStudentInfoList(new Student());
}
- 适用于更标准的 function calling 方式
- 需要使用
.defaultTools()注册
3. .defaultTools() 与 .defaultToolNames() 区别
| 方法 | 适用场景 | 注意点 |
|---|---|---|
.defaultTools(Object... tools) |
注册对象实例(Lambda、工具对象) | 如果 Lambda 没有 @Tool 注解,会报错 "No @Tool annotated methods found",需要使用 .toolCallbacks() |
.defaultToolNames(String... beanNames) |
自动注册 Spring 上下文中 Bean 名称对应的工具 | 只能识别 Bean 名称对应的 Supplier / Function 或 @Tool 方法 |
.toolCallbacks() |
注册 @Tool 注解方法或 ToolCallback |
支持标准 function-calling |
✅ 结论:
- Supplier / Function Bean → 推荐
.defaultToolNames() - 普通方法 + @Tool 注解 →
.defaultTools()
4. 自动收集 Bean 注册工具
在实际项目中,如果工具数量较多,不希望手动写 .defaultToolNames(...),可以通过循环自动收集:
java
Map<String, Supplier> supplierBeans = applicationContext.getBeansOfType(Supplier.class);
Map<String, Function> functionBeans = applicationContext.getBeansOfType(Function.class);
Set<String> allToolNames = supplierBeans.keySet().stream().collect(Collectors.toSet());
allToolNames.addAll(functionBeans.keySet());
ChatClient client = ChatClient.builder(chatModel)
.defaultSystem("你是智能助手")
.defaultAdvisors(...)
.defaultToolNames(allToolNames.toArray(new String[0]))
.build();
- 自动扫描 Spring 上下文的所有 Supplier / Function Bean
- 避免手动列出工具名称
- 保持 ChatClient 配置简洁
5. Supplier 与 Function 区别
| 类型 | 参数 | 返回值 | 使用场景 |
|---|---|---|---|
Supplier<R> |
无 | R | 无输入参数工具,直接返回结果 |
Function<T, R> |
T | R | 需要输入参数的工具,例如根据 ID 查询对象 |
示例:
java
Supplier<List<Student>> getAllStudents; // 无入参
Function<Long, Student> getStudentById; // 入参为学生ID

本文记录于 MindCampus 毕设项目开发过程中,2024年12月,如果对你有帮助不妨留一个赞