【AI应用开发捷径之路】第七课:实现多轮对话记忆功能

2025-12-30 09:53:47
文章摘要
模型的“记忆”并非像人类那样长期、连贯地存储经历,而是一种在交互过程中临时保存、提取和利用信息的能力。其核心目标是让模型在单次对话或任务中保持上下文连贯性。

前言

    大模型的“记忆”并非像人类那样长期、连贯地存储经历,而是一种在交互过程中临时保存、提取和利用信息的能力。其核心目标是让模型在单次对话或任务中保持上下文连贯性。

    大模型的记忆能力取决于大模型支持的token长度如果你发送过多聊天记录,可能就会导致token过长,更多的token也意味更多的费用,更久的解析时间。所以不建议太长(DEFAULT_MAX_MESSAGES默认20即10次对话),一旦超出DEFAULT_MAX_MESSAGES 只会存最后面N条(可以理解为先进先出)。

图片描述

在springAi中,如果需要修改对话次数,可以通过如下配置:


@TestConfiguration
    static class Config {
        ChatMemory chatMemory(ChatMemoryRepository chatMemoryRepository){
            return MessageWindowChatMemory.builder()
                    .maxMessages(10)  // 最多保存10条对话记录,先进先出的机制
                    .chatMemoryRepository(chatMemoryRepository)
                    .build();
        }
    }

SpringAI中实现记忆的交互图

图片描述

一、简单的实现记忆功能


package com.example.base;

import cn.myeasyai.FaceApplication;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SafeGuardAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest(classes = FaceApplication.class)
public class TestMemory {

    @Autowired
    DeepSeekChatModel deepSeekChatModel;
    @Test
    public void testMemory() {

        MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder().build();
        String conversationId ="s1";//当前对话唯一标识

        //第一轮对话
        UserMessage userMessage = new UserMessage("我叫发哥");
        chatMemory.add(conversationId, userMessage);

        ChatResponse response1 = deepSeekChatModel.call(new Prompt(chatMemory.get(conversationId)));
        chatMemory.add(conversationId, response1.getResult().getOutput());


        //第二轮对话
        UserMessage userMessage2 = new UserMessage("我叫什么名字");
        chatMemory.add(conversationId, userMessage2);

        ChatResponse response2 = deepSeekChatModel.call(new Prompt(chatMemory.get(conversationId)));
        chatMemory.add(conversationId, response2.getResult().getOutput());

        //输出响应结果
        System.out.println(response2.getResult().getOutput().getText());


    }
}

二、通过拦截器实现多轮对话记忆功能

添加依赖


<dependency>
      <groupid>org.springframework.ai</groupid>
      <artifactid>spring-ai-autoconfigure-model-chat-memory</artifactid>
</dependency>

测试类


package com.example.base;

import cn.myeasyai.FaceApplication;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SafeGuardAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest(classes = FaceApplication.class)
public class TestMemory {

    @Autowired
    DeepSeekChatModel deepSeekChatModel;


    @Test
    public void testMemoryAdvisor( @Autowired ChatMemory chatMemory) {


        ChatClient.Builder builder = ChatClient.builder(deepSeekChatModel);
        ChatClient chatClient  = builder.defaultAdvisors(
                                    PromptChatMemoryAdvisor.builder(chatMemory) //在拦截器中加入一个记忆拦截器
                                                        .build())
                                                        .build();

        String content = chatClient.prompt().user("我叫发哥").call().content();
        System.out.println(content);
        System.out.println("--------------------------------------------------------");


        content = chatClient.prompt().user("我叫什么名字").call().content();
        System.out.println(content);




    }
}

三、测试多轮对话输出

    下面代码中设置了只记忆一轮对话,可以看到:第四轮的对话中,第一轮的对话已经被遗忘;第三轮对话还能回答职业,是因为第二轮对话中问到了职业的原因,所以还保留着职业。


package com.example.base;

import cn.myeasyai.FaceApplication;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest(classes = FaceApplication.class)
public class TestMemory {

    @Autowired
    DeepSeekChatModel deepSeekChatModel;

    @Autowired
    private ChatMemoryRepository chatMemoryRepository;

    @Test
    public void testCustomMemory() {

        MessageWindowChatMemory build = MessageWindowChatMemory.builder()
                .maxMessages(1)  // 保存1条消息
                .chatMemoryRepository(chatMemoryRepository)
                .build();


        ChatClient.Builder builder = ChatClient.builder(deepSeekChatModel);
        ChatClient chatClient = builder
                .defaultAdvisors(
                        PromptChatMemoryAdvisor.builder(build)
                                .build()
                )
                .build();

        // 测试对话
        String content = chatClient.prompt()
                .user("我叫张三,今年25岁,是一名软件工程师")
                .call()
                .content();
        System.out.println("第一轮:" + content);
        //第一轮:好的,张三!很高兴认识你。25岁的软件工程师,正是充满活力和潜力的年纪呢。  

/**---------------------
---------------------
MEMORY:
---------------------
        */

        content = chatClient.prompt()
                .user("我的职业是什么?")
                .call()
                .content();
        System.out.println("第二轮:" + content);
        //第二轮:根据我们的对话记录,你之前提到过你的职业是**软件工程师**。

        /**---------------------
---------------------
MEMORY:
ASSISTANT:好的,张三!很高兴认识你。25岁的软件工程师,正是充满活力和潜力的年纪呢。  

请问有什么我可以帮你的吗?无论是技术问题、职业发展,还是日常生活中的疑问,我都很乐意为你提供帮助。
---------------------
        */


        content = chatClient.prompt()
                .user("我的职业是什么?")
                .call()
                .content();
        System.out.println("第三轮:" + content);
        //第三轮:根据我们的对话记录,你的职业是**软件工程师**。
   /**---------------------
---------------------
MEMORY:
ASSISTANT:根据我们的对话记录,你之前提到过你的职业是**软件工程师**。
---------------------
        */

        content = chatClient.prompt()
                .user("我的名字是什么?")
                .call()
                .content();
        System.out.println("第四轮:" + content);
        //第四轮:根据我们的对话记录,目前没有提到你的名字。如果你愿意告诉我,我可以记住它并在后续对话中使用。

    }


}

大模型的记忆功能正从完全依赖有限上下文窗口,向 “大上下文窗口 + 外部记忆系统”相结合的方向快速发展。其目标是实现更个性化、更连贯、更知情的交互体验

声明:该内容由作者自行发布,观点内容仅供参考,不代表平台立场;如有侵权,请联系平台删除。
标签:
多轮对话
对话式 AI
模型部署