SpringAI-Advisor
会被所有的Advisor拦截器所共享的资源,例如在第一个Advisor中进行了一个操作,第二个Advisor中可以拿到第一个Advisor所做的操作的信息,会有一个共享容器。和 StreamAdvisor 接⼝,同时提供了同步和流式的链式默认实现。在默认实现的环绕通知⽅法 中,前置和后置⽅法调⽤ before。⽅式等,每种实现⽅式都有特定的实现类。接⼝,同样提供了⼀个环绕通知adviseStrea
1.ChatMemoryRepository 接⼝
ChatMemoryRepository 接⼝是对话记忆存储的抽象。⽀持多种存储⽅式,例如:内存⽅式、 JDBC ⽅式以及 Redis ⽅式等,每种实现⽅式都有特定的实现类。⽐如内存⽅式就是通过 InMemoryChatMemoryRepository 类实现的。
源码:
public interface ChatMemoryRepository {
// 获取所有活跃会话ID列表
List<String> findConversationIds();
// 根据会话ID获取消息列表
List<Message> findByConversationId(String conversationId);
// 根据会话ID全量替换存储,清除旧消息,录⼊新消息
void saveAll(String conversationId, List<Message> messages);
// 根据会话ID清除消息列表
void deleteByConversationId(String conversationId);
}
2.Advisor机制(拦截器)(面试可能会问到)
2.1什么是Advisor
2.2大致流程
- 我们将提示词发送给 AI ⼤模型。
- ⼤模型附加的 Advisor ,会依次执⾏链中每个 Advisor 的 before ⽅法。
- 执⾏完所有的 before ⽅法后,交给⼤模型处理。
- ⼤模型处理后的响应,会依次执⾏链中每个 Advisor 的 after ⽅法。
- 执⾏完所有的 after ⽅法后,我们获得了最终的⼤模型响应内容,执⾏结束。
2.3核心功能
2.4基本架构

可以看到Advisor接口有两个子接口,分别是CallAdvisor和StreamAdvisor。
2.4.1Advisor接口
public interface Advisor extends Ordered {
int DEFAULT_CHAT_MEMORY_PRECEDENCE_ORDER = -2147482648;
String getName();
}
interface中自动加public static finial
public interface Ordered {
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
int getOrder();
}
2.4.2CallAdvisor 和 StreamAdvisor ⼦接⼝
public interface CallAdvisor extends Advisor {
ChatClientResponse adviseCall(ChatClientRequest chatClientRequest,
CallAdvisorChain callAdvisorChain);
}
StreamAdvisor 接⼝同样继承于 Advisor 接⼝,同样提供了⼀个环绕通知adviseStream() ⽅法,同样在⽬标⽅法执⾏前后执⾏逻辑,控制执⾏流程。
public interface StreamAdvisor extends Advisor {
Flux<ChatClientResponse> adviseStream(ChatClientRequest
chatClientRequest,
StreamAdvisorChain
streamAdvisorChain);
}
2.4.3CallAdvisorChain 接⼝和 StreamAdvisorChain 接⼝
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();
}
流程:
2.4.4BaseAdvisor 接⼝
BaseAdvisor 接⼝同时实现同步拦截(CallAdvisor)和流式拦截(StreamAdvisor )。BaseAdvisor 接⼝,这个接⼝同时继承了 CallAdvisor 和 StreamAdvisor 接⼝,同时提供了同步和流式的链式默认实现。在默认实现的环绕通知⽅法 中,前置和后置⽅法调⽤ before 和 after ⽅法⽤于使⽤者⾃定义。因此我们在需要时仅仅 定义我们的 before 和 after 即可。

3自定义Advisor
- 创建⼀个类,实现 CallAroundAdvisor 或 StreamAroundAdvisor 接⼝。
- 实现接⼝的 aroundCall()|aroundStream() 、 getName() 以及 getOrder() ⽅法。
- 调⽤⼤模型时,将自定义的 advisor 类添加进去即可。
入门案例:计算大模型的耗时
config包
package com.jiazhong.mingxing.ai.advisor.glm.config;
import com.jiazhong.mingxing.ai.advisor.glm.advisor.TimerAdvisor;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ChatClientConfig {
@Resource
private OpenAiChatModel openAiChatModel;
@Resource
private TimerAdvisor timerAdvisor;
@Bean("openAiChatClient")
public ChatClient openAiChatClient(){
return ChatClient.builder(openAiChatModel)
//3.进行全局注册
.defaultAdvisors(timerAdvisor)
.build();
}
}
advisor包
package com.jiazhong.mingxing.ai.advisor.glm.advisor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.CallAdvisor;
import org.springframework.ai.chat.client.advisor.api.CallAdvisorChain;
import org.springframework.stereotype.Component;
@Slf4j
@Component //将一个普通的 Java 类标记为 Spring 容器管理的 Bean
public class TimerAdvisor implements CallAdvisor {
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
//1.获取进来的时候的时间
long begin = System.currentTimeMillis();
log.info("开始时间:{}",begin);
//2.执行后面的操作(包含下一个Advisor(可能多个)以及大模型)
ChatClientResponse chatClientResponse = chain.nextCall(request);
//4.获取到出去的时候的时间
long end = System.currentTimeMillis();
log.info("结束时间:{}",end);
//5.计算时间
long time = end - begin;
log.info("总共花费了:"+time+"毫秒");
return chatClientResponse;
}
@Override
//Advisor的名字
public String getName() {
return "timer";
}
@Override
//Advisor的优先级,数字越小优先级越高
public int getOrder() {
return 0;
}
}
controller包
package com.jiazhong.mingxing.ai.advisor.glm.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/advisor")
public class AdvisorController {
@Resource
private ChatClient openAiChatClient;
@GetMapping(value = "/stream",produces = "text/html;charset=utf-8")
public String call(@RequestParam("question") String question){
return openAiChatClient.prompt()
.user(question)
.call().content();
}
}
AdvisorContext上下文
在TimerAdvisor类中进行添加
package com.jiazhong.mingxing.ai.advisor.glm.advisor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.CallAdvisor;
import org.springframework.ai.chat.client.advisor.api.CallAdvisorChain;
import org.springframework.stereotype.Component;
@Slf4j
@Component //将一个普通的 Java 类标记为 Spring 容器管理的 Bean
public class TimerAdvisor implements CallAdvisor {
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
//1.获取进来的时候的时间
long begin = System.currentTimeMillis();
request.context().put("A","这个是我在上下文中存放的内容");
log.info("开始时间:{}",begin);
//2.执行后面的操作(包含下一个Advisor(可能多个)以及大模型)
ChatClientResponse chatClientResponse = chain.nextCall(request);
//4.获取到出去的时候的时间
long end = System.currentTimeMillis();
Object a = request.context().get("A");
log.info("上下文存放的内容是:{}",a);
log.info("结束时间:{}",end);
//5.计算时间
long time = end - begin;
log.info("总共花费了:"+time+"毫秒");
return chatClientResponse;
}
@Override
//Advisor的名字
public String getName() {
return "timer";
}
@Override
//Advisor的优先级,数字越小优先级越高
public int getOrder() {
return 0;
}
}
新建SecondAdvisor类
package com.jiazhong.mingxing.ai.advisor.glm.advisor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.CallAdvisor;
import org.springframework.ai.chat.client.advisor.api.CallAdvisorChain;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class SecondAdvisor implements CallAdvisor {
@Override
public ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {
Object a = chatClientRequest.context().get("A");
log.info("secondAdvisor:{}",a);
return callAdvisorChain.nextCall(chatClientRequest);
}
@Override
public String getName() {
return "second";
}
@Override
public int getOrder() {
return 3;
}
}
修改Cinfig类
package com.jiazhong.mingxing.ai.advisor.glm.config;
import com.jiazhong.mingxing.ai.advisor.glm.advisor.SecondAdvisor;
import com.jiazhong.mingxing.ai.advisor.glm.advisor.TimerAdvisor;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ChatClientConfig {
@Resource
private OpenAiChatModel openAiChatModel;
@Resource
private TimerAdvisor timerAdvisor;
@Resource
private SecondAdvisor secondAdvisor;
@Bean("openAiChatClient")
public ChatClient openAiChatClient(){
return ChatClient.builder(openAiChatModel)
//3.进行全局注册
.defaultAdvisors(timerAdvisor,secondAdvisor)
.build();
}
}
运行结果

说明各个Advisor是互通的,根据优先级确定执行顺序。
4内置的Advisor
4.1. MessageChatMemoryAdvisor
4.2PromptChatMemoryAdvisor
@Bean("ollamaChatClient")
public ChatClient chatClient() {
return ChatClient
.builder(ollamaChatModel)
//.defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory))
// 内存⽅式
//.defaultAdvisors(new
MessageChatMemoryAdvisor(jdbcChatMemory)) // JDBC⽅式
.defaultAdvisors(new
PromptChatMemoryAdvisor(jdbcChatMemory)) // 替换成PromptChatMemoryAdvisor
.build();
}
4.3. SimpleLoggerAdvisor
- ⽇志记录:默认记录 Debug 级别的⽇志,包括⽤户输⼊⽂本、模型响应等内容,但默认不显示。
- 可配置性:⽀持通过配置⽂件调整⽇志级别(如改为 Info 级别),或下载源码⾃定义逻辑。
- 添加 SimpleLoggerAdvisor

- 修改配置⽂件
- 在application.yml文件中加入下述代码

- 测试结果

4.44. SafeGuardAdvisor
输入敏感词的结果如下图
更多推荐
所有评论(0)