
1.Advisor简介
Spring AI 中的 Advisor 是一种核心机制,用于拦截和增强 AI 应用程序中的请求与响应流。其设计灵感来源于 Spring AOP(面向切面编程)中的切面(Aspect)概念,但专门针对 AI 交互场景进行了优化。
1.1.核心概念
- 定义与定位
Advisor 是 Spring AI 中负责动态干预聊天请求和响应流程的组件,通过链式结构(Chain of Responsibility 模式)串联多个处理单元。每个 Advisor 可以修改请求参数、增强数据、拦截敏感操作,甚至中断请求传递。
- 与AOP的关系
其功能类似于 Spring 的 AspectJ
,但更专注于 AI 交互场景。例如,通过 AroundAdvisor
接口实现请求前后的增强逻辑。
1.2.Advisord的核心特点
- 模块化封装
- 重复任务封装:将生成式 AI 的通用模式(如上下文记忆、敏感词过滤)抽象为可复用的组件。
- 数据转换:优化发送至语言模型(LLM)的输入数据格式,并处理返回的响应(如结构化输出转换)。
- 可移植性:同一 Advisor 可适配不同模型(如 OpenAI、HuggingFace)和用例,提升代码灵活性。
- 链式处理机制
多个 Advisor 按顺序执行,每个环节可修改请求或响应,并决定是否继续传递。某些 Advisor(如 SafeGuardAdvisor
)可能直接中断链式流程。
- 内置与扩展性
Spring AI 提供多种内置 Advisor,同时也支持开发者自定义扩展,满足个性化需求。
2.Advisor源码及核心原理
2.1.关键类与关系
实现接口 实现接口 实现接口 依赖 依赖 参数 返回 参数 返回 <泛型元素> 生成 调用链 0..* 0..* 调用链 0..* 0..* <<interface>> Ordered +getOrder() : int <<interface>> Advisor +getName() : String CallAroundAdvisor +aroundCall(AdvisedRequest, CallAroundAdvisorChain) : AdvisedResponse StreamAroundAdvisor +aroundStream(AdvisedRequest, StreamAroundAdvisorChain) : Flux<AdvisedResponse> AdvisedRequest +... mutable Prompt data ... +adviseContext: Map<String, Object> AdvisedResponse +callResponse: ChatResponse +adviseContext: Map<String, Object> CallAroundAdvisorChain +nextAroundCall(AdvisedRequest) : AdvisedResponse StreamAroundAdvisorChain +nextAroundStream(AdvisedRequest) : Flux<AdvisedResponse> <<Reactive Stream>> Flux<AdvisedResponse> + ... 操作流的方法 ...
-
核心接口
-
Ordered
定义
getOrder()
方法,用于控制Advisor
的执行顺序(类似 Spring 的优先级机制)。小order先管请求、后管响应,大order反之;同值顺序随机。
-
Advisor
基础接口,定义
getName()
方法标识 Advisor 名称。
-
-
具体 Advisor 实现
CallAroundAdvisor
同步调用增强器,通过aroundCall()
方法拦截请求并返回响应。StreamAroundAdvisor
流式调用增强器,通过aroundStream()
方法处理流式响应(返回Flux<AdvisedResponse>
)。
-
请求与响应对象
AdvisedRequest
包含可变的 Prompt 数据和上下文信息(adviseContext
)。AdvisedResponse
封装 Chat 响应和上下文信息。
-
调用链(Chain)类
CallAroundAdvisorChain
通过nextAroundCall()
方法传递请求,支持链式调用多个CallAroundAdvisor
。StreamAroundAdvisorChain
类似CallAroundAdvisorChain
,但用于流式场景的链式调用。
2.2.核心交互流程

-
请求初始化
Spring AI框架将用户的输入(
Prompt
)转换为AdvisedRequest
,并创建一个空的共享上下文对象AdvisorContext
。 -
Advisor链处理请求
- 每个
Advisor
依次处理AdvisedRequest
,可以:- 修改请求内容(例如调整参数、添加元数据)。
- 直接拦截请求 ,阻止后续调用,并自行生成响应(
AdvisedResponse
)。
- 若未拦截,请求会传递到链中的下一个
Advisor
。
- 每个
-
调用Chat Model
最后一个框架内置的
Advisor
负责将处理后的请求发送给Chat Model(如GPT模型)。 -
响应逆向传递
- Chat Model生成的原始响应(
ChatResponse
)会转换为AdvisedResponse
,并携带共享的AdvisorContext
。 - 响应沿Advisor链反向传递 ,每个
Advisor
可对响应进行二次处理或修改(例如过滤敏感内容、格式化输出)。
- Chat Model生成的原始响应(
-
响应返回
最终的
AdvisedResponse
通过提取ChatCompletion
(响应核心内容)返回给客户端。
流程图如下:
2.3.设计特点
- 责任链模式
通过AdvisorChain
实现多个 Advisor 的链式调用,支持动态扩展增强逻辑。 - 上下文传递
AdvisedRequest
和AdvisedResponse
中的adviseContext
允许在链式调用中共享数据。 - 同步与流式分离
通过CallAroundAdvisor
和StreamAroundAdvisor
区分处理普通请求和流式请求。
2.4.Avisor相关源码解析
Advisor 接口位于org.springframework.ai.chat.client.advisor.api
包中,是实现自定义Advisor的关键接口:
java
public interface Advisor extends Ordered {
String getName();
}
同步和流式Advisor的两个子接口继承自Advisor:
- 同步的CallAroundAdvisor:
java
/**
* Around advisor that wraps the ChatModel#call(Prompt) method.
*
* @author Christian Tzolov
* @author Dariusz Jedrzejczyk
* @since 1.0.0
*/
public interface CallAroundAdvisor extends Advisor {
/**
* Around advice that wraps the ChatModel#call(Prompt) method.
* @param advisedRequest the advised request
* @param chain the advisor chain
* @return the response
*/
AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain);
}
- 流式的StreamAroundAdvisor:
java
/**
* Around advisor that runs around stream based requests.
*
* @author Christian Tzolov
* @author Dariusz Jedrzejczyk
* @since 1.0.0
*/
public interface StreamAroundAdvisor extends Advisor {
/**
* Around advice that wraps the invocation of the advised request.
* @param advisedRequest the advised request
* @param chain the chain of advisors to execute
* @return the result of the advised request
*/
Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain);
}
要使用Advice链,需在你的Advice实现中使用CallAroundAdvisorChain
和StreamAroundAdvisorChain
:
java
public interface CallAroundAdvisorChain {
AdvisedResponse nextAroundCall(AdvisedRequest advisedRequest);
}
java
public interface StreamAroundAdvisorChain {
Flux<AdvisedResponse> nextAroundStream(AdvisedRequest advisedRequest);
}
自定义Advisor就需要实现
CallAroundAdvisor
和StreamAroundAdvisor
中的最少一个。其中的关键方法是nextAroundCall()
或nextAroundStream()
。
3.Spring AI内置的Advisor
-
MessageChatMemoryAdvisor
作用:
责维护对话的上下文记忆,将用户的问题与模型的回答保存到内存中,确保多轮对话的连贯性。例如,在连续对话中,历史记录会被自动附加到新请求中,帮助模型理解上下文。
核心特点:
- 上下文增强 :通过
messages
参数传递历史对话记录。 - 模型兼容性要求 :仅适用于支持
messages
参数的模型(如 OpenAI 的 GPT 系列)。 - 动态扩展:每次对话自动更新内存中的历史记录。
- 上下文增强 :通过
-
PromptChatMemoryAdvisor
作用:
与
MessageChatMemoryAdvisor
类似,但将上下文历史记录封装到systemPrompt
提示词中,而非直接依赖messages
参数。这使得无论模型是否支持messages
参数,都能实现上下文记忆。核心特点:
- 灵活性 :通过修改系统提示词(
systemPrompt
)嵌入历史对话,兼容性更广。 - 无侵入式设计:不依赖模型底层接口,仅通过提示词工程实现上下文管理。
- 灵活性 :通过修改系统提示词(
-
QuestionAnswerAdvisor
作用:
实现检索增强生成(RAG),通过查询向量数据库或知识库获取相关文本片段,并将其附加到用户问题后,提升回答的准确性和相关性。
核心特点:
- 知识库集成 :支持自定义向量数据库(如:Milvus、Weaviate、Elasticsearch、FAISS)。
- 默认拒绝机制:若知识库无匹配内容,则拒绝回答用户问题,避免生成错误信息。
- 提示词优化:内置默认提示词模板,确保回答与检索内容强相关。
-
SafeGuardAdvisor
作用:
敏感词过滤与安全拦截,防止用户输入或模型输出包含违规内容。当检测到敏感词时,直接中断请求链,避免调用大模型处理。
核心特点:
- 实时拦截:基于预定义规则或动态词库进行校验。
- 链式中断:直接终止后续处理,降低资源消耗与安全风险。
-
VectorStoreChatMemoryAdvisor
作用:
将对话历史长期存储到向量数据库中,并在每次提问时检索相关历史记录,增强上下文提示的准确性和长期记忆能力。
核心特点:
- 向量化存储:利用向量数据库高效检索相似历史对话片段。
- 关键参数管理 :依赖
chat_memory_conversation_id
标识用户会话,避免数据冗余。 - 数据清理机制:需定期清理旧数据,防止数据库膨胀。
-
SimpleLoggerAdvisor
作用:
记录请求与响应的日志信息,便于调试和监控 AI 交互流程。例如,可打印用户输入、模型输出及处理耗时。
核心特点:
- 轻量级工具:无需复杂配置,快速集成日志功能。
- 可扩展性:支持自定义日志格式与存储方式。
4.自定义Advisor实现
4.1.自定义日志Advisor
我们自定义一个日志Advisor,在调用链中的下一个顾问之前记录AdvisedRequest
,之后记录AdvisedResponse
。
此advisor只观察请求和响应,不做任何膝盖且同时支持非流和流场景。
java
public class SimpleLoggerAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
private static final Logger logger = LoggerFactory.getLogger(SimpleLoggerAdvisor.class);
// 为Advisor提供一个唯一的名称
@Override
public String getName() {
return this.getClass().getSimpleName();
}
// 设置order值来控制执行顺序,值较小的将优先执行
@Override
public int getOrder() {
return 0;
}
@Override
public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
logger.debug("BEFORE: {}", advisedRequest);
AdvisedResponse advisedResponse = chain.nextAroundCall(advisedRequest);
logger.debug("AFTER: {}", advisedResponse);
return advisedResponse;
}
@Override
public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
logger.debug("BEFORE: {}", advisedRequest);
Flux<AdvisedResponse> advisedResponses = chain.nextAroundStream(advisedRequest);
// MessageAggregator是一个实用程序类,它将Flux响应聚合到单个AdvisedResponse中,
// MessageAggregator为只读,不可更改其中的响应
return new MessageAggregator().aggregateAdvisedResponse(advisedResponses,
advisedResponse -> logger.debug("AFTER: {}", advisedResponse));
}
}
4.2.Re2 Advisor
"重读提升大型语言模型的推理能力"一文介绍了一种名为重读(Re2)的技术,它可以提升大型语言模型的推理能力。Re2 技术需要像这样扩充输入提示:
{输入查询} 再次阅读问题:{Input_Query}
实现Re2技术的Advisor:
java
public class ReReadingAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
// 应用Re2增强用户的输入查询
private AdvisedRequest before(AdvisedRequest advisedRequest) {
Map<String, Object> advisedUserParams = new HashMap<>(advisedRequest.userParams());
advisedUserParams.put("re2_input_query", advisedRequest.userText());
return AdvisedRequest.from(advisedRequest)
.userText("""
{re2_input_query}
Read the question again: {re2_input_query}
""")
.userParams(advisedUserParams)
.build();
}
// 拦截非流式请求并应用Re2
@Override
public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
return chain.nextAroundCall(this.before(advisedRequest));
}
// 拦截流试请求并应用Re2技术
@Override
public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
return chain.nextAroundStream(this.before(advisedRequest));
}
@Override
public int getOrder() {
return 0;
}
@Override
public String getName() {
return this.getClass().getSimpleName();
}
}
5.Advisor使用示例
我们以MessageChatMemoryAdvisor
为例做一个advisor的使用实例,主要在ChatClient.builder中使用defaultAdvisors()方法配置Advisor,此方法可配置多个Advisor。
java
Builder defaultAdvisors(Advisor... advisor);
Builder defaultAdvisors(Consumer<AdvisorSpec> advisorSpecConsumer);
Builder defaultAdvisors(List<Advisor> advisors);
示例主要有controller、service及config配置 ,相关的pom依赖主要使用spring-ai-starter-model-minimax
包等,具体的pom及minimax模型 的配置请参考:Spring AI开发跃迁指南(第二章:极速上手------ChatClient20行代码构建人工智能应用)
5.1.示例代码
- ChatConfig
java
package com.common;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
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 ChatMemory chatMemory() {
return new InMemoryChatMemory(); // 简单内存实现
}
// 2. 创建 MessageChatMemoryAdvisor
@Bean
public MessageChatMemoryAdvisor chatMemoryAdvisor(ChatMemory chatMemory) {
return new MessageChatMemoryAdvisor(chatMemory);
}
// 配置 ChatClient,绑定 Advisor
@Bean
public ChatClient chatClient(ChatModel chatModel, MessageChatMemoryAdvisor advisor) {
return ChatClient.builder(chatModel)
.defaultAdvisors(advisor) // 添加 Advisor
.build();
}
}
- service
java
@Service
public class TestSpringAIServiceImpl {
@Autowired
private ChatClient chatClient;
@Override
public String generate(String message) {
return chatClient.prompt()
.advisors(advisorSpec -> advisorSpec
.param("chat_memory_conversation_id", "111")
.param("chat_memory_response_size", 100))
.user(message)
.call()
.content();
}
}
- controller
java
@RestController
public class TestSpringAIController {
@Autowired
private TestSpringAIServiceImpl service;
@GetMapping("/ai/generate")
public String generate(@RequestParam(value = "message", defaultValue = "生成一个中国女演员及其电影作品") String message) {
return service.generate(message);
}
}
- 运行结果
-
第一次运行结果:
-
第二次运行结果:
-
执行结果分析
- 第一次对话 :声明自己的名字为"张三",
MessageChatMemoryAdvisor
会将此对话记录(用户输入和模型回复)保存到内存中。 - 第二次对话 :用户提问"我的名字是什么?",模型会根据
MessageChatMemoryAdvisor
提供的上下文历史(包含第一次对话)生成正确回答。
5.2.关键机制解释
-
内存管理
InMemoryChatMemory
默认以List<Message>
形式存储对话历史,每次调用chatClient.call()
时,MessageChatMemoryAdvisor
会自动将历史记录附加到当前请求中(通过messages
参数传递)。 -
上下文传递
模型(如 OpenAI GPT)接收到完整的
messages
列表后,会自动解析历史对话,确保回答的连贯性。 -
会话隔离
若需区分不同用户的对话,需通过
ChatMemory
的conversationId
参数管理会话标识:java// 为不同用户分配唯一会话 ID ChatMemory memory = new InMemoryChatMemory("user-123");
若需自定义历史记录的条数或存储策略:
java
@Bean
public ChatMemory chatMemory() {
InMemoryChatMemory memory = new InMemoryChatMemory();
memory.setMaxHistorySize(10); // 限制最多保留 10 条历史记录
return memory;
}
注意:
- 模型兼容性 :确保底层模型(如 OpenAI、MiniMax)支持
messages
参数格式。- 内存泄漏风险 :若使用
InMemoryChatMemory
,需在长期运行的应用中定期清理过期会话。