Tool Calling 重塑、MCP 原生集成、Advisor 链式编排——Java AI 开发的新纪元


一、概览:Spring AI 2.0 是什么

2026 年 6 月 12 日,Spring AI 2.0.0 GA 正式发布。距离 2025 年 12 月 11 日的 M1 恰好半年。这半年里,团队交付了 8 个 milestone + 2 个 RC,最终完成了从底层到上层的彻底重构。

这不是一个小版本升级。基线全面拉升:

  • Spring Boot 4.1.0 + Spring Framework 7.0 + Jakarta EE 11
  • Java 17 起步,推荐 Java 21(虚拟线程原生支持)
  • MCP Java SDK 直接跳到 2.0.0(从 0.x 跨大版本)
  • Jackson 3 全面引入(GA 版本中 OpenAiChatModel 改回只用 Jackson 2,属于兼容修正)

版本时间线

版本 发布时间 性质
2.0.0 GA 2026-06-12 首个正式版
2.0.0-RC2 2026-06-09 预发布,修复 Bedrock 模型选项、Ollama 思考字段丢失等问题
2.0.0-RC1 2026-06-06 预发布
2.0.0-M8 2026-05-27 最后一个里程碑,引入 ChatResponseMetadata 暴露 Anthropic 限流
2.0.0-M1 2025-12-11 2.0 系列首个里程碑
1.1.x 持续维护 兼容 Spring Boot 3.5

GA 与 RC 的关键差异(很多人漏看)

类别 变化
新特性 OpenAiChatModel 改回只用 Jackson 2(RC 阶段误升级)
新特性 Google GenAI 模型列表更新,新增 GEMINI_3_1_PRO_PREVIEW
Bug 修复 Cassandra / Mongo / JDBC ChatMemory 不再处理 unsupported tool message
Bug 修复 OpenAiChatOptions 补齐 promptCacheKey 字段(OpenAI prompt caching 2.0 需要)
依赖升级 MCP SDK → 2.0.0
依赖升级 Spring Boot → 4.1.0(从 M 系列的 4.0 升上来)

关键时间节点:Spring Boot 3.5 和 Spring Framework 6.2 已于 2026-06-30 EOL,距 GA 发布仅 18 天。要么升 2.0,要么停在 1.1.x 等下一个 LTS,没有"再等等"的路。


二、核心架构变化:从"单体核心"到"领域驱动模块化"

2.1 模块拆分

spring-ai-core 被拆分为多个独立模块:

  • spring-ai-commons —— 公共工具和基础设施
  • spring-ai-model —— 模型抽象层
  • spring-ai-client-chat —— ChatClient 及其 Advisor 链
  • spring-ai-vector-store —— 向量存储抽象
  • spring-ai-rag —— RAG 检索增强生成

开发者可以按需引入,大幅减少不必要的依赖。模块间遵循严格的分层依赖原则(DAG),底层模块禁止向上依赖。

2.2 基线升级详情

升级项 说明
Jackson 3 JSON 处理引擎全面升级(GA 中 OpenAI 模块回退至 Jackson 2 以保兼容)
JSpecify Null 安全注解 编译期空指针检测,org.springframework.ai.image.observation 等包标记为 null-marked
Options 不可变 setter 废弃,builder 必须,不可变对象
ChatOptions#copy() 移除 改用 .mutate() 创建修改后的副本
[*]Options#fromOptions() 移除 同上,统一使用 .mutate() 模式

Options 设计从可变到不可变的转变,是整个 2.0 设计哲学的缩影:显式优于隐式,组合优于继承


三、Tool Calling 重塑:从"私有实现"到"一等公民"

这是 2.0 最核心的架构变化。 没有之一。

3.1 1.x 的痛点

在 Spring AI 1.x 中,每个 ChatModel 实现包含自己的私有工具执行循环。功能可用,但深埋在模型实现内部:

  • 无法观测中间步骤
  • 无法与其他行为组合(日志、校验、重试)
  • 无法在工具调用前后插入自定义逻辑
  • 工具调用的 request/response 对 Advisor 链完全不透明

一句话总结:你能调用工具,但无法在工具调用之上构建任何东西。

┌─────────────────────────┐
│       ChatClient        │
│  ┌───────────────────┐  │
│  │   Advisor Chain    │  │  ← 看不到工具调用过程
│  └───────┬───────────┘  │
│          ▼              │
│  ┌───────────────────┐  │
│  │    ChatModel       │  │
│  │  ┌─────────────┐  │  │
│  │  │ Tool Loop   │  │  │  ← 黑盒,私有循环
│  │  │ (不可见)     │  │  │
│  │  └─────────────┘  │  │
│  └───────────────────┘  │
└─────────────────────────┘

3.2 2.0 的解决方案:ToolCallingAdvisor

工具循环被提升到 Advisor 链中,成为一等公民、可组合的组件ChatClient 通过有序 Advisor 链处理每个请求,支持循环——允许 Advisor 重新进入下游链。同一机制驱动工具调用循环、结构化输出重试循环、评估循环。

┌──────────────────────────────────┐
│           ChatClient             │
│  ┌────────────────────────────┐  │
│  │      Advisor Chain         │  │
│  │  ┌──────────────────────┐  │  │
│  │  │  Memory Advisor      │  │  │  ← order: HIGHEST + 200
│  │  ├──────────────────────┤  │  │
│  │  │  ToolCallingAdvisor  │  │  │  ← order: HIGHEST + 300(递归)
│  │  │    ↻ 循环执行         │  │  │
│  │  ├──────────────────────┤  │  │
│  │  │  Custom Advisor      │  │  │
│  │  ├──────────────────────┤  │  │
│  │  │  LLM Call            │  │  │
│  │  └──────────────────────┘  │  │
│  └────────────────────────────┘  │
└──────────────────────────────────┘

ToolCallingAdvisor递归 Advisor——反复重新进入下游链,直到停止条件满足(模型输出不包含工具调用)。DefaultChatClient 自动将其加入链中,且同一时刻只允许一个 ToolAdvisor 存在

3.3 完整的工具调用生命周期

1. 工具注册
   通过 @Tool、@McpTool、java.util.function.Function 或 ToolCallback 定义
   ↓
2. 初始注入
   Advisor 提取工具的名称、描述和输入 JSON Schema
   注入到初始上下文(与用户问题、system prompt 合并)
   ↓
3. 迭代循环
   将累积的对话历史(用户消息 + AI 工具调用请求 + 工具响应)
   与当前上下文合并,发送给 LLM
   ↓
4. 判断响应
   ├─ 包含工具调用 → ToolCallingManager 执行工具 → 追加响应 → 回到步骤 3
   └─ 不包含工具调用 → 返回最终答案

Blocking(.call())和 Streaming(.stream())模式完全支持。

3.4 代码示例:定义工具

class WeatherTools {

    @Tool(description = "Get the current weather for a given city")
    public String getWeather(String city) {
        return weatherService.fetch(city);
    }

    @Tool(description = "Book a flight between two cities on a given date")
    public BookingConfirmation bookFlight(
            String origin,
            String destination,
            @ToolParam(description = "Date in YYYY-MM-DD format") String date) {
        return flightService.book(origin, destination, date);
    }
}

Spring AI 自动生成输入参数的 JSON Schema。@ToolParam 添加参数级别的描述和可选/必填提示。标记了 @Nullable 的参数默认视为可选。

3.5 代码示例:使用 ChatClient 调用

String response = ChatClient.create(chatModel)
    .prompt("What's the weather in Amsterdam? Book a flight from London if it's sunny.")
    .tools(new WeatherTools())
    .call()
    .content();

简洁到令人发指——背后是完整的工具发现、调用、结果合并、循环决策。

3.6 ToolSearchToolCallingAdvisor:大规模工具场景

问题:工具超过 20-30 个时,每次请求都把所有工具定义塞进 prompt,导致上下文膨胀、精度下降、token 成本翻倍。多 MCP Server 场景下,单次会话可能聚合数百个工具定义。

解决方案ToolSearchToolCallingAdvisor——渐进式工具发现(Progressive Tool Disclosure)。

工作原理:

  1. 会话开始时,索引全部工具集
  2. 每次迭代,只注入一个内置的 toolSearchTool
  3. 模型通过自然语言查询按需检索相关工具
  4. 只有被发现的工具才会加入后续请求

基准测试显示 34-64% 的 token 节省(覆盖 OpenAI、Anthropic、Gemini)。

配置示例:

spring.ai.chat.client.tool-search-advisor.enabled=true
spring.ai.chat.client.tool-search-advisor.tool-index-type=vector

三种索引策略:

策略 说明 适用场景
regex 轻量,无额外依赖,默认 工具数量 < 50,简单匹配
lucene 关键词搜索,starter 内置 中等规模工具集
vector 基于 Embedding 的语义搜索,需要 VectorStore bean 大规模工具集,语义相似度检索

注意:工具索引按 session 隔离,调用者必须提供 session ID

chatClient.prompt()
    .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "user-42-session"))
    .user("Help me plan my trip to Amsterdam")
    .call()
    .content();

该 Advisor 从社区毕业进入核心 Spring AI 2.0,是 ToolCallingAdvisor 的直接替代品。

3.7 Tool Argument Augmentation(工具参数增强)

动态扩展工具的输入 Schema,不修改工具实现。模型看到增强后的 Schema 并填充额外字段,你的代码通过 consumer 接收,原始工具只接收自己的参数。

主要用途:inner thinking——强制模型在执行工具前表达推理过程,提升可追溯性。

public record AgentThinking(
    @ToolParam(description = "Your reasoning for calling this tool")
    String innerThought) {}

AugmentedToolCallbackProvider<AgentThinking> toolProvider = 
    AugmentedToolCallbackProvider.<AgentThinking>builder()
    .toolObject(new WeatherTools())           // 包装原始工具
    .argumentType(AgentThinking.class)         // 增强的参数类型
    .argumentConsumer(event -> log.info(       // 可选 consumer
        "Tool: {} | Reasoning: {}", 
        event.toolDefinition().name(), 
        event.arguments().innerThought()))
    .build();

ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultTools(toolProvider)
    .build();

模型看到的是"天气工具 + innerThought 字段",执行时只调用原始工具方法,推理过程通过 consumer 被记录或送入长期记忆。

3.8 用户控制的工具执行

自动循环覆盖大多数场景。但有些场景需要你自己掌控每一步迭代:外部审批、中间进度推送(SSE/WebSocket)、条件逻辑、基于旁路信号停止。

退出自动循环的方式:AdvisorParams.toolCallingAdvisorAutoRegister(false)

ChatClient chatClient = ...;
ToolCallingManager toolCallingManager = ToolCallingManager.builder().build();
ToolCallback[] tools = ToolCallbacks.from(new WeatherTools());
ChatOptions chatOptions = ToolCallingChatOptions.builder().toolCallbacks(tools).build();

String question = "What is the weather in Amsterdam and Paris?";

// 禁用自动 ToolCallingAdvisor
ChatClientResponse response = chatClient.prompt()
    .user(question)
    .options(chatOptions)
    .advisors(AdvisorParams.toolCallingAdvisorAutoRegister(false))
    .call()
    .chatClientResponse();

Prompt prompt = new Prompt(List.of(new UserMessage(question)), chatOptions);

// 自己驱动循环——每次迭代可观察、可中断
while (response.chatResponse() != null && response.chatResponse().hasToolCalls()) {
    ToolExecutionResult result = toolCallingManager.executeToolCalls(prompt, response.chatResponse());
    prompt = new Prompt(result.conversationHistory(), chatOptions);
    response = chatClient.prompt()
        .messages(result.conversationHistory())
        .options(chatOptions)
        .advisors(AdvisorParams.toolCallingAdvisorAutoRegister(false))
        .call()
        .chatClientResponse();
}

四、Advisor 链:递归 Advisors 与可组合架构

4.1 Advisor 链核心概念

ChatClient 通过有序 Advisor 链处理请求。Advisor 按 getOrder() 值排序(值越小越先执行),处理 ChatClientRequestChatClientResponse

2.0 引入递归 Advisor——可以重新进入下游链,循环执行:

public class MyRecursiveAdvisor implements CallAdvisor {

    @Override
    public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
        // 初始调用
        ChatClientResponse response = chain.nextCall(request);

        // 条件不满足则循环
        while (!isConditionMet(response)) {
            ChatClientRequest modifiedRequest = modifyRequest(request, response);
            // 关键:chain.copy(this) 创建子链,避免重复执行上游 Advisor
            response = chain.copy(this).nextCall(modifiedRequest);
        }
        return response;
    }
}

chain.copy(this) 是核心设计——创建包含当前 Advisor 之后所有下游 Advisor 的子链,确保每次迭代经过完整的下游链,同时避免上游 Advisor 被重复执行。

同一机制驱动多种循环模式:

  • 工具调用循环(ToolCallingAdvisor
  • 结构化输出验证循环(StructuredOutputValidationAdvisor
  • 评估循环
  • 自定义重试逻辑

4.2 Advisor 排序的重要性

Advisor 相对于 ToolCallingAdvisor(默认 order: HIGHEST_PRECEDENCE + 300)的位置决定了行为:

位置 Order 值 行为
循环外部 < HIGHEST_PRECEDENCE + 300 只看到最终结果
循环内部 > HIGHEST_PRECEDENCE + 300 看到每次迭代的完整过程

这不是抽象的理论——直接决定了 Memory 存什么、日志看什么、监控采集什么。

4.3 Memory 与 Tool Loop 的协作

MessageChatMemoryAdvisor 放置位置决定了记忆存储的内容范围:

外部记忆(默认,order HIGHEST_PRECEDENCE + 200

  • 循环开始前加载一次历史
  • 只持久化最终的用户和助手消息
  • 工具请求/响应不写入存储
  • 兼容所有 ChatMemoryRepository 实现

内部记忆(order > ToolCallingAdvisor.DEFAULT_ORDER

  • 每次迭代都被调用
  • 持久化完整的工具请求/响应记录
  • 后续轮次中 LLM 可以推理之前尝试了什么、调用了哪些工具、返回了什么
  • 需要 ToolCallingAdvisor 禁用内部对话历史以避免重复写入(自动注册的 Advisor 会自动检测并处理)

支持完整消息集的内置仓库:

  • InMemoryChatMemoryRepository
  • RedisChatMemoryRepository
  • Neo4jChatMemoryRepository

对于需要 JDBC 持久化 + 完整工具消息支持 + 事件溯源历史 + 轮次感知压缩 + 多 Agent 分支隔离的场景,使用 Spring-AI-Session 社区项目(计划纳入 Spring AI 2.1)。

4.4 自定义 Advisor 扩展

通过 ToolCallingAdvisor.Builder<?> bean 替换默认实现:

@AutoConfiguration(
    beforeName = "org.springframework.ai.model.chat.client.autoconfigure.ChatClientAutoConfiguration")
@ConditionalOnProperty(prefix = "my.advisor", name = "enabled", havingValue = "true")
public class MyToolAdvisorAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    ToolCallingAdvisor.Builder<?> toolCallingAdvisorBuilder(
            ToolCallingManager toolCallingManager) {
        return MyCustomToolCallingAdvisor.builder()
            .toolCallingManager(toolCallingManager);
    }
}

ToolSearchToolCallingAdvisor 就是用这个机制注册的——它的 auto-configuration 注册一个 ToolSearchToolCallingAdvisor.Builder,类型标注为 ToolCallingAdvisor.Builder<?>DefaultChatClient 就会自动替换默认的 ToolCallingAdvisor

4.5 扩展点 Hook 方法

ToolSearchToolCallingAdvisor 不是什么框架魔法——它是 ToolCallingAdvisor 的子类,通过覆写 protected hook 方法在循环的关键节点拦截:

Hook 触发时机
doInitializeLoop / doInitializeLoopStream 第一次迭代前,仅执行一次
doBeforeCall / doBeforeStream 每次迭代前
doAfterCall / doAfterStream 每次迭代后
doFinalizeLoop / doFinalizeLoopStream 循环结束后,仅执行一次

五、MCP 原生集成:从社区模块到核心功能

5.1 MCP 概述

Model Context Protocol 正在成为 AI 集成的通用协议。Spring AI 2.0 直接搭载 MCP Java SDK 2.0.0,遵循 2025-11-25 规范。mcp-annotations 模块纳入核心。

一个 Spring Boot 应用可以同时充当 MCP Client 和 MCP Server。

5.2 注解驱动的 MCP Server

@Component
public class WeatherTools {

    @McpTool(description = "Get the current weather for a given city")
    public String getWeather(
            @McpToolParam(description = "City name") String city) {
        return weatherService.fetch(city);
    }
}

MCP Server 自动配置扫描 @McpTool 注解的 bean,自动生成 JSON Schema,注册到 MCP Server——无需额外布线。

添加依赖即可启用:

<dependency>
    <groupId>org.springframework.ai</groupId>

    <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>

</dependency>

5.3 MCP 传输层升级

传输方式 状态 说明
Streamable HTTP ✅ 默认 替代 SSE,支持双向通信,单一端点处理请求和流式响应
Streamable HTTP(无状态) ✅ 可选 牺牲双向性换取水平扩展能力
STDIO ✅ 保留 本地进程集成
SSE ❌ 废弃 被 Streamable HTTP 取代

传输层实现从 MCP Java SDK 移交给 Spring AI 侧(WebMVC/WebFlux),更好地与 Spring 生态集成。

配置示例:

server.port=3001
spring.ai.mcp.server.protocol=STREAMABLE

5.4 MCP Client 使用

添加 MCP Client starter:

<dependency>
    <groupId>org.springframework.ai</groupId>

    <artifactId>spring-ai-starter-mcp-client</artifactId>

</dependency>

配置 MCP Server 连接:

spring.ai.mcp.client.stdio.connections.my-server.command=npx
spring.ai.mcp.client.stdio.connections.my-server.args=-y,@modelcontextprotocol/server-everything

Auto-configuration 连接所有配置的 MCP Server,发现其工具,暴露为 SyncMcpToolCallbackProvider bean(异步客户端类型则为 AsyncMcpToolCallbackProvider)。

注意:MCP Provider 不会被自动注册到 ChatClient——因为列出工具会强制对每个连接的 MCP Server 发起网络请求。需要显式注入:

@Autowired SyncMcpToolCallbackProvider mcpTools;

ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultTools(mcpTools)
    .build();

// 或按调用注入
chatClient.prompt()
    .user("Search the web for the latest Spring AI release notes")
    .tools(mcpTools)
    .call()
    .content();

5.5 本地工具与 MCP 工具混合使用

本地 @Tool 和远程 MCP 工具共享同一个 ToolCallback 接口——模型和 ToolCallingAdvisor 不区分两者:

chatClient.prompt()
    .tools(new LocalTools(), mcpTools)
    .call()
    .content();

注意事项

  • 名称冲突仅在 MCP 侧处理DefaultMcpToolNamePrefixGenerator 为跨 MCP Server 的重名工具添加前缀,但不感知本地 @Tool 方法。如果本地工具和远程 MCP 工具同名,需要手动重命名或使用 McpToolFilter 过滤。
  • 限制暴露范围。MCP 工具来自外部源,使用 McpToolFilter bean 按 Server 身份、工具名或描述选择哪些工具进入命名空间。

5.6 MCP 企业级特性

MCP 进入核心意味着 Spring 的生产级栈可以直接继承:

  • 可观测性:Micrometer Span + OpenTelemetry 兼容指标,Server 交互延迟、错误率、调用量仪表盘
  • 安全:OAuth 2.0 和 API Key 认证(通过 spring-ai-community/mcp-security 项目)
  • 生产警告:外部暴露工具的 MCP Server 是事实上的攻击面,授权设计必须在第一天就确定

六、ChatModel 装饰器模式

生产环境中的 ChatModel 不再是"裸模型",而是多层包装:

InstrumentingTraceChatModel(Trace 追踪)
  → RecoveryInstrumentingChatModel(自愈重试)
    → 基础 ChatModel

装饰器模式让追踪、重试、降级等横切关注点与模型实现解耦。

6.1 ChatResponseMetadata

2.0 M8 引入、GA 完整保留——暴露 Anthropic 限流信息:

ChatResponse resp = chatClient.prompt().user("...").call().chatResponse();
RateLimitMeta rateLimit = resp.getMetadata().getRateLimit();

// rateLimit.getTokensRemaining()
// rateLimit.getResetAt()
// rateLimit.getTokensUsed()

之前 Anthropic 返回的限流 header(x-ratelimit-remaining-tokens 等)是被丢弃的——只能等 429 才能感知。现在能实时看到配额水位,支撑:

  • 实时监控面板
  • 接近限额时主动排队/降级
  • 用户面提示"系统繁忙,请稍后再试"而不是直接 500

做多 provider 混用的团队必看。


七、破坏性变更与迁移指南

7.1 必须升级的前提

  • Spring Boot 3.x 无法运行 Spring AI 2.0——这是架构限制,不是推荐
  • Spring Boot 3.5 和 Spring Framework 6.2 已于 2026-06-30 EOL
  • Java 17 最低,推荐 Java 21
  • Spring AI 2.0 是 Spring Boot 4.0+ 的依赖模型上构建的,不存在"只升 AI 不升 Boot"的路径

7.2 主要破坏性变更

类名迁移
旧名称 新名称 影响范围
MessageAggregator ChatClientMessageAggregator 所有流式输出代码
ToolCallAdvisor ToolCallingAdvisor 工具调用相关代码
FunctionCallback ToolCallback 整体重命名,Function → Tool
SemanticCacheorg.springframework.ai.cache SemanticCacheorg.springframework.ai.semantic.cache 语义缓存代码
Function beans 替换
// Before (1.x) — 裸 Function bean,按名称解析
@Bean @Description("Get the weather")
Function<WeatherRequest, WeatherResponse> currentWeather() {
    return weatherService::getWeather;
}
chatClient.prompt().toolNames("currentWeather"); // ❌ 不再存在

// After (2.0) — 显式 ToolCallback bean
@Bean
ToolCallback currentWeather() {
    return FunctionToolCallback.builder("currentWeather", weatherService::getWeather)
        .description("Get the weather")
        .inputType(WeatherRequest.class)
        .build();
}

// 注入 bean 并传递给 ChatClient——名称解析已移除
@Autowired ToolCallback currentWeather;
chatClient.prompt()
    .user("What's the weather in Copenhagen?")
    .tools(currentWeather)
    .call()
    .content();

SpringBeanToolCallbackResolvertoolNames() API 已被移除。工具必须注册为显式的 ToolCallback bean。

internalToolExecutionEnabled 移除
// Before (1.x)
chatClient.prompt()
    .options(OpenAiChatOptions.builder()
        .internalToolExecutionEnabled(false)
        .build())
    .call();

// After (2.0) — 使用 Advisor 级别控制
chatClient.prompt()
    .advisors(AdvisorParams.toolCallingAdvisorAutoRegister(false))
    .call();

internalToolExecutionEnabled 选项和对应配置属性已移除。每个模型内部的工具执行不再存在——ToolCallingAdvisor 是唯一执行路径。

streamToolCallResponses 移除

ToolCallingAdvisor.BuilderToolSearchToolCallingAdvisor.Builder 中移除。

原因:功能有缺陷。启用后只传递了 model 的 tool request messages 到下游,但 advisor 自身生成的 tool response messages 留在循环内部。外部 Advisor 只看到一半——有 request 没有 response——比什么都不看还糟。

替代方案:将 Advisor 放在循环内部(order > ToolCallingAdvisor.DEFAULT_ORDER),每次迭代都能看到完整的 request/response 历史。

Options 不可变
// Before (1.x)
ChatOptions copy = options.copy();
// 或
MyOptions modified = MyOptions.fromOptions(options);

// After (2.0)
ChatOptions modified = options.mutate()
    .temperature(0.7)
    .build();
Vector Store 异常处理
// Before (1.x)
vectorStore.delete(documentIds); // 返回 void,失败时静默

// After (2.0)
try {
    vectorStore.delete(documentIds);
} catch (VectorStoreException e) {
    log.error("向量删除失败: {}", e.getMessage());
    // 处理失败逻辑,考虑 Spring Retry
}

2.0 的 delete() 方法不再静默失败,而是抛出 VectorStoreException,必须显式捕获。

Provider 移除
原 Provider 状态 推荐替代 迁移复杂度
IBM Watson 已移除 OpenAI / Azure OpenAI
百度千帆 QianFan 已移除 智谱 ChatGLM / 通义千问 高(接口差异大)
月之暗面 MoonShot 已移除 OpenAI / Ollama(自部署) 中(兼容 OpenAI 协议)
MiniMax 已移除 Anthropic(接口兼容,需回归测试)

迁移示例(QianFan → 智谱 ChatGLM):

// Before (1.x QianFan)
@Bean
public ChatClient qianfanChatClient() {
    return ChatClient.builder(new QianFanChatModel(apiKey, secretKey))
        .build();
}

// After (2.0 智谱)
@Bean
public ChatClient chatglmChatClient() {
    return ChatClient.builder(
        new OpenAiChatModel(
            new OpenAiApi("https://open.bigmodel.cn/api/paas/v4/chat/completions",
                apiKey)
        )
    ).build();
}

7.3 推荐迁移路径

Step 1: 升级到 Spring Boot 3.5,处理所有 deprecation
         ↓
Step 2: 迁移 Jackson 2 → 3(如需要,GA 中 OpenAI 模块仍用 Jackson 2)
         ↓
Step 3: 升级 Spring Boot 到 4.0 / 4.1
         ↓
Step 4: 升级 Spring AI 到 2.0.0
         ↓
Step 5: 处理破坏性变更
         - 类名/包路径替换
         - Provider 替换
         - Function beans → ToolCallback beans
         - Vector Store 异常处理
         ↓
Step 6: 添加 JSpecify 注解,启用 NullAway 编译检查

八、Spring AI 2.0 vs LangChain4j

维度 Spring AI 2.0 LangChain4j
生态定位 Spring 官方 AI 框架 Java 社区 AI 框架
与 Spring Boot 集成 原生深度集成,auto-configuration 开箱即用 需要额外适配
MCP 支持 核心内置,注解驱动 需要第三方扩展
Advisor 链 原生支持递归 Advisor,可组合 无等价机制
工具调用架构 ToolCallingAdvisor 一等公民,可观测可拦截 内置工具循环,不可扩展
模块化 按需引入独立模块 相对粗粒度
可观测性 Micrometer + OpenTelemetry 原生 需手动集成
社区生态 Spring 生态背书,企业级支持 社区驱动,灵活性更高
适用场景 Spring 技术栈团队、企业级生产环境 非 Spring 或混合技术栈

选型建议:Spring 技术栈团队选 Spring AI 2.0,这不是一个需要犹豫的决定。 LangChain4j 的价值在于非 Spring 项目或需要更多定制灵活性的场景。


九、生产部署建议

9.1 何时升级

场景 建议 理由
✅ 新项目(Greenfield) 直接用 Boot 4.1 + AI 2.0 零包袱,最新架构
✅ 工具数量 > 10 的 Agent 系统 优先升级 ToolSearchToolCallingAdvisor 省 34-64% token
✅ 多 provider 混用 优先升级 ChatResponseMetadata 限流监控刚需
✅ Boot 已在 3.5 的新项目 直接走 Boot 4.1 + AI 2.0 迁移成本最低
⚠️ Boot 在 3.3/3.4 的旧项目 先升 3.5 处理 deprecation Boot 4 是一次性大跳
⚠️ 自定义 ChatMemory 的对话系统 评估迁移成本 Advisor 模块拆分,迁移成本不小
❌ 重度依赖已移除 Provider 先评估替代方案 Watson/QianFan/MoonShot 无直接替代

9.2 性能优化建议

虚拟线程

spring.threads.virtual.enabled=true

IO 密集型场景(LLM 调用、工具调用、MCP 通信)吞吐量提升 3-5 倍。Java 21 原生支持。

ToolSearchToolCallingAdvisor
大规模工具场景节省 34-64% token。工具超过 20 个就值得评估。

Advisor 顺序调优

  • 合理设置 Advisor 顺序,避免不必要的循环内执行
  • Memory Advisor 默认在循环外部——只在需要完整工具历史时才放入内部
  • 监控 Advisor 链的执行次数和耗时

HTTP Client 可配置(RC2 引入)
Anthropic 和 OpenAI 的 HTTP 客户端现在可配置——OkHttp / Reactor Netty / JDK 11 HttpClient 按需选择。

9.3 完整迁移 Checklist

升级前准备

  • 备份生产数据库和配置文件
  • 测试环境建立基线性能数据
  • 准备回滚方案(保留旧版本镜像)
  • 评估与已移除 Provider 的依赖关系
  • 评估团队对 Java 21 和 Spring Boot 4 的熟悉度

代码迁移

  • 类名替换:MessageAggregatorChatClientMessageAggregatorToolCallAdvisorToolCallingAdvisor
  • 包路径替换:SemanticCache 路径更新
  • Function beans → ToolCallback beans
  • vectorStore.delete() 添加异常处理
  • 替换已移除的 Provider
  • 移除 internalToolExecutionEnabled 调用
  • 移除 streamToolCallResponses 调用
  • Options copy()/fromOptions()mutate()
  • 添加 JSpecify 注解,启用 NullAway

测试验证

  • 单元测试 + 集成测试通过
  • 性能测试验证虚拟线程效果
  • 压力测试验证并发性能
  • 工具调用循环完整验证
  • MCP 连接测试

部署验证

  • Docker 构建成功
  • 健康检查通过
  • 监控指标正常
  • 生产灰度发布
  • P95/P99 响应时间对比

十、国内生态:Spring AI Alibaba 的适配现状

在国内,Spring AI 和 Spring AI Alibaba 几乎是绑定使用的。阿里巴巴在这套体系上投入了大量工程——Graph 工作流引擎、多 Agent 编排框架、MCP Gateway、DashScope 模型适配、Admin 可视化平台,这些都是生产级 Agent 开发的核心基础设施。所以 Spring AI 2.0 GA 了,大家第一个问题一定是:Spring AI Alibaba 跟上了吗?

当前版本状态

组件 最新稳定版 最新预发布 对应基线
Spring AI 2.0.0 GA(2026-06-12) Boot 4.1.0 + Framework 7.0
Spring AI Alibaba 1.1.2.2(2026-03-10) 2.0.0-M1.1(2026-06-25) Boot 4.0.0 + AI 2.0.0-M1

三个核心问题

1. 没有 GA 版本

Spring AI Alibaba 的 2.0 适配目前只有一个 Milestone 预发布版 v2.0.0-M1.1,尚未进入 RC 和 GA 阶段。而 Spring AI 官方已经发布了 2.0.0 GA——中间差了好几个迭代。对于生产环境来说,预发布版不适合直接采用。

2. 基线未对齐

v2.0.0-M1.1 对应的是 Spring AI 2.0.0-M1 + Spring Boot 4.0.0,而非最新的 Spring AI 2.0.0 GA + Spring Boot 4.1.0。即使现在冒险使用预发布版,底层基线也对不齐,后续 Alibaba 团队还需要再跟进 M2~GA 的变更。

3. 核心能力的兼容性未知

Spring AI Alibaba 的 Graph 引擎、多 Agent 编排(Supervisor/Routing/Handoffs)、MCP Gateway、AgentScope 集成等高级特性,在 2.0 的架构下是否有 API 变化、是否需要适配,目前都没有明确的文档说明。

实际影响

对于使用 Spring AI Alibaba 的团队(尤其是依赖 Graph 引擎和 DashScope 集成的项目),升级路径实际上被阻塞了:

你的现状                          目标状态
─────────                        ─────────
Spring Boot 3.5.x    ──?──→     Spring Boot 4.1.0
Spring AI 1.1.x      ──?──→     Spring AI 2.0.0 GA
Spring AI Alibaba    ──?──→     ??? (无 GA 版本)
  1.1.2.2

不是"改个版本号"就能解决的问题。整条链路中 Alibaba 这一层没有稳定版来兜底,Graph 引擎、Agent 框架、DashScope 适配都可能受影响。

建议策略

场景 建议
生产项目,依赖 Alibaba 生态 暂不升级,继续用 1.1.x 系列,关注 Alibaba 的 M2/RC 进展
新项目,不需要 Graph/Agent 框架 可以直接用 Spring AI 2.0 GA + Boot 4.1(不引入 Alibaba)
新项目,需要完整 Agent 能力 等 Spring AI Alibaba 2.0 GA 发布后再启动

核心原则:Spring AI 官方 GA ≠ 你的项目可以升级。 国内项目要等 Alibaba 生态同步跟进,这个时间差是客观存在的。


十一、总结

Spring AI 2.0 的五大核心变化:

  1. 从"单体核心"到"领域模块":按需引入,减少依赖,模块间严格分层
  2. 从"私有工具循环"到"可组合 Advisor":工具调用成为一等公民,可观测、可拦截、可组合。这是整个 2.0 最核心的架构决策
  3. 从"社区 MCP"到"核心内置":注解驱动的 MCP Server/Client,Streamable HTTP 默认传输,企业级安全与可观测性
  4. 从"可变配置"到"不可变设计":Options 不可变、JSpecify Null 安全、builder 必须——更安全、更可预测
  5. 从"能用"到"好用":ToolSearchToolCallingAdvisor 省 token、ChatResponseMetadata 暴露限流、HTTP Client 可配置、虚拟线程原生支持
  6. 从"官方 GA"到"生态就绪":Spring AI 2.0 GA 已发布,但国内广泛使用的 Spring AI Alibaba 尚在 M1 预发布阶段,升级路径客观存在时间差。技术决策不能只看上游节奏,要等整条链路就绪

给还在观望的团队一句话:Spring Boot 3.5 已经 EOL,Spring AI 1.1.x 没有独立的长期支持承诺。升级到 2.0 不是"要不要做"的问题,是"什么时候做"的问题。但如果你在用 Spring AI Alibaba,这个"什么时候"还得等 Alibaba 生态同步跟进。


参考链接

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐