一、Advisor 技术背景与行业架构痛点
1.1 传统 AI 开发的工程缺陷
在 Spring AI 未推出 Advisor 机制之前,绝大多数开发者对接大模型的代码是线性硬编码模式:参数写死、提示词硬拼、日志硬打、重试手写、权限判断写死在业务逻辑中。
这种写法在 demo 阶段看似简单,几行代码就能跑通一次对话,但进入企业级生产环境会暴露出致命的架构问题,这也是所有后端系统从 "玩具可用" 走向 "生产稳定" 的共性瓶颈:
-
横切逻辑冗余散落:日志打印、参数校验、Token 统计、权限拦截、缓存判断、重试机制、输出格式化,全部混杂在业务代码中。每新增一个 AI 接口就要重复写一遍,代码臃肿、复用率极低,后期改一个规则要改十几个地方。
-
无法统一管控请求链路:AI 请求从「入参 - 提示词组装 - 模型调用 - 结果返回 - 异常处理」全链路无统一拦截入口,没法做全局治理。比如要全网上调 temperature、要统一加敏感词校验,只能逐个业务方法修改,极易漏改、出错。
-
功能扩展侵入业务代码:新增风控、脱敏、记忆、追溯、限流功能,都要改动业务主流程,违反开闭原则。业务逻辑和治理逻辑搅在一起,代码可读性、可维护性直线下降。
-
多模型场景无法统一适配:Ollama、DeepSeek、百炼模型各自的调用逻辑分散,每个模型都要单独写一套日志、重试、校验逻辑,重复造轮子,维护成本翻倍。
-
缺少标准化插件体系:第三方增强功能、自定义 AI 能力没法插拔式扩展,加一个功能就要动主干代码,架构灵活性极差。
1.2 Spring AI Advisor 的诞生意义
Spring AI 官方借鉴了 Spring AOP 切面思想、Servlet Filter 过滤器链、MyBatis 拦截器插件的成熟设计,针对 AI 场景量身打造了 Advisor 顾问拦截器体系。
它的核心架构定位是:AI 全链路统一横切插件层。
Advisor 既不属于业务逻辑,也不属于模型调用逻辑,是独立于主流程之外的「增强治理层」,专门负责对 AI 请求、响应、异常、上下文做统一拦截、修改、增强、管控。业务代码只需要关心 "问什么、要什么结果",所有通用治理能力全部下沉到 Advisor 层,这也是企业级架构 "业务与治理分离" 的核心思想。
1.3 核心架构思想(架构师思维)
Advisor 的设计完全遵循四大经典架构原则,每一条都对应解决上面的一个痛点:
-
单一职责:每个 Advisor 只做一件增强事情(日志、记忆、安全、参数、重试),各司其职,互不干扰,出问题可以精准定位、单独优化。
-
开闭原则:增强功能插件化新增,不用改动原有业务调用代码。加一个治理能力,只需要新增一个 Advisor Bean,原有业务代码零修改。
-
责任链编排:多拦截器按优先级有序执行,支持放行、阻断、修改上下文,灵活适配复杂治理场景。
-
解耦分层:业务层只关心提问与结果,治理层由 Advisor 全权负责,两层彻底解耦,业务开发不用关心治理细节,架构治理不用侵入业务逻辑。
二、Advisor 核心优势与适用场景(架构取舍)
2.1 核心优点
-
全链路无侵入增强:不用修改任何一行 ChatClient 调用代码,新增一个 Bean 就能实现全局请求 / 响应增强,对业务代码完全透明。
-
插件化可插拔:内置十余种官方拦截器,按需开启、不用手写。不需要的功能直接移除 Bean 即可关闭,没有冗余代码。
-
支持顺序编排与阻断:责任链机制支持前置拦截、后置处理、异常兜底、流程终止。比如敏感词命中可以直接阻断请求,不用走到模型调用环节,节省算力成本。
-
统一多模型治理:无论本地 Ollama 还是云端 DeepSeek、通义千问,拦截逻辑全局统一。一套治理规则适配所有模型,不用重复开发。
-
极易自定义扩展:开发者可以快速实现任意企业级 AI 管控能力,比如数据脱敏、租户隔离、计费统计、全链路追踪、自定义风控,完全贴合企业内部规范。
-
适配同步 + 流式双模式:普通对话、流式打字机输出全部支持拦截,不会因为调用模式不同导致治理能力缺失。
2.2 架构缺点与取舍代价
没有银弹架构,Advisor 也有明确的取舍代价,架构选型时必须正视:
-
增加链路层级:多了一层拦截封装,会带来微小的性能损耗。但对于大模型调用本身几百毫秒到几秒的耗时来说,这点损耗在企业级场景完全可以忽略。
-
新手调试难度提升:链路经过多层拦截,出问题时不能只看业务代码,要理解责任链的执行顺序,排查路径变长了。
-
滥用会导致链路臃肿:不加规划地堆大量自定义 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 在链路中都拥有三个核心能力:
-
放行:执行完当前逻辑,调用下一个拦截器,链路继续向后走。
-
阻断:直接终止整条链路,不调用模型,直接返回自定义结果。比如敏感词拦截、限流熔断都用这个能力。
-
修改上下文:动态修改 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,自动插入责任链。
设计自定义拦截器有两个核心原则:
-
单一职责:一个拦截器只做一件事,不要把脱敏、计费、日志都塞到一个类里。
-
明确顺序:安全校验类放最前面,参数增强放中间,日志统计放最后,顺序错了会导致逻辑失效。
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 优点
-
完全贴合企业规则:可以实现任意专属的风控、脱敏、计费、租户、日志规范,不受官方内置能力限制。
-
无侵入扩展:不改动任何原有 AI 调用代码,新增治理能力对业务完全透明。
-
可插拔、可排序、可动态开关:通过注解、配置就可以控制是否生效、执行顺序,灵活适配不同环境。
-
全模型统一生效:不管是本地 Ollama 还是云端商用模型,所有调用都会经过拦截器,治理口径一致。
6.2 缺点
-
需要理解责任链的执行顺序,排序不当会导致逻辑覆盖、失效甚至出错。比如参数增强放在安全校验前面,就会出现非法内容还没被拦截就被修改了。
-
自定义逻辑出错会影响全局所有 AI 请求,风险比修改单个业务方法更高,需要充分测试。
-
过多自定义拦截器会拉长执行链路,增加系统复杂度和维护成本。
6.3 适用场景
企业级 AI 中台、私有化部署项目、数据安全管控要求高的系统、需要对接内部计费 / 审计体系的平台、多租户隔离的商用 AI 服务。
七、架构师选型与落地建议
7.1 内置与自定义的选配逻辑
判断用内置还是自定义,遵循一个简单的优先级: 官方内置能满足的,坚决不用自定义;通用横切逻辑,坚决用 Advisor;业务专属逻辑,坚决写在业务层。
-
日志、记忆、基础重试、参数补全:用官方内置,稳定可靠、维护成本低;
-
企业专属风控、计费、脱敏、租户隔离:用自定义,贴合内部规范;
-
某个业务独有的特殊处理(比如某个接口专属的提示词增强):写在业务代码里,不要放到全局拦截器。
7.2 责任链排序最佳实践
合理的顺序是拦截器稳定运行的关键,通用排序规则:
-
最前面:安全校验、非法阻断、权限校验(有问题直接拦,不浪费后续资源);
-
中间:上下文拼接、参数补全、提示词增强(处理请求内容);
-
靠后:日志、计费、监控统计(拿到最终数据再统计)。
7.3 避坑指南
-
不要在拦截器里做重 IO 操作,比如同步查库、调用第三方接口,会严重拖慢整个 AI 调用。需要落库尽量用异步处理。
-
前置拦截修改请求后,一定要保证上下文对象的完整性,不要只改字段破坏原有结构。
-
流式场景下的后置拦截,要注意是全流结束后才执行,不是每个分片都执行,避免统计逻辑写错。
-
拦截器抛出异常要可控,不要抛出未受检异常导致整个服务报错,建议统一异常封装。
八、架构师最终总结
-
Advisor 是 Spring AI 的 AOP 核心,它解决了 AI 开发横切逻辑散落、无法统一治理的工程化难题,是大模型从 demo 走向生产的标志性组件。
-
底层是标准责任链模式,有序执行、支持放行、阻断、修改,是企业插件化架构的经典实现,和 Spring 生态的设计思想一脉相承。
-
内置拦截器覆盖 80% 通用场景,日志、记忆、重试、参数填充、安全校验开箱即用,优先使用官方能力,降低维护成本。
-
自定义 Advisor 覆盖剩余 20% 企业定制场景,实现中台级别的统一管控,灵活适配企业专属规范。
-
工程选型核心原则:通用能力用官方拦截器,企业独有能力自定义拦截器,遵循单一职责、按需装配、顺序合理三大原则,保证架构简洁、稳定、可扩展。