现在我们与前端对接了,能够实现基本的对话功能以及基本的日志输出,那么现在还有个问题就是前面用户说的话后面再提问就忘了,用户体验效果很差
这个就跟OpenAI规范有关系了,如果每次只发送messages的system和role的提示词,大模型只能基于这两个回答,丝毫没有记忆,要把以前的对话也要封装在里面,现在要多出一个角色,assistant
message数组,用assistant表示大模型回复的内容,按顺序排列,先放用户的提问,然后放assistant中大模型的回复消息以及用户提问的问题,依次循环不断把以前的记录封装进去,最后一个肯定是用户最新一个提问,一起发送给大模型,大模型基于聊天历史和最新提问回答,这样就有了记忆
解决:使用springAI封装好的会话环绕增强advisor,能够帮助我们记录所有的会话历史,在发送的时候把记录拼接进去
定义会话存储方式:要有个会话存储方式,Spring AI定好了标准一套接口,例如:第一个就是前端要传给我们的会话ID,第二个就是集合存储的消息,该消息包含角色和内容(基于ID去存储),clear()根据ID清除,可以自己去实现这个接口保存到Redis或者是MySQL,然后可以把项目中的UserID和会话ID拼接在一起,然后去查
不过Spring AI有帮我们实现了这套接口,不过服务一重启会话记忆就没了,可以根据企业要求去实现持久化
@Configuration
public class ClientCofig {
// 定义会话记忆存储的方式 如果企业要求持久化自己实现接口,存储在库里面
@Bean
public ChatMemory chatMemory()
{
return new InMemoryChatMemory();
}
}
配置会话记忆:负责拦截请求做会话记录,提示词拼接
@Configuration
public class ClientCofig {
// 定义会话记忆存储的方式 如果企业要求持久化在这里自己实现接口,存储在库里面
@Bean
public ChatMemory chatMemory()
{
return new InMemoryChatMemory();
}
// 配置客户端 新:注入会话存储方式
@Bean
public ChatClient chatClient(OpenAiChatModel chatModel,ChatMemory chatMemory)
{
// 传一个模型,并且先设定一下system
return ChatClient
.builder(chatModel).defaultSystem("你是一名虚构的动漫里小熊的智能客服,你的名字叫一二。请以友好、热情、可爱的方式回答用户问题。")
// 配置日志环绕增强 还要开启日志级别以及配置 默认debug级别 新:传进去后,将来通过环绕增强,拦截对话,把会话记录保存到chaMemory,将来发新的请求重新拼接进去
.defaultAdvisors(new SimpleLoggerAdvisor(), new MessageChatMemoryAdvisor(chatMemory))
.build();
}
}
添加会话ID:每次发请求,不一定都是同一个人,都需要做会话记忆,不加以管理就会很容易造成混乱。会话都要有个ID,用户跟大模型多轮对话都是同一个ID,不同新的对话再有新的对话ID。可以让前端生成ID,不同新的页面就不同的ID,同一个页面就同一个ID。
我们如何把ID传递给Advisor帮我们管理:
需要发请求的时候传递,环绕增强:.param:向advisor添加上下文,一组键值对,Key-Valve
Key已经帮我们定义好了
@RequestMapping(value = "/chat",produces = "text/html;charset=utf-8")
public Flux<String> get(String prompt,String chatId){
//现在有个问题无法区分是否同一个人,不管谁来聊都会认为同一个人(区分不同的人,用会话ID)
return chatClient.prompt()
.user(prompt)
// 将来会根据这个key找会话ID
.advisors(a-> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY,chatId))
.stream()
.content();
}
结果:不同会话有不同的记忆了
上一次的对话存储:
[UserMessage{content='你好,我叫布布', properties={messageType=USER}, messageType=USER}, AssistantMessage [messageType=ASSISTANT, toolCalls=[], textContent=你好呀,布布!我是你的智能客服一二,很高兴见到你!今天有什么我可以帮你的吗?无论是关于动漫的问题还是其他任何疑问,我都在这里哦!😊, metadata={refusal=, finishReason=STOP, index=0, id=chatcmpl-f86f5315-c2e7-9880-9d5a-a876d85acdff, role=ASSISTANT, messageType=ASSISTANT}]]
XXXXXXXXXXXXXX
新的页面(新的对话窗口):没有跟前面产生联系了,是新的对话,新的会话ID