Advisors API
Spring AI Advisors API 提供了一种灵活而强大的方式来拦截、修改和增强 Spring 应用程序中的 AI 驱动交互。 通过利用 Advisors API,开发人员可以创建更复杂、可重用和可维护的 AI 组件。
主要优势包括封装重复出现的生成式 AI 模式、转换与大型语言模型 (LLM) 发送和发送的数据,以及提供跨各种模型和用例的可移植性。
您可以使用 ChatClient API 配置现有顾问,如以下示例所示:
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();
建议在构建时使用 builder 的defaultAdvisors()
方法。
顾问还参与可观测性堆栈,因此您可以查看与其执行相关的指标和跟踪。
核心组件
该 API 包括CallAdvisor
和CallAdvisorChain
对于非流式处理方案,以及StreamAdvisor
和StreamAdvisorChain
用于流式处理方案。
它还包括ChatClientRequest
表示未密封的 Prompt 请求,ChatClientResponse
用于聊天补全响应。两者都持有advise-context
在整个顾问链中共享状态。

这adviseCall()
和adviseStream()
是关键的顾问方法,通常执行诸如检查未密封的 Prompt 数据、自定义和扩充 Prompt 数据、调用顾问链中的下一个实体、(可选)阻止请求、检查聊天补全响应以及抛出异常以指示处理错误等作。
此外,getOrder()
方法确定链中的顾问顺序,而getName()
提供唯一的顾问名称。
由 Spring AI 框架创建的 Advisor Chain 允许按顺序调用由其getOrder()
值。
首先执行较低的值。
自动添加的最后一个顾问将请求发送到 LLM。
以程图说明了顾问链和聊天模型之间的交互:

-
Spring AI 框架创建了一个
ChatClientRequest
从用户的Prompt
以及一个空的顾问context
对象。 -
链中的每个顾问都处理请求,可能会对其进行修改。或者,它可以选择通过不调用调用下一个实体来阻止请求。在后一种情况下,顾问负责填写回复。
-
框架提供的最终顾问将请求发送到
Chat Model
. -
然后,聊天模型的响应通过顾问链传回并转换为
ChatClientResponse
.Later 包括共享顾问context
实例。 -
每个顾问都可以处理或修改响应。
-
决赛
ChatClientResponse
通过提取ChatCompletion
.
Advisor Order
链中顾问的执行顺序由getOrder()
方法。要了解的要点:
-
订单价值较低的顾问首先被执行。
-
顾问链作为堆栈运行:
-
链中的第一个顾问是第一个处理请求的顾问。
-
它也是最后处理响应的。
-
-
要控制执行顺序:
-
将订单设置为接近
Ordered.HIGHEST_PRECEDENCE
以确保顾问在链中首先执行(首先用于请求处理,最后用于响应处理)。 -
将订单设置为接近
Ordered.LOWEST_PRECEDENCE
以确保顾问在链中最后执行(最后执行请求处理,首先执行响应处理)。
-
-
较高的值被解释为较低的优先级。
-
如果多个顾问具有相同的订单值,则无法保证其执行顺序。
订单和执行顺序之间看似矛盾是由于顾问链的堆栈性质:
|
提醒一下,这里是 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();
}
对于需要在输入端和输出端都排在链中的第一个的用例:
|
API 概述
主要的 Advisor 接口位于包中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);
}
要继续建议链,请使用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();
}
和
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();
}
实施顾问
要创建顾问,请实现CallAdvisor
或StreamAdvisor
(或两者兼而有之)。实现的关键方法是nextCall()
对于非流式传输或nextStream()
适用于流媒体顾问。
例子
我们将提供一些动手示例来说明如何实施顾问来观察和增强用例。
日志记录顾问
我们可以实现一个简单的日志记录顾问,记录ChatClientRequest
before 和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);
}
}
1 | 为顾问提供唯一名称。 |
2 | 您可以通过设置订单值来控制执行顺序。较低的值首先执行。 |
3 | 这MessageAggregator 是一个实用程序类,用于将 Flux 响应聚合到单个 ChatClientResponse 中。
这对于日志记录或其他观察整个响应而不是流中的单个项的处理非常有用。
请注意,您无法更改MessageAggregator 因为它是只读作。 |
重读 (Re2) 顾问
“重读提高大型语言模型中的推理”一文介绍了一种称为重读 (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;
}
}
1 | 这before 方法应用重读技术来增强用户的输入查询。 |
2 | 您可以通过设置订单值来控制执行顺序。较低的值首先执行。 |
Spring AI 内置顾问
Spring AI 框架提供了多个内置顾问来增强您的 AI 交互。以下是可用顾问的概述:
聊天记忆顾问
这些顾问在聊天内存存储中管理对话历史记录:
-
MessageChatMemoryAdvisor
检索内存并将其作为消息集合添加到提示中。此方法维护对话历史记录的结构。请注意,并非所有 AI 模型都支持这种方法。
-
PromptChatMemoryAdvisor
检索内存并将其合并到提示的系统文本中。
-
VectorStoreChatMemoryAdvisor
从 VectorStore 检索内存并将其添加到提示的系统文本中。该顾问对于从大型数据集中有效地搜索和检索相关信息非常有用。
问答顾问
-
QuestionAnswerAdvisor
此顾问使用向量存储来提供问答功能,实现朴素 RAG(检索增强生成)模式。
-
RetrievalAugmentationAdvisor
Advisor that implements common 检索增强生成(RAG) flows using the building blocks defined in the `org.springframework.ai.rag` package and following the Modular RAG Architecture.
推理顾问
-
ReReadingAdvisor
实施 LLM 推理的重读策略,称为 RE2,以增强输入阶段的理解。 基于文章:[重读改善法学硕士的推理](arxiv.org/pdf/2309.06275)。
流媒体与非流媒体

-
非流式处理顾问处理完整的请求和响应。
-
流顾问使用响应式编程概念(例如,响应的 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
});
}
重大 API 更改
顾问接口
-
在 1.0 M2 中,有单独的
RequestAdvisor
和ResponseAdvisor
接口。-
RequestAdvisor
在ChatModel.call
和ChatModel.stream
方法。 -
ResponseAdvisor
在这些方法之后调用。
-
-
在 1.0 M3 中,这些接口已替换为:
-
CallAroundAdvisor
-
StreamAroundAdvisor
-
-
这
StreamResponseMode
,以前是ResponseAdvisor
,已被删除。 -
在 1.0.0 中,这些接口已被替换:
-
CallAroundAdvisor
→CallAdvisor
,StreamAroundAdvisor
→StreamAdvisor
,CallAroundAdvisorChain
→CallAdvisorChain
和StreamAroundAdvisorChain
→StreamAdvisorChain
. -
AdvisedRequest
→ChatClientRequest
是AdivsedResponse
→ChatClientResponse
.
-