向量化编码和RAG增强搜索

张开发
2026/5/24 7:50:21 15 分钟阅读
向量化编码和RAG增强搜索
向量化编码我们要想把文本进行向量化的处理我们需要使用redis7的新特性所以这里我们使用DockerDesktop来进行redis的使用我们在配置文件里面可以定义全局的文本向量化使用的大模型如果我们不在约束里面进行配置那么我们也可以在控制层进行指定效果如下package ai.controller; ​ import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingOptions; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.EmbeddingRequest; import org.springframework.ai.embedding.EmbeddingResponse; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; ​ import java.util.Arrays; import java.util.List; ​ RestController Slf4j public class EmbedVectorController { Resource private EmbeddingModel embeddingModel; ​ Resource private VectorStore vectorStore; GetMapping(/textembed) public EmbeddingResponse textEmbed(String msg) { EmbeddingResponse embeddingResponse embeddingModel.call(new EmbeddingRequest(List.of(msg), DashScopeEmbeddingOptions.builder().withModel(text-embedding-v3).build())); System.out.println(Arrays.toString(embeddingResponse.getResult().getOutput())); return embeddingResponse; } }当我们进行连接成功之后我们在浏览器进行搜索就可以得到我们进行文本向量化之后更重要的是存入redisStack所以我们需要以下设置。GetMapping(/addVectorStore) public void addVectorStore() { ListDocument documents List.of( new Document(I love you), new Document(I hate you) ); vectorStore.add(documents); }当我们调用这个方法的时候浏览器不会返回任何的东西但是我们可以在控制台查看redis的key是否成功的存入。这样我们就可以在这个地方正常的使用redis的向量化存储。我们首先需要写一个控制台的方法GetMapping(/getVectorStore) public List getAllVectorStore(RequestParam(name msg) String msg) { SearchRequest searchRequest SearchRequest.builder() .query(msg) .topK(5) .build(); ListDocument documents vectorStore.similaritySearch(searchRequest); System.out.println(documents); return documents; }然后我们进行访我问就可以实现这个功能。数据库里面有两条然后我们也可以实现这个功能最后我们在控制台进行输入我们可以看到redis的存储文件类型是json下面这一串向量化的东西就被转化成java了RAG检索增强生成我们在写的代码的时候我们就会发现一个问题经常有错误的时候我们就会在控制台输出很多错误无论怎么样我们都会在AI上面进行搜索所以无论怎么样大模型对于你传来的错误码比方说00000:successA0001:网络故障,A0002:系统限流如果问AI的话我们就会发现会出现很多错误的提示让我们不断的试错所以为了解决这个LLM缺陷因为大模型的知识并不是实时的所以是不具备知识更新的大模型是不知道你私有的领域和知识的比方说不同的大模型定义的错误码是不一样的所以生成的答案是不一样的同时大模型会出现幻读问题生成的问题逻辑很清楚但是答案却是错误的。我们在官网可以看到RAG的功能就是这样。大模型的知识是仅限于它所接受的训练数据所以如果我们想要让大模型了解某一个领域的知识那么就可以使用RAG简单来说嘛RAG是从我们给予的数据库知识来进行返回答案。因为大模型的幻读会出现已读乱回的情况所以我们就需要进行RAG的使用。总的来说RAG就是给我们的AI大模型装上了一个大脑当大模型需要回答的时候就会在数据库里面进行查找通过先查找资料然后再进行回答让AI摆脱传统模型的遗忘和幻觉回复。所以使用RAG需要两步走索引和检索首先我们需要先建立索引建立索引的话我们需要先将一个大的文档文件进行分割通过设置成统一的文本格式然后我们就可以把这些分好的块通过嵌入式模型把这些块编码成向量进行表示并存储在向量库当中。当我们创建索引之后就可以进行检索了检索(Retrieval):在收到用户查询(Query)后RAG 系统采用与索引阶段相同的编码模型将查询转换为向量表示然后计算索引语料库中查询向量与块向量的相似性得分。该系统优先级和检索最高k(Top-K)块显示最大的相似性查询。我们要想使用首先我们需要进行依赖的导入!--引入redisstack也就是redis8-- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-vector-store-redis/artifactId /dependency dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter-dashscope/artifactId /dependency当我们引入依赖之后就可以在yml文件里面进行配置了然后就可以编写配置类了我们可以提供相对应的脚本文件存入向量数据库RedisStack行成文档知识库。package ai.config;​ import jakarta.annotation.PostConstruct; import org.springframework.ai.document.Document; import org.springframework.ai.reader.TextReader; import org.springframework.ai.transformer.splitter.TokenTextSplitter; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; ​ import java.nio.charset.Charset; import java.util.List; ​ Configuration public class InitVectorDatabaseConfig { Autowired private VectorStore vectorStore; ​ Value(classpath:ops.text) private Resource opsFile; PostConstruct public void init() throws Exception { //1.读取文件 TextReader textReader new TextReader(opsFile); //设置编码格式 textReader.setCharset(Charset.defaultCharset()); //2.读取文件内容添加到向量数据库中 ListDocument transform new TokenTextSplitter().transform(textReader.read()); //3.添加到向量数据库中 vectorStore.add(transform); } }当我们的准备工作完成之后就可以进行控制层的编写。package ai.controller; ​ import jakarta.annotation.Resource; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor; import org.springframework.ai.rag.retrieval.search.VectorStoreDocumentRetriever; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; ​ RestController public class RagController { Resource private VectorStore vectorStore; Resource(name qwenChatClient) private ChatClient chatClient; GetMapping(/ragAIOps) public FluxString ragAIOps(String msg) { String systemInfo 你是一个AI情感助手你需要根据用户输入的查询内容从知识库中进行搜索 并给出相应的答案找不到就回复找不到信息; RetrievalAugmentationAdvisor advisor RetrievalAugmentationAdvisor.builder() .documentRetriever(VectorStoreDocumentRetriever .builder() .vectorStore(vectorStore) .build()) .build(); return chatClient .prompt() .system(systemInfo) .user( msg) .advisors( advisor) .stream() .content(); } }注意我们在使用redis的时候它的基础配置一定要设置好。我们围绕这个问题就可以得到我们需要的答案。这里有个问题当我们进行重启微服务的时候就会出现问题每当我们重启一次就会再一次出现向量库的编码。所以为了解决这个问题我们就需要这样配置了package ai.config; import cn.hutool.crypto.SecureUtil; import jakarta.annotation.PostConstruct; import org.springframework.ai.document.Document; import org.springframework.ai.reader.TextReader; import org.springframework.ai.transformer.splitter.TokenTextSplitter; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import org.springframework.data.redis.core.RedisTemplate; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.List; Configuration public class InitVectorDatabaseConfig { Autowired private VectorStore vectorStore; Autowired private RedisTemplate redisTemplate; Value(classpath:ops.text) private Resource opsFile; PostConstruct public void init() throws Exception { //1.读取文件 TextReader textReader new TextReader(opsFile); //设置编码格式 textReader.setCharset(StandardCharsets.UTF_8); //2.读取文件内容添加到向量数据库中 ListDocument transform new TokenTextSplitter().transform(textReader.read()); //3.添加到向量数据库中 /*vectorStore.add(transform);*/ //解决数据重复问题 String source (String) textReader.getCustomMetadata().get(source); String s SecureUtil.md5(source); String redisKey vector-xxx: s; //判断数据是否已经存在 Boolean retFlag redisTemplate.opsForValue().setIfAbsent(redisKey, 1); if (Boolean.TRUE.equals(retFlag)) { //数据不存在首次插入 vectorStore.add(transform); }else{ System.out.println(数据已经存在); } } }这样我们就可以看到我们设置的版本了

更多文章