1、问题与场景复现

  • 背景
  • 1、MessageWindowChatMemory + RedisChatMemoryRepository 存储短期记忆

正常情况下应该如图所示,“text”属性(String 类型)代表用户提问或者大模型回复

  • 问题复现

但是某一天变成了下图所示,即:所有记录的“text”字段都递归嵌套了Message类的JsonString,且这种情况会随着聊天次数的增加递归越来越深,最后导致上下文爆炸。

3、原因分析

直接给出答案:Message反序列化出错

详细分析:

(1)、问题出处:断点打在 RedisChatMemoryRepository findByConversation()方法上

(2)、可以看见messageString“text”属性正常(即:Message的序列化没问题)

(3)、但是当反序列化后,message对象却没有text属性,取而代之的是textContent属性,且不是正常情况下的提问/回复String,而是message的JsonString。

即:Message message = (Message)this.objectMapper.readValue(messageString, Message.class);出现了反序列化错误

(4)、那么是this.objectMapper的问题吗?

不完全是,根源其实是SpringAIMessage类的实现上。

(5)、以下代码可以看见,Message接口类继承自Content类,而Content类有一个getText()方法用于获取上述的提问/回复字符串。

public interface Message extends Content {
    MessageType getMessageType();
}
public interface Content {
    String getText();

    Map<String, Object> getMetadata();
}

(6)、但是重点来了,所有的Message实现类(UserMessage、AssistantMessage等等)都继承自AbstractMessage类。

重点:AbstractMessage类getText()方法返回的是textContent属性,而不是text属性???

public abstract class AbstractMessage implements Message {

    @Nullable
    protected final String textContent;
....

    @Nullable
    public String getText() {
        return this.textContent;
    }

    ...
}

(7)总结

1、AbstractMessage类getText()方法返回textContent的值,方法名和属性名不匹配。

2、因此序列化时有text属性,但是反序列化时找不到,于是this.objectMapper将整个messageJsonString赋值给了textContent属性,循环往复,导致记忆上下文越来越大。

4、解决办法

(1)、自定义Message类,设置textContent属性和getter、setter方法

详细可见:24.基本对话与课程咨询-会话记忆-代码实现(2)_哔哩哔哩_bilibili

(2)、修改objectMapper配置

强制采用基于字段(field-based) 的序列化/反序列化,忽略所有 getter/is-getter

参考alibabaBaseRedisChatMemoryRepository实现类

    public BaseRedisChatMemoryRepository() {
        this.objectMapper = ((JsonMapper.Builder)((JsonMapper.Builder)((JsonMapper.Builder)JsonMapper.builder().configure(MapperFeature.AUTO_DETECT_GETTERS, false)).configure(MapperFeature.AUTO_DETECT_IS_GETTERS, false)).visibility(PropertyAccessor.FIELD, Visibility.ANY)).build();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(Message.class, new MessageDeserializer());
        this.objectMapper.registerModule(module);
    }

(3)、更新Spring AISSA版本,直接使用或者复制已有的最新实现类

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐