Spring AI 是 Spring 生态面向人工智能应用开发提供的一组统一抽象。对于已经接触过 Spring Boot 的开发者,它最大的价值在于继续沿用 Bean、依赖注入、Controller、Service 等熟悉的开发方式,同时将大模型调用、工具调用、对话记忆、RAG 和调用增强等能力纳入 Spring 应用。

Spring AI 2.0.0 已于 2026 年 6 月正式发布,主要面向 Spring Boot 4.0/4.1 与 Spring Framework 7.0。对于 Agent 开发,2.0 中值得重点理解的一项变化是 Tool Calling 与 Advisor Chain 的进一步结合。工具调用循环可以由 ChatClient 中的 ToolCallingAdvisor 管理,因此工具、记忆、日志和其他增强逻辑能够在统一的调用链中组合

目录

一、Spring AI 2.0 中的 Agent 由哪些组件组成

二、ChatClient:Spring AI 应用的调用入口

三、Advisor:在模型调用过程中加入增强逻辑

四、ChatMemory:让 Agent 具备多轮上下文

五、Tool:让 Agent 能够真正使用程序能力

六、ToolCallingAdvisor:形成最小 Agent Loop

七、组合一个最小可运行 Spring AI Agent

1. 引入 Spring AI

2. 创建库存 Tool

3. 创建 ChatMemory 和 ChatClient

4. 提供接口

八、一次请求内部究竟发生了什么

九、继续丰富 Agent 时还会加入什么


一、Spring AI 2.0 中的 Agent 由哪些组件组成

先观察一个经过简化的 Spring AI Agent 调用过程:

用户请求
   ↓
ChatClient
   ↓
Advisor Chain
   ├── ChatMemory
   ├── 日志 / 安全控制
   ├── RAG
   └── ToolCallingAdvisor
             ↓
          ChatModel
             ↓
            LLM
             ↓
      判断是否调用 Tool
             ↓
          Java Tool
             ↓
      Tool Result 返回模型
             ↓
          最终回答

这里真正需要优先掌握的组件并不多。

组件作用
ChatClientSpring AI 应用中调用模型的主要入口
ChatModel对具体大模型提供统一模型抽象
Prompt表示发送给模型的消息和相关参数
Advisor在 AI 调用过程中进行观察、增强、修改或干预
ChatMemory保存需要继续提供给模型的对话上下文
Tool将 Java 方法开放给模型,使模型能够读取数据或执行操作
ToolCallingAdvisor管理模型请求工具、执行工具、继续调用模型的循环
RAG Advisor在调用模型以前检索外部知识并补充上下文
Structured Output将模型回答转换为 Java 对象

【核心迭代思路】这几个组件可以逐层加入。最初只有 ChatClient + ChatModel 时,程序已经可以完成普通大模型问答。加入 ChatMemory 后,应用能够维持多轮上下文。加入 Tool 后,模型可以使用 Java 程序提供的真实能力。再加入 Advisor,可以进一步完成日志、安全控制、RAG 和调用过程干预。

Spring AI 官方也将 ChatClient 作为高层模型交互 API。Spring Boot 可以自动创建 ChatClient.Builder,开发者随后通过链式 API 构造 Prompt、Advisor 和 Tools。


二、ChatClient:Spring AI 应用的调用入口

ChatClient 是 Spring AI 中非常值得先记住的类。它提供了类似 WebClientRestClient 的链式调用方式,可以组织用户消息、系统消息、工具和 Advisor【入口、组织功能】

最简单的调用只有下面几行:

@RestController
@RequestMapping("/ai")
public class AiController {

    // 注入 ChatClient,它是 Spring AI 中调用模型的统一入口
    private final ChatClient chatClient;

    // 通过构造器注入 ChatClient.Builder,并构建出 ChatClient 实例
    public AiController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    // 处理 GET 请求 /ai/chat,接收用户传入的 message 参数
    @GetMapping("/chat")
    public String chat(@RequestParam String message) {

        // 链式调用:构造 Prompt -> 加入用户消息 -> 发起同步调用 -> 获取模型返回文本
        return chatClient
                .prompt()
                .user(message)
                .call()
                .content();
    }
}

其中:

.prompt()

表示开始构造这一次模型请求。

.user(message)

加入用户消息。

.call()

发起同步模型调用

.content()

直接取得模型生成的文本结果。

因此,Spring AI 最值得先记住的一行代码就是:

chatClient
        .prompt()
        .user(message)
        .call()
        .content();

Spring AI 还可以通过:

.system("你是一个 Java 学习助手")

增加 System Prompt,用于规定模型长期角色和行为。

例如:

String result = chatClient
        .prompt()
        .system("你是一个 Java 学习助手,回答保持简洁。")
        .user("介绍一下 Redis")
        .call()
        .content();

ChatModel 位于更底层,负责提供统一的大模型调用接口。具体使用 DeepSeek、OpenAI、Ollama 等模型时,对应实现最终都进入这一模型抽象。日常 Agent 业务代码通常围绕 ChatClient 组织,因为后续的 Advisor、Memory 和 Tool 都可以继续挂接在这条调用路径上。


三、Advisor:在模型调用过程中加入增强逻辑

Advisor 是理解 Spring AI Agent 很重要的一个概念。可以将 Advisor 理解为 AI 调用过程中的拦截与增强机制它位于业务代码和真正的模型调用之间,可以查看请求、修改 Prompt、增加上下文、记录日志、执行安全检查,也可以处理模型返回结果。Spring AI 官方将 Advisor API 定义为用于 intercept、modify 和 enhance AI interaction 的可组合机制。

它的工作位置可以简化成:

Controller
    ↓
ChatClient
    ↓
Advisor 1
    ↓
Advisor 2
    ↓
Advisor 3
    ↓
ChatModel
    ↓
LLM

多个 Advisor 会组成一条 Advisor Chain每一个 Advisor 只负责自己的任务,然后将请求继续交给下一个 Advisor。执行顺序由 Advisor 的 order 决定。

这使得很多能力可以在不修改核心业务 Controller 的情况下加入

例如,一个原本的调用是:

chatClient
        .prompt()
        .user(message)
        .call()
        .content();

如果需要增加日志,可以加入 Spring AI 已经提供的:

SimpleLoggerAdvisor

代码只需要变成:

chatClient
        .prompt()
        .advisors(new SimpleLoggerAdvisor())
        .user(message)
        .call()
        .content();

业务仍然负责“向模型提出问题”,日志逻辑由 Advisor 单独处理。SimpleLoggerAdvisor 会记录 ChatClient 请求和响应数据,主要用于调试和监控。

Spring AI 已经提供了一些很有代表性的 Advisor:

MessageChatMemoryAdvisor
    → 对话记忆

QuestionAnswerAdvisor
    → 基础 RAG

RetrievalAugmentationAdvisor
    → 更完整的 RAG

SimpleLoggerAdvisor
    → 请求和响应日志

SafeGuardAdvisor
    → 内容安全控制

ToolCallingAdvisor
    → 工具调用循环

这些能力都可以沿着 Advisor Chain 加入 ChatClient。

因此,在 Agent 应用中,Advisor 很适合承担横向能力。例如记忆管理、RAG、日志、内容审核、调用跟踪等逻辑可以独立存在,Agent 主业务代码仍然保持较为简洁


四、ChatMemory:让 Agent 具备多轮上下文

大模型接口本身是无状态的。

ChatMemory 解决的是这一问题。它负责保存当前对话中需要继续提供给模型的消息,使后续请求能够携带之前的上下文。Spring AI 将具体消息存储职责进一步交给 ChatMemoryRepository,Memory 本身负责决定哪些消息应该继续保留

Spring AI 2.0 默认使用的实现是:

MessageWindowChatMemory

它维护一个滑动消息窗口。当消息数量超过限制时,会逐渐移除较早的消息,同时保留 System Message。默认窗口大小为 20 条消息。

也可以自行创建:

ChatMemory chatMemory = MessageWindowChatMemory.builder()
        .maxMessages(20)
        .build();

有了 Memory,还需要一个组件把历史消息真正放入每一次模型请求。这个任务由:

MessageChatMemoryAdvisor

完成。

ChatClient chatClient = ChatClient.builder(chatModel)
        .defaultAdvisors(
                MessageChatMemoryAdvisor
                        .builder(chatMemory)
                        .build()
        )
        .build();

此时调用路径变成:

用户新消息
    ↓
MessageChatMemoryAdvisor
    ↓
根据 conversationId 查找历史消息
    ↓
历史消息 + 当前消息
    ↓
ChatModel
    ↓
LLM
    ↓
新的回答继续写入 Memory

Spring AI 2.0 要求使用 Memory Advisor 时提供 conversationId。这个 ID 用于区分不同用户或者不同会话。缺少 ChatMemory.CONVERSATION_ID 会直接产生运行时异常。

例如:

String conversationId = "session-001";

String result = chatClient
        .prompt()
        .user("我负责键盘库存管理")
        .advisors(advisor -> advisor.param(
                ChatMemory.CONVERSATION_ID,
                conversationId
        ))
        .call()
        .content();

下一次继续使用相同的:

session-001

MessageChatMemoryAdvisor 就能够取得这段会话对应的上下文。

这里还有一个容易混淆的概念:ChatMemory 主要服务于“模型当前需要记住什么”。完整聊天记录通常属于业务数据,应当单独持久化Spring AI 官方也明确区分 Chat Memory 与完整 Chat History


五、Tool:让 Agent 能够真正使用程序能力

有了 Memory,Agent 可以记住上下文,但它目前仍然主要依靠模型自身知识回答问题。

假设用户询问:

keyboard 现在还有多少库存?

模型无法天然知道应用数据库中的实时库存

这时可以给模型一个 Java 方法:

getStock("keyboard")

Spring AI 将这种可以由模型请求执行的方法称为 Tool

一个最简单的 Tool 可以这样写:

@Component
public class InventoryTools {

    // 模拟商品库存数据:keyboard 有 6 件,mouse 有 24 件
    private static final Map<String, Integer> STOCK = Map.of(
            "keyboard", 6,
            "mouse", 24
    );

    // @Tool 注解将该方法暴露给模型,description 用于描述工具用途
    @Tool(description = "查询指定商品当前库存数量")
    public String getStock(
            @ToolParam(description = "商品名称") String product) {

        // 根据商品名称(转小写)查询库存
        Integer stock = STOCK.get(product.toLowerCase());

        // 未找到该商品时返回提示信息
        if (stock == null) {
            return "没有找到该商品";
        }

        // 返回库存查询结果
        return product + " 当前库存为 " + stock + " 件";
    }
}

这里真正关键的是:

@Tool

Spring AI 会根据这个 Java 方法生成对应的 Tool Definition,包括工具名称、描述以及参数结构。模型可以根据用户任务判断是否需要调用它。官方文档建议认真编写 Tool 的描述,因为模型会根据名称、描述和参数 Schema 判断工具用途

随后将 Tool 提供给 ChatClient:

String result = chatClient
        .prompt()
        .user("keyboard 现在还有多少库存?")
        .tools(inventoryTools)  // 将库存工具注册给 ChatClient
        .call()
        .content();

这里已经产生了一项很重要的变化。

普通模型调用是:

用户
 ↓
LLM
 ↓
回答

加入 Tool 后可能形成:

用户
 ↓
LLM
 ↓
判断需要查询库存
 ↓
调用 getStock("keyboard")
 ↓
Java 返回库存 6 件
 ↓
工具结果重新提供给 LLM
 ↓
LLM 生成最终回答

模型负责判断“需要使用哪个工具以及传入什么参数”。Java 应用真正执行工具方法


六、ToolCallingAdvisor:形成最小 Agent Loop

Tool 能够解决“Agent 可以做什么”的问题,还需要有组件负责管理整个工具调用过程

Spring AI 2.0 中,这个组件就是:

ToolCallingAdvisor

当使用 ChatClient 时,Spring AI 会自动注册 ToolCallingAdvisor。它负责执行模型产生的 Tool Call,将结果重新提供给模型,并继续这一过程,直到模型给出一个不再包含工具调用请求的结果。

因此,一个典型工具调用循环可以表示为:

用户任务
   ↓
LLM 第一次推理
   ↓
需要 Tool?
   ↓ 是
生成 Tool Call
   ↓
ToolCallingAdvisor
   ↓
执行 Java Tool
   ↓
得到 Tool Result
   ↓
再次调用 LLM
   ↓
还需要 Tool?
   ↓ 否
最终回答

这已经具备一个最小 Agent 的核心特征:模型能够根据当前任务决定下一步操作,调用外部能力,并根据执行结果继续完成任务。

Spring AI 2.0 将这一循环纳入 Advisor Chain,因此 Tool Calling 可以与 Memory、RAG、日志和其他 Advisor 继续组合

对于普通开发,通常不需要手动创建 ToolCallingAdvisor

只要:

.tools(inventoryTools)

或者在 ChatClient 中注册:

.defaultTools(inventoryTools)

即可。ChatClient 会负责默认工具调用循环。


七、组合一个最小可运行 Spring AI Agent

现在把前面的组件组合起来。这个 Agent 只做一件事情:管理简单商品库存。

它需要具备三项能力:

能够与用户对话
能够记住同一会话的上下文
能够自主调用库存查询 Tool

1. 引入 Spring AI

这里以 DeepSeek 为例。

Spring AI 2.0 官方提供:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>

Spring AI 官方 DeepSeek Starter 会通过 Spring Boot 自动配置创建对应的模型组件。

API Key 放在环境变量中:

spring:
  ai:
    deepseek:
      api-key: ${DEEPSEEK_API_KEY}

Spring AI 2.0 的官方 DeepSeek 配置属性使用【按指定路径填充DS API即可】:

spring.ai.deepseek.api-key

2. 创建库存 Tool

@Component
public class InventoryTools {

    // 模拟商品库存数据:keyboard 有 6 件,mouse 有 24 件
    private static final Map<String, Integer> STOCK = Map.of(
            "keyboard", 6,
            "mouse", 24
    );

    // @Tool 注解将该方法暴露给模型,description 用于描述工具用途
    @Tool(description = "查询商品库存。当用户询问库存数量或者是否需要补货时使用")
    public String getStock(
            @ToolParam(description = "商品名称") String product) {

        // 根据商品名称(转小写)查询库存
        Integer stock = STOCK.get(product.toLowerCase());

        // 未找到该商品时返回提示信息
        if (stock == null) {
            return "没有找到商品:" + product;
        }

        // 返回库存查询结果
        return product + " 当前库存为 " + stock + " 件";
    }
}

3. 创建 ChatMemory 和 ChatClient

@Configuration
public class AiConfig {

    // 创建 ChatMemory Bean,用于保存多轮对话上下文
    @Bean
    public ChatMemory chatMemory() {

        // 使用滑动窗口内存,最多保留 20 条消息
        return MessageWindowChatMemory.builder()
                .maxMessages(20)
                .build();
    }

    // 创建 ChatClient Bean,组装记忆、日志和工具
    @Bean
    public ChatClient chatClient(
            ChatClient.Builder builder,
            ChatMemory chatMemory,
            InventoryTools inventoryTools) {

        return builder
                // 设置系统提示词,定义 Agent 行为规则
                .defaultSystem("""
                        你是一个库存管理助手。
                        涉及商品实时库存时必须调用库存查询工具。
                        当库存低于 10 件时提醒补货。
                        回答保持简洁。
                        """)

                // 加入多轮对话记忆
                .defaultAdvisors(
                        MessageChatMemoryAdvisor
                                .builder(chatMemory)
                                .build(),

                        // 记录 ChatClient 请求和响应
                        new SimpleLoggerAdvisor()
                )

                // 将库存工具提供给 Agent
                .defaultTools(inventoryTools)

                .build();
    }
}

这里已经把三个非常重要的 Agent 组件组合到了一起:

System Prompt
    → 定义 Agent 行为

MessageChatMemoryAdvisor
    → 提供上下文

InventoryTools
    → 提供真实操作能力

Tool Calling Loop 则由 ChatClient 默认注册的 ToolCallingAdvisor 管理。


4. 提供接口

Controller 可以保持非常简单:

@RestController
@RequestMapping("/agent")
public class InventoryAgentController {

    // 注入 ChatClient,它是 Spring AI 中调用模型的统一入口
    private final ChatClient chatClient;

    // 通过构造器注入 ChatClient
    public InventoryAgentController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    // 处理 GET 请求 /agent,接收用户消息和会话 ID
    @GetMapping
    public String agent(
            @RequestParam String message,
            @RequestParam String conversationId) {

        return chatClient
                .prompt()

                // 当前用户消息
                .user(message)

                // 指定当前会话
                .advisors(advisor -> advisor.param(
                        ChatMemory.CONVERSATION_ID,
                        conversationId
                ))

                // 调用 Agent
                .call()
                .content();
    }
}

真正与 Spring AI 交互的业务代码最终仍然只有:

chatClient
        .prompt()
        .user(message)
        .advisors(...)
        .call()
        .content();

大量 Agent 能力已经通过 ChatClient 配置完成(Configuration文件)


八、一次请求内部究竟发生了什么

现在发送:

/agent?conversationId=001&message=keyboard需要补货吗

程序内部可以按照下面的过程理解:

① 用户请求

keyboard 需要补货吗?

        ↓

② ChatClient

构造当前 Prompt

        ↓

③ MessageChatMemoryAdvisor

读取 conversationId = 001
对应的历史消息

        ↓

④ LLM

发现回答问题需要真实库存

        ↓

⑤ Tool Calling

模型产生类似:

getStock("keyboard")

        ↓

⑥ Java Tool

返回:

keyboard 当前库存为 6 件

        ↓

⑦ ToolCallingAdvisor

把 Tool Result 重新交给模型

        ↓

⑧ LLM

结合规则:

库存低于 10 件需要提醒补货

        ↓

⑨ 最终回答

keyboard 当前库存为 6 件,
建议及时补货。

在这段过程中,Controller 没有编写:

if (用户问库存) {
    调用库存方法;
}

模型根据 Tool Definition 和当前任务决定是否使用工具

这正是最小 Agent 相比普通聊天程序最值得关注的变化。


九、继续丰富 Agent 时还会加入什么

在理解上面的最小 Agent 后,可以继续沿着同一结构扩展。

例如需要让 Agent 查询企业知识库,可以加入:

QuestionAnswerAdvisor

或者:

RetrievalAugmentationAdvisor

Spring AI 将 RAG 能力与 Advisor API 结合,可以在模型调用以前检索 Vector Store,并将相关文档加入上下文。( RAG 最直观的位置就是放在 MessageChatMemoryAdvisor 之后、第一次进入 LLM 之前。它先根据当前问题及必要的对话上下文检索知识库,然后把检索结果补进 Prompt。)

如果 Agent 的结果需要直接进入后端业务逻辑,可以使用 Structured Output:

record RestockDecision(
        String product,
        int stock,
        boolean needRestock
) {}

随后:

RestockDecision result = chatClient
        .prompt()
        .user("分析 keyboard 当前是否需要补货")
        .call()
        .entity(RestockDecision.class);  // 将模型结果转换为 Java 对象

Spring AI 的 .entity() 可以将模型结果直接转换成 Java 类型。2.0 还提供 Schema Validation 等能力,用于检查结构化结果在结构不符合要求时重新尝试

如果工具越来越多,还可以进一步接入 MCP。MCP 为模型访问外部工具和资源提供统一协议,使数据库、API、文件系统或独立工具服务能够通过标准化方式进入 Agent。

因此,一个更加完整的 Spring AI Agent 可以逐渐形成:

                   ChatClient
                       │
                Advisor Chain
                       │
       ┌───────────────┼───────────────┐
       │               │               │
     Memory           RAG            Safety
       │               │               │
       └───────────────┼───────────────┘
                       │
                ToolCallingAdvisor
                       │
                 ChatModel / LLM
                       │
             判断下一步需要什么
                       │
             ┌─────────┴─────────┐
             │                   │
           Tools                MCP
             │                   │
             └─────────┬─────────┘
                       │
                 外部真实能力

对于 Spring AI 2.0 的第一阶段学习,掌握下面这条路径已经足够:

ChatClient
    ↓
Advisor
    ↓
ChatMemory
    ↓
Tool
    ↓
ToolCallingAdvisor
    ↓
最小 Agent

其中 ChatClient 负责组织一次 AI 调用,Advisor 负责向调用过程加入独立增强逻辑,ChatMemory 负责维持上下文,Tool 将 Java 能力开放给模型,ToolCallingAdvisor 负责完成“模型判断—工具执行—结果返回模型—继续判断”的循环。

理解这一结构后,RAG、结构化输出、MCP、多 Agent 编排等内容都可以继续建立在同一套 Spring AI 调用模型之上。

Logo

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

更多推荐