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?pwd1234提取码0000Spring 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中的AOP或Filter过滤器那理解Advisors会觉得非常亲切。工作原理Advisors 如何运作Advisors 基于责任链模式和AOP 面向切面编程思想工作流程如下请求阶段用户→ChatClient→Advisor1→Advisor2→...→LLM每个 Advisor 可以修改请求如添加历史对话、优化提示词也可以拦截请求如发现敏感词直接返回错误响应阶段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 FluxChatClientResponse 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 表示高优先级 * 如果有多个 AdvisorSpring 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[promptPrompt{messages[UserMessage{content你是谁, metadata{messageTypeUSER}, messageTypeUSER}], modelOptionsOpenAiChatOptions: {model:qwen3.6-plus,streamUsage:false}}, context{}] 收到响应ChatClientResponse[chatResponseChatResponse [metadata{ id: chatcmpl-005ad77a-27b5-9816-80ad-b2b269dbba56, usage: DefaultUsage{promptTokens12, completionTokens658, totalTokens670}, rateLimit: { type: org.springframework.ai.openai.metadata.OpenAiRateLimit, requestsLimit: null, requestsRemaining: null, requestsReset: null, tokensLimit: null; tokensRemaining: null; tokensReset: null } }, generations[Generation[assistantMessageAssistantMessage [messageTypeASSISTANT, toolCalls[], textContent你好我是 Qwen通义千问是由阿里巴巴集团旗下通义实验室研发的大语言模型。你可以把我当作一个真诚、乐于助人的 AI 伙伴。 无论是探讨问题、寻找灵感还是协助处理文字和逻辑任务我都在这里。今天有什么我可以帮你的吗, metadata{roleASSISTANT, messageTypeASSISTANT, refusal, finishReasonSTOP, index0, annotations[{}], idchatcmpl-005ad77a-27b5-9816-80ad-b2b269dbba56}], chatGenerationMetadataDefaultChatGenerationMetadata[finishReasonSTOP, filters0, metadata0]]]], context{}]再测试流式的http://localhost:8080/ai2?question你是谁控制台输出项目里配置日志记录SimpleLoggerAdvisor我们给项目配置下内置的SimpleLoggerAdvisor日志记录Advisorpackage 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.19808:00 DEBUG 49764 --- [helloWorld] [nio-8080-exec-3] o.s.a.c.c.advisor.SimpleLoggerAdvisor : request: ChatClientRequest[promptPrompt{messages[UserMessage{content你是谁, metadata{messageTypeUSER}, messageTypeUSER}], modelOptionsOpenAiChatOptions: {model:qwen3.6-plus,streamUsage:false}}, context{}] 2026-04-25T14:33:43.23208: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 : [ ] } } ] }