Spring AI Advisor 全解

一、Advisor 技术背景与行业架构痛点

1.1 传统 AI 开发的工程缺陷

在 Spring AI 未推出 Advisor 机制之前,绝大多数开发者对接大模型的代码是线性硬编码模式:参数写死、提示词硬拼、日志硬打、重试手写、权限判断写死在业务逻辑中。

这种写法在 demo 阶段看似简单,几行代码就能跑通一次对话,但进入企业级生产环境会暴露出致命的架构问题,这也是所有后端系统从 "玩具可用" 走向 "生产稳定" 的共性瓶颈:

  1. 横切逻辑冗余散落:日志打印、参数校验、Token 统计、权限拦截、缓存判断、重试机制、输出格式化,全部混杂在业务代码中。每新增一个 AI 接口就要重复写一遍,代码臃肿、复用率极低,后期改一个规则要改十几个地方。

  2. 无法统一管控请求链路:AI 请求从「入参 - 提示词组装 - 模型调用 - 结果返回 - 异常处理」全链路无统一拦截入口,没法做全局治理。比如要全网上调 temperature、要统一加敏感词校验,只能逐个业务方法修改,极易漏改、出错。

  3. 功能扩展侵入业务代码:新增风控、脱敏、记忆、追溯、限流功能,都要改动业务主流程,违反开闭原则。业务逻辑和治理逻辑搅在一起,代码可读性、可维护性直线下降。

  4. 多模型场景无法统一适配:Ollama、DeepSeek、百炼模型各自的调用逻辑分散,每个模型都要单独写一套日志、重试、校验逻辑,重复造轮子,维护成本翻倍。

  5. 缺少标准化插件体系:第三方增强功能、自定义 AI 能力没法插拔式扩展,加一个功能就要动主干代码,架构灵活性极差。

1.2 Spring AI Advisor 的诞生意义

Spring AI 官方借鉴了 Spring AOP 切面思想、Servlet Filter 过滤器链、MyBatis 拦截器插件的成熟设计,针对 AI 场景量身打造了 Advisor 顾问拦截器体系

它的核心架构定位是:AI 全链路统一横切插件层

Advisor 既不属于业务逻辑,也不属于模型调用逻辑,是独立于主流程之外的「增强治理层」,专门负责对 AI 请求、响应、异常、上下文做统一拦截、修改、增强、管控。业务代码只需要关心 "问什么、要什么结果",所有通用治理能力全部下沉到 Advisor 层,这也是企业级架构 "业务与治理分离" 的核心思想。

1.3 核心架构思想(架构师思维)

Advisor 的设计完全遵循四大经典架构原则,每一条都对应解决上面的一个痛点:

  1. 单一职责:每个 Advisor 只做一件增强事情(日志、记忆、安全、参数、重试),各司其职,互不干扰,出问题可以精准定位、单独优化。

  2. 开闭原则:增强功能插件化新增,不用改动原有业务调用代码。加一个治理能力,只需要新增一个 Advisor Bean,原有业务代码零修改。

  3. 责任链编排:多拦截器按优先级有序执行,支持放行、阻断、修改上下文,灵活适配复杂治理场景。

  4. 解耦分层:业务层只关心提问与结果,治理层由 Advisor 全权负责,两层彻底解耦,业务开发不用关心治理细节,架构治理不用侵入业务逻辑。

二、Advisor 核心优势与适用场景(架构取舍)

2.1 核心优点

  1. 全链路无侵入增强:不用修改任何一行 ChatClient 调用代码,新增一个 Bean 就能实现全局请求 / 响应增强,对业务代码完全透明。

  2. 插件化可插拔:内置十余种官方拦截器,按需开启、不用手写。不需要的功能直接移除 Bean 即可关闭,没有冗余代码。

  3. 支持顺序编排与阻断:责任链机制支持前置拦截、后置处理、异常兜底、流程终止。比如敏感词命中可以直接阻断请求,不用走到模型调用环节,节省算力成本。

  4. 统一多模型治理:无论本地 Ollama 还是云端 DeepSeek、通义千问,拦截逻辑全局统一。一套治理规则适配所有模型,不用重复开发。

  5. 极易自定义扩展:开发者可以快速实现任意企业级 AI 管控能力,比如数据脱敏、租户隔离、计费统计、全链路追踪、自定义风控,完全贴合企业内部规范。

  6. 适配同步 + 流式双模式:普通对话、流式打字机输出全部支持拦截,不会因为调用模式不同导致治理能力缺失。

2.2 架构缺点与取舍代价

没有银弹架构,Advisor 也有明确的取舍代价,架构选型时必须正视:

  1. 增加链路层级:多了一层拦截封装,会带来微小的性能损耗。但对于大模型调用本身几百毫秒到几秒的耗时来说,这点损耗在企业级场景完全可以忽略。

  2. 新手调试难度提升:链路经过多层拦截,出问题时不能只看业务代码,要理解责任链的执行顺序,排查路径变长了。

  3. 滥用会导致链路臃肿:不加规划地堆大量自定义 Advisor,会让执行链路过长、逻辑分散、维护困难,反而降低系统稳定性。

架构师取舍结论:生产环境必须用 Advisor 做统一治理,但一定要遵循「按需装配、单一职责、数量可控」三大原则。通用能力用官方内置,定制能力才自定义,避免为了架构而架构。

2.3 最佳适用场景

判断一个功能该不该放到 Advisor 里,有一个简单的标准:是不是所有 AI 调用都需要、是不是和具体业务无关、是不是通用治理需求。满足就适合用 Advisor,否则更适合写在业务代码里。

典型适用场景包括:

  • 需要全局日志、全链路追溯的 AI 中台项目;

  • 需要对话记忆、上下文自动拼接的多轮对话系统;

  • 需要敏感词审核、内容脱敏、安全风控的公网 AI 服务;

  • 需要Token 统计、计费、限流、监控的商用 AI 平台;

  • 需要统一参数增强、统一异常兜底、重试机制的生产项目;

  • 需要插件化扩展、动态开关能力的企业级 AI 架构。

三、Spring AI Advisor 底层架构与责任链源码解析

3.1 核心源码接口分层

Spring AI 所有拦截器的顶层统一接口是 Advisor,在此基础上按执行时机拆分为三个核心子接口,覆盖全链路所有节点:

  • RequestAdvisor:请求前置拦截,在发往大模型之前执行,用于参数校验、脱敏、补全参数、拼接上下文。

  • ResponseAdvisor:响应后置拦截,在模型返回结果之后执行,用于格式化输出、内容审核、结果清洗、Token 统计。

  • StreamAdvisor:流式输出专属拦截器,针对 Flux 数据流做分片处理,适配流式对话场景。

3.2 责任链模式核心原理

Spring AI Advisor 是标准的责任链设计模式实现,和 Servlet 过滤器、Spring MVC 拦截器的执行逻辑一脉相承,学习成本极低。

一次同步 AI 请求的完整执行链路: ChatClient.prompt()前置 Advisor 链条按顺序依次执行 → 真正调用大模型 API → 后置 Advisor 链条按顺序依次执行 → 返回最终结果

每个 Advisor 在链路中都拥有三个核心能力:

  1. 放行:执行完当前逻辑,调用下一个拦截器,链路继续向后走。

  2. 阻断:直接终止整条链路,不调用模型,直接返回自定义结果。比如敏感词拦截、限流熔断都用这个能力。

  3. 修改上下文:动态修改 Prompt、模型参数、用户消息、输出内容,在不改动业务代码的前提下调整请求与响应。

3.3 源码级执行逻辑(架构精读)

框架底层会自动扫描 Spring 容器中所有的 Advisor Bean,根据 getOrder() 方法返回的优先级排序,组成一条有序的拦截器列表。

核心执行逻辑的伪代码如下,可以直观理解整条链路的运转方式:

复制代码
v// 1. 按优先级排序所有拦截器
List<Advisor> sortedAdvisors = sortByOrder(allAdvisors);

// 2. 前置拦截:依次执行所有 RequestAdvisor
AdvisedRequest currentRequest = originalRequest;
for (Advisor advisor : sortedAdvisors) {
    if (advisor instanceof RequestAdvisor requestAdvisor) {
        currentRequest = requestAdvisor.beforeRequest(currentRequest);
        // 若拦截器判定需要终止,直接返回兜底结果,不调用模型
        if (isInterrupted(currentRequest)) {
            return buildCustomResponse();
        }
    }
}

// 3. 经过所有前置校验后,真正调用大模型
ChatResponse originalResponse = callLLM(currentRequest);

// 4. 后置拦截:依次执行所有 ResponseAdvisor
AdvisedResponse currentResponse = originalResponse;
for (Advisor advisor : sortedAdvisors) {
    if (advisor instanceof ResponseAdvisor responseAdvisor) {
        currentResponse = responseAdvisor.afterResponse(currentResponse);
    }
}

// 5. 返回最终处理后的结果
return currentResponse;

架构核心亮点:Spring AI 把请求增强、响应增强、异常兜底、流式处理全部统一纳入责任链,实现了 AI 链路的 AOP 化治理。这也是 Spring 家族一贯的设计哲学:用统一的抽象屏蔽底层差异,用插件化机制支撑扩展能力。

3.4 流式场景的特殊处理

流式调用和同步调用的责任链逻辑有明显区别,很多新手容易踩坑:

  • 同步调用:前置拦截执行 1 次 → 模型调用 1 次 → 后置拦截执行 1 次;

  • 流式调用:前置拦截执行 1 次 → 模型返回每一个数据分片,都会经过流式拦截器处理 → 全部结束后后置拦截执行 1 次。

简单说,流式的分片内容增强是逐段执行的,不是等全部返回再统一处理,这样才能保证打字机效果的实时性。

四、Spring AI 内置 Advisor 全分类详解

官方内置的拦截器覆盖了绝大多数通用场景,优先用内置、少自定义,是降低维护成本的核心原则。下面逐个拆解其作用、原理、适用场景与取舍逻辑。

4.1 日志拦截器 SimpleLoggerAdvisor

核心作用 自动打印完整请求 Prompt、模型参数、最终响应内容、Token 消耗数据,不用手动在每个方法里写日志代码。

底层原理 在前置拦截阶段抓取 Prompt 消息与参数,后置阶段抓取返回结果与 usage 用量信息,统一格式化后输出到日志框架,支持集成 SLF4J、Logback 等常用日志组件。

为什么要做成拦截器 日志是典型的横切通用逻辑,每个 AI 调用都需要。如果写在业务代码里,每个接口都要写一遍,还容易漏打关键字段。做成拦截器后全局自动生效,统一日志格式,方便排查问题。

适用场景 开发调试、线上问题排查、AI 对话全链路追溯、审计留痕。

优缺点

  • 优点:零代码开启、全链路日志完整、排查问题效率极高。

  • 缺点:生产高并发下日志量大,可能占用存储资源。建议开发环境全开,生产环境按需开启或做脱敏降级。

4.2 对话记忆拦截器 ChatMemoryAdvisor

核心作用 自动读写对话上下文,自动拼接历史消息到 Prompt 中,不用开发者手动维护多轮对话记录、不用手动组装历史消息。

底层原理 基于内置的 ChatMemory 存储器,前置拦截时根据会话 ID 自动读取历史对话,追加到当前 Prompt 里;模型返回后,自动把最新的问答对存入存储器,全程对业务代码无感知。

为什么要做成拦截器 多轮对话的上下文读写是通用能力,和具体业务无关。做成拦截器后,业务代码只需要传会话 ID,完全不用关心记忆怎么存、怎么拼、怎么淘汰,极大简化业务开发。

适用场景 所有多轮对话、智能客服、持续问答、需求迭代式生成场景。

优缺点

  • 优点:彻底解放手动拼接上下文的工作,标准化多轮对话,避免手写记忆逻辑出错。

  • 缺点:默认是内存存储,服务重启数据丢失;生产环境需要替换为 Redis、数据库持久化存储。

4.3 内容安全拦截器 SafeGuardAdvisor

核心作用 对用户提问、模型输出做违规内容检测、敏感词拦截,防止非法输入与违规输出。

底层原理 前置阶段校验用户输入,后置阶段校验模型输出,命中违规规则直接阻断链路,返回标准化安全提示,不用业务代码做判断。

为什么要做成拦截器 安全合规是所有公网 AI 服务的硬性要求,必须全局生效、不能有遗漏。做成拦截器可以保证所有 AI 请求都经过安全校验,避免业务漏写校验导致合规风险。

适用场景 公网用户端 AI 产品、需要内容合规审核的系统、面向公众的智能服务。

优缺点

  • 优点:快速实现基础风控拦截,防止违规内容输出,降低合规风险。

  • 缺点:默认规则比较简单,复杂业务场景(比如行业专属敏感词、多级审核)需要自定义风控规则。

4.4 重试拦截器 RetryAdvisor

核心作用 针对模型超时、网络抖动、限流报错等瞬时异常,实现自动重试,提升接口成功率。

底层原理 捕获 AI 调用的异常,根据配置的重试次数、重试间隔、重试异常类型,自动重新发起请求,支持指数退避等策略。

为什么要做成拦截器 重试是典型的容错治理逻辑,和业务无关。如果每个业务方法都手写 try-catch 重试,代码冗余且策略不统一。做成拦截器后全局统一容错策略,配置灵活。

适用场景 网络不稳定环境、云端模型偶发超时、瞬时限流场景、对可用性要求高的生产服务。

优缺点

  • 优点:大幅提升接口稳定性,降低瞬时失败率,不用业务代码处理异常重试。

  • 缺点:重试不当会导致重复请求、重复扣费、数据重复生成,必须合理配置重试次数与触发条件。

4.5 参数增强拦截器 DefaultOptionsAdvisor

核心作用 全局统一填充模型默认参数(temperature、maxTokens、上下文窗口等),避免业务代码漏传参数,保证全项目参数口径统一。

底层原理 前置拦截时检测请求参数是否缺失,自动把全局配置的默认参数补全进去。业务代码传了参数就用业务的,没传就用全局默认值。

为什么要做成拦截器 模型参数如果散落在各个业务代码里,很容易出现有的地方温度高、有的地方低,输出效果参差不齐。做成拦截器统一兜底,规范项目 AI 调用标准。

适用场景 统一模型参数管控、规范项目 AI 调用标准、多团队协作的大型项目。

优缺点

  • 优点:统一参数口径、避免参数混乱、减少人为错误、降低业务代码冗余。

  • 缺点:全局参数和局部参数有优先级覆盖关系,理解不清容易出现 "改了配置不生效" 的问题。

五、自定义 Advisor 深度实战

5.1 自定义拦截器设计思想

当官方内置拦截器满足不了企业专属需求时,比如数据脱敏、租户隔离、计费统计、全链路 Trace 透传、自定义风控规则,就需要自定义 Advisor。

自定义的核心架构思想很简单:实现对应顶层 Advisor 接口,重写前置 / 后置方法,注册为 Spring Bean,自动插入责任链

设计自定义拦截器有两个核心原则:

  1. 单一职责:一个拦截器只做一件事,不要把脱敏、计费、日志都塞到一个类里。

  2. 明确顺序:安全校验类放最前面,参数增强放中间,日志统计放最后,顺序错了会导致逻辑失效。

5.2 自定义前置拦截器(敏感信息脱敏 + 非法内容拦截)

场景:全局拦截用户输入中的手机号、身份证号等敏感信息,命中非法话术直接阻断请求,所有 AI 调用统一生效。

复制代码
import org.springframework.ai.chat.client.advisor.api.AdvisedRequest;
import org.springframework.ai.chat.client.advisor.api.RequestAdvisor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * 全局AI请求安全拦截器
 * 执行顺序:优先级最高,所有拦截器最先执行
 */
@Component
public class SensitiveDataFilterAdvisor implements RequestAdvisor {

    // 数字越小优先级越高,安全校验放在最前面
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    @Override
    public AdvisedRequest beforeRequest(AdvisedRequest request) {
        String userContent = request.userText();

        // 1. 非法内容阻断:命中关键词直接终止请求
        if (containIllegalWords(userContent)) {
            throw new IllegalArgumentException("请求包含违规内容,已被拦截");
        }

        // 2. 敏感信息脱敏:手机号、身份证号替换为掩码
        String safeContent = userContent
                .replaceAll("1[3-9]\\d{9}", "****")
                .replaceAll("\\d{17}[\\dXx]", "****");

        // 3. 返回修改后的请求上下文,继续执行后续拦截器
        return AdvisedRequest.from(request)
                .userText(safeContent)
                .build();
    }

    private boolean containIllegalWords(String text) {
        // 实际项目替换为企业敏感词库
        return text.contains("违规测试词");
    }
}

5.3 自定义后置拦截器(Token 计费统计)

场景:全局统计每次调用的 Token 消耗量,对接企业内部计费系统,做用量统计与成本核算。

复制代码
import org.springframework.ai.chat.client.advisor.api.AdvisedResponse;
import org.springframework.ai.chat.client.advisor.api.ResponseAdvisor;
import org.springframework.stereotype.Component;

/**
 * 全局AI调用计费统计拦截器
 * 后置执行,统计Token消耗并落库
 */
@Component
public class TokenCostStatAdvisor implements ResponseAdvisor {

    @Override
    public int getOrder() {
        // 靠后执行,拿到最终的响应数据
        return Ordered.LOWEST_PRECEDENCE - 100;
    }

    @Override
    public AdvisedResponse afterResponse(AdvisedResponse response) {
        // 从响应元数据中获取Token消耗
        var metadata = response.response().getMetadata();
        long promptTokens = metadata.getPromptTokens();
        long completionTokens = metadata.getCompletionTokens();
        long totalTokens = metadata.getTotalTokens();

        // 异步落库/上报计费系统,避免阻塞主链路
        saveCostLog(promptTokens, completionTokens, totalTokens);

        // 返回原响应,不修改结果
        return response;
    }

    private void saveCostLog(long prompt, long completion, long total) {
        // 实际项目对接计费日志服务
        System.out.println("本次消耗Token:" + total);
    }
}

5.4 注入生效与测试

只要把自定义 Advisor 加上 @Component 注解,Spring Boot 启动时会自动扫描并加入责任链,业务代码零修改即可全局生效。

单元测试验证:

复制代码
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class CustomAdvisorTest {

    @Autowired
    private ChatClient chatClient;

    @Test
    void testAdvisorEffect() {
        // 包含手机号的请求,会被自动脱敏
        String result = chatClient.prompt()
                .user("我的手机号是13800138000,请介绍一下Spring AI Advisor")
                .call()
                .content();

        System.out.println("最终输出:\n" + result);
        // 控制台同时会打印Token消耗日志,说明两个拦截器都已生效
    }
}

六、自定义 Advisor 架构优缺点与适用场景

6.1 优点

  1. 完全贴合企业规则:可以实现任意专属的风控、脱敏、计费、租户、日志规范,不受官方内置能力限制。

  2. 无侵入扩展:不改动任何原有 AI 调用代码,新增治理能力对业务完全透明。

  3. 可插拔、可排序、可动态开关:通过注解、配置就可以控制是否生效、执行顺序,灵活适配不同环境。

  4. 全模型统一生效:不管是本地 Ollama 还是云端商用模型,所有调用都会经过拦截器,治理口径一致。

6.2 缺点

  1. 需要理解责任链的执行顺序,排序不当会导致逻辑覆盖、失效甚至出错。比如参数增强放在安全校验前面,就会出现非法内容还没被拦截就被修改了。

  2. 自定义逻辑出错会影响全局所有 AI 请求,风险比修改单个业务方法更高,需要充分测试。

  3. 过多自定义拦截器会拉长执行链路,增加系统复杂度和维护成本。

6.3 适用场景

企业级 AI 中台、私有化部署项目、数据安全管控要求高的系统、需要对接内部计费 / 审计体系的平台、多租户隔离的商用 AI 服务。

七、架构师选型与落地建议

7.1 内置与自定义的选配逻辑

判断用内置还是自定义,遵循一个简单的优先级: 官方内置能满足的,坚决不用自定义;通用横切逻辑,坚决用 Advisor;业务专属逻辑,坚决写在业务层。

  • 日志、记忆、基础重试、参数补全:用官方内置,稳定可靠、维护成本低;

  • 企业专属风控、计费、脱敏、租户隔离:用自定义,贴合内部规范;

  • 某个业务独有的特殊处理(比如某个接口专属的提示词增强):写在业务代码里,不要放到全局拦截器。

7.2 责任链排序最佳实践

合理的顺序是拦截器稳定运行的关键,通用排序规则:

  1. 最前面:安全校验、非法阻断、权限校验(有问题直接拦,不浪费后续资源);

  2. 中间:上下文拼接、参数补全、提示词增强(处理请求内容);

  3. 靠后:日志、计费、监控统计(拿到最终数据再统计)。

7.3 避坑指南

  1. 不要在拦截器里做重 IO 操作,比如同步查库、调用第三方接口,会严重拖慢整个 AI 调用。需要落库尽量用异步处理。

  2. 前置拦截修改请求后,一定要保证上下文对象的完整性,不要只改字段破坏原有结构。

  3. 流式场景下的后置拦截,要注意是全流结束后才执行,不是每个分片都执行,避免统计逻辑写错。

  4. 拦截器抛出异常要可控,不要抛出未受检异常导致整个服务报错,建议统一异常封装。

八、架构师最终总结

  1. Advisor 是 Spring AI 的 AOP 核心,它解决了 AI 开发横切逻辑散落、无法统一治理的工程化难题,是大模型从 demo 走向生产的标志性组件。

  2. 底层是标准责任链模式,有序执行、支持放行、阻断、修改,是企业插件化架构的经典实现,和 Spring 生态的设计思想一脉相承。

  3. 内置拦截器覆盖 80% 通用场景,日志、记忆、重试、参数填充、安全校验开箱即用,优先使用官方能力,降低维护成本。

  4. 自定义 Advisor 覆盖剩余 20% 企业定制场景,实现中台级别的统一管控,灵活适配企业专属规范。

  5. 工程选型核心原则:通用能力用官方拦截器,企业独有能力自定义拦截器,遵循单一职责、按需装配、顺序合理三大原则,保证架构简洁、稳定、可扩展。

相关推荐
YDS8291 小时前
大营销平台 —— 第二阶段应用接口实现
java·spring boot·ddd
用户69371750013841 小时前
DeepSeek 调价正式生效:一夜涨 11 倍,靠低价薅羊毛的日子结束了
前端·人工智能·后端
一水1 小时前
AI 时代审查思维:审查第一篇
java·jvm·数据库·spring
JAI科研1 小时前
Deepseek Agent Harness教程(二) | DeepSeek Harness 设计思路
人工智能·深度学习·算法·机器学习·自然语言处理·transformer·vllm
探物 AI1 小时前
yolo目标检测中的激活函数对比
人工智能·yolo·目标检测
用户298698530141 小时前
从入门到自动化:TXT 转 Word 的在线工具与代码实战方案
人工智能·后端·python
DeepIntelli1 小时前
AI问答品牌推荐:如何用GEO让品牌出现在豆包、文心一言的答案里
人工智能
m4Rk_1 小时前
【论文阅读】Agent 记忆机制(40):HiAgent——通过子目标级记忆提升长程任务执行能力
论文阅读·人工智能·学习·开源·github
还不秃顶的计科生1 小时前
具身智能论文学习10:π0: A Vision-Language-Action Flow Model for General Robot Control
人工智能·深度学习·算法·机器学习·语言模型·vla·vlm
静开1 小时前
Claude Code快速窥探:原来内核就是一个 while 循环外面套了八层壳
人工智能