大模型应用
用 LangChain4J 配置向量库做 RAG…
在 Java 应用中使用 LangChain4J 接入向量数据库(pgvector、Pinecone、MongoDB、Milvus、Neo4j)实现 RAG 语义检索时的配置、验证与生产优化做法。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 58/100 ×0.15
适用场景
用 LangChain4J 配置向量库做特定
解决思路
- 用 Builder 模式配置基础向量存储:通过 PgVectorEmbeddingStore.builder() 设置 host、port、database、user、password、table、dimension(如 OpenAI 的 1536)、createTable(true)、useIndex(true) 后 build(),并注册为 @Bean。
- 按验证工作流逐步确认配置正确:1) 用所需维度和连接参数构建 embedding store;2) 在写入数据前先做连接健康检查;3) 确认 embedding 模型维度与 store 配置一致;4) 写入一小批测试文档验证写入流程;5) 执行一次示例语义搜索确认检索准确;6) 全部通过后再进行全量数据写入。
- 用 @Qualifier 配置多个向量存储以服务不同场景:例如 documentsStore 用 PgVectorEmbeddingStore 存文档,chatHistoryStore 用 MongoDbEmbeddingStore 存聊天记录,分别指定 table/collectionName 和 dimension。
- 用 EmbeddingStoreIngestor 实现自动化文档摄入:配置 DocumentSplitters.recursive(300, 20, new OpenAiTokenizer(GPT_3_5_TURBO)) 做分片,并绑定 embeddingModel 与 embeddingStore。
- 配置元数据过滤:用 IndexMapping.builder().dimension(1536).metadataFieldNames(Set.of("category","source","created_date","author")) 建立字段映射;查询时用 EmbeddingSearchRequest.builder().queryEmbedding(...).maxResults(10).filter(and(metadataKey("category").isEqualTo("technical_docs"), metadataKey("created_date").isGreaterThan(LocalDate.now().minusMonths(6)))) 做过滤。
- 生产环境用连接池:通过 HikariConfig 设置 jdbcUrl、username、password、maximumPoolSize(20)、minimumIdle(5)、connectionTimeout(30000),构建 HikariDataSource 后传给 PgVectorEmbeddingStore.builder().dataSource(...),并开启 useIndex(true)。
- 实现健康检查:编写实现 HealthIndicator 的组件,用零向量(Collections.nCopies(1536, 0.0f))发起一次 maxResults(1) 的搜索,成功返回 Health.up() 并附带 store 类名,异常返回 Health.down() 并附带错误信息。
- 按场景选择向量库:开发测试用 InMemoryEmbeddingStore(快、无外部依赖、重启丢数据);生产可选 PostgreSQL+pgvector(已有 PG 环境)、Pinecone(托管、快速原型)、MongoDB Atlas(已有 MongoDB 应用)、Milvus/Zilliz(大规模高性能)。
- 按性能需求选择索引类型:高召回用 IndexType.FLAT(精确但慢);均衡用 IndexType.IVF_FLAT;高速近似搜索用 IndexType.HNSW(最快但精度略低)。
- 匹配 embedding 维度:OpenAI text-embedding-3-small 用 1536,text-embedding-3-large 用 3072,Sentence Transformers all-MiniLM-L6-v2 用 384、all-mpnet-base-v2 用 768。
- 用批量操作提升性能:按 BATCH_SIZE=100 用 Lists.partition 分批,将 Document 转为 TextSegment 后调用 embeddingModel.embedAll(segments).content() 批量生成向量,再用 embeddingStore.addAll(embeddings, segments) 批量写入。
- 安全配置:用 @Value("${vector.store.api.key:#{null}}") 从环境变量读取密钥,并在 @PostConstruct 中校验,缺失时抛出 IllegalStateException 快速失败。
- 生产环境加监控:用 MonitoredEmbeddingStore<>(store, meterRegistry) 包装底层 store,并注入 MeterRegistry 采集指标。
- 语义搜索服务实现:用 embeddingModel.embed(query).content() 生成查询向量,构造 EmbeddingSearchRequest 设置 maxResults 与 minScore(0.75),从 store.search(request).matches() 中提取 match.embedded().text() 返回。
- 注意维度必须与 embedding 模型一致,否则报错;大集合必须配置索引;embedding 生成昂贵需批处理与缓存;不同向量库支持的距离度量不同需确认兼容;生产必须用连接池防止连接耗尽;元数据过滤能力因实现而异;向量库内存占用大需监控;跨供应商迁移可能需重新 embedding;批量操作优于单条操作;启动时校验配置以快速失败。
适用边界 · 注意事项
- 不使用 LangChain4j 或 Java 技术栈的项目不适用。
- 仅做本地内存测试、不需要持久化或生产级向量检索时,无需按本文配置连接池、索引与监控。
- 未确定 embedding 模型维度或向量库供应商前,不要盲目套用具体 dimension 与索引类型配置。