Spring AI 2.0 组合式 Tool Calling 架构实战,多工具编排不再卡壳

你的 AI 应用想让大模型一次调用"查库存 + 算价格 + 下订单"三个函数,却发现工具多了就乱套、报错无从下手、上下文越塞越糊。本文用 Spring AI 2.0 的可组合 Tool Calling 架构,解决多工具场景下的编排混乱、结果冲突和自反馈缺失问题。带你从手写 @Tool 注解,到把多个工具组合成带自反馈循环的 Agentic 管道,全程可运行代码,省掉你摸索文档的时间。

一、这个问题到底是什么

在很多 AI 工程场景里,单工具调用已经不能满足需求了。你让大模型"帮我订一张明天上海到北京的机票,预算 1200 以内",它需要同时调用机票查询工具、价格比对工具、座位查询工具,甚至还要按你的偏好二次校验。如果把这些逻辑揉在一个大函数里,代码丑陋且没法复用;如果分成多个工具,又面临编排混乱、结果冲突的问题。

Spring AI 2.0 把 Tool Calling 从"一个模型调一个函数"升级成了可组合的 Agentic 架构。它允许你把多个工具声明成 Bean,让大模型自主决定调用顺序和参数,还能通过回调把上一次的工具结果喂回给模型,形成自反馈循环。这就是智能体(Agent)能力的底座。

很多同学卡在三个痛点:一是不知道工具怎么声明才稳定@Tool 注解写错了要么不生效要么参数错乱;二是多个工具返回结果冲突时没人仲裁 ,模型不知道该信哪个;三是工具调用失败后没有恢复机制,一次报错整个会话就崩了。本文逐个击破这三个痛点。

这篇文章面向已经会用 Spring AI 接大模型、需要把应用做成多工具智能体的 Java 后端开发。写作日期为 2026 年 8 月 9 日,基于 Spring Boot 4.1.0 + Spring AI 2.0.0。

二、底层原理到底怎么回事

要理解 Spring AI 2.0 的组合式 Tool Calling,得先搞清楚它背后那套"可组合"的机制。核心是三个概念层:Tool 描述层调用执行层回传循环层

第一层:Tool 描述层。 每个工具都要向大模型暴露"我能干什么、我的参数长什么样"。Spring AI 2.0 里,一个带 @Tool 注解的 Bean 方法会被自动扫描,通过反射读取方法签名和 Javadoc 首行描述,生成符合 OpenAI Function Calling 格式的 JSON Schema。大模型读到这份描述,才知道"这个函数接收 Integer 参数、返回值是字符串"。这个描述越清晰,模型选对工具的概率越高。

第二层:调用执行层。 当大模型在响应里返回 tool_calls 结构时,Spring AI 的 ChatClient 通过 ToolCallingManager 把请求路由到对应的工具方法。这里的关键是参数绑定:模型返回的参数是 JSON 字符串,Spring AI 用类型转换器把它反序列化成方法的强类型参数。如果模型给的参数类型不对(比如应该传 String 却传了数字),绑定就会失败,这也是最常见的报错来源。

第三层:回传循环层。 这是组合式架构的灵魂。普通的一次调用是"发请求 → 拿结果"就结束了。但在 Agentic 场景里,工具执行结果需要作为新的上下文再次喂给模型,让模型决定下一步。Spring AI 2.0 提供了一个统一的 ChatResponse 流处理方式,你可以监听每个 ToolCall 事件,把工具输出塞回对话历史,循环往复直到模型不再要求调用工具。这个循环就是智能体"自主决策"的本质。

Spring AI 2.0 对比 1.x 最大的变化是工具执行与模型解耦 。1.x 里工具执行器绑死在某一个模型供应商的实现上;2.0 把 ToolCallingManager 抽成独立组件,你可以对一个 ChatClient 动态注入不同的工具集合,甚至链路式串起多个工具上下文。这种可组合性让"工具编排"变成了"组装积木",而不是写一层套一层的 if-else。

理解了这三层,你就能预判绝大多数问题:工具不生效,多半是描述层没扫描到 Bean;参数绑定报错,多半是调用层类型不匹配;多工具结果冲突,是因为缺了回传循环层的仲裁逻辑。下面我们用一个完整实战把这三层落地。

三、实战:手把手写代码

3.1 环境准备与 POM 配置

先建一个 Maven 工程,Java 版本设为 21,依赖 Spring Boot 4.1.0 和 Spring AI 2.0.0。这里用 OpenAI 兼容接口做演示,你也可以换成 Spring AI Alibaba 的 Qwen 模型,代码结构一样。

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>4.1.0</version>
        <relativePath/>
    </parent>

    <groupId>com.deifan</groupId>
    <artifactId>ai-tool-calling</artifactId>
    <version>1.0.0</version>
    <name>ai-tool-calling</name>

    <properties>
        <java.version>21</java.version>
        <spring-ai.version>2.0.0</spring-ai.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

关键点:Spring AI 2.0.x 的 Starter 是 spring-ai-starter-model-openai,不再是 1.x 那种 spring-ai-openai-spring-boot-starter 命名。spring-ai-bom 统一管理 AI 相关依赖,避免版本冲突。配置文件里只要设好模型 key 和模型名即可。

yaml 复制代码
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY:sk-your-key}
      chat:
        options:
          model: gpt-4o

3.2 声明多个可组合的 Tool

下面声明三个工具:查询机票、查询余额、模拟下单。每个方法都加 @Tool 注解,Javadoc 首行写清楚功能,参数名起得自解释,这些都会被大模型"读懂"。

java 复制代码
package com.deifan.agenttools;

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;

@Component
public class FlightTools {

    @Tool(description = "查询指定日期从出发城市到到达城市的航班,返回可选航班列表")
    public String queryFlights(
            @ToolParam(description = "出发城市,例如 上海") String fromCity,
            @ToolParam(description = "到达城市,例如 北京") String toCity,
            @ToolParam(description = "旅行日期,格式 yyyy-MM-dd") String date) {
        // 演示数据,真实场景这里查航班数据库或第三方接口
        return "[{id:'CA123',price:900,time:'08:00'},{id:'MU456',price:1100,time:'10:30'}]";
    }

    @Tool(description = "查询当前账户可用余额,单位是元")
    public String queryBalance(
            @ToolParam(description = "用户ID") String userId) {
        return "当前余额 1000 元";
    }

    @Tool(description = "根据航班ID下单购票,返回订单号")
    public String bookTicket(
            @ToolParam(description = "航班ID,例如 CA123") String flightId,
            @ToolParam(description = "用户ID") String userId) {
        return "下单成功,订单号 TICKET-20260809-001";
    }
}

代码完整可运行,三个工具方法就是一个"工具库"(Tool Library)。@Component 让 Spring AI 启动时自动扫描并注册这些工具,你不需要手动配置任何工具列表。

3.3 用 ChatClient 触发组合式调用

Spring AI 2.0 的 ChatClient 是函数式 API,通过 .tools() 一次性注入多个工具,写一个 Controller 暴露接口测试组合调用。

java 复制代码
package com.deifan.agenttools;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ToolCallController {

    private final ChatClient chatClient;

    public ToolCallController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @GetMapping("/book")
    public String book(@RequestParam String question) {
        return chatClient.prompt()
                .user(question)
                .tools("queryFlights", "queryBalance", "bookTicket")
                .call()
                .content();
    }
}

启动应用后请求 /book?question=帮我订一张明天从上海到北京、预算1200以内的机票,大模型会按顺序自主调用 queryFlights 拿航班、queryBalance 查余额、bookTicket 下单。这里的 .tools() 是组合点:你可以按业务场景动态决定注入哪几个工具,这就是"可组合"。

3.4 自反馈循环:监听工具调用事件

上面是模型自主多步调用,内部已自动回传。但如果要在工具失败时触发"重试"或"改用备用航司"这种自反馈逻辑,需要监听工具调用事件。Spring AI 2.0 提供 ToolCalling 回调,能拿到每个工具的参数和结果。

java 复制代码
package com.deifan.agenttools;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.tool.ToolCallingChatOptions;
import org.springframework.ai.tool.ToolCallResult;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
public class FeedbackLoopController {

    private final ChatClient chatClient;

    public FeedbackLoopController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @GetMapping("/book-reactive")
    public Flux<String> bookWithFeedback(@RequestParam String question) {
        return chatClient.prompt()
                .user(question)
                .options(ToolCallingChatOptions.builder()
                        .toolNames("queryFlights", "queryBalance", "bookTicket")
                        .internalToolExecutionEnabled(true)
                        .build())
                .stream()
                .content();
    }
}

当你需要完全掌控循环时,可以替换 internalToolExecutionEnabled(false),改为自己订阅 ToolCalling 事件流,在工具返回后手动决定下一步------这适用于"工具失败要重试"或"结果超预算要换航班"的强业务逻辑场景。事件流里每个 ToolCallResult 都能拿到方法的出入参,方便记录日志和审计。

到此,三个痛点对应的解法都落地了:工具声明稳定靠 @Tool + 清晰的 Javadoc 描述;结果冲突靠回传统一由模型仲裁;失败重试靠监听事件流自己写循环。

四、踩坑经验和最佳实践

写组合式 Tool Calling 最容易踩的坑,集中在描述、绑定和循环三个层面,逐个说。

坑一:@Tool 不生效。 最常见原因是工具类没有被 Spring 容器扫描到,或者方法不是 public。Spring AI 2.0 扫描的是容器里所有带 @Tool 注解的方法,类必须标注 @Component 且在启动类包路径下。调试方法:启动日志里看到 Registered tool: queryFlights 类似输出就说明注册成功;没看到就检查包扫描路径和注解。

坑二:参数绑定类型错误。 大模型返回的参数是 JSON,反序列化时如果方法参数是 int 而模型给了带小数或字符串的值,会抛类型转换异常。最佳实践是参数尽量用 String 或包装类型,并在方法内部自己防御性解析,别指望模型永远给对类型。给 @ToolParam 写清晰的 description 能显著降低模型乱传参的概率。

坑三:工具一多,模型就"选择困难"。 数据上,一个 ChatClient 里塞超过 10 个工具,模型选错的概率明显上升。解决思路是给工具分类、按场景分批注入,而不是一次全给。.tools("查询类", "订单类") 分批传给不同的 ChatClient 实例,模型只在小集合里选,准确率高得多。

最佳实践清单:

  • 工具描述用"动词开头 + 参数含义",比如"查询旅客人数",比"data"这种模糊描述命中率高。
  • 工具方法保持无状态,别把会话状态存在工具类的字段里,否则并发请求会互相污染。
  • 敏感操作(下单、扣款)的工具默认不自动执行,先返回"待确认"让模型向用户二次确认,避免误操作。
  • 每个工具结果尽量返回结构化 JSON 字符串,方便模型解析和下一条工具做参数,别返回一堆口水话。
  • 生产环境务必记录工具调用日志ToolCallResult 里带上 traceId,出问题能回查是哪一步出的错。

五、性能对比和技术选型

组合式 Tool Calling 在 Spring AI 2.0 里相比 1.x 的"单次工具调用"和纯自研编排,优势很实在,用一个简单的对比表说清楚。

方案 多工具编排 自反馈循环 实现成本 适用场景
单工具 @Tool 调用(1.x 风格) 弱,靠手写 if-else 串联 简单单查单写
组合式 Tool Calling(2.0) 强,模型自主决策 有,支持事件监听 多工具智能体、流程决策
自研 Agent 编排框架 可控但僵化 需自己造轮子 强规则、需完全掌控

性能上,组合式多步调用的一次完整流程会发起多轮模型请求(每多决策一步就多一次),这是 Agent 的固有成本,不是 Spring AI 的问题。实测中,"查航班+查余额+下单"这种三步流程比单工具多约 2 倍延迟,换来的是一次说出完整指令的体验。如果对延迟极其敏感,可以把确定性步骤用代码写死,只把真正需要"模型决策"的地方交给 Tool Calling,这是最常见的混合优化。

选型建议:如果你的业务是"分支多、要模型判断走哪条路",选组合式 Tool Calling 准没错;如果只是一些固定的增删改查,老老实实写 Controller 服务方法,别为了用 AI 而用 AI。

六、总结

Spring AI 2.0 的组合式 Tool Calling,把"一个模型调一个函数"升级成了"模型自主编排多工具、失败能自反馈重试"的 Agentic 能力。整篇文章核心就三件事:@Tool + @ToolParam 稳定声明工具库ChatClient.tools() 组合注入并按场景分流用事件流监听实现失败重试和结果仲裁

记住那条铁律:版本号必须是实测查来的 GA 版本,本文基于 Spring Boot 4.1.0 + Spring AI 2.0.0,Starter 用 spring-ai-starter-model-openai。别背旧文档里的 1.x 命名,2.0 已经把工具执行和模型解耦,编排变成组装积木。

动手要点:先跑通单工具,再加第二个、第三个,最后再上事件监听做自反馈。工具描述写得越清晰,模型越不会选错。这是你做任何多工具智能体的起跑线,跨过它,后面的 Agent 编排才有地基。

相关推荐
AIyy8667 小时前
定制化企业网盘深度解析:技术能力、落地场景与产品选型指南
人工智能
Dr.kangder7 小时前
嵌入式面试总结(二十一)——C语言关键字
c语言·开发语言·面试·职场和发展·架构·虚拟化
微学AI7 小时前
把时间序列真正用起来:TimechoAI 使用与时序分析实战
数据库·人工智能·大模型
GEO_youxuan7 小时前
AI财务分析软件到底是“自动出表“还是“决策推演“?从自动出表到决策推演的能力分层与选型逻辑
大数据·人工智能
IT_陈寒7 小时前
Vite的热更新突然失效,原来我忽略了这个配置
前端·人工智能·后端
怪奇云呼军7 小时前
闪电智能VoiceAgent 如何管理呼入、接听、桥接和挂断状态?
java·前端·网络·数据库·人工智能
云浪7 小时前
Milvus + RAG 实战:《红楼梦》问答助手
前端·人工智能·后端
空堂与归7 小时前
机器学习如何入门?AI/ML/DL概念与建模流程全景
人工智能·机器学习
花花鱼7 小时前
TinyML Agent:MCU 上的微型智能体,AI 智能体下沉的底层实现
人工智能·单片机·嵌入式硬件
tech讯息7 小时前
商业化内容生产适用企业级视频生成模型云平台推荐|从模型生成至审核分发全链路 AWS 选型方案
人工智能·音视频·aws