爆米花烘焙
66.80M · 2026-04-14
Advisor 所对应的 Advisors API,提供了一种灵活而强大的方式来拦截、修改和增强 Spring 应用程序中 AI 驱动的交互。
当使用用户文本调用 AI 模型时,常见的模式是用上下文数据附加或增强提示。此上下文数据可以是不同类型,常见类型包括:
借助 Advisors API,开发者可以封装重复的生成式 AI 模式、转换发往大型语言模型(LLM)及从其接收的数据,并在不同模型与用例之间提供可移植性。
AdvisorSpecChatClient 的流畅 API 提供 AdvisorSpec 接口,用于配置 Advisor。该接口支持:添加参数、一次设置多个参数、向链中加入一个或多个 Advisor。
interface AdvisorSpec {
AdvisorSpec param(String k, Object v);
AdvisorSpec params(Map<String, Object> p);
AdvisorSpec advisors(Advisor... advisors);
AdvisorSpec advisors(List<Advisor> advisors);
}
重要约定:Advisor 在链中的添加顺序会影响执行逻辑;每个 Advisor 都会以某种方式修改提示或上下文,前一个 Advisor 的变更会传递给链中的下一个。
ChatClient.builder(chatModel)
.build()
.prompt()
.advisors(
MessageChatMemoryAdvisor.builder(chatMemory).build(),
QuestionAnswerAdvisor.builder(vectorStore).build()
)
.user(userText)
.call()
.content();
在此配置中,MessageChatMemoryAdvisor 会先执行,将对话历史加入提示;随后 QuestionAnswerAdvisor 会基于用户问题以及已加入的对话历史执行检索,从而可能得到更相关的结果。
视角 A(advisors() 注册与 order)
.advisors(A, B, C) 传入的顺序即注册顺序。order 升序(小 → 大)排序。order 相同,则按你传入的顺序执行。内置 Advisor 的默认 order
order 全部为 0。MessageChatMemoryAdvisor 与 QuestionAnswerAdvisor 默认均为 order = 0,执行顺序为:先 MessageChatMemoryAdvisor,后 QuestionAnswerAdvisor(与传入顺序一致)。建议在构建时使用构建器的 defaultAdvisors() 注册 Advisor;运行时可通过 advisors(advisor -> advisor.param(...)) 传入参数。
ChatMemory chatMemory = ... // 初始化聊天记忆
VectorStore vectorStore = ... // 初始化向量存储
var chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build(),
QuestionAnswerAdvisor.builder(vectorStore).build()
)
.build();
var conversationId = "678";
String response = this.chatClient.prompt()
.advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, conversationId))
.user(userText)
.call()
.content();
QuestionAnswerAdvisor 使用向量存储提供问答能力,实现 Naive RAG(检索增强生成) 模式。更完整的 RAG 流程还可参阅官方Spring AI中的 检索增强生成相关指南;另有 RetrievalAugmentationAdvisor,基于 org.springframework.ai.rag 中的构建块与模块化 RAG 架构实现常见 RAG 流。
SimpleLoggerAdvisorSimpleLoggerAdvisor 会记录 ChatClient 的 request 与 response 数据,便于调试与监控 AI 交互。
在创建 ChatClient 或单次 prompt 时将其加入 Advisor 链;建议放在链的末尾。
ChatResponse response = ChatClient.create(chatModel).prompt()
.advisors(new SimpleLoggerAdvisor())
.user("Tell me a joke?")
.call()
.chatResponse();
要看到日志,需将 Advisor 包的日志级别设为 DEBUG(写入 application.properties 或 application.yaml):
logging.level.org.springframework.ai.chat.client.advisor=DEBUG
可通过构造函数自定义从 AdvisedRequest 与 ChatResponse 中记录的内容,并指定 order:
SimpleLoggerAdvisor(
Function<ChatClientRequest, String> requestToString,
Function<ChatResponse, String> responseToString,
int order
)
示例:
SimpleLoggerAdvisor customLogger = new SimpleLoggerAdvisor(
request -> "Custom request: " + request.prompt().getUserMessage(),
response -> "Custom response: " + response.getResult(),
0
);
注意:生产环境需谨慎记录敏感信息。
BaseAdvisor:同步与流式的统一模板BaseAdvisor 是 Spring AI 中统一同步 / 流式调用的模板化增强接口,用于减少重复代码,使自定义增强逻辑(如提示词改写、日志、安全校验)同时适配 call() 与 stream()。
BaseAdvisor 继承 CallAdvisor 与 StreamAdvisor(或旧版 CallAroundAdvisor / StreamAroundAdvisor),作为双模式增强的统一入口。default 方法封装通用流程(before → 调用链 → after),开发者主要实现 before / after,无需分别手写同步与流式的样板代码。getOrder() 顺序控制。public interface BaseAdvisor extends CallAdvisor, StreamAdvisor {
@Override
default ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
ChatClientRequest processed = before(request, chain);
ChatClientResponse response = chain.nextCall(processed);
return after(response, chain);
}
@Override
default Flux<ChatClientResponse> adviseStream(ChatClientRequest request, StreamAdvisorChain chain) {
return Mono.just(request)
.map(req -> before(req, chain))
.flatMapMany(chain::nextStream)
.map(res -> after(res, chain));
}
ChatClientRequest before(ChatClientRequest request, AdvisorChainContext context);
ChatClientResponse after(ChatClientResponse response, AdvisorChainContext context);
int getOrder(); // 值越小优先级越高,默认 0
}
before:请求发往模型前执行。after:模型返回响应后执行。getOrder:多个 Advisor 时的执行顺序,值越小越先执行。CallAdvisor、CallAdvisorChain。StreamAdvisor、StreamAdvisorChain。ChatClientRequest(未封装的 Prompt 请求)、ChatClientResponse(聊天完成响应)。adviseCall() 与 adviseStream() 是关键方法,典型工作包括:检查 Prompt 数据、自定义与增强 Prompt、调用链中下一节点、可选地阻止请求、检查聊天完成响应、在错误时抛异常等。
此外,getOrder() 决定链中顺序,getName() 提供唯一名称。
ChatClientRequest。ChatClientResponse,其中包含共享的 Advisor context。ChatCompletion,将 ChatClientResponse 返回给客户端。getOrder() 与「堆栈」语义与 Spring Ordered 接口一致:
Ordered.HIGHEST_PRECEDENCE:更小数值,更高优先级。Ordered.LOWEST_PRECEDENCE:更大数值,更低优先级。public interface Ordered {
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
int getOrder();
}
材料中强调:优先级最高(order 值最低)的 Advisor 相当于在堆栈顶部;展开时最先处理请求,回卷时最后处理响应——这与「谁先谁后」的直观列表顺序容易混淆,需结合 order 与堆栈式回卷一起理解。
主要接口位于包 org.springframework.ai.chat.client.advisor.api。
public interface Advisor extends Ordered {
String getName();
}
同步与响应式子接口:
public interface CallAdvisor extends Advisor {
ChatClientResponse adviseCall(
ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain);
}
public interface StreamAdvisor extends Advisor {
Flux<ChatClientResponse> adviseStream(
ChatClientRequest chatClientRequest, StreamAdvisorChain streamAdvisorChain);
}
要继续 Advice 链,在实现中调用:
public interface CallAdvisorChain extends AdvisorChain {
ChatClientResponse nextCall(ChatClientRequest chatClientRequest);
List<CallAdvisor> getCallAdvisors();
}
public interface StreamAdvisorChain extends AdvisorChain {
Flux<ChatClientResponse> nextStream(ChatClientRequest chatClientRequest);
List<StreamAdvisor> getStreamAdvisors();
}
实现时:非流式实现 adviseCall,流式实现 adviseStream(或同时实现两者)。
下列实现在调用下一 Advisor 之前记录 ChatClientRequest,在之后记录 ChatClientResponse,不修改请求与响应;同时覆盖非流式与流式。
public class SimpleLoggerAdvisor implements CallAdvisor, StreamAdvisor {
private static final Logger logger = LoggerFactory.getLogger(SimpleLoggerAdvisor.class);
@Override
public String getName() {
return this.getClass().getSimpleName();
}
@Override
public int getOrder() {
return 0;
}
@Override
public ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {
logRequest(chatClientRequest);
ChatClientResponse chatClientResponse = callAdvisorChain.nextCall(chatClientRequest);
logResponse(chatClientResponse);
return chatClientResponse;
}
@Override
public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest,
StreamAdvisorChain streamAdvisorChain) {
logRequest(chatClientRequest);
Flux<ChatClientResponse> chatClientResponses = streamAdvisorChain.nextStream(chatClientRequest);
return new ChatClientMessageAggregator().aggregateChatClientResponse(chatClientResponses, this::logResponse);
}
private void logRequest(ChatClientRequest request) {
logger.debug("request: {}", request);
}
private void logResponse(ChatClientResponse chatClientResponse) {
logger.debug("response: {}", chatClientResponse);
}
}
说明摘要:
getName():提供唯一名称。getOrder():控制顺序,值越低越早。MessageAggregator:将 Flux 响应聚合为单个 ChatClientResponse,便于整体记录或观察;材料注明其为只读,不能在聚合器中改响应。《重读提高大型语言模型的推理能力》一文中的 Re2 技术,需要将用户查询增强为类似形式:
{Input_Query}
Read the question again: {Input_Query}
基于 BaseAdvisor 的示例实现要点:
before 中用模板把用户消息改写为上述结构。after 中可直接返回原响应。withOrder(int order) 或字段设置 getOrder()。(完整代码见给定材料中的 ReReadingAdvisor 类。)
聊天记忆类
MessageChatMemoryAdvisor:从记忆检索并作为消息集合加入 Prompt;维护对话结构;并非所有模型都支持。PromptChatMemoryAdvisor:检索记忆并合并到 系统文本。VectorStoreChatMemoryAdvisor:从 VectorStore 检索记忆并写入系统文本,适合大规模检索。问答 / RAG
QuestionAnswerAdvisor:基于向量存储的 Naive RAG。RetrievalAugmentationAdvisor:基于 org.springframework.ai.rag 与模块化 RAG 架构的常见 RAG 流。推理
ReReadingAdvisor:实现 RE2 重读策略以加强输入阶段理解(参见原文 arxiv 论文链接)。内容安全
SafeGuardAdvisor:用于降低有害或不适当内容生成风险。