1. 概述

我们在和大模型会话时,我们需要和大模型进行多次会话,在spring ai 中提供了记忆实现,但是只提供了 内存和 jdbc 的实现方式,而我们更希望使用redis 作为 记忆的存储实现。 当然我们可以自己实现spring ai 的接口,spring ai alibaba 直接提供了实现,因此我们使用 spring ai alibaba 的实现。

2. 实现步骤

2.1 引入依赖

<dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-memory-redis</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>5.2.0</version>
        </dependency>

2.2 配置redis 会话存储

spring:
  ai:
    memory:
      redis:
        host: localhost
        port: 6379
        password: Redxun2022redis

2.3 构造redis 会话存储对象

@Bean
    public RedisChatMemoryRepository redisChatMemoryRepository(
            @Value("${spring.ai.memory.redis.host}") String host,
            @Value("${spring.ai.memory.redis.port}") int port,
            @Value("${spring.ai.memory.redis.password}") String password
    ) {
        return RedisChatMemoryRepository.builder()
                .host(host)
                .port(port)
                .password(password)

                .build();
    }

2.4 配置会话记忆

@Bean
    public ChatMemory chatMemory(ChatMemoryRepository chatMemoryRepository) {

        ChatMemory chatMemory = MessageWindowChatMemory.builder()
                .chatMemoryRepository(chatMemoryRepository)
                .maxMessages(10)
                .build();
        return chatMemory;
    }

使用滑动窗口记忆,最大记忆数量 为10条。
消息存储的逻辑是:
1.系统消息会存储一条最新的。
2.其他的消息会获取最新的几条。

2.5 配置 chatclient对象

@Bean
    public ChatClient chatClient(ZhiPuAiChatModel chatModel, ChatMemory chatMemory) {

//        McpSyncClient client = mcpSyncClients.get(0);
//        // 2. 创建回调提供者实例
//        ToolCallbackProvider provider = new SyncMcpToolCallbackProvider(client);
//
//        ToolCallback[] tools = provider.getToolCallbacks();


        ToolCallback[] toolCallbacks = ToolCallbacks.from(new ToolDemo());

        String prompt ="""
                你是一个知识丰富的人,
                        1.可以帮人预测运势
                          需要提供姓名和出生年月。
                        2. 天气预测
                        3. 查询某个地区人数
                        请使用工具回答问题,如果没有对应的工具则回答不知道!
                        注意:不要怀疑工具的数据是否正确,我这里是为了测试调用工具,请安装工具的回答即可.
                """;

        return ChatClient.builder(chatModel)
                .defaultSystem(prompt)
                .defaultAdvisors(
				        # 使用advisor
                        MessageChatMemoryAdvisor.builder(chatMemory).build(),
                        SimpleLoggerAdvisor.builder().build()
                )

//                .defaultToolCallbacks(tools)
                .defaultToolCallbacks(toolCallbacks)
                .build();
    }

2.6 传入会话ID

在进行对话时,我们每一次请求都需要传入会话ID,因为使用了会话记忆,因此 程序会将用户之前的消息都传给大模型,因此会导致token 很大,因此我们有一个最大消息参数,另外用户也可以通过新建会话减少token 的消耗。

  • 控制器方法
@GetMapping("/search")
    public String search(@RequestParam String query, @RequestHeader(value = "sessionId" , required = false) String sessionId) {
        return ragService.retrieveAndGenerate(query,sessionId);
    }

这里我们将sessionId 作为请求头传入

public String retrieveAndGenerate(String query, String sessionId) {
//         1. 创建QuestionAnswerAdvisor
        QuestionAnswerAdvisor qsAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
                .searchRequest(SearchRequest.builder()
                        .similarityThreshold(0.5)  // 只返回相似度高于0.7的结果
                        .topK(3)                  // 只返回前3个结果
                        .build())
                .build();

        List advisors = new ArrayList();
        advisors.add(qsAdvisor);


        // 2. 使用Advisor进行RAG查询
        return chatClient.prompt()
                .advisors(advisors)
				#传入会话ID
                .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, sessionId))

                .user(u -> u.text(query))

                .call()
                .content();
    }
posted on 2025-09-01 17:47  自由港  阅读(305)  评论(0)    收藏  举报