Spring AI 2.0 开发Java Agent智能体 - Advisors —— 拦截器模式增强AI能力

大家好,我是Java1234_小锋老师,最近更新《2027版本 Spring AI 2.0 开发Java Agent智能体 视频教程》专辑,感谢大家支持。

本课程主要介绍和讲解Spring AI 2.0简介,Spring AI 2.0 HelloWorld搭建,Advisors --- 拦截器模式增强AI能力,对话与提示词工程(Prompt),工具调用(Function Calling / Tools) ,RAG(检索增强生成),MCP(模型 上下文协议)和多模态支持。

等这个Spring AI2.0基础课程录制完成,接下来要发布2个 企业级Java AI实战课程,RAG企业知识库系统和AI智能客服系统。大家可以点点关注,后面更精彩。

视频教程+课件+源码打包下载:

链接:https://pan.baidu.com/s/1o-zRfndo1HHrS_uFroOiCw?pwd=1234

提取码:0000

Spring AI 2.0 开发Java Agent智能体 - Advisors ------ 拦截器模式增强AI能力

Advisors 简介

Spring AI Advisors API 提供了一种灵活而强大的方式,用于拦截、修改和增强 Spring 应用程序中的 AI 驱动交互。通过利用 Advisors API,开发人员可以创建更复杂、可重用且易于维护的 AI 组件。

Spring AI 2.0 的Advisors(顾问) 本质是AI 交互的中间件 / 拦截器 ,像给 AI 聊天加了一层 "智能过滤网",能在请求发送前、响应返回后自动处理通用逻辑,让你专注于业务核心。

这个想法来自AOP(面向切面编程)。如果你学过Spring中的AOPFilter(过滤器),那理解Advisors会觉得非常亲切。

工作原理:Advisors 如何运作?

Advisors 基于责任链模式AOP 面向切面编程思想,工作流程如下:

  1. 请求阶段:用户→ChatClient→Advisor1→Advisor2→...→LLM

    • 每个 Advisor 可以修改请求(如添加历史对话、优化提示词)

    • 也可以拦截请求(如发现敏感词直接返回错误)

  2. 响应阶段:LLM→AdvisorN→...→Advisor2→Advisor1→ChatClient→用户

    • 每个 Advisor 可以修改响应(如格式化输出、提取关键信息)

    • 也可以拦截响应(如发现不符合要求时触发重试)

Spring AI 2.0 提供两种核心接口:

  • CallAdvisor:处理非流式请求(一问一答)

  • StreamAdvisor:处理流式请求(边生成边返回)Spring

核心方法是nextCall()(非流式)和nextStream()(流式),通过调用这些方法将请求传递给下一个 Advisor,形成完整的处理链。

常用内置 Advisors:开箱即用的能力

Spring AI 2.0提供了一批内置的、可以直接使用的强大顾问,覆盖了最常见的AI增强需求:

顾问名称 主要作用 通俗解释
MessageChatMemoryAdvisor 对话记忆 "记对话":记住用户最近说了啥,让聊天感觉是连续的
PromptChatMemoryAdvisor 提示记忆 "提炼对话":把整个聊天记忆压缩成一个精炼的提示摘要
VectorStoreChatMemoryAdvisor 向量存储记忆 "搜相关知识":根据用户问题,从向量数据库中找最相关的历史对话来增强记忆
QuestionAnswerAdvisor 检索增强生成 (RAG) "查资料":先在知识库里查相关信息,再把信息"喂"给AI来回答问题]
SimpleLoggerAdvisor 日志记录 "记流水账":忠实记录下每次请求和响应的内容,方便调试和监控
Semantic Cache Advisor 语义缓存 "聪明缓存":如果遇到意思相同的问题(而不是只字不差),可以直接返回之前缓存的答案,省时省力
ToolCallAdvisor 工具调用 "调用外部工具":实现AI调用外部API、数据库等能力,通过递归(Recursive) 模式可以多次循环执行
GuardrailsAdvisor 安全护栏 "安全检查":在请求到达AI前或AI响应返回前拦截不当内容

自定义实现Advisors

我们来实现一个自定义简单的请求和响应日志记录Advisor

第一步:新建MySimpleLoggerAdvisor类,实现CallAdvisor和StreamAdvisor接口,同时支持两种模式。

复制代码
package com.java1234.advisor;

import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.CallAdvisor;
import org.springframework.ai.chat.client.advisor.api.CallAdvisorChain;
import org.springframework.ai.chat.client.advisor.api.StreamAdvisor;
import org.springframework.ai.chat.client.advisor.api.StreamAdvisorChain;
import reactor.core.publisher.Flux;

/**
 * 实现CallAdvisor和StreamAdvisor接口,同时支持两种模式
 */
public class MySimpleLoggerAdvisor implements CallAdvisor, StreamAdvisor {

    @Override
    public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
        System.out.println("发送请求:" + request);
        // 调用下一个Advisor,继续处理链
        ChatClientResponse response = chain.nextCall(request);
        System.out.println("收到响应:" + response);
        return response;
    }

    @Override
    public Flux<ChatClientResponse> adviseStream(ChatClientRequest request, StreamAdvisorChain chain) {
        System.out.println("发送流式请求:" + request);
        return chain.nextStream(request)
                .doOnNext(response -> System.out.println("收到流式响应片段:"+response));
    }


    @Override
    public String getName() {
        return "简单日志Advisor";
    }

    /**
     * 这个 getOrder() 方法用于指定 Advisor(通知器)的执行顺序。
     * 作用说明:
     * 返回值越小,优先级越高,越早执行
     * 返回 0 表示高优先级
     * 如果有多个 Advisor,Spring AI 会按照此值从小到大依次执行
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

第二步:AiConfiguration的ChatClient聊天客户端里,构建ChatClient的时候,添加Advisor。

复制代码
    @Bean
    public ChatClient chatClient(OpenAiChatModel  model){
        return ChatClient
                .builder(model) // 创建 ChatClient 对象,并设置模型为 model
                .defaultAdvisors(new MySimpleLoggerAdvisor()) // 添加一个 MySimpleLoggerAdvisor,记录请求日志
                .build(); // 构建 ChatClient 对象
    }

最后我们来测试下:

先测试 阻塞式

复制代码
http://localhost:8080/ai?question=你是谁?

控制台输出:

复制代码
发送请求:ChatClientRequest[prompt=Prompt{messages=[UserMessage{content='你是谁?', metadata={messageType=USER}, messageType=USER}], modelOptions=OpenAiChatOptions: {"model":"qwen3.6-plus","streamUsage":false}}, context={}]
收到响应:ChatClientResponse[chatResponse=ChatResponse [metadata={ id: chatcmpl-005ad77a-27b5-9816-80ad-b2b269dbba56, usage: DefaultUsage{promptTokens=12, completionTokens=658, totalTokens=670}, rateLimit: { @type: org.springframework.ai.openai.metadata.OpenAiRateLimit, requestsLimit: null, requestsRemaining: null, requestsReset: null, tokensLimit: null; tokensRemaining: null; tokensReset: null } }, generations=[Generation[assistantMessage=AssistantMessage [messageType=ASSISTANT, toolCalls=[], textContent=你好!我是 Qwen(通义千问),是由阿里巴巴集团旗下通义实验室研发的大语言模型。你可以把我当作一个真诚、乐于助人的 AI 伙伴。

无论是探讨问题、寻找灵感,还是协助处理文字和逻辑任务,我都在这里。今天有什么我可以帮你的吗?, metadata={role=ASSISTANT, messageType=ASSISTANT, refusal=, finishReason=STOP, index=0, annotations=[{}], id=chatcmpl-005ad77a-27b5-9816-80ad-b2b269dbba56}], chatGenerationMetadata=DefaultChatGenerationMetadata[finishReason='STOP', filters=0, metadata=0]]]], context={}]

再测试流式的

复制代码
http://localhost:8080/ai2?question=你是谁?

控制台输出:

项目里配置日志记录SimpleLoggerAdvisor

我们给项目配置下内置的SimpleLoggerAdvisor日志记录Advisor

复制代码
package com.java1234.config;
​
import com.java1234.advisor.MySimpleLoggerAdvisor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
​
@Configuration
public class AiConfiguration {
​
    /**
     * 创建一个 ChatClient 对象,用于处理聊天请求。
     *
     * @param model OpenAiChatModel 对象,用于处理聊天请求。
     * @return ChatClient 对象,用于处理聊天请求。
     */
    @Bean
    public ChatClient chatClient(OpenAiChatModel  model){
        return ChatClient
                .builder(model) // 创建 ChatClient 对象,并设置模型为 model
                // .defaultAdvisors(new MySimpleLoggerAdvisor()) // 添加一个 MySimpleLoggerAdvisor,记录请求日志
                .defaultAdvisors(new SimpleLoggerAdvisor()) // 添加一个 SimpleLoggerAdvisor,记录请求日志
                .build(); // 构建 ChatClient 对象
    }
​
    /**
     * 创建一个 ChatClient 对象,用于处理聊天请求。
     *
     * @param model OllamaChatModel 模型,用于处理聊天请求。
     * @return ChatClient 模型,用于处理聊天请求。
     */
    @Bean
    public ChatClient chatClient2(OllamaChatModel model){
        return ChatClient
                .builder(model) // 创建 ChatClient 对象,并设置模型为 model
                .defaultAdvisors(new SimpleLoggerAdvisor()) // 添加一个 SimpleLoggerAdvisor,记录请求日志
                .build(); // 构建 ChatClient 对象
    }
}

以及application.yml里面要配置下日志级别:

复制代码
logging:
  level:
    org.springframework.ai: debug

我们来测试下:

复制代码
http://localhost:8080/ai?question=你是谁?

控制台日志输出,请求和响应都有完整的数据显示

复制代码
2026-04-25T14:33:37.198+08:00 DEBUG 49764 --- [helloWorld] [nio-8080-exec-3] o.s.a.c.c.advisor.SimpleLoggerAdvisor    : request: ChatClientRequest[prompt=Prompt{messages=[UserMessage{content='你是谁?', metadata={messageType=USER}, messageType=USER}], modelOptions=OpenAiChatOptions: {"model":"qwen3.6-plus","streamUsage":false}}, context={}]
2026-04-25T14:33:43.232+08:00 DEBUG 49764 --- [helloWorld] [nio-8080-exec-3] o.s.a.c.c.advisor.SimpleLoggerAdvisor    : response: {
  "metadata" : {
    "empty" : false,
    "id" : "chatcmpl-795a2d7a-ee98-9612-bb6f-0a1f741b5416",
    "model" : "qwen3.6-plus",
    "promptMetadata" : [ ],
    "rateLimit" : {
      "requestsLimit" : null,
      "requestsRemaining" : null,
      "requestsReset" : null,
      "tokensLimit" : null,
      "tokensRemaining" : null,
      "tokensReset" : null
    },
    "usage" : {
      "promptTokens" : 12,
      "completionTokens" : 267,
      "totalTokens" : 279,
      "nativeUsage" : {
        "completion_tokens" : 267,
        "prompt_tokens" : 12,
        "total_tokens" : 279,
        "prompt_tokens_details" : { },
        "completion_tokens_details" : {
          "reasoning_tokens" : 236
        }
      }
    }
  },
  "result" : {
    "metadata" : {
      "contentFilters" : [ ],
      "empty" : true,
      "finishReason" : "STOP"
    },
    "output" : {
      "media" : [ ],
      "messageType" : "ASSISTANT",
      "metadata" : {
        "role" : "ASSISTANT",
        "messageType" : "ASSISTANT",
        "finishReason" : "STOP",
        "refusal" : "",
        "index" : 0,
        "annotations" : [ { } ],
        "id" : "chatcmpl-795a2d7a-ee98-9612-bb6f-0a1f741b5416"
      },
      "text" : "我是 Qwen(通义千问),由阿里巴巴集团旗下通义实验室自主研发的大语言模型。有什么我可以帮你的吗?",
      "toolCalls" : [ ]
    }
  },
  "results" : [ {
    "metadata" : {
      "contentFilters" : [ ],
      "empty" : true,
      "finishReason" : "STOP"
    },
    "output" : {
      "media" : [ ],
      "messageType" : "ASSISTANT",
      "metadata" : {
        "role" : "ASSISTANT",
        "messageType" : "ASSISTANT",
        "finishReason" : "STOP",
        "refusal" : "",
        "index" : 0,
        "annotations" : [ { } ],
        "id" : "chatcmpl-795a2d7a-ee98-9612-bb6f-0a1f741b5416"
      },
      "text" : "我是 Qwen(通义千问),由阿里巴巴集团旗下通义实验室自主研发的大语言模型。有什么我可以帮你的吗?",
      "toolCalls" : [ ]
    }
  } ]
}
相关推荐
Komore3151 小时前
商户查询缓存
java·redis·缓存
shamalee1 小时前
程序员福音:Gemini3.1Pro自动生成日报
人工智能
新加坡内哥谈技术1 小时前
为什么 TUI 正在回归
人工智能
eastyuxiao1 小时前
流程图 + 配置清单 在团队 / 公司项目管理场景的落地应用
大数据·运维·人工智能·流程图
ch.ju1 小时前
Java程序设计(第3版)第二章——函数的返回值
java
倔强的猴子(翻版)1 小时前
我用 Python 写了个排序库,一亿数据量下比 C 级 np.sort() 快 7 倍
人工智能·python·算法·阿里云·文心一言
丝瓜蛋汤1 小时前
【腾讯位置服务开发者征文大赛】使用自然语言生成一个低碳出行助手
人工智能·腾讯云位置服务
郝学胜-神的一滴1 小时前
深入理解回归损失函数:MSE、L1 与 Smooth L1 的设计哲学
人工智能·python·程序人生·算法·机器学习·数据挖掘·回归