目录
[一、Chat Memory连续对话保存和持久化](#一、Chat Memory连续对话保存和持久化)
[1.1 对话记忆介绍](#1.1 对话记忆介绍)
[1.2 API介绍](#1.2 API介绍)
[1.3 安装redis](#1.3 安装redis)
[1.4 开发](#1.4 开发)
[2.1 向量文本化](#2.1 向量文本化)
[2.2 向量数据库](#2.2 向量数据库)
[2.3 开发](#2.3 开发)
[3.1 介绍](#3.1 介绍)
[3.2 构建模块](#3.2 构建模块)
[RAG 架构](#RAG 架构)
[3.3 开发](#3.3 开发)
建议大家先看前两章内容:
Spring AI Alibaba 入门开发1-环境搭建、ollama部署、Chat和ChatModel、流式输出-CSDN博客
Spring AI Alibaba 入门开发2-提示词功能、提示词模板、格式化输出-CSDN博客
一、Chat Memory连续对话保存和持久化
1.1 对话记忆介绍
"大模型的对话记忆"这一概念,根植于人工智能与自然语言处理领域,特别是针对具有深度学习能力的大型语言模型而言,它指的是模型在与用户进行交互式对话过程中,能够追踪、理解并利用先前对话上下文的能力。 此机制使得大模型不仅能够响应即时的输入请求,还能基于之前的交流内容能够在对话中记住先前的对话内容,并根据这些信息进行后续的响应。这种记忆机制使得模型能够在对话中持续跟踪和理解用户的意图和上下文,从而实现更自然和连贯的对话。
1.2 API介绍
RedisChatMemoryRepository:实现了Spring AI 规定的ChatMemoryRepository接口
支持redis持久化到本地。
public class RedisChatMemoryRepository implements ChatMemoryRepository, AutoCloseable { private static final Logger logger = LoggerFactory.getLogger(RedisChatMemoryRepository.class); private static final String DEFAULT_KEY_PREFIX = "spring_ai_alibaba_chat_memory:"; private final JedisPool jedisPool; private final ObjectMapper objectMapper; private RedisChatMemoryRepository(JedisPool jedisPool) { Assert.notNull(jedisPool, "jedisPool cannot be null"); this.jedisPool = jedisPool; this.objectMapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addDeserializer(Message.class, new MessageDeserializer()); this.objectMapper.registerModule(module); }
Advisor API:这是一个拦截器链设计模式,允许你通过注入检索数据(Retrieval Context)和对话历史(Chat Memory)来修改传入的 Prompt。
1.3 安装redis
请提前安装redis,Windows用户推荐使用docker+redis。

1.4 开发
新建子模块、修改pom.xml、创建启动类、新增配置文件。
server.port=8888 #解决中文乱码 server.servlet.encoding.charset=UTF-8 server.servlet.encoding.enabled=true server.servlet.encoding.force=true spring.application.name=ssa-07-StrucOutput #Sprig AI Alibaba 相关配置 spring.ai.dashscope.api-key=${qianwen-api} spring.ai.dashscope.base-url=https://ws-6tq01jo6mtthlhoq.cn-beijing.maas.aliyuncs.com/compatible-mode/v1 #spring.ai.dashscope.chat.options.model=qwen-max # ==========redis config =============== spring.data.redis.host=localhost spring.data.redis.port=6379 spring.data.redis.database=0 spring.data.redis.connect-timeout=3 spring.data.redis.timeout=5000ms spring.data.redis.password=
XML
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring-ai-alibaba dashscope-->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<!--spring-ai-alibaba memory-redis-->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-memory-redis</artifactId>
</dependency>
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
java
@SpringBootApplication
public class SSA_08_PersistentApplication {
public static void main(String[] args) {
SpringApplication.run(SSA_08_PersistentApplication.class, args);
}
}
2、新建Redis配置类
java
@Configuration
public class RedisMemoryConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Value("${spring.data.redis.password}")
private String password;
@Bean
public RedisChatMemoryRepository redisChatMemoryRepository() {
return
RedisChatMemoryRepository.builder()
.host(host)
.port(port)
.password(password)
.build();
}
}
创建ChatClient配置类,注意第二个参数
java
@Configuration
public class LLMConfig {
//定义各个模型名称
private final String DEEPSEEK_MODEL = "deepseek-v4-pro";
private final String QWEN_MODEL = "qwen-max";
//定义配置API-KEY的环境变量
private final String API_KEY = "qianwen-api";
//创建deepseekChatModel
@Bean(name = "deepseekChatModel")
public ChatModel deepseekChatModel() {
return
DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi.builder().apiKey(System.getenv(API_KEY)).build())
.defaultOptions(DashScopeChatOptions.builder().withModel(DEEPSEEK_MODEL).build())
.build();
}
//创建qwenChatModel
@Bean(name = "qwenChatModel")
public ChatModel qwenChatModel() {
return
DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi.builder().apiKey(System.getenv(API_KEY)).build())
.defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build())
.build();
}
//创建deepseekChatClient
@Bean(name = "deepseekChatClient")
public ChatClient deepseekChatClient(@Qualifier("deepseekChatModel")ChatModel chatModel,
RedisChatMemoryRepository redisChatMemoryRepository) {
MessageWindowChatMemory windowChatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(redisChatMemoryRepository)
.maxMessages(15)//最大聊天记录
.build();
return ChatClient.builder(chatModel)
.defaultOptions(ChatOptions.builder().model(DEEPSEEK_MODEL).build())
.defaultAdvisors(MessageChatMemoryAdvisor.builder(windowChatMemory).build())
.build();
}
//创建qwenChatClient
@Bean(name = "qwenChatClient")
public ChatClient qwenChatClient(@Qualifier("qwenChatModel") ChatModel chatModel,
RedisChatMemoryRepository redisChatMemoryRepository) {
MessageWindowChatMemory windowChatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(redisChatMemoryRepository)
.maxMessages(15)
.build();
return ChatClient.builder(chatModel)
.defaultOptions(ChatOptions.builder().model(QWEN_MODEL).build())
.defaultAdvisors(MessageChatMemoryAdvisor.builder(windowChatMemory).build())
.build();
}
}
二、向量化和向量数据库
2.1 向量文本化
嵌入(Embedding)的工作原理是将文本、图像和视频转换为称为向量(Vectors)的浮点数数组。这些向量旨在捕捉文本、图像和视频的含义。嵌入数组的长度称为向量的维度(Dimensionality)。
嵌入模型(EmbeddingModel)是嵌入过程中采用的模型。当前EmbeddingModel的接口主要用于将文本转换为数值向量,接口的设计主要围绕这两个目标展开:
- 可移植性:该接口确保在各种嵌入模型之间的轻松适配。它允许开发者在不同的嵌入技术或模型之间切换,所需的代码更改最小化。这一设计与 Spring 模块化和互换性的理念一致。
- 简单性:嵌入模型简化了文本转换为嵌入的过程。通过提供如
embed(String text)和embed(Document document)这样简单的方法,它去除了处理原始文本数据和嵌入算法的复杂性。这个设计选择使开发者,尤其是那些初次接触 AI 的开发者,更容易在他们的应用程序中使用嵌入,而无需深入了解其底层机制。

案例一:四个维度对比运输工具


如何确认相似性?

案例二:图片对比

总结:嵌入模型是一种机器学习模型,旨在在连续的低维向量空间中表示数据(例如文本、图像或其他形式的信息)。这些嵌入可以捕获数据之间的语义或上下文相似性,是机器能否更有效地执行比较、聚类或分类等任务。
假设要描述不同的水果,不用长篇大论,而是用数字来描述大小、颜色、甜度等特征。例如,苹果可能是8,5,4,香蕉是12,8,7。这些数字使比较或对相似的水果进行分组变更更容易。
2.2 向量数据库
向量存储 (VectorStore):是一种用于存储和检索高维向量数据的数据库或存储解决方案,它特别适用于处理那些经过嵌入模型转化后的数据。在 VectorStore 中,查询与传统关系数据库不同。它们执行相似性搜索,而不是精确匹配。当给定一个向量作为查询时,VectorStore 返回与查询向量"相似"的向量。
VectorStore 用于将您的数据与 AI 模型集成。在使用它们时的第一步是将您的数据加载到矢量数据库中。然后,当要将用户查询发送到 AI 模型时,首先检索一组相似文档。然后,这些文档作为用户问题的上下文,并与用户的查询一起发送到 AI 模型。这种技术被称为检索增强生成(Retrieval Augmented Generation,RAG)。
VectorStore API提供了简单易用的接口供开发者对 VectorStore 进行操作。
其核心功能是通过高效的索引结构和相似性计算算法,支持大规模向量数据的快速查询与分析,向量数据库维度越高,查询精准度也越高,查询效果也越好。
**向量数据库 :**将文本、图像和视频转换为称为向量(Vectors)的浮点数数组在 VectorStore中,查询与传统关系数据库不同。它们执行相似性搜索,而不是精确匹配。当给定一个向量作为查询时,VectorStore 返回与查询向量"相似"的向量。
**指征特点:**捕捉复杂的词汇关系(如语义相似性、同义词、多义词)。向量嵌入为检索增强生成 (RAG) 应用程序提供支持。
总结:将文本映射到高维空间中的点,使语义相似的文本在这个空间中距离较近.。
2.3 开发
使用redis8以上版本。新增子模块,修改pom.xml、新增启动类、新增controller
XML
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring-ai-alibaba dashscope-->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<!-- 添加 Redis 向量数据库依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-redis</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
server.port=8888 #解决中文乱码 server.servlet.encoding.charset=UTF-8 server.servlet.encoding.enabled=true server.servlet.encoding.force=true spring.application.name=ssa-11-EmbedToVertor #Sprig AI Alibaba 相关配置 spring.ai.dashscope.api-key=${qianwen-api} spring.ai.dashscope.base-url= spring.ai.dashscope.chat.options.model=qwen-max spring.ai.dashscope.embedding.options.model=text-embedding-v3 # ==========redis config =============== spring.data.redis.host=localhost spring.data.redis.port=6379 spring.data.redis.password= spring.ai.vectorstore.redis.initialize-schema=true spring.ai.vectorstore.redis.index-name=custom-index spring.ai.vectorstore.redis.prefix=custom-prefix
java
@SpringBootApplication
public class SSA_11_EmbedToVectorApplication {
public static void main(String[] args) {
SpringApplication.run(SSA_11_EmbedToVectorApplication.class, args);
}
}
java
@RestController
@Slf4j
public class EmbedToVVectorController {
@Resource
private EmbeddingModel embeddingModel;
@Resource
private VectorStore vectorStore;
//文本向量化
@GetMapping("/v1/chat")
public EmbeddingResponse char1(String msg) {
EmbeddingResponse response = embeddingModel.call(new EmbeddingRequest(List.of(msg),
DashScopeEmbeddingOptions.builder().withModel("text-embedding-v3").build()));
System.out.println(Arrays.toString(response.getResult().getOutput()));
return response;
}
//保存到redis
@GetMapping("/v2/add")
public void add()
{
List<Document> documents = List.of(
new Document("i study LLM"),
new Document("i love java")
);
vectorStore.add(documents);
}
//从redis查询
@GetMapping("/v3/get")
public List getAll(@RequestParam(name = "msg") String msg)
{
SearchRequest searchRequest = SearchRequest.builder()
.query(msg)
.topK(2)
.build();
List<Document> list = vectorStore.similaritySearch(searchRequest);
System.out.println(list);
return list;
}
}


三、RAG(检索增强生成)
3.1 介绍
大型语言模型(LLM)虽然强大,但有两个关键限制:
- 有限的上下文------它们无法一次性摄取整个语料库
- 静态知识------它们的训练数据在某个时间点被冻结
检索通过在查询时获取相关的外部知识来解决这些问题。这是**检索增强生成(RAG)**的基础:使用特定上下文的信息来增强 LLM 的回答。
构建知识库:
检索允许 LLM 在运行时访问相关上下文。但大多数实际应用更进一步:它们将检索与生成集成以产生基于事实的、上下文感知的答案。
这是**检索增强生成(RAG)**的核心思想。检索管道成为结合搜索和生成的更广泛系统的基础。
3.2 构建模块
在 Spring AI Alibaba 中,你可以使用以下组件构建 RAG 系统:
文档加载器和解析器
从外部源(文件、数据库、云存储、在线平台等)摄取数据,返回标准化的文档对象。Spring AI Alibaba 提供了丰富的 Document Reader 和 Document Parser 实现,支持 PDF、Word、Markdown、GitHub、Notion、语雀等多种数据源和格式。
文本分割器
将大型文档分解为更小的块,这些块可以单独检索并适合模型的上下文窗口。文本分割是 ETL 管道中的关键步骤,详见 ETL Pipeline。
嵌入模型
嵌入模型将文本转换为数字向量,使得具有相似含义的文本在向量空间中靠近在一起。Spring AI Alibaba 支持多种 Embedding Model 实现,包括 DashScope、OpenAI、Ollama 等。
向量存储
用于存储和搜索嵌入的专用数据库。Spring AI Alibaba 支持多种向量数据库,包括 Milvus、Pinecone、Redis、Elasticsearch 等。更多实现请查看 向量数据库文档。
检索器
检索器是一个接口,给定非结构化查询返回文档。Spring AI 提供了模块化的 RAG 架构,支持查询转换、查询扩展、文档后处理等高级功能。
RAG 架构
RAG 可以以多种方式实现,具体取决于你的系统需求。我们在下面的部分概述每种类型。

延迟 :延迟在两步 RAG 中通常更可预测,因为 LLM 调用的最大次数是已知且有上限的。这种可预测性假设 LLM 推理时间是主要因素。但是,实际延迟也可能受检索步骤性能的影响------例如 API 响应时间、网络延迟或数据库查询------这些可能因使用的工具和基础设施而异。
总结:RAG技术就像给AI大模型装上了「实时百科大脑」,为了让大模型获取足够的上下文,以便获得更加广泛的信息源,通过先查资料后回答的机制,让AI摆脱传统模型的"知识遗忘和幻觉回复"困境。通过引入外部知识源来增强LLM的输出能力,传统的LLM通常基于其训练数据生成响应,但这些数据可能过时或不够全面。RAG允许模型在生成答案之前,从特定的知识库中检索相关信息,从而提供更准确和上下文相关的回答。
RAG 流程分为两个不同的阶段:索引和检索
索引(Indexing):索引首先清理和提取各种格式的原始数据,如PDF、HTML、Word和Markdown,然后将其转换为统一的纯文本格式。为了适应语言模型的上下文限制,文本被分割成更小的、可消化的块(chunk)。然后使用嵌入模型将编码成向量表示,并存储在向量数据库中。这一步对于在随后的检索阶段实现高效是相似性搜索至关重要。知识库分割成chunks,并将chunks向量化至向量库中。
3.3 开发
需求:SpringAI+阿里百炼嵌入模型text-embedding-v3+向量数据库RedisStack+DeepSeek来实现RAG功能。
新建子模块,项目结构如下:

修改pom.xml、新增启动类、配置文件、配置类、controller。
XML
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring-ai-alibaba dashscope-->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<!-- 添加 Redis 向量数据库依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-redis</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
ops.txt
00000 系统OK正确执行后的返回 A0001 用户端错误一级宏观错误码 A0100 用户注册错误二级宏观错误码 B1111 支付接口超时 C2222 Kafka消息解压严重
server.port=8888 #解决中文乱码 server.servlet.encoding.charset=UTF-8 server.servlet.encoding.enabled=true server.servlet.encoding.force=true spring.application.name=ssa-11-EmbedToVertor #Sprig AI Alibaba 相关配置 spring.ai.dashscope.api-key=${qianwen-api} #spring.ai.dashscope.base-url=xxxx spring.ai.dashscope.chat.options.model=deepseek-r1 spring.ai.dashscope.embedding.options.model=text-embedding-v3 # ==========redis config =============== spring.data.redis.host=localhost spring.data.redis.port=6379 spring.data.redis.password= spring.ai.vectorstore.redis.initialize-schema=true spring.ai.vectorstore.redis.index-name=custom-index spring.ai.vectorstore.redis.prefix=custom-prefix
java
@SpringBootApplication
public class SSA_12_RAGApplication {
public static void main(String[] args) {
SpringApplication.run(SSA_12_RAGApplication.class, args);
}
}
java
@Configuration
public class InitVectorDatabaseConfig {
@Autowired
private VectorStore vectorStore;
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Value("classpath:ops.txt")
private Resource opsFile;
//-----------------------------------------第一版:写入向量数据库,当前无法去重,每次启动服务都会新增,下个版本修复
// @PostConstruct
// public void init() {
// //读取文件
// TextReader reader = new TextReader(opsFile);
// //设置文件编码
// reader.setCharset(Charset.defaultCharset());
// //文件转换成向量(分词)
// List<Document> documents = new TokenTextSplitter().transform(reader.read());
// //写入向量数据库,当前无法去重,每次启动服务都会新增,下个版本修复
// vectorStore.add(documents);
// }
//------------------------------第二版:
@PostConstruct
public void init()
{
//1 读取文件
TextReader textReader = new TextReader(opsFile);
textReader.setCharset(Charset.defaultCharset());
//2 文件转换为向量(开启分词)
List<Document> list = new TokenTextSplitter().transform(textReader.read());
//3 写入向量数据库RedisStack
//vectorStore.add(list);
// 解决上面第3步,向量数据重复问题,使用redis setnx命令处理
//4 去重复版本
String sourceMetadata = (String)textReader.getCustomMetadata().get("source");
String textHash = SecureUtil.md5(sourceMetadata);
String redisKey = "vector-xxx:" + textHash;
// 判断是否存入过,redisKey如果可以成功插入表示以前没有过,可以假如向量数据
Boolean retFlag = redisTemplate.opsForValue().setIfAbsent(redisKey, "1");
System.out.println("****retFlag : "+retFlag);
if(Boolean.TRUE.equals(retFlag))
{
//键不存在,首次插入,可以保存进向量数据库
vectorStore.add(list);
}else {
//键已存在,跳过或者报错
//throw new RuntimeException("---重复操作");
System.out.println("------向量初始化数据已经加载过,请不要重复操作");
}
}
}
java
@Configuration
public class LLMConfig {
//定义各个模型名称
private final String DEEPSEEK_MODEL = "deepseek-v4-pro";
private final String QWEN_MODEL = "qwen-max";
//定义配置API-KEY的环境变量
private final String API_KEY = "qianwen-api";
@Bean(name = "deepseekChatModel")
public ChatModel deepseekChatModel() {
return DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi
.builder()
.apiKey(System.getenv(API_KEY))
.build())
.defaultOptions(DashScopeChatOptions.
builder().
withModel(DEEPSEEK_MODEL)
.build())
.build();
}
@Bean(name = "qwenChatModel")
public ChatModel qwenChatModel() {
return
DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi
.builder()
.apiKey(API_KEY)
.build())
.defaultOptions(DashScopeChatOptions
.builder()
.withModel(QWEN_MODEL)
.build())
.build();
}
@Bean(name = "deepseekChatClient")
public ChatClient deepseekChatClient(@Qualifier("deepseekChatModel") ChatModel chatModel) {
return
ChatClient.builder(chatModel)
.defaultOptions(ChatOptions
.builder()
.model(DEEPSEEK_MODEL)
.build())
.build();
}
@Bean(name = "qwenChatClient")
public ChatClient qwenChatClient(@Qualifier("qwenChatModel") ChatModel chatModel) {
return
ChatClient
.builder(chatModel)
.defaultOptions(ChatOptions
.builder()
.model(QWEN_MODEL)
.build())
.build();
}
}
java
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactor)
{
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactor);
//设置key序列化方式string
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
java
@RestController
public class RagController {
@Resource(name = "qwenChatClient")
private ChatClient chatClient;
@Resource
private VectorStore vectorStore;
@GetMapping("/v1/chat")
public Flux<String> chat1(String msg){
String sysRoleInfo = """
你是一位运维工程师,按照给出的编码给出对应故障解释,否者回复找不到错误信息。
""";
RetrievalAugmentationAdvisor advisor = RetrievalAugmentationAdvisor
.builder()
.documentRetriever(
VectorStoreDocumentRetriever
.builder()
.vectorStore(vectorStore)
.build()
)
.build();
return chatClient
.prompt()
.system(sysRoleInfo)
.user(msg)
.advisors(advisor) // RAG功能,向量数据库查询
.stream().content();
}
}