一个 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 由 heepengpeng2024 年 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 的"大脑":

  1. 没有任务规划能力:Agent 收到一个复杂任务后,无法先分解成子任务再逐步执行。当前的循环是"被动反应式"的——LLM 决定调用什么工具,而不是 Agent 主动规划执行路径。

  2. 没有多 Agent 编排callAdvisorChain.copy(this) 只实现了当前 Advisor 的递归调用。没有"Agent A 调用 Agent B"的机制。你需要自己拼。

  3. 没有会话状态持久化:循环中的 instructions(消息列表)存在于方法栈中。方法返回就没了。如果 Agent 执行到一半需要暂停、恢复、回滚,你做不到。

  4. 没有控制流抽象:条件分支(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,它的任务是:

  1. 接收一段代码
  2. 分析代码是否有 bug
  3. 如果有 bug,用工具检查相关的测试文件
  4. 生成审查报告

用 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 的潜在差异化:

  1. Spring 生态集成:依赖注入、事务管理、安全框架、批处理——企业级能力的天然整合
  2. 可观测性:Micrometer 集成,Agent 执行全链路可追踪。这在 Python 生态是痛点
  3. 类型安全:Java 强类型 + Structured Output + @Tool 注解,比 Python 的 dict 调试体验好一个量级
  4. 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 + Redisspring-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 团队需要在以下问题上尽快给出答案:

  1. Agent 抽象的设计理念——是提供预置 Agent 类型(ReAct、Plan-and-Execute),还是只提供底层框架让用户自己拼?
  2. 控制流引擎——线性 Advisor 管道够不够?还是需要引入图编排能力(类似 LangGraph 的 StateGraph)?
  3. Session 与 Agent 的关系——Session 是 Agent 的内部状态容器,还是独立的横切关注点?
  4. 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 可能完全不同。