当前位置: 首页 > wzjs >正文

专业做网站设计的公司百度搜索引擎关键词

专业做网站设计的公司,百度搜索引擎关键词,wordpress付费阅读,临汾市住房城乡建设局网站原文链接:SpringAI的Advisor:快速上手源码解读 教程说明 说明:本教程将采用2025年5月20日正式的GA版,给出如下内容 核心功能模块的快速上手教程核心功能模块的源码级解读Spring ai alibaba增强的快速上手教程 源码级解读 版…

原文链接:SpringAI的Advisor:快速上手+源码解读

教程说明

说明:本教程将采用2025年5月20日正式的GA版,给出如下内容

  1. 核心功能模块的快速上手教程
  2. 核心功能模块的源码级解读
  3. Spring ai alibaba增强的快速上手教程 + 源码级解读

版本:JDK21 + SpringBoot3.4.5 + SpringAI 1.0.0 + SpringAI Alibaba最新

将陆续完成如下章节教程

快速上手

实战代码可见:https://github.com/GTyingzi/spring-ai-tutorial 下的 advisor

pom 文件

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-autoconfigure-model-openai</artifactId><version>${spring-ai.version}</version></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-autoconfigure-model-chat-client</artifactId><version>${spring-ai.version}</version></dependency></dependencies>

application.yml

server:port: 8080spring:application:name: advisor-baseai:openai:api-key: ${DASHSCOPEAPIKEY}base-url: https://dashscope.aliyuncs.com/compatible-modechat:options:model: qwen-max

controller

MemoryMessageAdvisorController
package com.spring.ai.tutorial.advisor.controller;import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.messages.Message;
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 java.util.List;import static org.springframework.ai.chat.memory.ChatMemory.CONVERSATIONID;/*** @author yingzi* @date 2025/5/22 22:59*/
@RestController
@RequestMapping("/advisor/memory/message")
public class MemoryMessageAdvisorController {private final ChatClient chatClient;private final InMemoryChatMemoryRepository chatMemoryRepository = new InMemoryChatMemoryRepository();private final int MAXMESSAGES = 100;private final MessageWindowChatMemory messageWindowChatMemory = MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository).maxMessages(MAXMESSAGES).build();public MemoryMessageAdvisorController(ChatClient.Builder builder) {this.chatClient = builder.defaultAdvisors(MessageChatMemoryAdvisor.builder(messageWindowChatMemory).build()).build();}@GetMapping("/call")public String call(@RequestParam(value = "query", defaultValue = "你好,我的外号是影子,请记住呀") String query,@RequestParam(value = "conversationid", defaultValue = "yingzi") String conversationId) {return chatClient.prompt(query).advisors(a -> a.param(CONVERSATIONID, conversationId)).call().content();}@GetMapping("/messages")public List<Message> messages(@RequestParam(value = "conversationid", defaultValue = "yingzi") String conversationId) {return messageWindowChatMemory.get(conversationId);}}
效果

以会话 Id=“yingzi”,先告知模型我的名字

再以同一个会话 Id=“yingzi”,模型能根据以往的消息记住了我的名字

获取历史消息记录,我们能得到历史消息记录

MemoryPromptAdvisorController
package com.spring.ai.tutorial.advisor.controller;import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.messages.Message;
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 java.util.List;import static org.springframework.ai.chat.memory.ChatMemory.CONVERSATIONID;/*** @author yingzi* @date 2025/5/23 17:29*/
@RestController
@RequestMapping("/advisor/memory/prompt")
public class MemoryPromptAdvisorController {private final ChatClient chatClient;private final InMemoryChatMemoryRepository chatMemoryRepository = new InMemoryChatMemoryRepository();private final int MAXMESSAGES = 100;private final MessageWindowChatMemory messageWindowChatMemory = MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository).maxMessages(MAXMESSAGES).build();public MemoryPromptAdvisorController(ChatClient.Builder builder) {this.chatClient = builder.defaultAdvisors(PromptChatMemoryAdvisor.builder(messageWindowChatMemory).build()).build();}@GetMapping("/call")public String call(@RequestParam(value = "query", defaultValue = "你好,我的外号是影子,请记住呀") String query,@RequestParam(value = "conversationid", defaultValue = "yingzi") String conversationId) {return chatClient.prompt(query).advisors(a -> a.param(CONVERSATIONID, conversationId)).call().content();}@GetMapping("/messages")public List<Message> messages(@RequestParam(value = "conversationid", defaultValue = "yingzi") String conversationId) {return messageWindowChatMemory.get(conversationId);}
}
效果

以会话 Id=“yingzi”,先告知模型我的名字

再以同一个会话 Id=“yingzi”,模型能根据以往的消息记住了我的名字

获取历史消息记录,我们能得到历史消息记录

advisor 源码篇

[!TIP]
本源码取自:Spring AI 的 5 月 20 号发布的 1.0.0(GA 版)

  1. 基础只提供 BaseChatMemoryAdvisor
  2. rag 模块引入 RAG,源码可参照 Rag 源码篇

架构图

Advisor

advisor 基础信息配置

  • name:指定名字,确保唯一性
  • order:数值越小,执行越靠前
package org.springframework.ai.chat.client.advisor.api;import org.springframework.core.Ordered;public interface Advisor extends Ordered {int DEFAULTCHATMEMORYPRECEDENCEORDER = -2147482648;String getName();
}
package org.springframework.core;public interface Ordered {int HIGHESTPRECEDENCE = Integer.MINVALUE;int LOWESTPRECEDENCE = Integer.MAXVALUE;int getOrder();
}
CallAdvisor

call 调用,跟 AI 模型交互前、后的一些逻辑

package org.springframework.ai.chat.client.advisor.api;import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;public interface CallAdvisor extends Advisor {ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain);
}
StreamAdvisor

Stream 调用,跟 AI 模型交互前、后的一些逻

package org.springframework.ai.chat.client.advisor.api;import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import reactor.core.publisher.Flux;public interface StreamAdvisor extends Advisor {Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest, StreamAdvisorChain streamAdvisorChain);
}
BaseAdvisor

类说明:继承 CallAdvisor、StreamAdvisor,提供统一扩展点,统计拦截机制实现与 AI 模型请求和响应后的统一交互逻辑。

字段说明

字段名称
类型
描述
DEFAULTSCHEDULER
Scheduler
定义默认调度器Schedulers.boundedElastic(),用于流式处理时的线程调度

方法说明

方法名称
描述
adviseCall
同步调用,拦截call调用AI模型的请求和响应。子类实现before、after方法
adviseStream
流式调用,拦截stream调用AI模型的请求和响应。子类实现before、after方法
before
AI模型请求前的逻辑,需要子类实现
after
AI模型响应后的逻辑,需要子类实现
package org.springframework.ai.chat.client.advisor.api;import java.util.Objects;
import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.AdvisorUtils;
import org.springframework.util.Assert;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;public interface BaseAdvisor extends CallAdvisor, StreamAdvisor {Scheduler DEFAULTSCHEDULER = Schedulers.boundedElastic();default ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {Assert.notNull(chatClientRequest, "chatClientRequest cannot be null");Assert.notNull(callAdvisorChain, "callAdvisorChain cannot be null");ChatClientRequest processedChatClientRequest = this.before(chatClientRequest, callAdvisorChain);ChatClientResponse chatClientResponse = callAdvisorChain.nextCall(processedChatClientRequest);return this.after(chatClientResponse, callAdvisorChain);}default Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest, StreamAdvisorChain streamAdvisorChain) {Assert.notNull(chatClientRequest, "chatClientRequest cannot be null");Assert.notNull(streamAdvisorChain, "streamAdvisorChain cannot be null");Assert.notNull(this.getScheduler(), "scheduler cannot be null");Mono var10000 = Mono.just(chatClientRequest).publishOn(this.getScheduler()).map((request) -> this.before(request, streamAdvisorChain));Objects.requireNonNull(streamAdvisorChain);Flux<ChatClientResponse> chatClientResponseFlux = var10000.flatMapMany(streamAdvisorChain::nextStream);return chatClientResponseFlux.map((response) -> {if (AdvisorUtils.onFinishReason().test(response)) {response = this.after(response, streamAdvisorChain);}return response;}).onErrorResume((error) -> Flux.error(new IllegalStateException("Stream processing failed", error)));}default String getName() {return this.getClass().getSimpleName();}ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain);ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain);default Scheduler getScheduler() {return DEFAULTSCHEDULER;}
}

BaseChatMemoryAdvisor

类说明:从传入的上下文 Map 中提取会话 Id,若不存在则使用默认值

package org.springframework.ai.chat.client.advisor.api;import java.util.Map;
import org.springframework.util.Assert;public interface BaseChatMemoryAdvisor extends BaseAdvisor {default String getConversationId(Map<String, Object> context, String defaultConversationId) {Assert.notNull(context, "context cannot be null");Assert.noNullElements(context.keySet().toArray(), "context cannot contain null keys");Assert.hasText(defaultConversationId, "defaultConversationId cannot be null or empty");return context.containsKey("chatmemoryconversationid") ? context.get("chatmemoryconversationid").toString() : defaultConversationId;}
}
MessageChatMemoryAdvisor

类的说明:消息记忆存储的 Advisor 类

字段说明

字段名称
类型
描述
order
int
指定顺序
defaultConversationId
String
默认会话Id
chatMemory
ChatMemory
聊天记忆接口
scheduler
Scheduler
流式处理时的线程调度

方法说明

方法名称
描述
before
1. 从ChatMemory中取出历史消息
2. 当前消息加入ChatMemory
3. 整合当前消息+历史消息
after
将模型响应的消息加入ChatMemory
adviseStream
覆盖了BaseAdvisor默认实现逻辑
- 注:在将多个流式响应合并成一个完整响应对象后,在调用after,确保只保留完整的模型输出,避免部分信息写入memory导致混乱
package org.springframework.ai.chat.client.advisor;import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
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.AdvisorChain;
import org.springframework.ai.chat.client.advisor.api.BaseAdvisor;
import org.springframework.ai.chat.client.advisor.api.BaseChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.api.StreamAdvisorChain;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.util.Assert;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;public final class MessageChatMemoryAdvisor implements BaseChatMemoryAdvisor {private final ChatMemory chatMemory;private final String defaultConversationId;private final int order;private final Scheduler scheduler;private MessageChatMemoryAdvisor(ChatMemory chatMemory, String defaultConversationId, int order, Scheduler scheduler) {Assert.notNull(chatMemory, "chatMemory cannot be null");Assert.hasText(defaultConversationId, "defaultConversationId cannot be null or empty");Assert.notNull(scheduler, "scheduler cannot be null");this.chatMemory = chatMemory;this.defaultConversationId = defaultConversationId;this.order = order;this.scheduler = scheduler;}public int getOrder() {return this.order;}public Scheduler getScheduler() {return this.scheduler;}public ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain) {String conversationId = this.getConversationId(chatClientRequest.context(), this.defaultConversationId);List<Message> memoryMessages = this.chatMemory.get(conversationId);List<Message> processedMessages = new ArrayList(memoryMessages);processedMessages.addAll(chatClientRequest.prompt().getInstructions());ChatClientRequest processedChatClientRequest = chatClientRequest.mutate().prompt(chatClientRequest.prompt().mutate().messages(processedMessages).build()).build();UserMessage userMessage = processedChatClientRequest.prompt().getUserMessage();this.chatMemory.add(conversationId, userMessage);return processedChatClientRequest;}public ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain) {List<Message> assistantMessages = new ArrayList();if (chatClientResponse.chatResponse() != null) {assistantMessages = chatClientResponse.chatResponse().getResults().stream().map((g) -> g.getOutput()).toList();}this.chatMemory.add(this.getConversationId(chatClientResponse.context(), this.defaultConversationId), assistantMessages);return chatClientResponse;}public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest, StreamAdvisorChain streamAdvisorChain) {Scheduler scheduler = this.getScheduler();Mono var10000 = Mono.just(chatClientRequest).publishOn(scheduler).map((request) -> this.before(request, streamAdvisorChain));Objects.requireNonNull(streamAdvisorChain);return var10000.flatMapMany(streamAdvisorChain::nextStream).transform((flux) -> (new ChatClientMessageAggregator()).aggregateChatClientResponse(flux, (response) -> this.after(response, streamAdvisorChain)));}public static Builder builder(ChatMemory chatMemory) {return new Builder(chatMemory);}public static final class Builder {private String conversationId = "default";private int order = -2147482648;private Scheduler scheduler;private ChatMemory chatMemory;private Builder(ChatMemory chatMemory) {this.scheduler = BaseAdvisor.DEFAULTSCHEDULER;this.chatMemory = chatMemory;}public Builder conversationId(String conversationId) {this.conversationId = conversationId;return this;}public Builder order(int order) {this.order = order;return this;}public Builder scheduler(Scheduler scheduler) {this.scheduler = scheduler;return this;}public MessageChatMemoryAdvisor build() {return new MessageChatMemoryAdvisor(this.chatMemory, this.conversationId, this.order, this.scheduler);}}
}
PromptChatMemoryAdvisor

类的说明:将聊天记忆嵌入到系统提示词的 Advisor 类

字段说明

字段名称
类型
描述
order
int
指定顺序
defaultConversationId
String
默认会话Id
chatMemory
ChatMemory
聊天记忆接口
scheduler
Scheduler
流式处理时的线程调度
systemPromptTemplate
PromptTemplate
当前使用的系统提示模板

方法说明

方法名称
描述
before
1. 从ChatMemory中取出历史消息
2. 当前消息加入ChatMemory
3. 将历史消息结合系统提示消息作为最新的系统提示
after
将模型响应的消息加入ChatMemory
adviseStream
覆盖了BaseAdvisor默认实现逻辑
- 注:在将多个流式响应合并成一个完整响应对象后,在调用after,确保只保留完整的模型输出,避免部分信息写入memory导致混乱
package org.springframework.ai.chat.client.advisor;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.AdvisorChain;
import org.springframework.ai.chat.client.advisor.api.BaseAdvisor;
import org.springframework.ai.chat.client.advisor.api.BaseChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.api.StreamAdvisorChain;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.MessageType;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.util.Assert;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;public final class PromptChatMemoryAdvisor implements BaseChatMemoryAdvisor {private static final Logger logger = LoggerFactory.getLogger(PromptChatMemoryAdvisor.class);private static final PromptTemplate DEFAULTSYSTEMPROMPTTEMPLATE = new PromptTemplate("{instructions}\n\nUse the conversation memory from the MEMORY section to provide accurate answers.\n\n---------------------\nMEMORY:\n{memory}\n---------------------\n\n");private final PromptTemplate systemPromptTemplate;private final String defaultConversationId;private final int order;private final Scheduler scheduler;private final ChatMemory chatMemory;private PromptChatMemoryAdvisor(ChatMemory chatMemory, String defaultConversationId, int order, Scheduler scheduler, PromptTemplate systemPromptTemplate) {Assert.notNull(chatMemory, "chatMemory cannot be null");Assert.hasText(defaultConversationId, "defaultConversationId cannot be null or empty");Assert.notNull(scheduler, "scheduler cannot be null");Assert.notNull(systemPromptTemplate, "systemPromptTemplate cannot be null");this.chatMemory = chatMemory;this.defaultConversationId = defaultConversationId;this.order = order;this.scheduler = scheduler;this.systemPromptTemplate = systemPromptTemplate;}public static Builder builder(ChatMemory chatMemory) {return new Builder(chatMemory);}public int getOrder() {return this.order;}public Scheduler getScheduler() {return this.scheduler;}public ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain) {String conversationId = this.getConversationId(chatClientRequest.context(), this.defaultConversationId);List<Message> memoryMessages = this.chatMemory.get(conversationId);logger.debug("[PromptChatMemoryAdvisor.before] Memory before processing for conversationId={}: {}", conversationId, memoryMessages);String memory = (String)memoryMessages.stream().filter((m) -> m.getMessageType() == MessageType.USER || m.getMessageType() == MessageType.ASSISTANT).map((m) -> {String var10000 = String.valueOf(m.getMessageType());return var10000 + ":" + m.getText();}).collect(Collectors.joining(System.lineSeparator()));SystemMessage systemMessage = chatClientRequest.prompt().getSystemMessage();String augmentedSystemText = this.systemPromptTemplate.render(Map.of("instructions", systemMessage.getText(), "memory", memory));ChatClientRequest processedChatClientRequest = chatClientRequest.mutate().prompt(chatClientRequest.prompt().augmentSystemMessage(augmentedSystemText)).build();UserMessage userMessage = processedChatClientRequest.prompt().getUserMessage();this.chatMemory.add(conversationId, userMessage);return processedChatClientRequest;}public ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain) {List<Message> assistantMessages = new ArrayList();if (chatClientResponse.chatResponse() != null) {assistantMessages = chatClientResponse.chatResponse().getResults().stream().map((g) -> g.getOutput()).toList();} else if (chatClientResponse.chatResponse() != null && chatClientResponse.chatResponse().getResult() != null && chatClientResponse.chatResponse().getResult().getOutput() != null) {assistantMessages = List.of(chatClientResponse.chatResponse().getResult().getOutput());}if (!assistantMessages.isEmpty()) {this.chatMemory.add(this.getConversationId(chatClientResponse.context(), this.defaultConversationId), assistantMessages);logger.debug("[PromptChatMemoryAdvisor.after] Added ASSISTANT messages to memory for conversationId={}: {}", this.getConversationId(chatClientResponse.context(), this.defaultConversationId), assistantMessages);List<Message> memoryMessages = this.chatMemory.get(this.getConversationId(chatClientResponse.context(), this.defaultConversationId));logger.debug("[PromptChatMemoryAdvisor.after] Memory after ASSISTANT add for conversationId={}: {}", this.getConversationId(chatClientResponse.context(), this.defaultConversationId), memoryMessages);}return chatClientResponse;}public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest, StreamAdvisorChain streamAdvisorChain) {Scheduler scheduler = this.getScheduler();Mono var10000 = Mono.just(chatClientRequest).publishOn(scheduler).map((request) -> this.before(request, streamAdvisorChain));Objects.requireNonNull(streamAdvisorChain);return var10000.flatMapMany(streamAdvisorChain::nextStream).transform((flux) -> (new ChatClientMessageAggregator()).aggregateChatClientResponse(flux, (response) -> this.after(response, streamAdvisorChain)));}public static final class Builder {private PromptTemplate systemPromptTemplate;private String conversationId;private int order;private Scheduler scheduler;private ChatMemory chatMemory;private Builder(ChatMemory chatMemory) {this.systemPromptTemplate = PromptChatMemoryAdvisor.DEFAULTSYSTEMPROMPTTEMPLATE;this.conversationId = "default";this.order = -2147482648;this.scheduler = BaseAdvisor.DEFAULTSCHEDULER;this.chatMemory = chatMemory;}public Builder systemPromptTemplate(PromptTemplate systemPromptTemplate) {this.systemPromptTemplate = systemPromptTemplate;return this;}public Builder conversationId(String conversationId) {this.conversationId = conversationId;return this;}public Builder scheduler(Scheduler scheduler) {this.scheduler = scheduler;return this;}public Builder order(int order) {this.order = order;return this;}public PromptChatMemoryAdvisor build() {return new PromptChatMemoryAdvisor(this.chatMemory, this.conversationId, this.order, this.scheduler, this.systemPromptTemplate);}}
}

ChatMemory

类说明:管理会话聊天记忆的接口,提供了保存、获取、清除对话消息的基本功能

字段说明

字段名称
类型
描述
CONVERSATIONID
String
会话Id。当作键,方便提取对应的List

方法说明

方法名称
描述
add
添加消息到指定会话Id中
get
根据指定会话Id获取消息
clear
根据会话Id清除消息
package org.springframework.ai.chat.memory;import java.util.List;
import org.springframework.ai.chat.messages.Message;
import org.springframework.util.Assert;public interface ChatMemory {String DEFAULTCONVERSATIONID = "default";String CONVERSATIONID = "chatmemoryconversationid";default void add(String conversationId, Message message) {Assert.hasText(conversationId, "conversationId cannot be null or empty");Assert.notNull(message, "message cannot be null");this.add(conversationId, List.of(message));}void add(String conversationId, List<Message> messages);List<Message> get(String conversationId);void clear(String conversationId);
}
MessageWindowChatMemory

类说明:消息窗口类,提供了保存、获取、清除对话消息的基本功能

字段说明

字段名称
类型
描述
maxMessages
int
当前会话最多保留的消息数量
chatMemoryRepository
ChatMemoryRepository
存储后端,实现该接口可拓展内存、Mysql、Redis、ES等数据库存储消息

其他方法说明

方法名称
描述
process
用于控制消息数量,核心逻辑下
1. 新增 SystemMessage 时,清除之前的 SystemMessage
2. 若消息数超过限制,优先保留SystemMessage
package org.springframework.ai.chat.memory;import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.util.Assert;public final class MessageWindowChatMemory implements ChatMemory {private static final int DEFAULTMAXMESSAGES = 20;private final ChatMemoryRepository chatMemoryRepository;private final int maxMessages;private MessageWindowChatMemory(ChatMemoryRepository chatMemoryRepository, int maxMessages) {Assert.notNull(chatMemoryRepository, "chatMemoryRepository cannot be null");Assert.isTrue(maxMessages > 0, "maxMessages must be greater than 0");this.chatMemoryRepository = chatMemoryRepository;this.maxMessages = maxMessages;}public void add(String conversationId, List<Message> messages) {Assert.hasText(conversationId, "conversationId cannot be null or empty");Assert.notNull(messages, "messages cannot be null");Assert.noNullElements(messages, "messages cannot contain null elements");List<Message> memoryMessages = this.chatMemoryRepository.findByConversationId(conversationId);List<Message> processedMessages = this.process(memoryMessages, messages);this.chatMemoryRepository.saveAll(conversationId, processedMessages);}public List<Message> get(String conversationId) {Assert.hasText(conversationId, "conversationId cannot be null or empty");return this.chatMemoryRepository.findByConversationId(conversationId);}public void clear(String conversationId) {Assert.hasText(conversationId, "conversationId cannot be null or empty");this.chatMemoryRepository.deleteByConversationId(conversationId);}private List<Message> process(List<Message> memoryMessages, List<Message> newMessages) {List<Message> processedMessages = new ArrayList();Set<Message> memoryMessagesSet = new HashSet(memoryMessages);Stream var10000 = newMessages.stream();Objects.requireNonNull(SystemMessage.class);boolean hasNewSystemMessage = var10000.filter(SystemMessage.class::isInstance).anyMatch((messagex) -> !memoryMessagesSet.contains(messagex));var10000 = memoryMessages.stream().filter((messagex) -> !hasNewSystemMessage || !(messagex instanceof SystemMessage));Objects.requireNonNull(processedMessages);var10000.forEach(processedMessages::add);processedMessages.addAll(newMessages);if (processedMessages.size() <= this.maxMessages) {return processedMessages;} else {int messagesToRemove = processedMessages.size() - this.maxMessages;List<Message> trimmedMessages = new ArrayList();int removed = 0;for(Message message : processedMessages) {if (!(message instanceof SystemMessage) && removed < messagesToRemove) {++removed;} else {trimmedMessages.add(message);}}return trimmedMessages;}}public static Builder builder() {return new Builder();}public static final class Builder {private ChatMemoryRepository chatMemoryRepository;private int maxMessages = 20;private Builder() {}public Builder chatMemoryRepository(ChatMemoryRepository chatMemoryRepository) {this.chatMemoryRepository = chatMemoryRepository;return this;}public Builder maxMessages(int maxMessages) {this.maxMessages = maxMessages;return this;}public MessageWindowChatMemory build() {if (this.chatMemoryRepository == null) {this.chatMemoryRepository = new InMemoryChatMemoryRepository();}return new MessageWindowChatMemory(this.chatMemoryRepository, this.maxMessages);}}
}

ChatMemoryRepository

package org.springframework.ai.chat.memory;import java.util.List;
import org.springframework.ai.chat.messages.Message;public interface ChatMemoryRepository {List<String> findConversationIds();List<Message> findByConversationId(String conversationId);void saveAll(String conversationId, List<Message> messages);void deleteByConversationId(String conversationId);
}
InMemoryChatMemoryRepository

类说明:基于内存的实际存储数据,维护一个会话 Id 到消息列表的键值对

package org.springframework.ai.chat.memory;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.ai.chat.messages.Message;
import org.springframework.util.Assert;public final class InMemoryChatMemoryRepository implements ChatMemoryRepository {Map<String, List<Message>> chatMemoryStore = new ConcurrentHashMap();public List<String> findConversationIds() {return new ArrayList(this.chatMemoryStore.keySet());}public List<Message> findByConversationId(String conversationId) {Assert.hasText(conversationId, "conversationId cannot be null or empty");List<Message> messages = (List)this.chatMemoryStore.get(conversationId);return (List<Message>)(messages != null ? new ArrayList(messages) : List.of());}public void saveAll(String conversationId, List<Message> messages) {Assert.hasText(conversationId, "conversationId cannot be null or empty");Assert.notNull(messages, "messages cannot be null");Assert.noNullElements(messages, "messages cannot contain null elements");this.chatMemoryStore.put(conversationId, messages);}public void deleteByConversationId(String conversationId) {Assert.hasText(conversationId, "conversationId cannot be null or empty");this.chatMemoryStore.remove(conversationId);}
}

问题

MessageChatMemoryAdvisor 和 PromptChatMemoryAdvisor 的区别是什么?

PromptChatMemoryAdvisor

  1. 有些模型可能可能不支持 messag

    1. 如本地部署,LLaMA、BLOOM 等 text-in/text-out 模型
  2. 调试时,希望快速看到完整上下文

MessageChatMemoryAdvisor

  1. 需要精确控制消息类型(用户、系统、助手)
  2. 使用 OpenAI GPT-3.5/4 等 chat 模型

总结:MessageChatMemoryAdvisor 是面向结构化对话记忆的最佳实践,而 PromptChatMemoryAdvisor 是面向文本提示增强的经典方案

为什么需要覆盖 adviseStream 方法?

在将多个流式响应合并成一个完整响应对象后,在调用 after,确保只保留完整的模型输出,避免部分信息写入 memory 导致混乱

http://www.dtcms.com/wzjs/114225.html

相关文章:

  • 怎么创建东莞百度seo电话
  • wordpress 瀑布流主题排名优化怎么做
  • 潍坊网站网站建设网络广告策划书模板范文
  • 网站默认模板微信上如何投放广告
  • 快速建网站工具成都推广系统
  • 网络设计师干什么的汕头seo外包平台
  • 头条网站模版网站建设公司好
  • 郑州哪里有做网站的安全优化大师下载
  • 地方生活门户网站有哪些网站免费优化
  • 做产品网站建设电商网站seo怎么做
  • 做信息类网站seo网站快速排名外包
  • 网站访问慢原因广州疫情最新情况
  • 网站维护建设费应计入科目网络营销策略理论
  • 做网站竞价还需要推广公司淘宝关键词排名查询
  • 2017年用什么语言做网站新产品推广方案策划
  • 房地产建设企业网站浏览器地址栏怎么打开
  • 全国购网站建设王通seo
  • 用html5做京东网站代码武汉网络营销公司排名
  • 北京专业的做网站seo技术交流论坛
  • 江苏省建设厅网站挂证存疑名单长春网站seo哪家好
  • 好用的wordpress编辑器站长工具seo综合查询烟雨楼
  • 字体排版设计网站sem是什么分析方法
  • 专门做鞋的网站信息流优化师是什么
  • 营销型网站哪家做的好百度权重怎么查询
  • 上海专业网站建设流程谷歌外贸平台叫什么
  • 如何能让企业做网站的打算mac923水蜜桃923色号
  • 携程做旅游的网站查关键词
  • 凡科建站是什么网站关键词优化排名外包
  • 自己做的网站如何链接到百度富阳网站seo价格
  • 网站集约化建设工作总结网站seo分析工具