参考完成RAG技术

This commit is contained in:
spllzh
2025-08-05 11:37:05 +08:00
parent ee95df10bd
commit bdb78caf59
10 changed files with 279 additions and 8 deletions

View File

@@ -16,7 +16,8 @@ import reactor.core.publisher.Flux;
chatModel = "openAiChatModel",
streamingChatModel = "openAiStreamingChatModel", //配置流式 输出模型
// chatMemory = "chatMemory", // 配置聊天记忆对象 ,基于内存
chatMemoryProvider = "chatMemoryProvider"
chatMemoryProvider = "chatMemoryProvider",//配置会话记忆 提供者对象 基于Redis
contentRetriever = "contentRetriever" // 配置向量数据库检索对象
)
public interface CstAIStreamingService {
@@ -25,6 +26,10 @@ public interface CstAIStreamingService {
@SystemMessage(fromResource = "system.txt")
public Flux<String> chatMemoryId(@MemoryId String memoryId, @UserMessage String message);
// @SystemMessage(fromResource = "system.txt")
public Flux<String> chatMemoryIdRAG(@MemoryId String memoryId, @UserMessage String message);
}

View File

@@ -1,11 +1,14 @@
package com.cst.langchain4jheima.config;
import com.cst.langchain4jheima.aiservice.CstAIService;
import com.cst.langchain4jheima.repository.RedisChatMemoryStore;
import dev.langchain4j.community.store.embedding.redis.RedisEmbeddingStore;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -38,6 +41,12 @@ public class CommonConfig {
return build;
}
@Autowired
RedisChatMemoryStore redisChatMemoryStore;
@Bean
public ChatMemoryProvider chatMemoryProvider() {
@@ -48,6 +57,7 @@ public class CommonConfig {
MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(10)
.chatMemoryStore(redisChatMemoryStore)
.build();
return chatMemory;
}

View File

@@ -65,4 +65,23 @@ public class ChatController
return chat;
}
/**
* 通过 memoryId ,实现会话隔离
* 会话信息保存在Redis中
* 加载的本地文档保存在向量数据库
* 基于向量数据库进行信息检索
*
* @param memoryId
* @param question
* @return
*/
@GetMapping("/chatByStreamingByMemoryIdByRAG" )
public Flux<String> chatByStreamingByMemoryIdByRAG(String memoryId,String question)
{
Flux<String> chat = streamingModel.chatMemoryIdRAG(memoryId,question);
return chat;
}
}

View File

@@ -0,0 +1,122 @@
package com.cst.langchain4jheima.embedding;
import dev.langchain4j.community.store.embedding.redis.RedisEmbeddingStore;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.loader.ClassPathDocumentLoader;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.parser.apache.pdfbox.ApachePdfBoxDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.List;
/**
* Author: 李中华 wx: spllzh email(qq): 28668817@qq.com
* Date: 2025/8/4 18:21
**/
@Configuration
public class EnbedingModelConfig {
@Autowired
private EmbeddingModel embeddingModel;
@Autowired
RedisEmbeddingStore redisEmbeddingStore;
/**
* 创建向量数据库操作对象
* @return
*/
@Bean("myEmbeddingStoreInMemory")
// @Primary
public EmbeddingStore embeddingStoreInMemory() {
//1 , 加载知识库文档进 内存
List<Document> documents = ClassPathDocumentLoader.loadDocuments("knowledge");
//2 构建向量数据库操作对象
InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
//3 构建EmbeddingStoreIngestor 完成文本数据的切割, 向量化, 存储
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingStore(embeddingStore)
.build();
ingestor.ingest( documents);
return embeddingStore;
}
@Bean("myEmbeddingStoreInMemory2")
// @Primary
public EmbeddingStore embeddingStoreInMemory2() throws IOException {
//1 , 加载知识库文档进 内存
List<Document> documents1 = ClassPathDocumentLoader.loadDocuments("knowledge\\pdf",new ApachePdfBoxDocumentParser());
// List<Document> documents2 = ClassPathDocumentLoader.loadDocuments("knowledge");
//2 构建向量数据库操作对象
InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
//构建文档 分割器对象
DocumentSplitter recursiveSplitter = DocumentSplitters.recursive(300, 50);
//3 构建EmbeddingStoreIngestor 完成文本数据的切割, 向量化, 存储
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingStore(embeddingStore)
.documentSplitter(recursiveSplitter) //设置文档分割器
.embeddingModel(embeddingModel)
.build();
ingestor.ingest( documents1);
return embeddingStore;
}
@Bean("myEmbeddingStoreInRedis")
// @Primary
public EmbeddingStore embeddingStoreInRedis() throws IOException {
//1 , 加载知识库文档进 内存
List<Document> documents1 = ClassPathDocumentLoader.loadDocuments("knowledge\\pdf",new ApachePdfBoxDocumentParser());
// List<Document> documents2 = ClassPathDocumentLoader.loadDocuments("knowledge");
//构建文档 分割器对象
DocumentSplitter recursiveSplitter = DocumentSplitters.recursive(300, 50);
//3 构建EmbeddingStoreIngestor 完成文本数据的切割, 向量化, 存储
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingStore(redisEmbeddingStore)
.documentSplitter(recursiveSplitter) //设置文档分割器
.embeddingModel(embeddingModel)
.build();
ingestor.ingest( documents1);
return redisEmbeddingStore;
}
@Bean
public ContentRetriever contentRetriever(@Qualifier("myEmbeddingStoreInMemory2")EmbeddingStore store){
EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(redisEmbeddingStore)
.embeddingModel(embeddingModel)
.minScore(0.5)//相似度
.maxResults(3) //最多返回3条
.build();
return contentRetriever;
}
}

View File

@@ -0,0 +1,51 @@
package com.cst.langchain4jheima.repository;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.ChatMessageDeserializer;
import dev.langchain4j.data.message.ChatMessageSerializer;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
import java.time.Duration;
import java.util.List;
/**
* Author: 李中华 wx: spllzh email(qq): 28668817@qq.com
* Date: 2025/8/4 17:39
**/
@Repository
public class RedisChatMemoryStore implements ChatMemoryStore {
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public List<ChatMessage> getMessages(Object memoryId) {
//获取当前会话id的 聊天列表是json串
String chatMessageListJson = redisTemplate.opsForValue().get(memoryId.toString());
// 把JSON转换成会话列表
List<ChatMessage> chatMessages = ChatMessageDeserializer.messagesFromJson(chatMessageListJson);
return chatMessages;
}
@Override
public void updateMessages(Object memoryId, List<ChatMessage> list) {
//把会话列表转换成JSON
String chatMessageListJson = ChatMessageSerializer.messagesToJson(list);
//更新当前会话id的值保存到Redis里
redisTemplate.opsForValue().set(memoryId.toString(), chatMessageListJson, Duration.ofDays(1));
}
@Override
public void deleteMessages(Object memoryId) {
// 删除当前会话id的值
redisTemplate.delete(memoryId.toString());
}
}