Spring AI Alibaba Graph框架实现Tools工具调用

目录

前言

[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 来管理工具调用的完整生命周期。整个流程如下:

  1. 注入工具定义 :ChatClient 将 @Tool 方法的名称、描述、参数 Schema 提取出来,连同用户问题一起发送给模型。

  2. 模型决策:模型判断是否需要调用工具。如果需要,返回一个包含工具调用请求的响应(指定调用哪个工具、传什么参数)。

  3. 执行工具 :ToolCallingManager 找到对应的工具方法并执行,将返回值追加到对话历史中。

  4. 循环推理:更新后的对话历史(包含工具执行结果)再次发送给模型,模型基于工具返回的数据生成最终回答。

  5. 终止条件 :当模型返回的响应中不包含任何工具调用请求时,循环结束,最终答案返回给用户。

值得注意的是,上述流程在需要时会自动循环执行------如果模型需要连续调用多个工具,框架会持续迭代,直到模型给出不含工具调用的最终回答。

八、注意事项

1. 工具描述的质量直接影响调用准确率

@Tool 的 description 是模型判断"是否调用"和"调用哪个"的唯一依据。描述应该清晰说明工具的用途和使用场景,而不是简单的方法名翻译。

2. 参数类型要明确

@ToolParam 中的描述应包含参数格式提示(如日期格式、城市名称示例等),帮助模型正确填充参数。

3. 工具返回结果不宜过长

工具返回的内容会作为上下文发送给模型,过长的返回结果会消耗 Token 并可能干扰模型推理。建议只返回模型需要的核心信息。

4. 模型支持情况

并非所有大模型都支持工具调用功能。DashScope 的 qwen-plus、qwen-max 等模型均已支持。

5. 后续进阶

本篇介绍的是 ChatClient 层级的工具调用 ,这是最基础也最常用的方式。Spring AI Alibaba 的 Graph 框架提供了更强大的 ToolNode 工具节点,可以将工具调用作为工作流中的一个独立节点进行编排,支持并行执行、条件路由等高级能力。这部分内容将在后续博客中展开。

九、小结

本篇博客完成了以下工作:

  1. 理解了 Tools 工具调用的核心价值和使用场景

  2. 通过 @Tool 和 @ToolParam 注解定义了两个工具方法(无参数 + 带参数)

  3. 使用 defaultTools() 将工具注册到 ChatClient

  4. 验证了 AI 能够自动识别并调用工具完成实时信息查询

下一篇将进入 Spring AI Alibaba Graph 框架,探索如何用 Graph 编排更复杂的 Agent 工作流。

相关推荐
开开心心就好1 小时前
视频模糊怎么修复?免费工具支持批量处理
java·前端·人工智能·智能手机·pdf·excel
茉莉玫瑰花茶2 小时前
GO [ 并发 · 调度器 ]
开发语言·后端·golang
zhangzeyuaaa2 小时前
深入理解 Ruby 可变对象与不可变对象的原理、坑点与最佳实践
开发语言·后端·ruby
wdfk_prog2 小时前
Wi-Fi Direct 教程 05:control socket 与 eloop——P2P_FIND 怎样进入 wpa_supplicant 命令解析器
运维·服务器·后端·网络协议·ubuntu·p2p·wifi-direct
资深技术分享员2 小时前
遗留系统——把“改不动的老系统“接过来
java·服务器·数据库
IT_陈寒2 小时前
Python的GIL锁让我把多线程代码全重写了!
前端·人工智能·后端
江湖有缘2 小时前
Docker实战 | 使用Docker部署Bibliotheca阅读习惯管理工具
java·docker·容器
艾莉丝努力练剑2 小时前
【AI大模型接入SDK】ChatSDK:CMake构建静态库完整实现
java·开发语言·网络·c++·人工智能·学习·sdk
百度一下吧2 小时前
umi后台管理项目实战:从工程搭建到生产构建
java·前端·javascript