1.局部作用

timerAdvisor只在call2起作用,在call1不起作用
2.传参
2.1全局传参
java
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.StreamAdvisor;
import org.springframework.ai.chat.client.advisor.api.StreamAdvisorChain;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
@Component
@Slf4j
public class ThirdAdvisor implements StreamAdvisor {
@Override
public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest, StreamAdvisorChain streamAdvisorChain) {
UserMessage userMessage=chatClientRequest.prompt().getUserMessage();
String question=userMessage.getText();
log.info("用户的提问是:{}",question);
Object a = chatClientRequest.context().get("A");
log.info("获取到了用户传递过来的参数:{}",a);
Flux<ChatClientResponse> chatClientResponseFlux = streamAdvisorChain.nextStream(chatClientRequest);
return chatClientResponseFlux;
}
@Override
public String getName() {
return "third";
}
@Override
public int getOrder() {
return 88;
}
}


运行结果

2.案例--基于Redis与Advisor实现多轮会话
在前边的案例中,我们讲解了多轮会话,分别基于内存和 JDBC ⽅式,⽽官⽅的 ChatMemory 并没 有提供基于 Redis 的实现⽅式。 下来我们使⽤⾃定义的 advisor 来实现⾃⼰的多轮会话。
2.1. 引入依赖
XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.59</version>
</dependency>
2.2配置yml文件
server:
port: 8004
spring:
application:
name: ai-siliconflow-glm
ai:
openai:
base-url: https://api.siliconflow.cn
api-key: sk-rlpneielwjrtbzwghvmtnkrfzsqoorkclubnimumojlptvqz
chat:
options:
model: "Qwen/Qwen2.5-7B-Instruct"
temperature: 0.7
data:
redis:
host: 192.168.11.88
port: 6379
2.3⾃定义可序列化的 Message 包装类
因为 Message 接⼝下的常⽤实现类均没有序列化操作,我们需要⾃定义⼀个类去进⾏序列化
和反序列化操作。
java
package com.jiazhong.mingxing.ai.siliconflow.advisor.glm.redis.bean;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.MessageType;
import org.springframework.ai.chat.messages.UserMessage;
import java.io.Serializable;
import java.util.Map;
@Data
@NoArgsConstructor
//因为Message没有序列化,不能存到Redis中,要包装一下,所以要写SerializableMessage
public class SerializableMessage implements Serializable {
private static final long serialVersionUID = 12354846L;
private MessageType messageType;
private String content;
private Map<String,Object> properties;
public SerializableMessage(Message message) {
this.messageType=message.getMessageType();// 消息类型
this.content=message.getText();// 消息内容
this.properties=message.getMetadata();// 消息元数据
}
public Message getMessage(){
if (this.messageType.equals(MessageType.USER)){
return new UserMessage(this.content);
}else if (this.messageType.equals(MessageType.ASSISTANT)){
return new AssistantMessage(this.content,this.properties);
}
return null;
}
}
2.4 ⾃定义 Memory 类
定义⼀个类 RedisMessageWindowChatMemory ,实现 ChatMemory 接⼝,重点书写添加和
获取的⽅法。
java
package com.jiazhong.mingxing.ai.siliconflow.advisor.glm.redis.memory;
import com.alibaba.fastjson2.JSONArray;
import com.jiazhong.mingxing.ai.siliconflow.advisor.glm.redis.bean.SerializableMessage;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
@Slf4j
public class RedisMessageWindowChatMemory implements ChatMemory {
@Resource
private StringRedisTemplate stringRedisTemplate;
private static final String prefix_key="REDIS_MESSAGE_KEY";
@Override
public void add(String conversationId, List<Message> messages) {
//1.创建存储消息的空集合 message -> serializableMessages
List<SerializableMessage> serializableMessages=new ArrayList<>();
//2.因为Redis中只能存储序列化的消息,所以要将消息转到序列化消息数组中
for (Message message :messages){
SerializableMessage serializableMessage=new SerializableMessage(message);
serializableMessages.add(serializableMessage);
}
//3.redis中只能存储Json格式
String jsonString = JSONArray.toJSONString(serializableMessages);
stringRedisTemplate.opsForValue().set(prefix_key+conversationId,jsonString);
}
@Override
public List<Message> get(String conversationId) {
String jsonString = stringRedisTemplate.opsForValue().get(prefix_key + conversationId);
List<SerializableMessage> serializableMessages=JSONArray.parseArray(jsonString,SerializableMessage.class);
if (serializableMessages!=null){
List<Message> messages=new ArrayList<>();
for (SerializableMessage serializableMessage:serializableMessages){
Message message = serializableMessage.getMessage();
messages.add(message);
}
return messages;
}
return List.of();
}
@Override
public void clear(String conversationId) {
stringRedisTemplate.delete(prefix_key+conversationId);
}
}
2.5⾃定义 advisor 类
javascript
package com.jiazhong.mingxing.ai.siliconflow.advisor.glm.redis.advisor;
import com.jiazhong.mingxing.ai.siliconflow.advisor.glm.redis.memory.RedisMessageWindowChatMemory;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.ai.chat.client.ChatClientMessageAggregator;
import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.BaseAdvisor;
import org.springframework.ai.chat.client.advisor.api.StreamAdvisor;
import org.springframework.ai.chat.client.advisor.api.StreamAdvisorChain;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
@Component
public class RedisAdvisor implements StreamAdvisor {
@Resource
private RedisMessageWindowChatMemory redisChatMemory;
private String id="";
@Override
public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest, StreamAdvisorChain streamAdvisorChain) {
Mono var10000 = Mono.just(chatClientRequest).publishOn(BaseAdvisor.DEFAULT_SCHEDULER)
.map((request) -> this.before(request));//调用请求前方法
return var10000.flatMapMany((Function<ChatClientRequest, Publisher<?
extends ChatClientResponse>>) streamAdvisorChain::nextStream)
.transform((Function<Flux<ChatClientResponse>,
Flux<ChatClientResponse>>) flux ->//通过循环将流一个一个打出来
(new ChatClientMessageAggregator())
.aggregateChatClientResponse(flux, response ->
observeAfter(response)));//调用响应后的方法
}
//请求大模型之前
private ChatClientRequest before(ChatClientRequest request){
//1.获取conversationId
id=request.context().get("id").toString();
//2.获取当前conversationId的会话记忆
List<Message> messageList=this.redisChatMemory.get(id);
//3.合并消息列表
String question=request.prompt().getUserMessage().getText();//得到问题
UserMessage message=new UserMessage(question);//将当次的问题写成UserMessage
if (messageList.isEmpty()){
messageList=List.of(message);
}else {
messageList.add(message);
}
//4.创建一个新的请求
ChatClientRequest processedChatClientRequest=request.mutate().prompt(request.prompt().mutate().messages(messageList).build()).build();
//5。将新的消息添加到对话记忆中
this.redisChatMemory.add(id,messageList);//历史记录和问的记录,回答的记录在调用大模型响应之后写
//6.提交本次请求
return processedChatClientRequest;
}
//响应之后 大模型拿到之后
private ChatClientResponse observeAfter(ChatClientResponse chatClientResponse){
List<AssistantMessage> assistantMessages=new ArrayList<>();//new一个助手消息
//获取到刚才的助手消息
if (chatClientResponse.chatResponse()!=null){
assistantMessages=chatClientResponse.chatResponse().getResults().stream().map((g)->g.getOutput()).toList();
}
List<Message> messages=this.redisChatMemory.get(id);
messages.addAll(assistantMessages);//拿到过去的历史记录
this.redisChatMemory.add(id,messages);//将助手消息和历史记录添加到Redis中
return chatClientResponse;
}
@Override
public String getName() {
return "redisAdvisor";
}
@Override
public int getOrder() {
return 0;
}
}
2.6配置类
java
package com.jiazhong.mingxing.ai.siliconflow.advisor.glm.redis.config;
import com.jiazhong.mingxing.ai.siliconflow.advisor.glm.redis.advisor.RedisAdvisor;
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 RedisAdvisor redisAdvisor;
@Bean("openAiChatClient")
public ChatClient openAiChatClient(){
return ChatClient.builder(openAiChatModel)
.defaultAdvisors(redisAdvisor)
.build();
}
}
2.7controller类
java
package com.jiazhong.mingxing.ai.siliconflow.advisor.glm.redis.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;
import reactor.core.publisher.Flux;
@RestController
@RequestMapping("/redis")
public class RedisController {
@Resource
private ChatClient openAiChatClient;
@GetMapping(value = "/stream",produces = "text/html;charset=utf-8")
public Flux<String> stream(@RequestParam("question") String question,@RequestParam("id") String id){
return openAiChatClient.prompt()
.advisors(e->e.param("id",id))
.user(question)
.stream().content();
}
}
2.8启动类
java
package com.jiazhong.mingxing.ai.siliconflow.advisor.glm.redis;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AiSiliconflowAdvisorGlmRedisApplication {
public static void main(String[] args) {
SpringApplication.run(AiSiliconflowAdvisorGlmRedisApplication.class);
}
}
会在Redis中获得数据
