核心内容摘要
SeqGPT-560M零样本实战:不提供训练数据,仅靠Prompt完成司法文书要素抽取
使用 PostgreSQL pgvector 实现 RAG 向量存储与语义检索Java 实战在 RAGRetrieval-Augmented Generation系统中向量存储与相似度检索是最核心的一环。
本文将使用PostgreSQL pgvector结合Java 阿里百炼 Embedding 模型实现一个完整、可运行的向量存储与语义检索示例。
本文不仅关注“能跑”更重点解释为什么这么设计以及RAG 中最容易踩的坑。
pgvector 是什么pgvector是 PostgreSQL 的一个扩展插件为 PostgreSQL 提供了专门的vector 类型用于存储高维向量并支持余弦距离cosine distance欧氏距离L2内积inner product向量索引ivfflat / hnsw这使得 PostgreSQL 可以直接作为向量数据库使用非常适合中小规模 RAG 场景。
安装 PostgreSQL 与 pgvector安装过程不再赘述。
可参考 CSDN 博主进击的女IT的文章https://blog.csdn.net/weixin_63908159/article/details/156075242
建表与索引设计非常重要1️⃣ 建表语句CREATETABLEdocument(id BIGSERIALPRIMARYKEY,contentTEXTNOTNULL,embedding vector(
,create_timeTIMESTAMPDEFAULTnow());⚠️注意vector(
必须与 Embedding 模型输出的向量维度一致。
如果模型输出是 1536 维这里必须改成vector(
否则插入时会报错expected xxx dimensions。
2️⃣ 向量索引否则数据一多会非常慢CREATEINDEXidx_document_embeddingONdocumentUSINGivfflat(embedding vector_cosine_ops)WITH(lists
;查询前建议设置SETivfflat.probes10;
Java 实体类设计pgvector在 Java 中无需特殊类型映射直接使用String承载即可。
DatapublicclassDocument{privateLongid;privateStringcontent;/** * pgvector 字段 * 使用 String 承载例如[
12,
34,...] */privateStringembedding;privateLocalDateTimecreateTime;}
Embedding 模型配置阿里百炼配置文件 (application.yml)alibaba:dashscope:key:sk-xxxurl:https://dashscope.aliyuncs.com/compatible-mode/v1/embeddingsmodel:text-embedding-v4配置类ConfigurationConfigurationProperties(prefixalibaba.dashscope)DatapublicclassAlibabaDashscopeConfig{privateStringkey;privateStringurl;privateStringmodel;}
文本向量化服务EmbeddingService功能文本 → 向量 (ListFloat)ServiceSlf4jpublicclassEmbeddingService{AutowiredprivateAlibabaDashscopeConfigconfig;publicListFloatgetEmbedding(Stringtext){if(StrUtil.isBlank(text)){returnList.of();}MapString,ObjectbodyMap.of(model,config.getModel(),input,List.of(text));HttpResponseresponseHttpRequest.post(config.getUrl()).header(Authorization,Bearer config.getKey()).header(Content-Type,application/json).body(JSONUtil.toJsonStr(body)).timeout(
.execute();JSONObjectjsonJSONUtil.parseObj(response.body());JSONArrayembeddingjson.getJSONArray(data).getJSONObject(
.getJSONArray(embedding);returnembedding.toList(Float.class);}}
向量存储与相似度查询MapperMapperpublicinterfaceDocumentMapperextendsBaseMapperDocument{/** * 向量相似度搜索余弦距离 */Select( SELECT id, content FROM document ORDER BY embedding #{embedding}::vector LIMIT #{limit} )ListDocumentsearchByEmbedding(Param(embedding)Stringembedding,Param(limit)intlimit);Insert( INSERT INTO document (content, embedding) VALUES (#{content}, #{embedding}::vector) )voidinsertDocument(Param(content)Stringcontent,Param(embedding)Stringembedding);}ServiceServiceRequiredArgsConstructorpublicclassDocumentService{privatefinalDocumentMappermapper;privatefinalEmbeddingServiceembeddingService;publicvoidaddDocument(Stringcontent){ListFloatvectorembeddingService.getEmbedding(content);StringpgVectorvector.stream().map(String::valueOf).collect(Collectors.joining(,,[,]));mapper.insertDocument(content,pgVector);}publicListDocumentsearch(Stringquery,inttopK){ListFloatvectorembeddingService.getEmbedding(query);if(vector.isEmpty()){returnList.of();}StringpgVectorvector.stream().map(String::valueOf).collect(Collectors.joining(,,[,]));returnmapper.searchByEmbedding(pgVector,topK);}}
Controller 接口RestControllerRequestMapping(/document)RequiredArgsConstructorpublicclassDocumentController{privatefinalDocumentServiceservice;GetMapping(/add)publicvoidadd(RequestParamStringcontent){service.addDocument(content);}GetMapping(/search)publicListDocumentsearch(RequestParamStringquery,RequestParam(defaultValue
inttopK){returnservice.search(query,topK);}}
为什么“最近流行什么”查询不到结果这是语义检索中最容易被误解的一点向量检索 ≠ 关键词匹配向量检索判断的是语义是否在同一语义空间。
示例文本语义中心Java 是一门流行的后端开发语言编程 / 后端最近流行什么趋势 / 热点 两者在语义空间中的距离很远因此检索不到是正常且正确的行为。
正确做法Query Rewrite查询重写补充领域上下文例如最近流行的后端开发语言有哪些
十、
总结pgvector可以让 PostgreSQL 直接作为向量数据库使用。
向量检索本质是语义相似度计算。
RAG 的效果高度依赖于文档内容的表达方式Query 是否足够具体相似度阈值与 TopK 的设计项目完整源码地址Giteehttps://gitee.com/tfxing12138/rag-demo.git