Advisors API
Spring AI Advisors API 提供了一种灵活且强大的方式,用于拦截、修改和增强 Spring 应用程序中的 AI 交互。借助 Advisors API,开发人员可以创建更加复杂、可复用且易于维护的 AI 组件。
主要优势包括:封装重复出现的生成式 AI 模式,转换发送给大型语言模型(LLMs)的数据以及从 LLMs 接收的数据,并在多种模型和使用场景中提供可移植性。
您可以通过 ChatClient API 配置现有的 advisors,示例如下:
ChatMemory chatMemory = ... // Initialize your chat memory store
VectorStore vectorStore = ... // Initialize your vector store
var chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build(), // chat-memory advisor
QuestionAnswerAdvisor.builder(vectorStore).build() // RAG advisor
)
.build();
var conversationId = "678";
String response = this.chatClient.prompt()
// Set advisor parameters at runtime
.advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, conversationId))
.user(userText)
.call()
.content();
建议使用构建器的 defaultAdvisors() 方法在构建时注册 advisors。
Advisor 也参与可观测性(Observability)技术栈,因此您可以查看与其执行相关的指标(metrics)和追踪(traces)。
核心组件
API 由 CallAdvisor 和 CallAdvisorChain(用于非流式场景)以及 StreamAdvisor 和 StreamAdvisorChain(用于流式场景)组成。此外,它还包含 ChatClientRequest,用于表示未封装的 Prompt 请求;以及 ChatClientResponse,用于表示 Chat Completion 响应。两者都持有 advise-context,以便在 advisor 链中共享状态。

adviseCall() 和 adviseStream() 是核心的 Advisor 方法,通常执行诸如检查未密封的 Prompt 数据、定制和增强 Prompt 数据、调用 Advisor 链中的下一个实体、可选地阻止请求、检查聊天补全响应以及抛出异常以指示处理错误等操作。
此外,getOrder() 方法用于确定链中顾问(advisor)的顺序,而 getName() 方法则提供唯一的顾问名称。
Advisor Chain(由 Spring AI 框架创建)支持按照各 advisor 的 getOrder() 值对多个 advisor 进行排序,并按顺序依次调用。值较小的 advisor 会先执行。自动添加的最后一个 advisor 负责将请求发送给 LLM。
以下流程图展示了顾问链与 Chat Model 之间的交互:

-
Spring AI 框架从用户的
Prompt及一个空的 advisorcontext对象创建一个ChatClientRequest。 -
链中的每个 advisor 都会处理请求,并可能对其进行修改。或者,它可以选择阻断请求,即不调用
invoke来执行下一个实体。在后一种情况下,由该 advisor 负责填充响应。 -
由框架提供的最后一个 advisor 会将请求发送给
Chat Model。 -
Chat Model的响应随后通过 advisor 链回传,并转换为ChatClientResponse。其中包含共享的 advisorcontext实例。 -
每个 advisor 都可以处理或修改响应。
-
最终通过提取
ChatCompletion,将ChatClientResponse返回给客户端。
Advisor Order
链中顾问(advisors)的执行顺序由 getOrder() 方法决定。需要理解的关键点:
-
订单值(order value)较低的顾问(Advisor)会先执行。
-
顾问链(advisor chain)作为一个栈(stack)运行:
-
链中的第一个顾问最先处理请求。
-
它也是最后处理响应的顾问。
-
-
若要控制执行顺序:
-
将 order 设置为接近
Ordered.HIGHEST_PRECEDENCE,以确保顾问在链中首先执行(请求处理时最先,响应处理时最后)。 -
将 order 设置为接近
Ordered.LOWEST_PRECEDENCE,以确保顾问在链中最后执行(请求处理时最后,响应处理时最先)。
-
-
值越大,解释为优先级越低。
-
如果多个顾问具有相同的 order 值,则它们的执行顺序不予保证。
顺序与执行序列之间看似矛盾之处,源于建议者链(advisor chain)的栈式特性:
- 具有最高优先级(最低 order 值)的建议者会被添加到栈顶。
- 随着栈展开(unwind),它将最先处理请求。
- 随着栈回退(rewind),它将最后处理响应。
作为提醒,以下是 Spring Ordered 接口的语义:
public interface Ordered {
/**
* Constant for the highest precedence value.
* @see java.lang.Integer#MIN_VALUE
*/
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
/**
* Constant for the lowest precedence value.
* @see java.lang.Integer#MAX_VALUE
*/
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
/**
* Get the order value of this object.
* <p>Higher values are interpreted as lower priority. As a consequence,
* the object with the lowest value has the highest priority (somewhat
* analogous to Servlet {@code load-on-startup} values).
* <p>Same order values will result in arbitrary sort positions for the
* affected objects.
* @return the order value
* @see #HIGHEST_PRECEDENCE
* @see #LOWEST_PRECEDENCE
*/
int getOrder();
}
对于需要在输入端和输出端都位于链首的使用场景:
- 为每一端使用独立的 advisor。
- 为它们配置不同的 order 值。
- 使用 advisor context 在它们之间共享状态。
API 概述
主要的 Advisor 接口位于包 org.springframework.ai.chat.client.advisor.api 中。创建自定义 Advisor 时,您将会遇到以下关键接口:
public interface Advisor extends Ordered {
String getName();
}
同步和响应式 Advisor 的两个子接口是
public interface CallAdvisor extends Advisor {
ChatClientResponse adviseCall(
ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain);
}
and
public interface StreamAdvisor extends Advisor {
Flux<ChatClientResponse> adviseStream(
ChatClientRequest chatClientRequest, StreamAdvisorChain streamAdvisorChain);
}
要在 Advice 中继续调用 Advice 链,请在你的 Advice 实现中使用 CallAdvisorChain 和 StreamAdvisorChain:
这些接口是
public interface CallAdvisorChain extends AdvisorChain {
/**
* Invokes the next {@link CallAdvisor} in the {@link CallAdvisorChain} with the given
* request.
*/
ChatClientResponse nextCall(ChatClientRequest chatClientRequest);
/**
* Returns the list of all the {@link CallAdvisor} instances included in this chain at
* the time of its creation.
*/
List<CallAdvisor> getCallAdvisors();
}
and
public interface StreamAdvisorChain extends AdvisorChain {
/**
* Invokes the next {@link StreamAdvisor} in the {@link StreamAdvisorChain} with the
* given request.
*/
Flux<ChatClientResponse> nextStream(ChatClientRequest chatClientRequest);
/**
* Returns the list of all the {@link StreamAdvisor} instances included in this chain
* at the time of its creation.
*/
List<StreamAdvisor> getStreamAdvisors();
}
实现 Advisor
要创建一个顾问,需实现 CallAdvisor 或 StreamAdvisor(或同时实现两者)。需要实现的关键方法是非流式场景下的 nextCall() 或流式场景下的 nextStream()。
示例
我们将提供几个动手示例,以说明如何实现顾问(Advisors)来观察和增强用例。
日志顾问
我们可以实现一个简单的日志记录切面,在调用链中下一个切面前记录 ChatClientRequest,在调用后记录 ChatClientResponse。请注意,该切面仅观察请求和响应,不会对其进行修改。此实现同时支持非流式和流式场景。
public class SimpleLoggerAdvisor implements CallAdvisor, StreamAdvisor {
private static final Logger logger = LoggerFactory.getLogger(SimpleLoggerAdvisor.class);
@Override
public String getName() { 1
return this.getClass().getSimpleName();
}
@Override
public int getOrder() { 2
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); 3
}
private void logRequest(ChatClientRequest request) {
logger.debug("request: {}", request);
}
private void logResponse(ChatClientResponse chatClientResponse) {
logger.debug("response: {}", chatClientResponse);
}
}
为 advisor 提供一个唯一的名称。
你可以通过设置 order 值来控制执行顺序。值越小,执行优先级越高。
MessageAggregator是一个实用类,用于将 Flux 响应聚合为单个 ChatClientResponse。这对于日志记录或其他需要观察整个响应(而非流中的单个项)的处理场景非常有用。注意,由于这是一个只读操作,你无法在MessageAggregator中修改响应。
重读(Re2)顾问
"重新阅读提升大语言模型的推理能力" 一文介绍了一种名为 Re-Reading (Re2) 的技术,该技术能够提升大语言模型的推理能力。Re2 技术需要对输入提示词进行如下增强:
{Input_Query}
Read the question again: {Input_Query}
实现一个将 Re2 技术应用于用户输入查询的顾问可以这样做:
public class ReReadingAdvisor implements BaseAdvisor {
private static final String DEFAULT_RE2_ADVISE_TEMPLATE = """
{re2_input_query}
Read the question again: {re2_input_query}
""";
private final String re2AdviseTemplate;
private int order = 0;
public ReReadingAdvisor() {
this(DEFAULT_RE2_ADVISE_TEMPLATE);
}
public ReReadingAdvisor(String re2AdviseTemplate) {
this.re2AdviseTemplate = re2AdviseTemplate;
}
@Override
public ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain) { 1
String augmentedUserText = PromptTemplate.builder()
.template(this.re2AdviseTemplate)
.variables(Map.of("re2_input_query", chatClientRequest.prompt().getUserMessage().getText()))
.build()
.render();
return chatClientRequest.mutate()
.prompt(chatClientRequest.prompt().augmentUserMessage(augmentedUserText))
.build();
}
@Override
public ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain) {
return chatClientResponse;
}
@Override
public int getOrder() { 2
return this.order;
}
public ReReadingAdvisor withOrder(int order) {
this.order = order;
return this;
}
}
before方法通过应用 Re-Reading 技术来增强用户的输入查询。您可以通过设置顺序值来控制执行顺序。较小的值会先执行。
Spring AI 内置顾问
Spring AI 框架提供了多个内置的 advisors 以增强您的 AI 交互体验。以下是可用的 advisors 概览:
聊天记忆顾问
这些顾问在聊天记忆存储中管理对话历史记录:
-
MessageChatMemoryAdvisor检索记忆并将其作为消息集合添加到提示词中。这种方法保留了对话历史的结构。请注意,并非所有 AI 模型都支持这种方法。
-
VectorStoreChatMemoryAdvisor从
VectorStore中检索记忆,并将其添加到提示词的system文本中。该advisor适用于从大型数据集中高效搜索和检索相关信息。
Question Answering Advisor
-
QuestionAnswerAdvisor该顾问使用向量存储提供问答能力,实现了 Naive RAG(检索增强生成)模式。
-
RetrievalAugmentationAdvisor使用
org.springframework.ai.rag包中定义的构建模块并遵循模块化 RAG 架构,实现了常见的检索增强生成(RAG)流程的顾问。
推理建议器
-
ReReadingAdvisor实现了一种用于 LLM 推理的复读策略,称为 RE2,以增强输入阶段的理解能力。基于文章:Re-Reading Improves Reasoning in LLMs。
Tool Calling Advisor
-
ToolCallingAdvisor作为 advisor 链的一部分处理工具调用循环。该 advisor 始终由
ChatClient自动注册(除非明确禁用),因此即使未配置静态工具,也支持由其他 advisor 在运行时注入的工具。它会执行模型请求的工具调用并返回结果,持续迭代直到不再需要工具调用。实现了ToolAdvisor,这是一个标记接口,用于防止第二个ToolCallingAdvisor被自动注册。完整文档请参阅 Recursive Advisors - ToolCallingAdvisor 和 ChatClient - Tool Calling。
内容安全顾问
-
SafeGuardAdvisor一个旨在防止模型生成有害或不恰当内容的简单顾问(advisor)。
流式与非流式

- 非流式顾问(Non-streaming advisors)处理完整的请求和响应。
- 流式顾问(Streaming advisors)将请求和响应作为连续的数据流处理,使用响应式编程概念(例如,使用 Flux 处理响应)。
@Override
public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest, StreamAdvisorChain chain) {
return Mono.just(chatClientRequest)
.publishOn(Schedulers.boundedElastic())
.map(request -> {
// This can be executed by blocking and non-blocking Threads.
// Advisor before next section
})
.flatMapMany(request -> chain.nextStream(request))
.map(response -> {
// Advisor after next section
});
}
最佳实践
-
保持 Advisor 专注于特定任务,以获得更好的模块性。
-
必要时使用
adviseContext在 Advisor 之间共享状态。 -
为你的 Advisor 实现流式和非流式版本,以获得最大的灵活性。
-
仔细考虑 Advisor 链中 Advisor 的顺序,以确保数据流正确。
破坏性 API 变更
顾问接口
-
在 1.0 M2 版本中,存在独立的
RequestAdvisor和ResponseAdvisor接口。-
RequestAdvisor会在ChatModel.call和ChatModel.stream方法执行之前被调用。 -
ResponseAdvisor会在这些方法执行之后被调用。
-
-
在 1.0 M3 版本中,这些接口已被替换为:
-
CallAroundAdvisor -
StreamAroundAdvisor
-
-
此前属于
ResponseAdvisor的StreamResponseMode已被移除。 -
在 1.0.0 版本中,这些接口已被替换:
-
CallAroundAdvisor→CallAdvisor,StreamAroundAdvisor→StreamAdvisor,CallAroundAdvisorChain→CallAdvisorChain以及StreamAroundAdvisorChain→StreamAdvisorChain。 -
AdvisedRequest→ChatClientRequest以及AdivsedResponse→ChatClientResponse。
-
上下文映射处理
-
在 1.0 M2 中:
-
上下文映射是一个独立的方法参数。
-
该映射是可变的,并沿着调用链传递。
-
-
在 1.0 M3 中:
-
上下文映射现在是
AdvisedRequest和AdvisedResponse记录的一部分。 -
该映射是不可变的。
-
要更新上下文,请使用
updateContext方法,该方法会创建一个包含更新内容的新不可变映射。
-
章节摘要
递归顾问
Recursive advisors 是一种特殊类型的 advisor,它可以多次循环执行下游 advisor 链。当你需要反复调用 LLM,直到满足某个条件时,这种模式非常有用,例如: