Spring AI 2.0 GA 实战:构建生产级 AI Agent 系统------Advisor 链、MCP 2.0 与工具发现机制全解析
2026 年 6 月 12 日,Spring AI 2.0.0 正式 GA。这不是一次简单的版本号升级------它重新定义了 Java 生态中 AI Agent 的构建方式。本文将深入解析 Spring AI 2.0 的核心架构变化,并通过完整代码示例带你实战上手。
作者:超人不会飞
一、为什么 Spring AI 2.0 值得关注
在 Spring AI 1.x 时代,开发者面临几个核心痛点:
- 工具调用循环被锁死在每个 ChatModel 内部------你想拦截、包装或替换工具执行策略?做不到。
- Options 和配置属性耦合严重 ------
.options前缀让人困惑,默认值散落在各处。 - MCP 集成停留在早期规范------SSE 传输已显过时,缺乏企业级安全与可观测性。
- Null 安全缺失------运行时 NPE 频发,Kotlin 开发者体验尤差。
Spring AI 2.0 用一次彻底的架构重构回答了这些问题。基于 Spring Boot 4.0 / Spring Framework 7.0 基线,引入 Jackson 3 、JSpecify Null 安全注解 、不可变 Options Builder,并将工具调用循环提升为 Advisor 链中的一等公民。

二、核心架构变化一览
2.1 基础设施升级
| 维度 | Spring AI 1.x | Spring AI 2.0 |
|---|---|---|
| Spring Boot 基线 | 3.x | 4.0 / 4.1 |
| JSON 序列化 | Jackson 2 | Jackson 3 |
| Null 安全 | 无 | JSpecify 全量注解 |
| Options 模型 | 构造函数 + 可变 | Builder + 不可变 |
| 配置属性 | 含 .options 前缀 |
扁平化,无前缀 |
| 模型提供商 | 多变体(Azure/HTTP/SDK 并存) | 统一 SDK 优先 |
2.2 聚焦的模型提供商
Spring AI 2.0 精简了内置支持,聚焦于:
- OpenAI(SDK 实现,兼容所有 OpenAI API 协议的服务)
- Anthropic(SDK 实现,兼容 Minimax 等)
- Amazon Bedrock
- Google GenAI(统一为 GenAI SDK)
- Mistral AI
- DeepSeek
- Ollama
OCI Generative AI 和 Azure Cosmos DB 等由厂商直接维护,这种分工模式让核心代码库更聚焦。
三、Advisor 链:AI Agent 的神经中枢
这是 Spring AI 2.0 最重要的架构变化。在 1.x 中,每个 ChatModel 内部都有一个私有的工具调用循环,你无法介入。2.0 将这个循环提升到了 Advisor 链 中。
3.1 什么是 Advisor 链
ChatClient 的每次请求都会经过一个有序的 Advisor 链。Advisor 可以:
-
拦截请求和响应(日志、审计、限流)
-
循环------让下游链重新进入(工具调用循环、结构化输出重试循环、评估循环)
-
组合 ------多个 Advisor 按顺序协作

User Request
│
▼
┌─────────────────────────────┐
│ Advisor Chain │
│ ┌───────────────────────┐ │
│ │ LoggingAdvisor │ │
│ │ → log request │ │
│ ├───────────────────────┤ │
│ │ ToolCallingAdvisor │ │◄── Auto-registered
│ │ → execute tools │ │
│ │ → loop until done │ │
│ ├───────────────────────┤ │
│ │ StructuredOutput │ │◄── Auto-registered
│ │ ValidationAdvisor │ │
│ │ → validate & retry │ │
│ ├───────────────────────┤ │
│ │ ToolSearchAdvisor │ │◄── Optional
│ │ → progressive │ │
│ │ tool discovery │ │
│ └───────────────────────┘ │
└─────────────────────────────┘
│
▼
ChatModel (pure inference)
3.2 ToolCallingAdvisor 实战
ToolCallingAdvisor 是自动注册的,它实现了完整的工具调用往返:
java
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AgentApplication {
public static void main(String[] args) {
SpringApplication.run(AgentApplication.class, args);
}
}
/**
* 股票查询工具 - 使用 @Tool 注解声明
* Spring AI 2.0 会自动将其注册到 ToolCallingAdvisor
*/
@Service
public class StockQueryService {
@Tool(description = "查询指定股票代码的实时行情数据,包括价格、涨跌幅、成交量")
public StockQuote getRealtimeQuote(
@ToolParam(description = "股票代码,如 600519.SH") String stockCode) {
// 实际项目中这里会调用行情 API
return new StockQuote(stockCode, 1850.50, 2.35, 12500000);
}
@Tool(description = "查询指定股票的历史K线数据")
public List<KlineData> getHistoryKline(
@ToolParam(description = "股票代码") String stockCode,
@ToolParam(description = "天数,默认30天") int days) {
// 返回模拟K线数据
return KlineData.generateMockData(stockCode, days);
}
}
/**
* 行情数据 DTO
*/
public record StockQuote(
String code,
double price,
double changePercent,
long volume
) {}
/**
* K线数据 DTO
*/
public record KlineData(
String date,
double open,
double close,
double high,
double low,
long volume
) {
public static List<KlineData> generateMockData(String code, int days) {
// 模拟数据生成
return java.util.stream.IntStream.range(0, days)
.mapToObj(i -> new KlineData(
java.time.LocalDate.now().minusDays(days - i).toString(),
1800 + Math.random() * 100,
1800 + Math.random() * 100,
1850 + Math.random() * 50,
1780 + Math.random() * 50,
(long)(Math.random() * 20000000)
))
.toList();
}
}
配置 ChatClient 并调用:
java
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ChatClientConfig {
@Bean
public ChatClient chatClient(ChatClient.Builder builder,
StockQueryService stockService) {
return builder
.defaultSystem("你是一个专业的A股分析助手,请根据用户的问题调用相应工具获取数据后给出分析。")
.defaultTools(stockService) // 注册工具,ToolCallingAdvisor 自动接管
.build();
}
}
/**
* Agent 控制器 - 处理用户查询
*/
@RestController
@RequestMapping("/api/agent")
public class AgentController {
private final ChatClient chatClient;
public AgentController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@PostMapping("/chat")
public ResponseEntity<String> chat(@RequestBody ChatRequest request) {
String response = chatClient.prompt()
.user(request.getMessage())
.call()
.content();
return ResponseEntity.ok(response);
}
}
public record ChatRequest(String message) {}
关键理解 :你不需要手动管理工具调用循环。ToolCallingAdvisor 会自动:
- 将用户消息发送给模型
- 如果模型返回工具调用请求,执行对应工具
- 将工具结果回传给模型
- 重复直到模型给出最终文本回复
如果你需要更细粒度的控制(比如限制循环次数、添加人工审批环节),可以禁用自动注册并手动驱动。
四、ToolSearch:让 Agent 管理数百个工具
当你的 Agent 系统扩展到几十甚至上百个工具时,每次请求都注册所有工具会严重消耗 Token 预算。ToolSearchToolCallingAdvisor 实现了渐进式工具发现:
┌────────────────────────────────────────────┐
│ ToolSearch Flow │
│ │
│ 1. Index all tools (once per session) │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │Tool 1│ │Tool 2│ │Tool N│ ... │
│ └──┬───┘ └──┬───┘ └──┬───┘ │
│ └─────────┴─────────┘ │
│ Tool Index │
│ │
│ 2. Model requests → search relevant tools │
│ "I need stock data" → [getQuote, │
│ getKline, │
│ getNews] │
│ │
│ 3. Only matched tools sent to model │
│ → Saves token budget │
│ → Reduces confusion │
└────────────────────────────────────────────┘
java
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.resolution.ToolSearchToolCallingAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
@Configuration
public class ScalableAgentConfig {
/**
* 配置支持大量工具的 ChatClient
* ToolSearchToolCallingAdvisor 按需暴露工具,而非全量注册
*/
@Bean
public ChatClient scalableChatClient(
ChatClient.Builder builder,
List<Object> allToolBeans) {
return builder
.defaultSystem("你是一个全能金融分析助手,可以根据需要查找并使用相关工具。")
// ToolSearchToolCallingAdvisor 会索引所有工具
// 模型每次只能看到与当前任务相关的工具子集
.defaultAdvisors(
new ToolSearchToolCallingAdvisor(allToolBeans)
)
.build();
}
}

工作原理:
- Advisor 在会话开始时对所有工具建立索引(基于
@Tool的 description) - 每次模型请求时,根据上下文搜索最相关的工具子集
- 只有匹配的工具被发送给模型
- 随着对话深入,工具集动态调整
五、MCP 2.0 集成:AI 应用的标准协议
5.1 什么是 MCP
Model Context Protocol (MCP) 正在成为 AI 集成的通用协议。Spring 团队同时维护着 官方 MCP Java SDK,Spring AI 2.0 直接搭载了 MCP Java SDK 2.0.0 ,遵循 2025-11-25 规范。

5.2 注解驱动的 MCP Server
Spring AI 2.0 将 mcp-annotations 模块纳入核心。只需一个方法注解,就能将任何 Spring 服务暴露为 MCP Server:
java
import org.springframework.ai.tool.mcp.annotation.McpTool;
import org.springframework.ai.tool.mcp.annotation.McpResource;
import org.springframework.ai.tool.mcp.annotation.McpPrompt;
import org.springframework.ai.tool.mcp.McpSyncRequestContext;
import org.springframework.stereotype.Service;
/**
* MCP Server 服务 - 通过注解暴露给外部 AI Agent 使用
* 任何 MCP 客户端(Claude Desktop、Cursor 等)都可以调用这些工具
*/
@Service
public class McpFinancialService {
/**
* @McpTool - 将方法暴露为 MCP 工具
* McpSyncRequestContext 提供日志、进度报告、采样等能力
*/
@McpTool(description = "查询A股实时行情,返回价格、涨跌幅、成交量等数据")
public StockQuote queryStockQuote(
String stockCode,
McpSyncRequestContext context) {
// 报告进度(MCP 协议支持)
context.reportProgress(0.5, "正在获取行情数据...");
// 调用行情服务
StockQuote quote = fetchQuoteFromMarket(stockCode);
// 记录审计日志
context.log("查询股票: " + stockCode + ", 价格: " + quote.price());
return quote;
}
/**
* @McpResource - 将方法暴露为 MCP 资源(可被 Agent 读取的数据源)
*/
@McpResource(
uri = "market://watchlist/{userId}",
name = "用户自选股列表",
description = "获取指定用户的自选股列表及其最新行情"
)
public List<WatchlistItem> getWatchlist(String userId) {
return watchlistRepository.findByUserId(userId);
}
/**
* @McpPrompt - 将方法暴露为 MCP 提示模板
*/
@McpPrompt(
name = "stock-analysis",
description = "股票深度分析提示模板"
)
public String stockAnalysisPrompt(String stockCode, String analysisType) {
return String.format("""
请对股票 %s 进行%s分析。
分析维度包括:
1. 基本面(PE、PB、ROE、营收增速)
2. 技术面(均线、MACD、KDJ)
3. 资金面(主力流向、北向资金)
4. 行业对比(同行业PE/PB分位数)
""", stockCode, analysisType);
}
private StockQuote fetchQuoteFromMarket(String code) {
// 实际实现:调用行情 API
return new StockQuote(code, 100.0, 1.5, 5000000);
}
// ... 其他依赖注入
private final WatchlistRepository watchlistRepository;
public McpFinancialService(WatchlistRepository watchlistRepository) {
this.watchlistRepository = watchlistRepository;
}
}
public record WatchlistItem(String stockCode, String stockName, double currentPrice) {}
5.3 MCP 传输层升级
Spring AI 2.0 对 MCP 传输层做了重要升级:
| 传输方式 | 状态 | 说明 |
|---|---|---|
| Streamable HTTP | ✅ 默认 | 替代 SSE,支持双向通信 |
| Streamable HTTP (无状态) | ✅ 可选 | 牺牲双向性换取水平扩展能力 |
| STDIO | ✅ 保留 | 本地进程集成 |
| SSE | ❌ 废弃 | 被 Streamable HTTP 取代 |
配置 MCP Server 传输:
yaml
# application.yml
spring:
ai:
mcp:
server:
name: financial-tools-server
version: 1.0.0
transport: streamable-http # 默认传输方式
# 如需水平扩展,使用无状态模式:
# transport: streamable-http-stateless
5.4 MCP 企业级特性
Spring AI 2.0 的 MCP 集成继承了完整的 Spring 生产级能力:
- 可观测性:Micrometer Span + OpenTelemetry 兼容指标
- 安全 :OAuth 2.0 和 API Key 认证(通过
mcp-security项目) - 监控:Server 交互延迟、错误率、调用量仪表盘
java
import io.micrometer.observation.annotation.Observed;
import org.springframework.ai.tool.mcp.annotation.McpTool;
import org.springframework.stereotype.Service;
/**
* 带完整可观测性的 MCP 工具示例
* Micrometer 自动记录调用耗时、成功/失败率
*/
@Service
public class ObservableMcpTools {
@McpTool(description = "查询宏观经济数据(GDP、CPI、PMI)")
@Observed(name = "mcp.tool.macro_data",
contextualName = "macro-data-query")
public MacroData queryMacroData(String indicator, String period) {
// Micrometer 自动记录:
// - 调用耗时
// - 成功/失败计数
// - 异常类型分布
return macroDataService.query(indicator, period);
}
private final MacroDataService macroDataService;
public ObservableMcpTools(MacroDataService macroDataService) {
this.macroDataService = macroDataService;
}
}
六、结构化输出自修正
即使开启了 Native Structured Output,模型也可能返回不合规的 JSON。StructuredOutputValidationAdvisor 会自动检测并修正:
java
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 结构化输出示例 - 自动修正不合规的 JSON
*/
@Service
public class StructuredAnalysisService {
private final ChatClient chatClient;
public StructuredAnalysisService(ChatClient.Builder builder) {
this.chatClient = builder
.defaultSystem("你是股票分析师,请严格按照指定格式输出分析结果。")
// StructuredOutputValidationAdvisor 自动注册
// 当模型返回不合规 JSON 时,自动重新提示模型修正
.build();
}
/**
* 获取结构化的股票分析报告
* 返回类型定义了期望的 JSON Schema
*/
public StockAnalysisReport analyzeStock(String stockCode) {
return chatClient.prompt()
.user("请分析股票 " + stockCode + " 的投资价值")
.call()
.entity(StockAnalysisReport.class);
}
}
/**
* 股票分析报告 - 结构化输出目标类
*/
public record StockAnalysisReport(
String stockCode,
String stockName,
Rating rating,
double targetPrice,
List<String> bullReasons,
List<String> bearReasons,
RiskAssessment risk
) {
public enum Rating { STRONG_BUY, BUY, HOLD, SELL, STRONG_SELL }
public record RiskAssessment(
int level, // 1-5
String description,
List<String> factors
) {}
}
七、Options 重构:告别配置混乱
Spring AI 2.0 的 Options 模型做了彻底重构:
java
import org.springframework.ai.openai.OpenAiChatOptions;
/**
* Spring AI 2.0 Options 使用方式
* 关键变化:
* 1. 使用 Builder 创建,不可变
* 2. 默认值统一在 Options 层定义
* 3. 不再有 .options 配置前缀
*/
public class OptionsExample {
/**
* 方式一:在 ChatClient 级别设置默认 Options
*/
public ChatClient createClient(ChatClient.Builder builder) {
return builder
.defaultOptions(
OpenAiChatOptions.builder()
.model("gpt-4o")
.temperature(0.7)
.maxTokens(4096)
.build() // 不可变对象
)
.build();
}
/**
* 方式二:在请求级别覆盖 Options(作为 customizer)
* 部分指定即可,未指定的继承默认值
*/
public String chatWithCustomOptions(ChatClient chatClient) {
return chatClient.prompt()
.options(
OpenAiChatOptions.builder()
.temperature(0.3) // 只覆盖温度
.build()
)
.user("分析贵州茅台的投资价值")
.call()
.content();
}
}
配置文件也变简洁了:
yaml
# Spring AI 2.0 配置(注意:没有 .options 前缀)
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
model: gpt-4o
temperature: 0.7
max-tokens: 4096
# MCP Server 配置
mcp:
server:
name: my-agent-server
version: 1.0.0

对比 1.x 的配置:
yaml
# Spring AI 1.x 配置(已废弃)
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options: # ← 多余的 .options 层级
model: gpt-4o
temperature: 0.7
八、完整实战项目搭建
8.1 项目初始化
通过 start.spring.io 创建项目,选择:
- Spring Boot: 4.0+
- Dependencies: Spring AI (OpenAI), Spring Web
- Java: 21+
8.2 Maven 依赖
xml
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI OpenAI (包含核心 + MCP) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<!-- Spring AI MCP Annotations -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-annotations</artifactId>
</dependency>
<!-- 可观测性 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
</dependencies>
8.3 项目结构
src/main/java/com/example/agent/
├── AgentApplication.java # 主启动类
├── config/
│ ├── ChatClientConfig.java # ChatClient 配置
│ └── McpServerConfig.java # MCP Server 配置
├── tools/
│ ├── StockQueryService.java # 股票查询工具
│ ├── MacroDataService.java # 宏观数据工具
│ └── NewsSearchService.java # 新闻搜索工具
├── mcp/
│ └── McpFinancialService.java # MCP 对外暴露服务
├── controller/
│ └── AgentController.java # REST API
└── model/
├── StockQuote.java
├── StockAnalysisReport.java
└── MacroData.java
8.4 自定义 Advisor 示例
java
import org.springframework.ai.chat.client.advisor.api.*;
import reactor.core.publisher.Flux;
/**
* 自定义 Advisor:审计日志 + Token 用量统计
* 演示如何在 Advisor 链中插入自定义逻辑
*/
public class AuditAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
private final AuditRepository auditRepository;
public AuditAdvisor(AuditRepository auditRepository) {
this.auditRepository = auditRepository;
}
@Override
public String getName() {
return "AuditAdvisor";
}
@Override
public int getOrder() {
// 在 ToolCallingAdvisor 之前执行(默认 0)
return -10;
}
@Override
public AdvisedResponse aroundCall(AdvisedRequest request,
CallAroundAdvisorChain chain) {
// 请求前:记录输入
long startTime = System.currentTimeMillis();
auditRepository.logRequest(
request.userText(),
request.systemText(),
request.tools().size()
);
// 执行下游链(包括 ToolCallingAdvisor、模型调用等)
AdvisedResponse response = chain.nextAroundCall(request);
// 请求后:记录输出和耗时
long duration = System.currentTimeMillis() - startTime;
auditRepository.logResponse(
response.response().getResult().getOutput().getText(),
duration,
response.response().getMetadata().getUsage()
);
return response;
}
@Override
public Flux<AdvisedResponse> aroundStream(AdvisedRequest request,
StreamAroundAdvisorChain chain) {
// 流式请求的审计处理
return chain.nextAroundStream(request);
}
}
注册自定义 Advisor:
java
@Bean
public ChatClient auditedChatClient(ChatClient.Builder builder,
AuditRepository auditRepo) {
return builder
.defaultAdvisors(new AuditAdvisor(auditRepo)) // 自定义 Advisor
// ToolCallingAdvisor 和 StructuredOutputValidationAdvisor
// 会自动注册,无需手动添加
.build();
}
九、与社区扩展的协同
Spring AI 2.0 的架构为社区扩展提供了坚实基础:
9.1 spring-ai-session(事件溯源会话记忆)
替代内置 ChatMemory 的事件溯源方案,支持:
- 所有消息类型(包括工具调用,在工具循环中安全使用)
- 可插拔的上下文压缩策略(含 LLM 摘要)
9.2 spring-ai-agent-utils(Agent 工具集)
基于 2.0 Advisor 架构的生产级 Agent 原语:
- Agent Skills(AgentSkills 规范的 Spring AI 原生实现)
- 文件、Shell、Web Fetch、Task、Auto-Memory 等工具
java
/**
* 集成社区扩展的完整配置示例
*/
@Configuration
public class FullStackAgentConfig {
@Bean
public ChatClient fullStackClient(
ChatClient.Builder builder,
SessionManager sessionManager) {
return builder
.defaultAdvisors(
// 事件溯源会话记忆
new SessionMemoryAdvisor(sessionManager),
// Agent Skills 支持
new AgentSkillsAdvisor()
)
.build();
}
}
十、迁移指南:从 1.x 到 2.0
10.1 必做项
- 升级 Spring Boot 到 4.0+
- 移除配置中的
.options前缀 - 检查 Options 创建方式:构造函数 → Builder
- 处理 Null 安全注解:JSpecify 可能暴露之前隐藏的 NPE 风险
10.2 推荐项
- 将自定义工具循环迁移到 Advisor 模式
- 评估 MCP 传输方式(Streamable HTTP vs 无状态模式)
- 启用 StructuredOutputValidationAdvisor 提升输出质量
- 考虑 ToolSearch 优化大规模工具场景的 Token 消耗
10.3 破坏性变更清单
| 变更 | 影响 | 迁移方式 |
|---|---|---|
| Options 不可变 | 无法运行时修改 | 用 Builder 创建新实例 |
| 模型变体合并 | 某些 Azure/HTTP 专用类移除 | 统一使用 SDK 实现 |
| SSE 传输废弃 | MCP SSE 客户端不再工作 | 切换到 Streamable HTTP |
| Jackson 3 | 部分自定义序列化器不兼容 | 参考 Jackson 3 迁移指南 |
十一、总结与展望
Spring AI 2.0 GA 标志着 Java AI Agent 开发进入新阶段:
- Advisor 链让 Agent 行为完全可编程、可观测、可审计
- MCP 2.0 让 Java 应用无缝融入全球 AI Agent 生态
- ToolSearch 解决了大规模工具场景的 Token 效率问题
- Null 安全 + 不可变 Options 提升了代码质量和开发体验
对于 Java 开发者来说,现在是将 AI Agent 能力融入企业应用的最佳时机。Spring AI 2.0 提供了从原型到生产的完整路径,而且它运行在你已经熟悉的 Spring Boot 生态之上。

上图展示了从 1.x 迁移到 2.0 的分阶段路径。每个阶段独立推进,按自己的节奏采用即可。
版权声明:本文内容为原创,基于 Spring 官方博客及 GitHub 公开资料独立撰写。文中示例代码可自由使用于学习和个人项目。转载或引用请注明出处。
参考来源:
- Spring AI 2.0.0 GA Release Notes - 核心架构变化与特性说明
- Spring AI Reference Documentation - 官方文档
- MCP Java SDK 2.0.0 - MCP 协议实现
- Spring Modulith 2.1 GA - 模块化架构
- MCP Specification 2025-11-25 - 协议规范