一个 2024 年 3 月就提出的 Agent 支持请求,两年后才进入正式路标。在 AI 领域,两年约等于一个纪元。
背景:Spring AI 的速度与节奏
2026 年 6 月 12 日,Spring AI 2.0.0 正式 GA。这是一个标志性节点——Spring 生态完成了 AI 工程化的基础设施铺设:ChatClient API、Tool Calling、MCP 协议支持、Vector Store 抽象、Advisors 管道、Structured Output……该有的积木块都有了。
但如果你一直在关注 AI 应用开发,你会发现一个明显的缺口:Agent。
LangChain 2023 年就推出了 Agents 模块。LangGraph 把有状态的多步 Agent 编排做成了核心卖点。AutoGen、CrewAI、OpenAI Swarm、Dify、Coze……Agent 框架百花齐放。Python 生态已经把 Agent 从概念跑到了生产落地。
而 Spring AI 呢?在这方面的动作可以用两个字概括:沉默。
看看这些时间节点:
- 2023 年 10 月:社区开发者提交
#607,带来了基于 Spring AI 的 Agent 框架(spring-ai-collab),官方没有采纳 - 2024 年 3 月:
#403提出Agent 支持,原文是"Implement Agent like in Langchain with different methods, such as CoT, ReACT"——两年零三个月后才进入 2.1.x milestone - 2025 年 8 月:
#4017再次追问"Spring AI 是否有 Agent 计划?ReAct、plan-exec-replan、reflection 这些在 Python 生态已经成熟",官方回应:在考虑中 - 2025 年 10 月:PR
#4622引入 ToolCallAdvisor 和 StructuredOutputValidationAdvisor——这是 Agent 雏形,但还远不是 Agent 框架 - 2026 年 6 月:2.0.0 GA,Agent 支持被正式放入 2.1.x 路标
两年。 在 AI 领域,两年意味着什么?GPT-3.5 → GPT-4 → GPT-4o → o1 → o3 → GPT-4.1,整整三代模型迭代。Claude 从 1 到 3.7 Sonnet。开源阵营从 LLaMA 1 跑到了 DeepSeek R1。整个 Agent 概念从 ReAct 论文(2022年)演进到了 AI Employee、Devin、Computer Use。
节奏分析:优先级选择的代价
从时间线可以看出,Spring AI 在 1.0 → 2.0 周期选择了优先铺基础设施——ChatClient 重构、MCP 支持、Vector Store 扩展、Advisors 管道。Agent 能力被推迟到 2.1.x。从工程角度,这个优先级排序有其合理性:基础设施不稳,上层 Agent 能力就是空中楼阁。
但代价是客观存在的。2024-2025 年间,大量 Java 团队因为 Spring AI 缺少 Agent 能力,不得不自研框架。基于 Spring AI 封装的、基于 LangChain4j 的、纯手写的,方案各异,重复成本显著。实际项目中,自研 Agent 层的投入少则一两个人月,多则半年——都在解决同一个问题:官方没给的,自己补。
2.1.x 路标终于把 Agent 放进来了。接下来的问题是:它值不值得等?
2.1.x 路标中的关键 Issue
翻看 Spring AI GitHub 仓库的 2.1.x Milestone(milestone #43),目前有 8 个 Issue。逐个分析:
1. Agent 支持(#403)——迟到的承诺
这个 Issue 由 heepengpeng 在 2024 年 3 月 6 日 提交,标题简单直接:“Agent support”:
Implement Agent like in Langchain with different methods, such as CoT, ReACT
标签是 enhancement + agents。被放入 2.1.x milestone——但没有 assignee,没有 due date,没有具体设计方案。
这意味着什么?官方认可了"Agent 是必须做的",但还没开始做。这更像是一个意向声明,而不是一个执行计划。
对比一下:#4017(2025年8月)中社区追问 Agent 计划时,Mark Pollack 和 Ilayaperumal G(Spring AI 核心团队)都没有正面回应具体方案。#607(2023年10月)有人直接贡献了一个 Agent 框架(spring-ai-collab),官方也没有采纳。
这暴露了一个问题:Spring AI 团队对 Agent 的方向长期模糊。 不是不知道要做,而是在"怎么做"上缺乏决断。是该像 LangChain 一样提供预置的 Agent 类型(ReAct Agent、Plan-and-Execute Agent),还是只提供底层抽象让用户自己拼?是该集成 LangGraph 式的图编排,还是走 Spring 自己的路?
2.1.x 路标把 Issue 放进来了,但答案还没有。
2. Session 一等公民(#5458)——Agent 的地基
Establish sessions as a First-Class Citizen in Spring AI. Draw inspiration and best practices from related memory architectures like MemGPT, Mem0, OpenClaw, and Crew AI.
这个 Issue 的含金量很高。Spring AI 要引入 spring-ai-session 模块,把会话管理从 ChatClient 的辅助功能提升为独立的一等公民。
为什么 Session 是 Agent 的前置依赖? 这里需要深入理解 Agent 的运行机制。
Agent 的核心是多步推理 + 工具调用循环(ReAct 模式:Thought → Action → Observation → Thought → …)。每一步都需要:
- 上下文累积:Agent 的思考链、工具调用记录、中间结果,都需要在会话中保留
- 状态持久化:Agent 执行到一半可能被中断(超时、异常、人工审批),需要能恢复
- 记忆分层:短期记忆(当前任务上下文)+ 长期记忆(跨会话的用户偏好、历史决策)
Spring AI 现有的 ChatMemory 只是最基础的对话消息列表。MessageWindowChatMemory 2.0 刚加了 turn-boundary snapping(按对话轮次截断),但这远远不够。
真正的 Agent 需要的是结构化的会话生命周期管理:Session → Turn → Step,每层都有自己的元数据和状态。MemGPT 用虚拟内存管理的思路(core memory / archival memory / recall memory),OpenClaw 用文件系统(MEMORY.md + memory/*.md + session transcripts)。Spring AI 会走哪条路?Issue 里提到了"draw inspiration",但具体方案还是空白。
不过,方向是对的。 先有 Session 再有 Agent,比先有 Agent 再补 Session 要合理得多。Spring AI 选择在 2.1.x 同步推进这两个模块,说明团队理解了它们的依赖关系。
3. OpenAI Responses API 支持(#2962)
OpenAI positions the Responses API as a more “agentic” primitive that natively supports tool usage (web search, file search, computer use, etc.), built-in state handling (previous_response_id).
OpenAI 的 Responses API 是面向 Agent 设计的原语——内置状态管理(previous_response_id 串接上下文)、原生工具调用(web search、file search、computer use)。Spring AI 对它的支持不只是加一个 API 适配,而是要考虑如何把 Responses API 的有状态特性与自己的 ChatMemory/Session 模型对齐。
4. 其他增强
@Tool自动发现(#6306,已关闭/完成):Spring 自动扫描@Tool注解的@Component,不再需要手动注册。典型的 Spring 风格——约定优于配置。2.0 周期已完成。- 流式 Tool Call 参数增量(#5910):大参数工具调用(如代码生成)在流式模式下需要实时推送增量片段。
- 废弃 API 清理(#6347):清除 2.0 开发期标记的 8 类
@Deprecated(forRemoval=true)API——JsonParser、TokenTextSplitter 旧构造器、MCP SSE 传输层等。
5. Backlog 中的 Agent 相关
- A2A 协议支持(#2911):Google 推出的 Agent-to-Agent 通信协议。如果 Spring AI 要支持 multi-agent,A2A 是一个标准化的通信层选择。
- OpenAPI Spec 工具调用(#806):直接通过 OpenAPI 规范定义工具,不需要手写
@Tool方法。这对企业集成非常有价值——现有的 REST API 可以直接变成 Agent 的工具。
代码级深度:从 Advisors 看出 Agent 雏形
说 Spring AI 现在完全没有 Agent 能力是不公平的。2.0 引入的两个关键 Advisor 实际上已经实现了 Agent 的核心循环——只是封装得还不够好。
ToolCallingAdvisor:ReAct 循环的代码真相
直接看源码(spring-ai-client-chat 模块)。ToolCallingAdvisor.adviseCall() 的核心逻辑:
do {
// 1. 构建请求
var processedChatClientRequest = ChatClientRequest.builder()
.prompt(new Prompt(instructions, toolCallingChatOptions))
.context(chatClientRequest.context())
.build();
// 2. 调用 LLM
chatClientResponse = callAdvisorChain.copy(this).nextCall(processedChatClientRequest);
// 3. 检查是否有工具调用
isToolCall = this.toolExecutionEligibilityChecker.isToolCallResponse(chatResponse);
if (isToolCall) {
// 4. 执行工具
ToolExecutionResult toolExecutionResult =
this.toolCallingManager.executeToolCalls(prompt, chatResponse);
// 5. 如果工具标记了 returnDirect,直接返回结果
if (toolExecutionResult.returnDirect()) {
break;
}
// 6. 把工具执行结果加入上下文,继续循环
instructions = this.doGetNextInstructionsForToolCall(
chatClientRequest, chatClientResponse, toolExecutionResult);
}
} while (isToolCall); // 循环直到没有工具调用
这就是 ReAct 模式的实现。 翻译成 Agent 语言:
- Thought → LLM 生成回复(含工具调用请求)
- Action →
toolCallingManager.executeToolCalls()执行工具 - Observation → 工具结果被加入 instructions
- 循环 → 直到 LLM 认为不需要再调用工具
它甚至支持 returnDirect——工具可以直接返回结果给用户,绕过 LLM。这是 “Tool-as-Service” 模式的雏形。
但缺什么? 缺的是 Agent 的"大脑":
没有任务规划能力:Agent 收到一个复杂任务后,无法先分解成子任务再逐步执行。当前的循环是"被动反应式"的——LLM 决定调用什么工具,而不是 Agent 主动规划执行路径。
没有多 Agent 编排:
callAdvisorChain.copy(this)只实现了当前 Advisor 的递归调用。没有"Agent A 调用 Agent B"的机制。你需要自己拼。没有会话状态持久化:循环中的
instructions(消息列表)存在于方法栈中。方法返回就没了。如果 Agent 执行到一半需要暂停、恢复、回滚,你做不到。没有控制流抽象:条件分支(if-else)、循环(repeat-until)、并行执行(fan-out/fan-in)、人工审批(human-in-the-loop)——这些 LangGraph 已经做得很成熟的控制流,在 Spring AI 中完全没有。
StructuredOutputValidationAdvisor:Self-Refine 的实现
do {
// 1. 调用 LLM
chatClientResponse = callAdvisorChain.copy(this).nextCall(processedChatClientRequest);
// 2. 校验输出
SchemaValidation validationResponse = validateOutputSchema(chatClientResponse);
isValidationSuccess = validationResponse.success();
if (!isValidationSuccess) {
// 3. 把校验错误信息追加到 Prompt,让 LLM 自我修正
String validationErrorMessage = "Output JSON validation failed because of: "
+ validationResponse.errorMessage();
Prompt augmentedPrompt = chatClientRequest.prompt()
.augmentUserMessage(userMessage -> userMessage.mutate()
.text(userMessage.getText() + System.lineSeparator() + validationErrorMessage)
.build());
// 4. 用增强后的 Prompt 重新调用
processedChatClientRequest = chatClientRequest.mutate().prompt(augmentedPrompt).build();
}
} while (!isValidationSuccess && repeatCounter <= this.maxRepeatAttempts);
这就是 Self-Refine / Self-Correction 模式——LLM 生成 → 校验 → 如果不通过,把错误信息反馈给 LLM → 重新生成。默认最多重试 3 次。
这个模式的潜力被严重低估了。它不仅用于结构化输出校验,本质上是一种反馈驱动的迭代优化框架。如果有 Agent 能在这个基础上扩展——比如用业务规则替代 JSON Schema 校验、用另一个 LLM 做 reviewer——就是 Reflection 模式了。
Advisor 的根本局限
两个 Advisor 暴露了 Advisor 架构的根本局限:它是线性管道,不是图。
Advisors 是责任链——A → B → C → LLM → C → B → A。每个 Advisor 可以递归调用自己(通过 chain.copy(this).nextCall()),但你无法表达:
- 并行执行两个 Advisor 分支然后合并结果
- 基于中间结果动态决定走哪个分支
- 在某个节点暂停,等待外部信号后继续
而这些恰恰是复杂 Agent 工作流的核心需求。LangGraph 的解决方案是把 Agent 建模为 StateGraph——节点是函数,边是条件路由。Spring AI 如果要在 2.1.x 真正支持 Agent,绕不开这个架构选择。
实战对比:用现有 Spring AI 2.0 拼 Agent 有多麻烦?
说了这么多架构层面的问题,来看一个具体的例子。假设我们要构建一个代码审查 Agent,它的任务是:
- 接收一段代码
- 分析代码是否有 bug
- 如果有 bug,用工具检查相关的测试文件
- 生成审查报告
用 LangChain(Python)实现
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.tools import tool
@tool
def read_test_file(file_path: str) -> str:
"""读取测试文件内容"""
with open(file_path) as f:
return f.read()
@tool
def generate_report(code: str, issues: str, tests: str) -> str:
"""生成审查报告"""
return f"审查报告:\n问题: {issues}\n测试覆盖: {tests}"
agent = create_tool_calling_agent(llm, tools=[read_test_file, generate_report])
executor = AgentExecutor(agent=agent, tools=[read_test_file, generate_report])
result = executor.invoke({"input": "审查这段代码: ..."})
10 行代码。核心是 create_tool_calling_agent ——一个标准的 ReAct Agent,自动处理 Thought → Action → Observation 循环。
用 Spring AI 2.0 实现
@Service
public class CodeReviewAgent {
private final ChatClient chatClient;
public CodeReviewAgent(ChatClient.Builder builder) {
this.chatClient = builder
.defaultAdvisors(
ToolCallingAdvisor.builder()
.toolCallingManager(toolCallingManager)
.build(),
// 需要自己管理对话历史
MessageChatMemoryAdvisor.builder(chatMemory).build()
)
.build();
}
@Tool(description = "读取测试文件内容")
String readTestFile(@ToolParam(description = "文件路径") String filePath) {
try {
return Files.readString(Path.of(filePath));
} catch (IOException e) {
return "读取失败: " + e.getMessage();
}
}
@Tool(description = "生成审查报告")
String generateReport(@ToolParam(description = "代码") String code,
@ToolParam(description = "问题列表") String issues,
@ToolParam(description = "测试情况") String tests) {
return "审查报告:\n问题: " + issues + "\n测试覆盖: " + tests;
}
public String review(String code) {
return chatClient.prompt()
.user("审查这段代码: " + code +
"。如果有问题,请调用 readTestFile 查看测试文件," +
"然后用 generateReport 生成报告。")
.tools(this)
.call()
.content();
}
}
看起来也不复杂?但魔鬼在细节里。
问题一:任务分解需要 Prompt 硬编码。LangChain 的 Agent 内置了 ReAct 推理框架,LLM 自动决定"先分析 → 再调用工具 → 最后生成报告"。Spring AI 中,你需要把推理步骤写在 Prompt 里(“如果有问题,请调用 readTestFile…然后…"),依赖 LLM 的指令遵循能力。这不是 Agent,这是带工具的 Chat。
问题二:没有状态管理。如果 review 过程中 Agent 执行了三步工具调用,然后你想在同一会话中追加一个问题"再看一下异常处理”,你需要确保 ChatMemory 正确保留了前三步的上下文。现有 ChatMemory 只保存对话消息,不保存 Agent 的思考链和工具调用中间状态。Session 抽象的缺失在这里是致命的。
问题三:无法做条件控制流。“如果有 bug 且测试覆盖率低于 50%,则额外调用 coverage_analysis 工具”——这种条件分支在当前架构下只能靠 Prompt 描述,无法保证执行。
问题四:不可恢复。Agent 执行到第 3 步时超时了?抱歉,从头来过。没有检查点(checkpoint),没有状态快照。
如果 2.1.x 的 Agent 框架到位
理想情况下,2.1.x 应该提供类似这样的 API(推测):
// 假想的 2.1.x Agent API
Agent codeReviewAgent = Agent.builder()
.name("代码审查 Agent")
.chatClient(chatClient)
.tools(codeReviewTools)
.strategy(AgentStrategy.REACT) // 或 PLAN_AND_EXECUTE, REFLECTION
.session(sessionManager) // spring-ai-session 一等公民
.maxIterations(10)
.build();
// 有状态的 Agent 执行
Session session = sessionManager.createSession();
String result = codeReviewAgent.execute("审查这段代码: ...", session);
// 同一会话追加请求
String followUp = codeReviewAgent.execute("再看一下异常处理", session);
// 支持中断和恢复
session.saveCheckpoint();
// ... 做其他事情
codeReviewAgent.resume(session);
这才是 Agent 框架该有的样子。 但目前这只是猜测——2.1.x 还没有发布任何设计文档或 RFC。
与竞品的对比:Spring AI 的差异化在哪?
vs LangChain / LangGraph
LangGraph 的核心优势是图结构编排。你可以定义节点(函数)、边(条件路由),精确控制 Agent 的执行流程。它的 StateGraph 支持并行分支、人工中断、状态回滚——这些在生产环境中非常重要。
Spring AI 的潜在差异化:
- Spring 生态集成:依赖注入、事务管理、安全框架、批处理——企业级能力的天然整合
- 可观测性:Micrometer 集成,Agent 执行全链路可追踪。这在 Python 生态是痛点
- 类型安全:Java 强类型 + Structured Output +
@Tool注解,比 Python 的 dict 调试体验好一个量级 - MCP 一等支持:Boot Starter 级别的 MCP 集成,工具发现和调用标准化
但差异化不等于优势。如果 Agent 框架的设计不够好,这些差异化点也救不了。
vs LangChain4j
LangChain4j 是 Java 生态的另一个选手,在 Agent 方面走得更激进——已经有了 AiServices、动态工具、RAG 增强、结构化输出。但它的 Spring 集成相对浅,更像是 Java 移植版的 LangChain,而不是原生 Spring 框架。
Spring AI 的优势在于"原生"——Spring Boot Auto Configuration、Starter 依赖、与 Spring Cloud / Spring Security 的无缝集成。企业如果已经在 Spring 生态中,Spring AI 是更自然的选择。
vs 自研框架
很多团队(包括我们自己)在 2025 年就已经基于 Spring AI 自研 Agent 框架。原因很简单——等不起。自研框架通常包含:
- Agent 运行时(任务调度、循环控制)
- 记忆管理(短期/长期、会话持久化)
- 工具注册中心(MCP + 自定义工具)
- 编排引擎(简单的状态机或流程引擎)
Spring AI 2.1.x 官方 Agent 出来后,自研框架的选择:
- 底层运行时 → 切换到 Spring AI 标准 Agent,避免重复造轮子
- 业务编排层 → 保留自研,这是业务差异化
- 记忆/Session → 迁移到
spring-ai-session,但保留业务层面的记忆策略
对实践的冲击:企业级 AI 应用的下一个阶段
1. AI 原生应用平台将直接受益
对于构建 AI 原生应用平台的团队,Spring AI 2.1.x 的 Agent + Session 组合解决了两个 P0 级痛点:
- 记忆服务:之前需要自建,现在有了官方参考架构(MemGPT/Mem0 模式的 Spring 实现)
- 会话服务:之前只有 ChatMemory 这种简单实现,Session 一等公民带来结构化的会话生命周期管理
2. MCP + Agent = 企业工具链整合
MCP 协议让 Agent 的工具发现和调用变得标准化。Spring AI 已有 MCP Boot Starter 支持(STDIO、SSE、Streamable-HTTP 传输)。加上 Agent 框架,企业可以快速构建"AI 员工"——能查系统、能发邮件、能操作业务流程。
#806(OpenAPI Spec → Tool)如果也落地,现有 REST API 可以零代码变成 Agent 工具。这在企业集成场景中的价值巨大——数百个内部微服务直接成为 Agent 的"手脚"。
3. 可观测性闭环
Spring AI 的 Observability + Agent 多步执行 = 全链路可追踪:
- 每一步推理的 thought 可追溯
- 每一次工具调用的输入/输出可审计
- Agent 执行全链路的性能可分析
- 异常和幻觉可在早期被发现
这是 Python 生态至今没有解决好的问题。Spring AI 如果在这里做出深度,将是真正的企业级差异化。
什么时候能用?
目前 2.1.x 没有设定 due date,2.0.0 刚在 6 月 12 日 GA。
参考 Spring 项目的发版节奏:
- Spring AI 1.0.0 GA:2025 年 5 月
- Spring AI 1.1.0 GA:约 4 个月后
- Spring AI 2.0.0 GA:约 7 个月后(2026 年 6 月)
- Spring AI 2.1.0 GA:乐观估计 2026 年 Q4 到 2027 年 Q1
但也不必干等。关注以下信号:
spring-ai-session模块的提交活动(GitHub main 分支)#403的 assignee 分配和设计讨论- Spring One 大会(2026 年 8 月)上可能的官方公布
- 2.0.x 维护版本中可能提前引入的 Agent 相关基础设施
面向未来的架构建议:如何设计能平滑迁移到 2.1.x 的 Agent
说"不要等"很容易,但真正的问题是:现在基于 Spring AI 2.0 自研 Agent,怎么设计才能在 2.1.x 到来时不推倒重来?
以下是基于 Spring AI 2.0 实际 API 和 2.1.x 已知路标,给出的架构建议。核心原则只有一条:隔离变化面。
架构总览:三层分离
┌─────────────────────────────────────────────┐
│ 业务 Agent 层 (你的) │
│ 代码审查Agent / 数据分析Agent / 客服Agent │
├─────────────────────────────────────────────┤
│ Agent 抽象层 (你的,薄) │
│ Agent接口 / 任务规划 / 编排引擎 / 检查点 │
├─────────────────────────────────────────────┤
│ Spring AI 基础设施层 (官方的) │
│ ChatClient / Advisors / Tools / MCP / Memory │
└─────────────────────────────────────────────┘
第三层是 Spring AI 的,会随版本演进。第一层是你的业务逻辑,变化频率低。关键是第二层——Agent 抽象层——它要足够薄,既能屏蔽底层 API 变化,又能在 2.1.x 到来时被官方 API 替换。
具体设计:5 个关键决策
决策 1:不要直接暴露 ChatClient,用 Agent 接口封装
错误做法(直接耦合):
// ❌ 业务代码直接调 ChatClient
@Service
public class CodeReviewService {
private final ChatClient chatClient; // 直接注入
public String review(String code) {
return chatClient.prompt()
.user("审查代码: " + code)
.tools(toolCallbacks)
.advisors(toolCallingAdvisor, memoryAdvisor)
.call()
.content();
}
}
问题:如果 2.1.x 的 Agent API 改变了调用方式(几乎一定会),所有业务代码都要改。
正确做法(接口隔离):
// ✅ 定义自己的 Agent 抽象
public interface Agent {
AgentResult execute(AgentTask task, AgentContext context);
}
// 具体实现内部用 Spring AI 2.0
public class SpringAIReActAgent implements Agent {
private final ChatClient chatClient;
private final List<ToolCallback> tools;
@Override
public AgentResult execute(AgentTask task, AgentContext context) {
// 内部使用 ToolCallingAdvisor 实现 ReAct 循环
String result = chatClient.prompt()
.system(task.systemPrompt())
.user(task.userPrompt())
.tools(tools)
.advisors(new ToolCallingAdvisor(...))
.call()
.content();
return new AgentResult(result, context.sessionId());
}
}
迁移成本:2.1.x 出了官方 Agent 后,只需要把 SpringAIReActAgent 的实现替换为官方 API,业务层的 Agent 接口不变。
决策 2:Session 设计要预留持久化扩展点
2.1.x 的 spring-ai-session(#5458)一定会引入 Session 生命周期管理。现在自研时就要预留:
// 自研 Session 接口——对齐 #5458 的方向
public interface AgentSession {
String sessionId();
void save(); // 持久化
void restore(String sessionId); // 恢复
List<Message> getHistory(); // 对话历史
Map<String, Object> getMetadata(); // Agent 中间状态
void addMetadata(String key, Object value); // 检查点
}
关键点:把 getMetadata() 设计成通用的 key-value 结构。这样 2.1.x 的 Session 如果提供了更丰富的 API(比如分层记忆、摘要压缩),你可以在 AgentSession 的实现层适配,业务代码不受影响。
Redis 持久化示例:
public class RedisAgentSession implements AgentSession {
private final StringRedisTemplate redis;
private static final String KEY_PREFIX = "agent:session:";
@Override
public void save() {
// 序列化整个 Session 状态
SessionState state = new SessionState(sessionId, history, metadata);
redis.opsForValue().set(KEY_PREFIX + sessionId,
JSON.toJSONString(state), Duration.ofHours(2));
}
@Override
public void restore(String sessionId) {
String json = redis.opsForValue().get(KEY_PREFIX + sessionId);
if (json != null) {
SessionState state = JSON.parseObject(json, SessionState.class);
this.history = state.getHistory();
this.metadata = state.getMetadata();
}
}
}
2.1.x 的 spring-ai-session 如果提供了 Redis 后端,直接把 RedisAgentSession 替换为官方实现。如果官方只提供接口,你的实现层加上官方逻辑。
决策 3:工具注册走 MCP,不要只绑死在 @Tool 注解上
Spring AI 2.0 同时支持 @Tool 注解和 MCP 协议工具。强烈建议企业级 Agent 走 MCP 路线。
原因:
- MCP 是跨框架标准协议,Agent 框架怎么变,工具定义不变
- Spring AI 的 MCP Boot Starter 已经很成熟(STDIO/SSE/Streamable-HTTP 全覆盖)
#806(OpenAPI Spec → Tool)一旦落地,REST API 可以零代码变成工具- 工具可以独立部署、独立扩展、独立监控
// ✅ 工具走 MCP Server 独立部署
@mcpServer // Spring AI MCP 注解
@Component
public class CodeTools {
@McpTool(description = "读取文件内容")
String readFile(@McpToolParam(description = "路径") String path) {
return Files.readString(Path.of(path));
}
@McpTool(description = "执行测试")
TestResult runTests(@McpToolParam(description = "模块") String module) {
return testRunner.run(module);
}
}
// Agent 侧通过 MCP Client 动态发现工具
@Bean
public ChatClient chatClient(McpClient mcpClient) {
return ChatClient.builder(chatModel)
.defaultTools(mcpClient.getToolCallbacks()) // 动态发现
.build();
}
2.1.x Agent 出来后,工具侧零迁移——MCP 协议不变,只是 Agent 调用工具的路径变了。
决策 4:编排逻辑用状态机,不要硬编码在 Prompt 里
Spring AI 2.0 的 Advisor 是线性管道,复杂编排只能靠 Prompt 硬编码。但你可以自己在业务层加一个轻量状态机:
public class AgentStateMachine {
// 定义状态
enum AgentState {
ANALYZING, // 分析任务
SEARCHING, // 搜索相关文件
REVIEWING, // 审查代码
REPORTING, // 生成报告
DONE
}
// 定义转移(条件路由)
private final Map<AgentState, List<Transition>> transitions;
public AgentState next(AgentState current, Map<String, Object> context) {
return transitions.get(current).stream()
.filter(t -> t.condition().test(context))
.findFirst()
.map(Transition::target)
.orElse(AgentState.DONE);
}
}
// 每个状态对应一个 Agent 调用
public String execute(String task) {
AgentState state = AgentState.ANALYZING;
Map<String, Object> context = new HashMap<>();
while (state != AgentState.DONE) {
AgentTask stepTask = buildTaskForState(state, task, context);
AgentResult result = agent.execute(stepTask, session);
context.putAll(result.metadata());
state = stateMachine.next(state, context);
session.addMetadata("lastState", state); // 检查点
session.save(); // 每步持久化
}
return (String) context.get("report");
}
迁移策略:如果 2.1.x 提供了图编排能力(类似 LangGraph),把 AgentStateMachine 替换为官方编排引擎。如果没提供(比如只提供了预置的 ReAct Agent),你的状态机继续用——它不依赖 Spring AI 任何 API。
决策 5:Observability 从第一天就接入
Spring AI 2.0 内置了 Micrometer 观测能力。自研 Agent 时要把观测面扩展到 Agent 层:
@Observed(name = "agent.execute",
contextualName = "agent-step")
public AgentResult execute(AgentTask task, AgentContext context) {
// Spring AI 的 ChatClient 调用已经自动被观测
// 这里补充 Agent 层的元数据
Observation.addTag("agent.name", task.agentName());
Observation.addTag("agent.state", context.currentState());
Observation.addTag("agent.iteration", context.iteration());
AgentResult result = doExecute(task, context);
// 记录工具调用结果摘要
Observation.addTag("agent.toolsUsed",
String.join(",", result.toolsUsed()));
return result;
}
这样在 Grafana / Prometheus 中可以看到:每个 Agent 的执行步数、耗时、工具调用频率、失败率——全链路可观测。
2.1.x Agent 出来后,如果官方提供了内置的 Observability 支持,你只需要去掉自己的 @Observed 注解。如果没有(Python 生态至今仍是痛点),你自研的观测层就是核心竞争力。
迁移评估清单
当 Spring AI 2.1.x 正式发布 Agent 框架时,用以下清单评估迁移:
| 评估项 | 你的现状 | 2.1.x 官方 | 迁移决策 |
|---|---|---|---|
| Agent 接口 | 自定义 Agent 接口 | 官方 Agent API | 如果官方 API 更完善 → 适配层替换;否则保留 |
| Session 管理 | AgentSession + Redis | spring-ai-session | 如果官方支持 Redis 后端 → 直接换;否则保留 |
| 工具注册 | MCP Server + @Tool | 不变 | ✅ 零迁移 |
| 编排引擎 | 自研状态机 | 官方图编排? | 如果官方提供了 → 替换;否则保留 |
| 观测能力 | Micrometer + 自定义 tag | 官方 Agent Observability? | 合并两者 |
| 业务逻辑 | 各业务 Agent | 不变 | ✅ 零迁移 |
总结:5 个决策点中,工具注册和业务逻辑是零迁移;Agent 接口和 Session 是适配层替换(1-2 人天);编排引擎视官方能力决定保留或替换。 总迁移成本:乐观 1 周,悲观 1 个月。比起推倒重来,这是可接受的。
结语:迟到的承诺,未知的答案
回看整个过程,我的评价是:方向对了,但太慢了,而且细节还是未知数。
把 Agent 放入 2.1.x 路标本身是一个积极信号——至少不再是"在考虑中"了。但 #403 没有 assignee、没有设计方案、没有时间表,它更像是一张空头支票。
Spring AI 团队需要在以下问题上尽快给出答案:
- Agent 抽象的设计理念——是提供预置 Agent 类型(ReAct、Plan-and-Execute),还是只提供底层框架让用户自己拼?
- 控制流引擎——线性 Advisor 管道够不够?还是需要引入图编排能力(类似 LangGraph 的 StateGraph)?
- Session 与 Agent 的关系——Session 是 Agent 的内部状态容器,还是独立的横切关注点?
- Multi-Agent 支持——A2A 协议(#2911)是 Agent 间通信的标准方案吗?
2024 年做 Agent,你需要从零搭一切。2026 年做 Agent,Spring AI 帮你把积木块准备好了——但拼装说明书还没写。
但"等不起"不是借口,“乱搭"也不是答案。 上面的架构建议给出了第三条路:基于 2.0 先跑起来,用三层分离的架构隔离变化面——Agent 接口封装、Session 预留扩展点、工具走 MCP、编排用状态机、观测从第一天接入。2.1.x 到来时,迁移成本可控,业务逻辑不动。
节奏比完美更重要。但有节奏的乱跑,不如有架构的快走。
本文基于 Spring AI GitHub 仓库公开的 2.1.x Milestone 信息和源码分析撰写。截至 2026 年 6 月 25 日,2.1.x 尚无发布日期和设计文档。文中观点仅为作者个人分析,不代表官方立场。代码示例中的 2.1.x API 为基于趋势的推测,实际 API 可能完全不同。