目录
[Spring AI Alibaba Graph框架实现Agent工作流水线](#Spring AI Alibaba Graph框架实现Agent工作流水线)
[一、为什么需要 Tools 工具调用?](#一、为什么需要 Tools 工具调用?)
[三、定义工具类 MyTools](#三、定义工具类 MyTools)
[四、配置 ChatClient 注册工具](#四、配置 ChatClient 注册工具)
[defaultTools 与 tools 的区别](#defaultTools 与 tools 的区别)
[五、Controller 层](#五、Controller 层)
前言
在上一篇博客中,我们完成了 Spring AI Alibaba 项目的搭建,实现了基本的 ChatClient 对话功能。但此时的 AI 还只是一个"只会聊天"的模型------它无法获取实时信息,也无法执行任何实际操作。本篇博客将在此基础上,为 ChatClient 集成 Tools 工具调用能力,让 AI 能够真正"动手做事"。
阅读前提:建议先阅读第一篇,了解 Spring AI Alibaba 的基础配置和 ChatClient 的构建方式。
Spring AI Alibaba Graph框架实现Agent工作流水线
一、为什么需要 Tools 工具调用?
大语言模型有一个根本性的局限:它无法访问实时信息,也无法执行操作。
当你问"现在几点了",模型只能回复"我无法获取实时时间"。当你问"北京天气怎么样",模型同样无能为力------因为这些信息不在它的训练数据中,它也没有能力主动去查询。
Tools(工具调用)正是为了解决这个问题。它的本质是:让模型能够请求调用应用程序中定义的方法,并将方法返回值作为上下文继续推理。
需要特别强调的是,模型永远无法直接访问 你定义的任何工具 API。整个流程是:模型只负责"决定调用哪个工具、传什么参数",真正的执行逻辑完全由客户端应用程序负责-15。这是一个关键的安全设计。
Tools 主要用于两类场景:
-
信息检索:从数据库、Web 服务、文件系统等外部源获取数据,增强模型的知识
-
执行操作:发送邮件、创建记录、提交表单、触发工作流等自动化任务
二、项目依赖
在第一篇的基础上,需要确保以下依赖已配置:
java
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool-all.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
application.yml 配置:
java
spring:
ai:
dashscope:
api-key: ${AI_DASHSCOPE_API_KEY}
chat:
options:
model: qwen-plus
或者application.properties配置:
java
spring.ai.openai.api-key=${AI_DASHSCOPE_API_KEY}
spring.ai.openai.base-url=https://llm-o4uz6dvcl1e8uyxv.cn-beijing.maas.aliyuncs.com/compatible-mode
#spring.ai.openai.chat.options.model=qwen3.7-max
spring.ai.openai.chat.options.model=deepseek-v4-flash
三、定义工具类 MyTools
在 Spring AI 中,定义工具最简单的方式是使用 @Tool 注解。任何 Spring Bean 中的方法,只要加上 @Tool 注解,就可以被大模型识别并调用。我们创建一个 MyTools 类,包含两个工具:一个无参数的"获取当前时间",一个带参数的"查询天气":
java
@Component
public class MyTools {
// ===== 无参数工具:获取当前时间 =====
@Tool(description = "获取当前系统时间,包括年月日时分秒")
public String getCurrentTime() {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
return now.format(formatter);
}
// ===== 带参数工具:查询天气 =====
@Tool(description = "查询指定城市的实时天气情况")
public String getWeather(
@ToolParam(description = "城市名称,如:北京、上海、深圳") String city) {
// 这里可以调用第三方天气 API,目前返回模拟数据
return String.format("城市:%s,天气:晴,温度:28°C,湿度:60%%", city);
}
}
关键注解说明
@Tool :标记一个方法为可调用工具。description 属性至关重要,它告诉模型这个工具是做什么的、什么时候应该使用它。描述越准确,模型选择工具的准确性越高-。
@ToolParam :为工具方法的参数添加描述。Spring AI 会根据方法签名自动生成参数的 JSON Schema,而 @ToolParam 则为每个参数提供人类可读的说明,帮助模型正确填充参数值-10。
类上的 @Component:工具类必须注册为 Spring Bean,这样才能在 ChatClient 构建时注入。
四、配置 ChatClient 注册工具
接下来修改 AIServiceImpl,在构建 ChatClient 时通过 defaultTools() 方法注册工具:
java
@Service
public class AIServiceImpl implements AIService {
private final ChatClient chatClient;
public AIServiceImpl(ChatClient.Builder builder, ChatMemory chatMemory, MyTools myTools) {
this.chatClient = builder
// 注册对话记忆
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
// 注册 Tool:让大模型知道有哪些工具可用
.defaultTools(myTools)
.build();
}
public String ask(String question) {
return chatClient.prompt()
.user(question)
.call()
.content();
}
}
defaultTools 与 tools 的区别
Spring AI 提供了两种注册工具的方式:
| 方法 | 作用范围 | 适用场景 |
|---|---|---|
.defaultTools() |
该 ChatClient 的所有请求 | 全局工具,所有对话都可用 |
.tools() |
仅当前一次请求 | 临时工具,针对特定问题 |
defaultTools() 是 ChatClient.Builder 接口的方法,注册的工具会在该 Builder 构建出的所有 ChatClient 请求中生效-。对于本项目来说,时间和天气是通用能力,适合使用 defaultTools()。
五、Controller 层
Controller 层保持不变,直接调用 Service 即可:
java
@GetMapping("/ask")
public String ask(@RequestParam String question) {
return aiService.ask(question);
}
六、测试验证
启动项目后,通过浏览器或 curl 测试:
测试 1:询问时间
java
GET http://localhost:8080/ask?question=现在几点了
预期 AI 会调用 getCurrentTime() 工具,返回类似:
java
现在是2025年6月15日 14:30:25。

测试 2:查询天气
java
GET http://localhost:8080/ask?question=北京天气怎么样
预期 AI 会调用 getWeather("北京") 工具,返回类似:
java
北京当前天气:晴,温度28°C,湿度60%。

测试 3:不涉及工具的普通对话
java
GET http://localhost:8080/ask?question=你好
AI 会正常回复,不会触发任何工具调用。
七、工具调用的底层原理
理解工具调用的执行流程,有助于排查问题和优化效果。
Spring AI 在底层通过 ToolCallingAdvisor 来管理工具调用的完整生命周期。整个流程如下:
-
注入工具定义 :ChatClient 将
@Tool方法的名称、描述、参数 Schema 提取出来,连同用户问题一起发送给模型。 -
模型决策:模型判断是否需要调用工具。如果需要,返回一个包含工具调用请求的响应(指定调用哪个工具、传什么参数)。
-
执行工具 :
ToolCallingManager找到对应的工具方法并执行,将返回值追加到对话历史中。 -
循环推理:更新后的对话历史(包含工具执行结果)再次发送给模型,模型基于工具返回的数据生成最终回答。
-
终止条件 :当模型返回的响应中不包含任何工具调用请求时,循环结束,最终答案返回给用户。
值得注意的是,上述流程在需要时会自动循环执行------如果模型需要连续调用多个工具,框架会持续迭代,直到模型给出不含工具调用的最终回答。
八、注意事项
1. 工具描述的质量直接影响调用准确率
@Tool 的 description 是模型判断"是否调用"和"调用哪个"的唯一依据。描述应该清晰说明工具的用途和使用场景,而不是简单的方法名翻译。
2. 参数类型要明确
@ToolParam 中的描述应包含参数格式提示(如日期格式、城市名称示例等),帮助模型正确填充参数。
3. 工具返回结果不宜过长
工具返回的内容会作为上下文发送给模型,过长的返回结果会消耗 Token 并可能干扰模型推理。建议只返回模型需要的核心信息。
4. 模型支持情况
并非所有大模型都支持工具调用功能。DashScope 的 qwen-plus、qwen-max 等模型均已支持。
5. 后续进阶
本篇介绍的是 ChatClient 层级的工具调用 ,这是最基础也最常用的方式。Spring AI Alibaba 的 Graph 框架提供了更强大的 ToolNode 工具节点,可以将工具调用作为工作流中的一个独立节点进行编排,支持并行执行、条件路由等高级能力。这部分内容将在后续博客中展开。
九、小结
本篇博客完成了以下工作:
-
理解了 Tools 工具调用的核心价值和使用场景
-
通过
@Tool和@ToolParam注解定义了两个工具方法(无参数 + 带参数) -
使用
defaultTools()将工具注册到 ChatClient -
验证了 AI 能够自动识别并调用工具完成实时信息查询
下一篇将进入 Spring AI Alibaba Graph 框架,探索如何用 Graph 编排更复杂的 Agent 工作流。