Advisors API
Spring AI Advisors API 提供了一种灵活而强大的方法来拦截、修改和增强 Spring 应用程序中的 AI 驱动的交互。 通过利用 Advisors API,开发人员可以创建更复杂、可重用和可维护的 AI 组件。
主要优势包括封装重复的生成式 AI 模式、转换发送到语言模型 (LLM) 和从语言模型 (LLM) 发送的数据,以及提供跨各种模型和用例的可移植性。
您可以使用 ChatClient API 配置现有顾问,如以下示例所示:
var chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
new MessageChatMemoryAdvisor(chatMemory), // chat-memory advisor
new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults()) // RAG advisor
)
.build();
String response = this.chatClient.prompt()
// Set advisor parameters at runtime
.advisors(advisor -> advisor.param("chat_memory_conversation_id", "678")
.param("chat_memory_response_size", 100))
.user(userText)
.call()
.content();
建议在构建时使用 builder 的方法注册 advisor。defaultAdvisors()
顾问还参与可观测性堆栈,因此您可以查看与其执行相关的指标和跟踪。
核心组件
API 由非流式处理方案和 和 流式处理方案组成。
它还包括表示 Chat Completion 响应的未密封 Prompt 请求。两者都在 advisor 链中持有 to share 状态。CallAroundAdvisor
CallAroundAdvisorChain
StreamAroundAdvisor
StreamAroundAdvisorChain
AdvisedRequest
AdvisedResponse
advise-context
和 是关键的 advisor 方法,通常执行各种操作,例如检查未密封的 Prompt 数据、自定义和扩充 Prompt 数据、调用 advisor 链中的下一个实体、选择性地阻止请求、检查聊天完成响应以及引发异常以指示处理错误。nextAroundCall()
nextAroundStream()
此外,该方法确定链中的 advisor 顺序,同时提供唯一的 advisor 名称。getOrder()
getName()
由 Spring AI 框架创建的 Advisor 链允许按顺序调用多个按其值排序的 advisor。
首先执行较低的值。
自动添加的最后一个 advisor 将请求发送到 LLM。getOrder()
以程图说明了顾问链和聊天模型之间的交互:
-
Spring AI 框架创建一个 from user's 以及一个空对象。
AdvisedRequest
Prompt
AdvisorContext
-
链中的每个 advisor 都会处理请求,并可能对其进行修改。或者,它也可以选择通过不调用下一个实体来阻止请求。在后一种情况下,顾问负责填写回复。
-
框架提供的最后一个 advisor 将请求发送到 .
Chat Model
-
然后,聊天模型的响应将通过顾问链传回并转换为 .later 包括共享实例。
AdvisedResponse
AdvisorContext
-
每个顾问都可以处理或修改响应。
-
final 通过提取 .
AdvisedResponse
ChatCompletion
顾问订单
链中 advisor 的执行顺序由方法决定。需要了解的要点:getOrder()
-
首先执行订单值较低的顾问。
-
advisor 链以堆栈的形式运行:
-
链中的第一个 advisor 是第一个处理请求的人。
-
它也是最后一个处理响应的服务器。
-
-
要控制执行顺序:
-
将 order close 设置为 以确保 advisor 在链中首先执行 (first 用于请求处理,last 用于响应处理)。
Ordered.HIGHEST_PRECEDENCE
-
将订单 close 设置为 以确保 advisor 在链中最后执行 (last 用于请求处理,first 用于响应处理)。
Ordered.LOWEST_PRECEDENCE
-
-
较高的值被解释为较低的优先级。
-
如果多个 advisor 具有相同的订单价值,则不能保证他们的执行顺序。
顺序和执行顺序之间看似矛盾是由于 advisor 链的堆栈性质: * 具有最高优先级 (最低订单价值) 的顾问被添加到堆栈顶部。 * 当堆栈展开时,它将第一个处理请求。 * 当堆栈倒带时,它将是最后一个处理响应的。 |
提醒一下,以下是 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 界面位于包 中。以下是您在创建自己的 advisor 时会遇到的关键界面:org.springframework.ai.chat.client.advisor.api
public interface Advisor extends Ordered {
String getName();
}
同步和反应式 Advisor 的两个子接口是
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);
}
和
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 实现中使用 and:CallAroundAdvisorChain
StreamAroundAdvisorChain
这些接口包括
public interface CallAroundAdvisorChain {
AdvisedResponse nextAroundCall(AdvisedRequest advisedRequest);
}
和
public interface StreamAroundAdvisorChain {
Flux<AdvisedResponse> nextAroundStream(AdvisedRequest advisedRequest);
}
实施 Advisor
要创建 advisor,请实施 or (或两者)。要实现的关键方法是针对非流式处理或流式处理顾问。CallAroundAdvisor
StreamAroundAdvisor
nextAroundCall()
nextAroundStream()
例子
我们将提供一些动手实践示例来说明如何实施 advisor 来观察和增强用例。
日志记录顾问
我们可以实现一个简单的日志 advisor,记录对链中下一个 advisor 的调用之前和之后。
请注意,advisor 仅观察请求和响应,不会修改它们。
此实现支持非流式处理和流式处理方案。AdvisedRequest
AdvisedResponse
public class SimpleLoggerAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
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 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);
return new MessageAggregator().aggregateAdvisedResponse(advisedResponses,
advisedResponse -> logger.debug("AFTER: {}", advisedResponse)); (3)
}
}
1 | 为 advisor 提供唯一名称。 |
2 | 您可以通过设置 order 值来控制执行顺序。较低的值首先执行。 |
3 | 它是一个实用程序类,用于将 Flux 响应聚合到单个 AdvisedResponse 中。
这对于记录或其他观察整个响应而不是流中单个项目的处理非常有用。
请注意,您不能更改 中的响应,因为它是只读操作。MessageAggregator MessageAggregator |
重读 (Re2) 顾问
“Re-Reading Improves Reasoning in Large Language Models” 一文介绍了一种称为 Re-Reading (Re2) 的技术,该技术可以提高大型语言模型的推理能力。 Re2 技术需要像这样扩充输入提示:
{Input_Query} Read the question again: {Input_Query}
实现将 Re2 技术应用于用户输入查询的 advisor 可以像这样完成:
public class ReReadingAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
private AdvisedRequest before(AdvisedRequest advisedRequest) { (1)
Map<String, Object> advisedUserParams = new HashMap<>(advisedRequest.userParams());
advisedUserParams.put("re2_input_query", advisedRequest.userText());
return AdvisedRequest.from(advisedRequest)
.withUserText("""
{re2_input_query}
Read the question again: {re2_input_query}
""")
.withUserParams(advisedUserParams)
.build();
}
@Override
public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) { (2)
return chain.nextAroundCall(this.before(advisedRequest));
}
@Override
public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) { (3)
return chain.nextAroundStream(this.before(advisedRequest));
}
@Override
public int getOrder() { (4)
return 0;
}
@Override
public String getName() { (5)
return this.getClass().getSimpleName();
}
}
1 | 该方法应用 Re-Reading 技术来增强用户的输入查询。before |
2 | 该方法拦截非流式处理请求并应用 Re-Reading 技术。aroundCall |
3 | 该方法拦截流请求并应用 Re-Reading 技术。aroundStream |
4 | 您可以通过设置 order 值来控制执行顺序。较低的值首先执行。 |
5 | 为 advisor 提供唯一名称。 |
Spring AI 内置顾问程序
Spring AI 框架提供了几个内置的顾问程序来增强您的 AI 交互。以下是可用顾问的概述:
流式处理与非流式处理
-
非流式处理顾问处理完整的请求和响应。
-
Streaming advisor 使用反应式编程概念(例如,用于响应的 Flux)将请求和响应作为连续流处理。
@Override
public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
return Mono.just(advisedRequest)
.publishOn(Schedulers.boundedElastic())
.map(request -> {
// This can be executed by blocking and non-blocking Threads.
// Advisor before next section
})
.flatMapMany(request -> chain.nextAroundStream(request))
.map(response -> {
// Advisor after next section
});
}
向后兼容性
该类将移动到新包中。
虽然该接口仍然可用,但它被标记为已弃用,并将在 M3 版本期间删除。
建议将 new 和 interfaces 用于新实施。AdvisedRequest RequestResponseAdvisor CallAroundAdvisor StreamAroundAdvisor |
重大 API 更改
Spring AI Advisor 链从 1.0 M2 版本到 1.0 M3 发生了重大变化。以下是主要修改:
Advisor 接口
-
在 1.0 M2 中,有单独的 and 接口。
RequestAdvisor
ResponseAdvisor
-
RequestAdvisor
在 and 方法之前调用。ChatModel.call
ChatModel.stream
-
ResponseAdvisor
在这些方法之后调用。
-
-
在 1.0 M3 中,这些接口已被替换为:
-
CallAroundAdvisor
-
StreamAroundAdvisor
-
-
的 ,以前是 的一部分已被删除。
StreamResponseMode
ResponseAdvisor
上下文映射处理
-
在 1.0 m2 中:
-
上下文映射是一个单独的方法参数。
-
地图是可变的,并沿着链传递。
-
-
在 1.0 m3 中:
-
上下文映射现在是 和 记录的一部分。
AdvisedRequest
AdvisedResponse
-
map 是不可变的。
-
要更新上下文,请使用该方法,该方法使用更新的内容创建一个新的不可修改的映射。
updateContext
-
在 1.0 M3 中更新上下文的示例:
@Override
public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
this.advisedRequest = advisedRequest.updateContext(context -> {
context.put("aroundCallBefore" + getName(), "AROUND_CALL_BEFORE " + getName()); // Add multiple key-value pairs
context.put("lastBefore", getName()); // Add a single key-value pair
return context;
});
// Method implementation continues...
}