Spring AI Advisor 完全指南:拦截器机制与实战全解

场景

SpringAI+Ollama本地模型实现快速对话入门实例:

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/160983728

在上面基础上实现Advisor 拦截器机制与实战全解。

在 Spring AI 的体系中,Advisor(顾问) 类似于 Web 应用中的过滤器(Filter)或 Spring 切面(AOP Around Advice),

它提供了一种无侵入的方式,在调用 AI 模型的前后对请求和响应进行拦截、修改甚至短路。通过 Advisor,

我们可以把日志记录、多轮对话记忆、安全过滤、性能监控等横切关注点模块化,并灵活组合成处理链,让业务代码保持干净。

本文将聚焦于 Spring AI 1.1.2 版本的 Advisor 机制,从概念、内置实现到自定义实战,

结合完整的代码示例和常见问题,帮助你彻底掌握 Advisor 的使用。

Advisor 核心概念

执行生命周期

ChatClient 请求 → Advisor1.before → Advisor2.before → ... → 调用 AI 模型

Advisor1.after ← Advisor2.after ← ... ← AI 模型响应

before:在请求发送给模型之前执行,可以修改请求内容或中断链路。

after:在模型返回响应之后执行,可以修改响应内容。

Advisor 链

Advisor 以链式组织,通过 Ordered 接口控制执行顺序(值越小优先级越高)。

请求沿 Order 由小到大执行 before,响应沿 Order 由大到小执行 after。

核心 API

目的 1.0.0-M4(旧) 1.1.2(新)

简单修改(不短路) RequestResponseAdvisor BaseAdvisor

非流式短路 CallAroundAdvisor CallAdvisor

流式短路 StreamAroundAdvisor StreamAdvisor

请求对象 AdvisedRequest ChatClientRequest

响应对象 AdvisedResponse ChatClientResponse

短路是指 Advisor 直接返回一个响应,不再调用后续 Advisor 和 AI 模型,常用于安全过滤等场景。

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi

实现

SimpleLoggerAdvisor:快速日志记录

SimpleLoggerAdvisor 是 Spring AI 内置的日志 Advisor,开启后可在 DEBUG 级别记录每次请求和响应,非常便于调试。

注册方式:

复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ChatConfig {

    @Bean
    public ChatClient chatClient(ChatModel chatModel) {
        return ChatClient.builder(chatModel)
                .defaultAdvisors(new SimpleLoggerAdvisor())
                .build();
    }
}

开启日志:在 application.yml 中配置:

复制代码
logging:
  level:
    org.springframework.ai.chat.client.advisor: DEBUG

启动后在调用接口时,控制台会输出类似:

DEBUG ... SimpleLoggerAdvisor - request: AdvisedRequest...

DEBUG ... SimpleLoggerAdvisor - response: AdvisedResponse...

MessageChatMemoryAdvisor:多轮对话记忆

1、MessageChatMemoryAdvisor 可以将对话历史存储在 ChatMemory 中,并在后续请求中自动附加上下文。

注意:

InMemoryChatMemory 在 Spring AI 1.1.2 版本中已被移除。

为了更精细地控制记忆逻辑(例如防止超出模型 Token 限制),框架的 API 进行了重构,

将存储职责与记忆管理策略分离了。

直接后果是 InMemoryChatMemory 被废弃,取而代之的是 InMemoryChatMemoryRepository 和 MessageWindowChatMemory 组合

在 Spring AI 的较新版本(如 1.1.2 及其后续版本)中,框架提供了更完善的自动配置能力。

通过配置文件定制参数:

在 application.yml 中添加配置,以控制记忆的最大消息数量。

复制代码
spring:
  ai:
    chat:
      memory:
        max-messages: 10

完整配置文件

复制代码
​
server:
  port: 886

spring:
  ai:
    ollama:
      base-url: http://localhost:11434
      chat:
        model: qwen2.5:7b-instruct
        options:
          temperature: 0.7
          num-ctx: 4096                         # 上下文窗口大小
    chat:
      memory:
        max-messages: 10

logging:
  level:
    # 将 Advisor 包的日志级别设置为 DEBUG,才能看到日志输出
    org.springframework.ai.chat.client.advisor: DEBUG

​

2、注册 Advisor

复制代码
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;

@Bean
public ChatClient chatClient(ChatModel chatModel, ChatMemory chatMemory) {
    return ChatClient.builder(chatModel)
            .defaultAdvisors(
                MessageChatMemoryAdvisor.builder(chatMemory).build()
            )
            .build();
}

3、控制器传入会话ID

每个会话需要唯一标识,通过请求参数动态传入:

复制代码
package com.badao.ai.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class ToolChatController {

    private final ChatClient chatClient;

    public ToolChatController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @PostMapping("/chat/multi")
    public ChatResponse multiTurnChat(@RequestBody MultiTurnChatRequest request) {
        String result = chatClient.prompt()
                .user(request.message())
                .advisors(advisor -> advisor
                        // 动态传入会话 ID,告诉 MessageChatMemoryAdvisor 这是哪个会话
                        .param("chat_memory_conversation_id", request.conversationId())
                )
                .call()
                .content();
        return new ChatResponse(200, "success", result);
    }

    public record MultiTurnChatRequest(String message, String conversationId) {}
    public record ChatResponse(int code, String msg, String data) {}
}

自定义 Advisor 实战:敏感词过滤

许多业务需要对用户输入进行安全审查,并在发现敏感词时直接返回警告,不调用 AI 模型(短路)。

1、BaseAdvisor 是 Spring AI 1.1.2 新增的便捷基类,它统一了 Call 和 Stream 模式,你只需重写 before 和 after 方法

复制代码
package com.badao.ai.advisor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.AdvisorChain;
import org.springframework.ai.chat.client.advisor.api.BaseAdvisor;
import org.springframework.core.Ordered;
import java.util.Arrays;
import java.util.List;

public class SensitiveWordGuardAdvisor implements BaseAdvisor {

    private final Logger logger = LoggerFactory.getLogger(SensitiveWordGuardAdvisor.class);
    private final List<String> sensitiveWords = Arrays.asList("暴力", "违禁");

    @Override
    public ChatClientRequest before(ChatClientRequest request, AdvisorChain chain) {
        String userText = request.prompt().getContents();
        if (containsSensitiveWord(userText)) {
            logger.warn("BaseAdvisor 检测到敏感词: {}", userText);
        }
        return request; // BaseAdvisor 无法直接短路,仅做记录或修改
    }

    @Override
    public ChatClientResponse after(ChatClientResponse response, AdvisorChain chain) {
        return response;
    }

    private boolean containsSensitiveWord(String text) {
        return sensitiveWords.stream().anyMatch(text::contains);
    }

    @Override
    public String getName() {
        return "SensitiveWordGuardAdvisor";
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

2、注册到链中

复制代码
package com.badao.ai.config;

import com.badao.ai.advisor.SensitiveWordGuardAdvisor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ai.chat.model.ChatModel;

@Configuration
public class ChatConfig {

    @Bean
    public ChatClient chatClient(ChatModel chatModel, ChatMemory chatMemory) {
        return ChatClient.builder(chatModel)
                .defaultAdvisors(
                        new SensitiveWordGuardAdvisor(), // 自定义安全检查 Advisor
                        new SimpleLoggerAdvisor(), // 将 SimpleLoggerAdvisor 注册为全局 Advisor
                        MessageChatMemoryAdvisor.builder(chatMemory)   // 对话记忆 ← 使用 builder
                                .build() // 记忆 Advisor
                )
                .build();
    }
}

测试验证

测试记忆和日志功能

传递001,告诉名字,然后再询问名字

传递002,询问名字

敏感词测试

相关推荐
云烟成雨TD2 小时前
Spring AI Alibaba 1.x 系列【69】Token 用量统计
java·人工智能·spring
十三画者2 小时前
【AI学习笔记】:DeepSeek 大模型本地部署与调用实战指南
人工智能
丁常彦-自媒体-常言道2 小时前
从首发4nm智驾芯片到兜底城市领航安全,比亚迪开启AI新征程
人工智能
JAVA9652 小时前
JAVA面试-并发篇 03-使用synchronized doublecheck实现单例有什么坑
java·单例模式·面试
在繁华处2 小时前
Java从零到熟练(四):面向对象基础
java·开发语言
小杨在厦门3 小时前
从AI验布到智能质检:纺织企业智能化升级的三个台阶
人工智能·服装·服装厂·服装机械·铺布机
达之云*驭影3 小时前
解锁流量密码:详解抖音AI智能推荐封面功能
人工智能
小江的记录本4 小时前
【JVM虚拟机】堆内存分代模型:年轻代(Eden+Survivor)、老年代、元空间Metaspace(附《思维导图》+《面试高频考点清单》)
java·前端·jvm·后端·python·spring·面试
火山引擎开发者社区4 小时前
ArkClaw 投研助理 —— 零门槛做投研,从一句话开始产出你的第一份深度研报
人工智能