Spring AI Alibaba Tools 完全指南:从基础到进阶
本文基于 Spring AI Alibaba 1.1.2.0 官方文档,提供一份完整、可直接运行的 Tools 示例项目,涵盖所有常见创建方式、注册方法、高级特性,并修正了常见的编译错误(如内部 public record 问题)。
一、Tools 核心概念
Tools(工具) 是 Agent 调用来执行操作的组件,它们通过定义良好的输入和输出让模型与外部世界交互。主要应用场景:
| 场景 | 说明 | 示例 |
|---|---|---|
| 信息检索 | 从外部源获取实时数据 | 查询天气、搜索数据库、获取当前时间 |
| 执行操作 | 在系统中执行具体任务 | 发送邮件、创建记录、设置闹钟 |
工作流程:
用户提问 → Model 决定调用 Tool → 应用程序执行 Tool → 结果返回 → 发送回 Model → 生成最终回复
在 AI 应用中,大语言模型(LLM)本身无法访问实时信息或执行实际操作。Tools(工具) 正是为了解决这一限制而设计的。
1.1 Tools 的核心价值
Tools 是 Agent 调用来执行操作的组件,它们通过定义良好的输入和输出让模型与外部世界交互,从而扩展模型的能力。Tools 主要应用于两大场景:
| 场景 | 说明 | 示例 |
|---|---|---|
| 信息检索 | 从外部源获取实时数据 | 查询天气、搜索数据库、获取当前时间 |
| 执行操作 | 在系统中执行具体任务 | 发送邮件、创建记录、设置闹钟 |
1.2 Tool Calling 的工作流程
Tool calling 的核心流程如下:
text
1. 用户提问 → 2. Model 决定调用 Tool → 3. 应用程序执行 Tool
↓
4. Tool 结果返回 → 5. 结果发送回 Model → 6. Model 生成最终回复
关键安全原则:Model 永远无法直接访问作为 Tools 提供的任何 API,Tool 的实际执行由客户端应用程序完成,这是一个关键的安全考量。
二、创建 Tool 的方式
Spring AI Alibaba 提供了三种创建 Tool 的方式:
2.1 声明式:使用 @Tool 注解(推荐)
这是最常用、最简洁的方式,通过在方法上添加 @Tool 注解将方法转换为 Tool。
java
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;
@Component
public class DateTimeTools {
@Tool(description = "Get the current date and time in the user's timezone")
String getCurrentDateTime() {
return LocalDateTime.now().atZone(
LocaleContextHolder.getTimeZone().toZoneId()
).toString();
}
@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);
}
}
@Tool 注解属性说明
| 属性 | 说明 |
|---|---|
name |
Tool 名称,默认使用方法名。必须在所有 Tool 中唯一 |
description |
Tool 描述,强烈建议提供,帮助模型理解何时调用 |
returnDirect |
是否将结果直接返回给客户端而非模型,默认 false |
resultConverter |
自定义结果转换器 |
@ToolParam 注解属性说明
| 属性 | 说明 |
|---|---|
description |
参数描述,帮助模型理解参数格式和用途 |
required |
是否必需,默认 true |
2.2 编程式:MethodToolCallback
通过编程方式构建 MethodToolCallback,适用于需要精细控制的场景。
java
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.method.MethodToolCallback;
import org.springframework.ai.tool.ToolDefinitions;
import org.springframework.util.ReflectionUtils;
Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
ToolCallback toolCallback = MethodToolCallback.builder()
.toolDefinition(ToolDefinitions.builder(method)
.description("Get the current date and time in the user's timezone")
.build())
.toolMethod(method)
.toolObject(new DateTimeTools())
.build();
对于静态方法,可以省略 toolObject():
java
class DateTimeTools {
static String getCurrentDateTime() { /* ... */ }
}
Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
ToolCallback toolCallback = MethodToolCallback.builder()
.toolDefinition(ToolDefinitions.builder(method)
.description("Get the current date and time")
.build())
.toolMethod(method)
.build();
2.3 函数式:FunctionToolCallback
通过 FunctionToolCallback 将 Function、Supplier、Consumer 或 BiFunction 转换为 Tool。
java
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.function.FunctionToolCallback;
public record WeatherRequest(String location, Unit unit) {}
public enum Unit { C, F }
public record WeatherResponse(double temp, Unit unit) {}
public class WeatherService implements Function<WeatherRequest, WeatherResponse> {
@Override
public WeatherResponse apply(WeatherRequest request) {
return new WeatherResponse(25.0, Unit.C);
}
}
ToolCallback toolCallback = FunctionToolCallback
.builder("currentWeather", new WeatherService())
.description("Get the weather in location")
.inputType(WeatherRequest.class)
.build();
2.4 动态规范:@Bean 方式
将 Tool 定义为 Spring Bean,由框架在运行时动态解析:
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import java.util.function.Function;
@Configuration(proxyBeanMethods = false)
class WeatherTools {
public static final String CURRENT_WEATHER_TOOL = "currentWeather";
@Bean(CURRENT_WEATHER_TOOL)
@Description("Get the weather in location")
Function<WeatherRequest, WeatherResponse> currentWeather() {
return new WeatherService();
}
}
2.5 方法 Tool 的限制
以下类型不支持作为 Tool 方法的参数或返回类型:
Optional- 异步类型(
CompletableFuture、Future) - 响应式类型(
Flow、Mono、Flux) - 函数类型(
Function、Supplier、Consumer)
函数类型可通过 FunctionToolCallback 方式支持。
三、Tool 的注册与使用
3.1 在 ChatClient 中使用
通过 tools() 方法传递 Tool 实例:
java
ChatModel chatModel = ...;
String response = ChatClient.create(chatModel)
.prompt("What day is tomorrow?")
.tools(new DateTimeTools())
.call()
.content();
3.2 在 Agent 中使用
在 ReactAgent 中注册 Tool,需要将 @Tool 注解的对象转换为 ToolCallback 数组:
java
@Bean
public ReactAgent assistantAgent(ChatModel chatModel, AgentTools agentTools) {
ToolCallback[] toolCallbacks = MethodToolCallbackProvider.builder()
.toolObjects(agentTools)
.build()
.getToolCallbacks();
return ReactAgent.builder()
.name("assistant_agent")
.model(chatModel)
.tools(toolCallbacks) // 传入 ToolCallback 数组
.systemPrompt("...")
.build();
}
3.3 添加默认 Tools 到 ChatClient.Builder
通过 defaultToolCallbacks() 添加所有请求共享的默认 Tool:
java
ChatModel chatModel = ...;
ToolCallback toolCallback = ...;
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultToolCallbacks(toolCallback)
.build();
3.4 动态 Tool 名称解析
使用 toolNames() 按名称动态解析 Tool:
java
ChatClient.create(chatModel)
.prompt("What's the weather like in Copenhagen?")
.toolNames("currentWeather")
.call()
.content();
四、高级特性
4.1 JSON Schema 与参数描述
Spring AI 会自动为 @Tool 注解方法的输入参数生成 JSON Schema。可以通过多种注解自定义生成的 Schema:
| 注解 | 说明 |
|---|---|
@ToolParam(description = "...") |
Spring AI 原生注解 |
@JsonClassDescription |
Jackson 注解 |
@JsonPropertyDescription |
Jackson 注解 |
@Schema(description = "...") |
Swagger 注解 |
必需/可选参数:默认所有参数都是必需的,可通过以下注解设为可选:
java
@Tool(description = "Update customer information")
void updateCustomerInfo(Long id,
String name,
@ToolParam(required = false) String email) {
// ...
}
4.2 自定义结果转换
默认情况下,Tool 结果使用 Jackson 序列化为 JSON 发送给模型。可以通过自定义 ToolCallResultConverter 改变序列化行为:
java
class CustomerTools {
@Tool(description = "Retrieve customer information",
resultConverter = CustomToolCallResultConverter.class)
Customer getCustomerInfo(Long id) {
return customerRepository.findById(id);
}
}
4.3 返回直接(Return Direct)
默认情况下,Tool 结果会发送回 Model 继续处理。将 returnDirect 设为 true 可以让结果直接返回给调用者,适用于:
- RAG 场景中直接返回检索结果
- 应该结束 Agent 推理循环的 Tool
java
@Tool(description = "Retrieve customer information", returnDirect = true)
Customer getCustomerInfo(Long id) {
return customerRepository.findById(id);
}
4.4 自定义 ToolCallingManager
通过提供自定义 ToolCallingManager Bean 来控制 Tool 执行行为:
java
@Bean
ToolCallingManager toolCallingManager() {
return ToolCallingManager.builder().build();
}
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
五、环境搭建
5.1 pom.xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
</parent>
<groupId>com.example.ai</groupId>
<artifactId>spring-ai-alibaba-tools-demo</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
<spring-ai-alibaba.version>1.1.2.0</spring-ai-alibaba.version>
<jackson.version>2.16.2</jackson.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Agent Framework 核心 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-agent-framework</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
<!-- DashScope 模型接入 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
<!-- 强制锁定 Jackson 版本,避免 NoSuchMethodError -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
5.2 application.yml
yaml
server:
port: 885
spring:
ai:
dashscope:
api-key: ${DASHSCOPE_API_KEY} # 从环境变量读取
chat:
options:
model: deepseek-v4-flash # 或 qwen-max
logging:
level:
com.alibaba.cloud.ai: debug
六、完整可运行代码
6.1 项目结构
src/main/java/com/example/ai/
├── SpringAiDemoApplication.java # 启动类
├── config/
│ └── AgentConfig.java # Agent 配置类
├── tools/
│ ├── DateTimeTools.java # 日期时间工具(声明式 @Tool)
│ ├── WeatherTools.java # 天气工具(函数式 FunctionToolCallback)
│ └── CustomerTools.java # 客户工具(returnDirect + 可选参数)
├── service/
│ └── AgentService.java # Agent 服务层
└── controller/
└── AgentController.java # REST 控制器
6.2 启动类
java
package com.example.ai;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringAiDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringAiDemoApplication.class, args);
}
}
6.3 工具类定义
DateTimeTools.java(声明式 @Tool)
java
package com.example.ai.tools;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class DateTimeTools {
@Tool(description = "获取当前日期和时间(用户时区)")
public String getCurrentDateTime() {
return LocalDateTime.now()
.atZone(LocaleContextHolder.getTimeZone().toZoneId())
.toString();
}
@Tool(description = "设置闹钟(ISO-8601 格式时间)")
public String setAlarm(@ToolParam(description = "时间,格式:yyyy-MM-ddTHH:mm:ss,例如 2026-06-18T15:30:00")
String time) {
LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
return "闹钟已设置为 " + alarmTime;
}
}
WeatherTools.java(函数式 FunctionToolCallback)
修正说明 :为避免 public record 导致的编译错误,将 record 定义为 非 public(package-private),与工具类放在同一文件中。
java
package com.example.ai.tools;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.function.FunctionToolCallback;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
// 非 public record(包内可见)
record WeatherRequest(String location) {}
record WeatherResponse(String location, String weather, double temperature, String unit) {}
@Component
public class WeatherTools {
private static final Map<String, WeatherResponse> WEATHER_DATA = new HashMap<>();
static {
WEATHER_DATA.put("北京", new WeatherResponse("北京", "晴", 25.0, "°C"));
WEATHER_DATA.put("上海", new WeatherResponse("上海", "多云", 28.0, "°C"));
WEATHER_DATA.put("杭州", new WeatherResponse("杭州", "小雨", 22.0, "°C"));
WEATHER_DATA.put("深圳", new WeatherResponse("深圳", "晴", 30.0, "°C"));
}
public ToolCallback getWeatherTool() {
return FunctionToolCallback
.builder("getWeather", (Function<WeatherRequest, WeatherResponse>) request -> {
String location = request.location();
return WEATHER_DATA.getOrDefault(location,
new WeatherResponse(location, "未知", 0.0, "°C"));
})
.description("获取指定城市的当前天气")
.inputType(WeatherRequest.class)
.build();
}
}
CustomerTools.java(高级特性:returnDirect + 可选参数)
java
package com.example.ai.tools;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class CustomerTools {
private final Map<Long, String> customerDatabase = new HashMap<>();
public CustomerTools() {
customerDatabase.put(1L, "张三 - VIP 客户");
customerDatabase.put(2L, "李四 - 普通客户");
}
@Tool(description = "根据 ID 查询客户信息", returnDirect = true)
public String getCustomerInfo(@ToolParam(description = "客户 ID") Long id) {
return customerDatabase.getOrDefault(id, "未找到该客户");
}
@Tool(description = "更新客户信息(姓名必填,邮箱可选)")
public String updateCustomerInfo(@ToolParam(description = "客户 ID") Long id,
@ToolParam(description = "新姓名") String name,
@ToolParam(required = false, description = "新邮箱地址")
String email) {
customerDatabase.put(id, name + (email != null ? " (" + email + ")" : ""));
return "客户 " + id + " 更新成功";
}
}
6.4 Agent 配置类
java
package com.example.ai.config;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.agent.hook.modelcalllimit.ModelCallLimitHook;
import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver;
import com.example.ai.tools.CustomerTools;
import com.example.ai.tools.DateTimeTools;
import com.example.ai.tools.WeatherTools;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class AgentConfig {
@Value("${spring.ai.dashscope.api-key}")
private String apiKey;
@Bean
public ChatModel chatModel() {
DashScopeApi dashScopeApi = DashScopeApi.builder()
.apiKey(apiKey)
.build();
return DashScopeChatModel.builder()
.dashScopeApi(dashScopeApi)
.defaultOptions(DashScopeChatOptions.builder()
.withModel("deepseek-v4-flash")
.withTemperature(0.7)
.withMaxToken(2000)
.build())
.build();
}
@Bean
public ReactAgent assistantAgent(ChatModel chatModel,
DateTimeTools dateTimeTools,
CustomerTools customerTools,
WeatherTools weatherTools) {
// 1. 从 @Tool 注解的对象转换 ToolCallback
ToolCallback[] methodCallbacks = MethodToolCallbackProvider.builder()
.toolObjects(dateTimeTools, customerTools)
.build()
.getToolCallbacks();
// 2. 获取函数式 Tool
ToolCallback weatherCallback = weatherTools.getWeatherTool();
// 3. 合并所有 Tool
List<ToolCallback> allCallbacks = new ArrayList<>();
allCallbacks.addAll(List.of(methodCallbacks));
allCallbacks.add(weatherCallback);
return ReactAgent.builder()
.name("assistant_agent")
.model(chatModel)
.tools(allCallbacks.toArray(new ToolCallback[0])) // 关键:传入 ToolCallback 数组
.systemPrompt("""
你是一个智能助手,可以帮助用户完成各种任务。
你有以下能力:
1. 获取当前日期和时间 (getCurrentDateTime)
2. 设置闹钟 (setAlarm)
3. 查询城市天气 (getWeather)
4. 查询客户信息 (getCustomerInfo) - 结果将直接返回
5. 更新客户信息 (updateCustomerInfo)
请根据用户的问题,选择合适的工具来解决问题。
如果用户的问题不需要工具,直接回答即可。
""")
.hooks(ModelCallLimitHook.builder().runLimit(5).build())
.saver(new MemorySaver())
.build();
}
}
6.5 Service 层
java
package com.example.ai.service;
import com.alibaba.cloud.ai.graph.RunnableConfig;
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.stereotype.Service;
@Service
public class AgentService {
private final ReactAgent agent;
public AgentService(ReactAgent agent) {
this.agent = agent;
}
public String chat(String userMessage) throws GraphRunnerException {
AssistantMessage response = agent.call(userMessage);
return response.getText();
}
public String chatWithMemory(String userMessage, String sessionId) throws GraphRunnerException {
RunnableConfig config = RunnableConfig.builder()
.threadId(sessionId)
.build();
AssistantMessage response = agent.call(userMessage, config);
return response.getText();
}
}
6.6 Controller 层
java
package com.example.ai.controller;
import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import com.example.ai.service.AgentService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
import java.util.UUID;
@RestController
@RequestMapping("/api/agent")
public class AgentController {
private static final Logger log = LoggerFactory.getLogger(AgentController.class);
private final AgentService agentService;
public AgentController(AgentService agentService) {
this.agentService = agentService;
}
@PostMapping("/chat")
public Map<String, Object> chat(@RequestBody Map<String, String> request) {
String message = request.get("message");
try {
String response = agentService.chat(message);
return Map.of("success", true, "response", response);
} catch (GraphRunnerException e) {
log.error("Agent 执行失败", e);
return Map.of("success", false, "error", "Agent 执行失败: " + e.getMessage());
}
}
@PostMapping("/chat/session")
public Map<String, Object> chatWithSession(@RequestBody Map<String, String> request) {
String message = request.get("message");
String sessionId = request.getOrDefault("sessionId", UUID.randomUUID().toString());
try {
String response = agentService.chatWithMemory(message, sessionId);
return Map.of("success", true, "sessionId", sessionId, "response", response);
} catch (GraphRunnerException e) {
log.error("Agent 执行失败", e);
return Map.of("success", false, "error", "Agent 执行失败: " + e.getMessage());
}
}
}
七、测试与验证
7.1 启动应用
确保环境变量 DASHSCOPE_API_KEY 已设置,然后运行 SpringAiDemoApplication。
7.2 测试命令
bash
# 1. 获取当前时间
curl -X POST http://localhost:885/api/agent/chat \
-H "Content-Type: application/json" \
-d '{"message": "现在几点了?"}'
# 2. 查询天气
curl -X POST http://localhost:885/api/agent/chat \
-H "Content-Type: application/json" \
-d '{"message": "北京今天天气怎么样?"}'
# 3. 设置闹钟
curl -X POST http://localhost:885/api/agent/chat \
-H "Content-Type: application/json" \
-d '{"message": "请帮我设置一个10分钟后的闹钟"}'
# 4. 查询客户信息(returnDirect 示例)
curl -X POST http://localhost:885/api/agent/chat \
-H "Content-Type: application/json" \
-d '{"message": "查询客户ID为1的信息"}'
# 5. 更新客户信息
curl -X POST http://localhost:885/api/agent/chat \
-H "Content-Type: application/json" \
-d '{"message": "更新客户ID为2的名字为王五"}'
# 6. 多轮对话(带记忆)
curl -X POST http://localhost:885/api/agent/chat/session \
-H "Content-Type: application/json" \
-d '{"message": "我叫张三", "sessionId": "test-001"}'
curl -X POST http://localhost:885/api/agent/chat/session \
-H "Content-Type: application/json" \
-d '{"message": "我叫什么名字?", "sessionId": "test-001"}'
7.3 预期输出示例
对于 "北京今天天气怎么样?":
json
{
"success": true,
"response": "北京今天的天气是晴,温度25.0°C。"
}
测试客户查询:

测试更新客户:

八、常见问题与解决方案
8.1 Cannot resolve method 'tools(AgentTools)'
原因 :ReactAgent.builder() 的 .tools() 方法接受 ToolCallback... 类型。
解决 :使用 MethodToolCallbackProvider 转换:
java
ToolCallback[] toolCallbacks = MethodToolCallbackProvider.builder()
.toolObjects(agentTools)
.build()
.getToolCallbacks();
ReactAgent.builder()
.tools(toolCallbacks)
.build();
8.2 public record 导致编译错误
原因 :在单个 .java 文件中,只能有一个 public 顶层类/record。
解决 :将 record 改为 非 public(package-private)或移到独立文件。
java
// ✅ 正确:非 public record
record WeatherRequest(String location) {}
record WeatherResponse(String location, String weather, double temperature, String unit) {}
8.3 Model 不调用 Tool
解决方案:
- 检查
@Tool注解的description是否清晰 - 在 System Prompt 中明确列出所有 Tool 及其用途
- 确保 Tool 方法参数类型与模型推理匹配
8.4 参数解析错误
解决方案:
- 使用
@ToolParam(description = "...")提供清晰描述 - 使用
@Schema或@JsonProperty标注数据结构 - 避免使用不支持的类型(
Optional、CompletableFuture等)
8.5 returnDirect 与多 Tool 同时调用
规则 :如果需要同时请求多个 Tool,所有 Tool 的 returnDirect 属性必须一致(全部 true 或全部 false)。
8.6 Unhandled exception: GraphRunnerException
解决方案 :在 Service 方法上声明 throws GraphRunnerException,由 Controller 统一捕获处理。
java
public String chat(String userMessage) throws GraphRunnerException {
AssistantMessage response = agent.call(userMessage);
return response.getText();
}
九、总结
本文提供了 Spring AI Alibaba Tools 的完整可运行示例,涵盖了:
| 知识点 | 实现方式 |
|---|---|
| 声明式 Tool | @Tool + @ToolParam 注解 |
| 函数式 Tool | FunctionToolCallback + Function |
| Tool 注册 | MethodToolCallbackProvider → ToolCallback[] |
| 返回直接 | returnDirect = true |
| 可选参数 | @ToolParam(required = false) |
| 多 Tool 组合 | 合并多个 ToolCallback 数组 |
| 记忆对话 | MemorySaver + threadId |
| 异常处理 | GraphRunnerException 统一捕获 |
你可以基于此示例快速构建自己的 Tools 集合,扩展 Agent 的能力边界。
📎 参考资源:Spring AI Alibaba GitHub | 官方文档 | Tools 教程原文