spring boot4+springAI 2加redis多轮对话存储

1、采用redis的方式进行存储,安装maven依赖

bash 复制代码
<!-- 模型:OpenAI 兼容 -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-chat-memory-repository-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

2、yml配置

bash 复制代码
spring:
  ai:
    openai:
      base-url: https://api.deepseek.com
      api-key: xxxxxx
      chat:
        temperature: 0.3
        model: deepseek-v4-flash

  data:
    redis:
      host: localhost
      port: 6379
      password: xxxxxx
      jedis:
        pool:
          max-active: 18
      database: 0

3、AI配置类

bash 复制代码
package com.example.web_service.tj.ai.config;

import com.example.web_service.tj.ai.service.IProjectTagQueryService;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.memory.repository.redis.RedisChatMemoryRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.RedisClient;

import java.time.Duration;

@Configuration
public class AiConfig {

    @Value("${spring.data.redis.host}")
    private String redisHost;

    @Value("${spring.data.redis.port}")
    private int redisPort;

    @Value("${spring.data.redis.password}")
    private String redisPassword;

    @Bean
    public ChatMemory chatMemory() {
        RedisClient redisClient=RedisClient.create(redisHost, redisPort,null,redisPassword);
        RedisChatMemoryRepository repo=RedisChatMemoryRepository.builder()
                .jedisClient(redisClient)
                .keyPrefix("chat:memory:")
                .indexName("chat-memory-idx")
                .timeToLive(Duration.ofHours(2))
                .initializeSchema(true)
                .build();
        return MessageWindowChatMemory.builder()
                .chatMemoryRepository(repo)
                .maxMessages(20)
                .build();
    }


    @Bean
    public ChatClient chatClient(ChatClient.Builder builder,ChatMemory chatMemory, IProjectTagQueryService projectTagQueryService) {
        return builder
                .defaultSystem("""
                        我是一个物联网数据查询助手,支持以下能力:
                        ---
                        ## 能力1:查询1个或者多个点位/变量的当前值
                        触发词:点位、变量、当前值
                        参数:
                        - tagCodes: 点位列表(List<String>),如 ["forward", "reverse", "start"]
                        ---
                        
                        ---
                        ## 能力2:查询点位/变量的历史数据,指定时间范围,从.....到......
                        触发词:点位、变量、历史数据、时间范围
                        参数:
                        - tag: 点位/变量,如"forward"
                        - startDateTime: 开始时间,格式 yyyy-MM-dd HH:mm:ss,必须包含年月日时分秒,如 2026-09-01 08:00:00,如果分钟或者秒不存在,则都写成0
                        - endDateTime: 结束时间,格式 yyyy-MM-dd HH:mm:ss,必须包含年月日时分秒,如 2026-09-01 08:00:00,如果分钟或者秒不存在,则都写成0
                        ---
                        
                        """)
                .defaultTools(projectTagQueryService)//带入业务接口/类(对象)
                .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
                .build();
    }
}

其中IProjectTagQueryService projectTagQueryService是业务对象

4、控制器测试

bash 复制代码
@RestController
@RequestMapping("/businessAi")
public class BusinessAiController {
    @Resource
    @Lazy
    private ChatClient chatClient;

    @PostMapping("/chat")
    public ResultMap chat(@RequestBody Map<String,String> params) {
        String chatId="%s-%s".formatted(AuthUserUtils.getUser().getTenantId(),AuthUserUtils.getUser().getUserId());
        return ResultMap.SUCCESS.setNewData(chatClient.prompt()
                .advisors(v->v.param(ChatMemory.CONVERSATION_ID, chatId))
                .user(params.get("message"))
                .call()
                .content());

    }
}
相关推荐
ServBay24 分钟前
Claude Fable 5.5 测试曝光,但它在悄悄给你打分
后端·ai编程·claude
AI源码43 分钟前
旅游推荐管理系统
spring boot
IT规划师1 小时前
一文讲透五种发布机制:滚动、蓝绿、金丝雀、红黑与 AB
后端·面试
一条Go3 小时前
两套权限目录,三重闸门:Alioth 的多租户 RBAC 为什么这么拧
后端·程序员·github
Tokenfree3 小时前
把多模态 OCR 接进业务系统:四千张运单,三个坑
后端
用户859313061353 小时前
我给 AI Agent 写了个下载器:293KB 的网页,不再吃掉 7 万 token
后端
phil63 小时前
沙箱核心功能系列 06:编排调度与资源管理
后端
小兔子3 小时前
if (system(cmd) != 0) 判不出命令失败:它返回的是等待状态,不是退出码
后端
艾迪的技术之路3 小时前
16k 条慢查询,128 张分表,我这么解决
后端·github
dpharness3 小时前
我踩过的四个记忆坑,从预算到换机
前端·后端