当前位置: 首页 > news >正文

【SpringAI】6.向量检索(redis)

基于redis的向量检索

向量数据库可以使用milvus,redis,Elasticsearch等,本文以redis为例:

docker启动redis-stack-server

docker run -d --name redis-stack-server -p 6380:6379  -v /home/redis/data:/data -e REDIS_ARGS="--requirepass mima --bind 0.0.0.0 --protected-mode no"  redis/redis-stack-server:latest

1,pom引入依赖

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-vector-store-redis</artifactId>
</dependency> 

2,yml配置

这里以硅基流动的免费量化模型测试

spring:data:redis:host: xx.xx.xx.xxport: 6380password: xxxai:openai:api-key: sk-xxxxxxxxxxxxxxxxxxxxembedding:base-url: https://api.siliconflow.cnoptions:model: BAAI/bge-m3vectorstore:redis:## 是否初始化所需的 schemainitialize-schema: true## 用于存储向量的索引的名称index-name: knowledgeId## Redis 键的前缀prefix: glmapper_

3,文本向量化和文本检索


import lombok.RequiredArgsConstructor;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.ai.document.Document;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;@Component
@RequiredArgsConstructor
public class VectorService {private final VectorStore vectorStore;// 将上传的文本文件向量化并保存到向量数据库public void embedFile(MultipartFile file,String knowledgeId) {try {// 读取上传文件内容String content = new String(file.getBytes(), StandardCharsets.UTF_8);// 切分为小块List<Document> docs = splitTextToDocuments(content,knowledgeId); // 每500字符为一块// 写入向量库vectorStore.add(docs);} catch (Exception e) {throw new RuntimeException("文件向量化失败: " + e.getMessage(), e);}}// 按固定长度分割文本为 Document 列表private List<Document> splitTextToDocuments(String text,String knowledgeId) {List<Document> docs = new ArrayList<>();int length = text.length();for (int i = 0; i < length; i += 500) {int end = Math.min(length, i + 500);String chunk = text.substring(i, end);Document document = new Document(chunk);//指定向量数据的知识库Id
//            document.getMetadata().put("knowledgeId",knowledgeId);docs.add(document);}return docs;}public void store(List<Document> documents) {if (documents == null || documents.isEmpty()) {return;}vectorStore.add(documents);}public List<Document> search(String query,String knowledgeId,Double threshold) {FilterExpressionBuilder b = new FilterExpressionBuilder();return vectorStore.similaritySearch(SearchRequest.builder().query(query).topK(5)   //返回条数.similarityThreshold(threshold)   //相似度,阈值范围0~1,值越大匹配越严格‌
//                .filterExpression(b.eq("knowledgeId", knowledgeId).build()).build());}public void delete(Set<String> ids) {vectorStore.delete(new ArrayList<>(ids));}}

原本想将量化数据按照知识库分组和过滤,实际并没有效果,即使按照官方文档手动定义Bean指定knowledgeId的tag也无效,官方提供的手动定义如下:

@Bean
public VectorStore vectorStore(JedisPooled jedisPooled, EmbeddingModel embeddingModel) {return RedisVectorStore.builder(jedisPooled, embeddingModel).indexName("custom-index")                // Optional: defaults to "spring-ai-index".prefix("custom-prefix")                  // Optional: defaults to "embedding:".metadataFields(                         // Optional: define metadata fields for filteringMetadataField.tag("country"),MetadataField.numeric("year")).initializeSchema(true)                   // Optional: defaults to false.batchingStrategy(new TokenCountBatchingStrategy()) // Optional: defaults to TokenCountBatchingStrategy.build();
}// This can be any EmbeddingModel implementation
@Bean
public EmbeddingModel embeddingModel() {return new OpenAiEmbeddingModel(new OpenAiApi(System.getenv("OPENAI_API_KEY")));
}

搜索时代码如下:

vectorStore.similaritySearch(SearchRequest.builder().query("The World").topK(TOP_K).similarityThreshold(SIMILARITY_THRESHOLD).filterExpression(b.and(b.in("country", "UK", "NL"),b.gte("year", 2020)).build()).build());

4,测试接口

@Tag(name = "向量检索", description = "向量检索")
@RestController
@RequestMapping("/vector")
public class VectorController {@Autowiredprivate VectorService vectorService;@Operation(summary = "文本文件向量化", description = "文本文件向量化")@PostMapping("/uploadFile")public RestVO<Map<String, Object>> uploadFile(@RequestPart MultipartFile file, @RequestParam String knowledgeId) {vectorService.embedFile(file, knowledgeId);return RestVO.success(Map.of("success", true, "message", "文件已向量化"));}@Operation(summary = "向量检索", description = "向量检索")@GetMapping("/query")public RestVO<List<Document>> uploadFile(@RequestParam String query, @RequestParam Double threshold, @RequestParam(required = false) String knowledgeId) {List<Document> documentList = vectorService.search(query, knowledgeId,threshold);return RestVO.success(documentList);}
}

查询结果
在这里插入图片描述

5, 检索结果运用

        List<Message> messages = new ArrayList<>();//省略历史会话UserMessage userMessage;//TODO 可以先对用户问题做关键词提取再去检索List<Document> documentList = vectorStore.similaritySearch(body.getMessage());System.out.println("检索结果" + documentList.size());if (documentList != null && !documentList.isEmpty()) {String context = documentList.stream().map(Document::getText).collect(Collectors.joining(""));userMessage = new UserMessage("参考内容:【\n" + context + "】\n\n回答:【" + body.getMessage() + "】");} else {userMessage = new UserMessage(body.getMessage());}messages.add(userMessage);Prompt prompt = new Prompt(messages);

预览效果
在这里插入图片描述

http://www.xdnf.cn/news/1100305.html

相关文章:

  • javaweb之相关jar包和前端包下载。
  • PHY模式,slave master怎么区分
  • 7.11文件和异常
  • 什么是进程、什么是线程(进程、线程的全方面解析)
  • 界面组件DevExpress WPF中文教程:Grid - 如何检查节点?
  • 在 React Three Fiber 中实现 3D 模型点击扩散波效果
  • JavaWeb笔记二
  • 企业级配置:Azure 邮件与 Cloudflare 域名解析的安全验证落地详解
  • CReFT-CAD 笔记 带标注工程图dxf,png数据集
  • JVM 内存结构
  • 每天一个前端小知识 Day 29 - WebGL / WebGPU 数据可视化引擎设计与实践
  • 人工智能-基础篇-29-什么是低代码平台?
  • AI问答之手机相机专业拍照模式的主要几个参数解释
  • 人工智能-基础篇-28-模型上下文协议--MCP请求示例(JSON格式,客户端代码,服务端代码等示例)
  • 大数据学习7:Azkaban调度器
  • 《Effective Python》第十三章 测试与调试——使用 Mock 测试具有复杂依赖的代码
  • Three.js+Shader实现三维波动粒子幕特效
  • 量子计算系统软件:让“脆弱”的量子计算机真正可用
  • DDL期间TDSQL异常会话查询造成数据库主备切换
  • 【NLP入门系列六】Word2Vec模型简介,与以《人民的名义》小说原文实践
  • 如何利用个人电脑搭建数据库服务器实现远程协作
  • RabbitMQ用法的6种核心模式全面解析
  • 零基础入门物联网-远程门禁开关:云平台创建
  • 自动驾驶控制系统
  • 李宏毅(深度学习)--(2)
  • 【TCP/IP】10. 引导协议与动态主机配置协议
  • 查看uniapp 项目中没有用到依赖
  • mx6ull-裸机学习实验15——RTC 实时时钟实验
  • 【养老机器人】核心技术
  • 栈题解——有效的括号【LeetCode】两种方法