暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring AI新特性之Advisor机制,绝了!

IT周瑜 2024-06-29
42

阅读过程产生的疑问,关注公众号后可联系我进行交流。


感谢先赞再看的朋友,祝你们洪福齐天,长命百岁。
全军出击!
Spring AI 1.0.0-M1这个版本相对前一个版本增加了很多新特性,比如多模态的支持、模型结果评估机制、Fluent API等等,但其中我觉得最有意思的是引入了Spring AOP中的Advisor机制。

众所周知,Advisor是Spring AOP中的概念,一个Advisor表示一个切面,由Advice和PointCut组成,Advice表示切面逻辑,也就是增强逻辑,PointCut表示切点,也就是切哪些方法。

在Spring AI的源码中定义了一个RequestResponseAdvisor接口:

图片可以点击放大

很明显,这个接口表示对请求和响应进行增强,传入一个请求或响应,返回增强后的请求或响应,有点类似于Spring MVC中的拦截器,联系到Spring AI的核心功能就是请求大模型接口以及处理大模型响应结果,所以RequestResponseAdvisor接口的作用就是增强对于大模型的请求和响应,但具体增强逻辑是什么由具体的实现类来定义。

第一个实现类:MessageChatMemoryAdvisor,类名中的ChatMemory也是Spring AI中的一个机制,也是1.0.0版本新增的一个特性,来源于LangChain4j,作用是用来保存与大模型的聊天上下文,或者说聊天记录,或者说会话记录,或者说问答记录,都是一个意思,ChatMemory是一个接口,默认实现类为InMemoryChatMemory,表示聊天记录都存储在内存中(InMemory),当然你可以自定义一个实现类把聊天记录存在数据库中,InMemoryChatMemory的实现其实很简单:

基于源码,我们可以把ChatMemory理解为就是一个Map,key为会话ID,value为会话对应的历史消息列表,注意这里的消息既包含了我们发送给大模型的UserMessage(比如“你是谁?”),也包含了大模型返回给我们的AssistantMessage(比如“我是gpt-4o...”),都是Message。

回到MessageChatMemoryAdvisor,它增强的是某一次请求和对应的响应,它的第一个作用就是把当前请求所发送的UserMessage添加到ChatMemory中,重点是第二个作用,由于大模型本身是无状态的,也就是大模型本身并不会保存我们和大模型之间的聊天记录,所以,我们如果想让大模型知道我们之前聊了什么,我们就需要在请求大模型时将历史聊天记录跟着当前请求一起发送给大模型,这样大模型才能知道前面聊了什么,而具体实现方式就是发送一个List<Message>给大模型,这个List<Message>中既包含了历史消息,也包含了最新消息,这样大模型就能知道前面聊天的内容了。

所以,当Spring AI接收到一个请求时,这个请求一开始只会携带一条UserMessage,比如“请换一个风格”,之后MessageChatMemoryAdvisor会将该请求对应的UserMessage添加到ChatMemory中,也就是上文提到的Map中当前会话ID对应的List<Message>中,然后生成一个新的请求,将List<Message>设置到新请求中,因此这个新的请求中就不止一条UserMessage了,而是一个List<Message>,然后Spring AI会将这个新的请求发送给大模型,此时大模型也就知道了历史聊天记录,就能知道“请换一个风格”到底是什么意思了。

当大模型处理完请求后,会向Spring AI返回一个响应,在Spring AI中就是一条AssistantMessage,那么MessageChatMemoryAdvisor需要对响应做什么增强逻辑呢?很简单,只需要将AssistantMessage添加到ChatMemory即可。

以上就是MessageChatMemoryAdvisor这个Advisor对请求和响应的增强逻辑分析,此外还有一个PromptChatMemoryAdvisor,其实它的作用和MessageChatMemoryAdvisor类似,也会利用ChatMemory来保存聊天记录,它和MessageChatMemoryAdvisor的区别在于,最终发送给大模型的请求中不是一个List<Message>了,而是会额外设置了一个系统提示词SystemMessage,内容为:

Use the conversation memory from the MEMORY section to provide accurate answers.
---------------------
MEMORY:
{memory}
---------------------

{memory}相当于一个变量,发送给大模型之前会进行占位符的填充,那填充的是啥呢?没错啦,就是历史聊天记录,源码中会把List<Message>System.lineSeparator()
进行连接,相当于把历史聊天记录转为一个字符串,然后放到系统提示词中随着请求一起发送给大模型,这样大模型也能知道之前聊天的内容,从而准确的理解当前问题,和MessageChatMemoryAdvisor一样,PromptChatMemoryAdvisor也会将大模型的响应AssistantMessage保存到ChatMemory中。

看到这,大家是否Get到了Advisor在Spring AI中的作用了呢,我一开始看到源码时还是觉得挺惊艳的,Spring还是那么的优雅,切面机制永远这么强大。

不过需要注意的是,以上MessageChatMemoryAdvisor和PromptChatMemoryAdvisor虽然都叫做Advisor,但是它们都不是通过动态代理来实现的,而是这么实现的:

针对原始的请求和响应,依次利用RequestResponseAdvisor进行增强,有没有感觉和BeanPostProcessor的实现机制很像呢。

好啦,关于Spring AI的Advisor机制就分析到这啦,希望得到大家的点赞、分享、在看,感谢!

关于Spring AI的其他新特性,比如多模态的支持、模型结果评估机制、Fluent API等等,我会陆续进行分享,希望得到大家的点赞、分享、在看,感谢!

另外,除开MessageChatMemoryAdvisor和PromptChatMemoryAdvisor,Spring AI中其实还有一个VectorStoreChatMemoryAdvisor,只不过它涉及到了另外一个概念VectorStore,大家如果感兴趣,欢迎点击下方小程序或链接加入我的Java程序员的AI精品课,学习更多AI大模型知识,卷起来!

文章转载自IT周瑜,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论