SpringAi学习之Advisors API
顾问 API
Spring AI Advisors API 提供了一种灵活且强大的方式,用于拦截、修改和增强 Spring 应用程序中由 AI 驱动的交互。通过利用 Advisors API,开发人员能够创建更复杂、可重用且易于维护的 AI 组件。
其主要优势包括封装重复出现的生成式人工智能模式、转换与大型语言模型(LLMs)之间发送和接收的数据,以及在各种模型和用例中提供可移植性。
开发者可以使用ChatClient API配置现有的顾问,如下例所示:
1 | ChatMemory chatMemory = ... // Initialize your chat memory store |
建议在构建时使用构建器的defaultAdvisors()方法注册顾问。顾问也参与可观测性堆栈,因此开发者可以查看与其执行相关的指标和轨迹。
核心组件
Advisors API 包含用于非流式场景的CallAdvisor和CallAdvisorChain,以及用于流式场景的StreamAdvisor和StreamAdvisorChain。它还包括用于表示未封装的提示词请求的ChatClientRequest,以及用于聊天补全响应的ChatClientResponse。两者都包含一个advise-context,用于在顾问链之间共享状态。

<font style="color:rgb(25, 30, 30);">adviseCall()</font>和<font style="color:rgb(25, 30, 30);">adviseStream()</font>是关键的顾问方法,通常会执行一些操作,例如检查未密封的提示数据、定制和扩充提示数据、调用顾问链中的下一个实体、选择性地阻止请求、检查聊天完成响应,以及抛出异常以指示处理错误。
此外,getOrder()方法确定链中顾问的顺序,而getName()提供唯一的顾问名称。
由Spring AI框架创建的Advisor Chain(顾问链)允许按多个顾问的getOrder()值排序来依次调用它们。值越小,执行得越早。最后一个顾问会被自动添加,它负责将请求发送给大语言模型。
以下流程图展示了顾问链与聊天模型之间的交互:

- Spring AI框架根据用户的
<font style="color:rgb(25, 30, 30);">Prompt</font>以及一个空的顾问<font style="color:rgb(25, 30, 30);">context</font>对象创建一个<font style="color:rgb(25, 30, 30);">ChatClientRequest</font>。 - 链中的每个顾问都会处理请求,并可能对其进行修改。或者,顾问也可以选择不调用下一个实体来阻止请求。在后一种情况下,该顾问负责完成响应。
- 框架提供的最后一个顾问会将请求发送至
<font style="color:rgb(25, 30, 30);">Chat Model</font>。 - 然后,聊天模型的响应会通过顾问链传回,并转换为
<font style="color:rgb(25, 30, 30);">ChatClientResponse</font>。其包含共享的顾问<font style="color:rgb(25, 30, 30);">context</font>实例。 - 每个顾问都可以处理或修改响应。
- 最终的
<font style="color:rgb(25, 30, 30);">ChatClientResponse</font>通过提取<font style="color:rgb(25, 30, 30);">ChatCompletion</font>返回给客户端。
顾问顺序(Advisor Order)
链中顾问的执行顺序由<font style="color:rgb(25, 30, 30);">getOrder()</font>方法决定。需要理解的关键点有如下所示:
- 顺序值较低的顾问会先执行。
- 顾问链以栈的方式运作:
- 链中的第一个顾问会首先处理请求。
- 它也是最后一个处理响应的。
- 控制执行顺序:
- 将顺序设置为接近
<font style="color:rgb(25, 30, 30);">Ordered.HIGHEST_PRECEDENCE</font>,以确保顾问在链中首先执行(请求处理时首先执行,响应处理时最后执行)。 - 将顺序设置为接近
<font style="color:rgb(25, 30, 30);">Ordered.LOWEST_PRECEDENCE</font>,以确保顾问在链中最后执行(请求处理时最后执行,响应处理时最先执行)。
- 将顺序设置为接近
- 值越高,表示优先级越低。
- 如果多个顾问具有相同的顺序值,它们的执行顺序无法保证。
顺序和执行顺序之间的表面矛盾是由于顾问链的栈式特性: 具有最高优先级(顺序值最低)的顾问被添加到栈的顶部。随着栈的展开,它将是第一个处理请求的。 随着栈的回卷,它将是最后一个处理响应的。
作为提醒,以下是Spring Ordered接口的语义:
1 | public interface Ordered { |
对于需要在输入侧和输出侧都处于链中首位的用例:
- 为每一侧使用单独的顾问。
- 为它们配置不同的顺序值。
- 使用顾问上下文在它们之间共享状态。
API概览
主要的Advisor接口位于org.springframework.ai.chat.client.advisor.api包中。以下是开发者自定义自己的advisor时会遇到的关键接口:
1 | public interface Advisor extends Ordered { |
这是顾问的基本接口,它扩展了 Ordered 接口,意味着顾问具有顺序和名称。
对于同步和响应式顾问的两个子接口分别是:
1 | public interface CallAdvisor extends Advisor { |
和
1 | public interface StreamAdvisor extends Advisor { |
为了继续顾问链的执行,开发者可以在顾问实现中使用CallAdvisorChain和StreamAdvisorChain:
1 | public interface CallAdvisorChain extends AdvisorChain { |
和
1 | public interface StreamAdvisorChain extends AdvisorChain { |
实现顾问
要创建一个顾问,需实现CallAdvisor或StreamAdvisor(或两者都实现)。对于非流式顾问,要实现的关键方法是nextCall();对于流式顾问,则是nextStream()。
示例
我们将提供几个实际操作示例,以说明如何为观察和增强用例实现顾问功能。
日志顾问
我们可以实现一个简单的日志通知器,在调用链中下一个通知器之前记录ChatClientRequest,之后记录ChatClientResponse。请注意,该通知器仅观察请求和响应,不会对其进行修改。此实现同时支持非流式和流式场景。
1 | public class SimpleLoggerAdvisor implements CallAdvisor, StreamAdvisor { |
- 提供顾问的唯一名称。
- 您可以通过设置顺序值来控制执行顺序。值越低,越早执行。
- MessageAggregator 是一个实用工具类,它能将多个Flux 响应聚合成单个ChatClientResponse。这对于记录整个响应而不是流中的单个项目非常有用。请注意,您不能在 MessageAggregator 中更改响应,因为它是只读操作。
重读(Re2)顾问
《“重新阅读提升大型语言模型的推理能力”》一文介绍了一种名为“重新阅读(Re2)”的技术,该技术可增强大型语言模型的推理能力。Re2技术需要对输入提示进行如下增强:
1 | {Input_Query}再读一遍问题:{Input_Query} |
实现一个将Re2技术应用于用户输入查询的顾问可以这样做:
1 | public class ReReadingAdvisor implements BaseAdvisor { |
1、<font style="color:rgb(25, 30, 30);">before</font>方法通过应用重读技术来增强用户的输入查询。
2、开发者可以通过设置order值来控制执行顺序。值越小,执行越早。
Spring AI 内置顾问
Spring AI框架提供了几个内置的顾问来增强您的AI交互。以下是可用顾问的概述:
聊天记忆顾问
这些顾问在聊天记忆存储中管理对话历史:
<font style="color:rgb(25, 30, 30);">MessageChatMemoryAdvisor</font>
检索记忆并将其作为消息集合添加到提示中。这种方法能保持对话历史的结构。请注意,并非所有人工智能模型都支持这种方法。
<font style="color:rgb(25, 30, 30);">PromptChatMemoryAdvisor</font>
检索记忆并将其整合到提示词的系统文本中。
<font style="color:rgb(25, 30, 30);">VectorStoreChatMemoryAdvisor</font>
从向量存储中检索记忆并将其添加到提示词的系统文本中。该辅助工具有助于高效地从大型数据集中搜索和检索相关信息。
问答顾问
<font style="color:rgb(25, 30, 30);">QuestionAnswerAdvisor</font>
该顾问使用向量存储来提供问答功能,采用了简单的检索增强生成(RAG)模式。
<font style="color:rgb(25, 30, 30);">RetrievalAugmentationAdvisor</font>
- 该顾问使用org.springframework.ai.rag包中定义的构建块并遵循模块化RAG架构,实现了常见的检索增强生成(RAG)流程。
推理顾问
<font style="color:rgb(25, 30, 30);">ReReadingAdvisor</font>
实现了一种用于大语言模型推理的重读策略,称为RE2,以增强输入阶段的理解。基于文章:《重读提升大语言模型的推理能力》(arxiv.org/pdf/2309.06275)。
内容安全顾问
<font style="color:rgb(25, 30, 30);">SafeGuardAdvisor</font>
一个简单的顾问,旨在防止模型生成有害或不当内容。
流式与非流式

- 非流式顾问处理完整的请求和响应。
- 流式顾问将请求和响应作为连续流来处理,采用响应式编程概念(例如,使用Flux处理响应)。
1 | @Override |
最佳实践
- 让顾问专注于特定任务,以实现更好的模块化。
- 必要时,使用
<font style="color:rgb(25, 30, 30);">adviseContext</font>在顾问之间共享状态。 - 实现顾问的流式和非流式版本,以获得最大的灵活性。
- 仔细考虑链中顾问的顺序,以确保数据的正确流转。
API重大变更
顾问接口
- 在1.0 M2中,存在独立的
<font style="color:rgb(25, 30, 30);">RequestAdvisor</font>和<font style="color:rgb(25, 30, 30);">ResponseAdvisor</font>接口。<font style="color:rgb(25, 30, 30);">RequestAdvisor</font>在<font style="color:rgb(25, 30, 30);">ChatModel.call</font>和<font style="color:rgb(25, 30, 30);">ChatModel.stream</font>方法之前被调用。<font style="color:rgb(25, 30, 30);">ResponseAdvisor</font>是在这些方法之后被调用的。
- 在1.0 M3中,这些接口已被替换为:
<font style="color:rgb(25, 30, 30);">CallAroundAdvisor</font><font style="color:rgb(25, 30, 30);">StreamAroundAdvisor</font>
- 此前属于
<font style="color:rgb(25, 30, 30);">ResponseAdvisor</font>的<font style="color:rgb(25, 30, 30);">StreamResponseMode</font>已被移除。 - 在1.0.0版本中,这些接口已被替换:
<font style="color:rgb(25, 30, 30);">CallAroundAdvisor</font>→<font style="color:rgb(25, 30, 30);">CallAdvisor</font>、<font style="color:rgb(25, 30, 30);">StreamAroundAdvisor</font>→<font style="color:rgb(25, 30, 30);">StreamAdvisor</font>、<font style="color:rgb(25, 30, 30);">CallAroundAdvisorChain</font>→<font style="color:rgb(25, 30, 30);">CallAdvisorChain</font>以及<font style="color:rgb(25, 30, 30);">StreamAroundAdvisorChain</font>→<font style="color:rgb(25, 30, 30);">StreamAdvisorChain</font>。<font style="color:rgb(25, 30, 30);">AdvisedRequest</font>→<font style="color:rgb(25, 30, 30);">ChatClientRequest</font>是<font style="color:rgb(25, 30, 30);">AdivsedResponse</font>→<font style="color:rgb(25, 30, 30);">ChatClientResponse</font>。
上下文映射处理
- 在1.0 M2中:
- 上下文映射是一个单独的方法参数。
- 该映射是可变的,并在链中传递。
- 在1.0 M3中:
- 上下文映射现在是
<font style="color:rgb(25, 30, 30);">AdvisedRequest</font>和<font style="color:rgb(25, 30, 30);">AdvisedResponse</font>记录的一部分。 - 该映射是不可变的。
- 要更新上下文,请使用
<font style="color:rgb(25, 30, 30);">updateContext</font>方法,该方法会创建一个包含更新内容的新的不可修改映射。
- 上下文映射现在是
