LangChain4j 集成 Valkey基于 HNSW 向量索引的 Java Embedding Store 实战【免费下载链接】langchain4jLangChain4j is an idiomatic, open-source Java library for building LLM-powered applications on the JVM. It offers a unified API over popular LLM providers and vector stores, and makes implementing tool calling (including MCP support), agents and RAG easy. It integrates seamlessly with enterprise Java frameworks like Quarkus and Spring Boot.项目地址: https://gitcode.com/GitHub_Trending/la/langchain4jValkey 是 Redis 的高性能开源分支自 Valkey 8 起内置原生向量检索能力。本文以langchain4j-community-valkey模块为主线讲解如何在纯 Java 或 Spring Boot 应用中把 Valkey 作为 LangChain4j 的 Embedding Store覆盖环境搭建、索引自动创建、向量写入与相似度检索、元数据过滤等完整实战链路。读完本文你将能够独立搭建一套基于 Valkey HNSW 索引的 RAG 向量检索底座并与 LangChain4j 的统一EmbeddingStoreAPI 无缝对接。集成概览Valkey 为何适合做向量存储langchain4j-community-valkey是 LangChain4j 社区提供的一个 Embedding Store 集成模块其核心思想是把 Valkey 既当作内存数据存储又当作向量数据库使用。根据官方文档描述该集成的关键设计如下依赖 Valkey 内置向量检索能力需要 Valkey 8 版本而本模块实际要求Valkey 9.1因为索引创建依赖较新的 Search 与 JSON 模块使用官方valkey-glide客户端glideGeneral Language Integrated Data-plane Engine是 Valkey 官方维护的高性能多语言客户端支持异步、集群模式JSON 结构化存储Embedding 向量、原文文本TextSegment与元数据Metadata以结构化 JSON 文档形式存入 ValkeyHNSW 索引默认基于 HNSWHierarchical Navigable Small World图索引配合 COSINE 距离度量目标是在海量向量上实现亚毫秒级相似度检索。需要说明的是该模块由 langchain4j-community 社区仓库维护不在当前 langchain4j 主仓库源码树内但它在 API 层面完全遵循 LangChain4j 核心定义的EmbeddingStore统一接口因此接入方式与其他 30 种 Embedding Store 完全一致。环境准备一条命令启动带向量检索的 Valkey由于向量索引依赖 JSON 与 Search 模块官方建议直接使用内置这两个模块的valkey/valkey-bundle镜像而不要使用纯基础镜像docker run -d --name valkey -p 6379:6379 valkey/valkey-bundle:latest参数说明参数含义-d后台运行容器--name valkey容器命名为valkey-p 6379:6379将容器内 6379 端口映射到宿主机供localhost:6379访问启动后即可通过GlideClient连接。如果你已有其他方式运行的 Valkey 9.1 实例只要具备 JSON 与 Search 模块同样可以接入。添加 Maven 依赖Valkey 集成在dev.langchain4j组下的langchain4j-community系列 artifact 中分为纯 Java 与 Spring Boot Starter 两种坐标。纯 Java 应用dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-community-valkey/artifactId version${latest version here}/version /dependencySpring Boot 应用dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-community-valkey-spring-boot-starter/artifactId version${latest version here}/version /dependency使用 BOM 统一管理版本如果你在一个多模块项目里同时使用多个 LangChain4j 集成推荐引入langchain4j-community-bom避免逐个维护版本号dependencyManagement dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-community-bom/artifactId version${latest version here}/version typepom/type scopeimport/scope /dependency /dependencyManagement使用 BOM 后各langchain4j-community-*依赖的version标签可以省略。注意实际使用时将${latest version here}替换为 Maven Central 上的最新版本号。创建 ValkeyEmbeddingStoreValkeyEmbeddingStore是该集成的核心入口类通过 Builder 模式构建构建过程分两步先建立GlideClient连接再基于连接构建存储。import dev.langchain4j.community.store.embedding.valkey.ValkeyEmbeddingStore; import glide.api.GlideClient; import glide.api.models.configuration.GlideClientConfiguration; import glide.api.models.configuration.NodeAddress; // 1. Create a GlideClient connection GlideClientConfiguration config GlideClientConfiguration.builder() .address(NodeAddress.builder().host(localhost).port(6379).build()) .build(); GlideClient client GlideClient.createClient(config).get(); // 2. Build the embedding store ValkeyEmbeddingStore embeddingStore ValkeyEmbeddingStore.builder() .client(client) .dimension(384) // Must match your embedding models output dimension .indexName(my-index) // Optional, defaults to embedding-index .prefix(docs:) // Optional, defaults to embedding: .build();关键点解读dimension必须与 Embedding 模型的输出维度一致。上例使用 384 维对应常见的all-MiniLM-L6-v2系列模型若维度不匹配检索时会出现向量长度校验错误indexName可省略默认值为embedding-indexprefix是存储 key 的前缀建议以:结尾以形成命名空间隔离默认embedding:。RAG 场景下可用不同前缀区分不同文档集调用build()时存储会检查 Valkey 中是否已存在同名索引若不存在会自动创建 HNSW 索引并使用 COSINE 距离度量均为默认值这也是为什么dimension在索引不存在时是必填项。配置选项一览ValkeyEmbeddingStore.builder()支持的配置参数如下参数说明默认值clientGlideClient实例必填—dimensionEmbedding 向量维度索引不存在时必填—indexNameValkey 搜索索引名称embedding-indexprefix存储的 key 前缀应以:结尾embedding:metadataKeys需要持久化为 Tag 字段的元数据 key 集合—metadataConfig元数据 key 到FieldInfo的映射用于自定义字段类型—operationTimeoutSeconds每次 Valkey 操作的超时时间秒60其中metadataKeys与metadataConfig与后续元数据过滤能力直接相关详见下文「元数据过滤」一节。距离度量MetricTypeValkey 内置的向量搜索支持三种距离度量通过MetricType枚举选择枚举值含义说明COSINE余弦相似度默认值度量向量方向上的相似性对向量模长不敏感最常用于文本语义检索IP内积Inner Product适合归一化后的向量内积越大越相似L2欧氏距离度量绝对距离数值越小越相似选择建议绝大多数文本 Embedding 场景使用默认的COSINE即可若你的 Embedding 模型已做 L2 归一化IP与COSINE结果等价但计算更快L2更适合对绝对距离有语义要求的场景。存储与检索 Embedding下面是一个从「批量写入」到「相似度查询」的完整示例使用 LangChain4j 内置的AllMiniLmL6V2EmbeddingModel384 维作为本地 Embedding 模型import dev.langchain4j.data.embedding.Embedding; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.model.embedding.EmbeddingModel; import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel; import dev.langchain4j.store.embedding.EmbeddingMatch; import dev.langchain4j.store.embedding.EmbeddingSearchRequest; import dev.langchain4j.store.embedding.EmbeddingSearchResult; import java.util.List; EmbeddingModel embeddingModel new AllMiniLmL6V2EmbeddingModel(); // Batch ingest ListTextSegment docs List.of( TextSegment.from(Valkey is a high-performance in-memory data store.), TextSegment.from(Vector search finds similar items by embedding distance.), TextSegment.from(HNSW is an algorithm for approximate nearest neighbors.) ); ListEmbedding embeddings embeddingModel.embedAll(docs).content(); ListString ids embeddingStore.addAll(embeddings, docs); // Search Embedding queryEmbedding embeddingModel.embed(How does similarity search work?).content(); EmbeddingSearchResultTextSegment results embeddingStore.search( EmbeddingSearchRequest.builder() .queryEmbedding(queryEmbedding) .maxResults(3) .minScore(0.5) .build() ); for (EmbeddingMatchTextSegment match : results.matches()) { System.out.printf(%.3f: %s%n, match.score(), match.embedded().text()); }这段代码背后的 API 契约来自 LangChain4j 核心模块embeddingStore.addAll(...)返回自动生成的 UUID 字符串 ID 列表——在 EmbeddingStore 接口 中addAll(embeddings, embedded)默认方法会先generateIds(size)生成 ID再调用带 ID 的重载完成批量写入EmbeddingSearchRequest中的maxResults控制返回条数minScore控制相似度阈值低于该分数的匹配会被过滤掉二者是 LangChain4j 所有 Embedding Store 共用的统一检索参数EmbeddingMatch.score()返回的是相似度分值COSINE 语义下越大越相似范围通常在 01 之间embedded()返回命中的原始文本段。这一整套add / addAll / search方法与 30 种其他 Embedding Store如 Chroma、Elasticsearch、Milvus 等完全一致意味着后续更换向量库时业务代码几乎零改动这正是 LangChain4j 统一 API 设计的价值所在。元数据过滤元数据过滤Metadata Filtering是 RAG 场景中「先过滤、再检索」的常用手段可以显著提升检索精度。Valkey 集成支持的过滤类型如下数值字段Numericeq、neq、gt、gte、lt、lte标签/文本字段Tag/Texteq、neq、in、notIn要启用过滤能力必须在构建 store 时声明元数据字段否则这些字段不会被索引为可查询字段。方式一简单标签过滤metadataKeys如果元数据字段全部按文本 Tag 处理用metadataKeys声明即可ValkeyEmbeddingStore store ValkeyEmbeddingStore.builder() .client(client) .dimension(384) .metadataKeys(List.of(category, author)) .build();方式二类型化字段metadataConfig如果同一索引中既有文本又有数值字段需要用metadataConfig精确声明每个字段的 JSON 路径与类型。FieldInfo支持通过TagField、NumericField等子类描述字段类型import glide.api.models.commands.FT.FTCreateOptions.FieldInfo; import glide.api.models.commands.FT.FTCreateOptions.NumericField; import glide.api.models.commands.FT.FTCreateOptions.TagField; MapString, FieldInfo metadataConfig Map.of( category, new FieldInfo($.category, category, new TagField(,, true)), year, new FieldInfo($.year, year, new NumericField()) ); ValkeyEmbeddingStore store ValkeyEmbeddingStore.builder() .client(client) .dimension(384) .indexName(filtered-docs) .prefix(filtered:) .metadataConfig(metadataConfig) .build();上例中category被声明为 Tag 字段分隔符,true表示该字段可空year被声明为数值字段对应 JSON 路径分别为$.category与$.year。在检索请求中使用 Filter过滤条件通过 LangChain4j 核心的MetadataFilterBuilder构建入口位于 MetadataFilterBuilder支持单条件、AND 组合与 OR 组合import static dev.langchain4j.store.embedding.filter.MetadataFilterBuilder.metadataKey; // TAG filter Filter securityFilter metadataKey(category).isEqualTo(security); // NUMERIC filter Filter recentFilter metadataKey(year).isGreaterThanOrEqualTo(2025); // Combined AND filter Filter combined metadataKey(category).isEqualTo(security) .and(metadataKey(year).isGreaterThanOrEqualTo(2025)); // OR filter Filter either metadataKey(category).isEqualTo(security) .or(metadataKey(category).isEqualTo(performance)); EmbeddingSearchResultTextSegment results store.search( EmbeddingSearchRequest.builder() .queryEmbedding(queryEmbedding) .maxResults(5) .filter(combined) .build() );从 MetadataFilterBuilder 源码 可以看到metadataKey(key)返回一个针对指定元数据 key 的构建器isEqualTo、isGreaterThanOrEqualTo、in、notIn等方法分别构造IsEqualTo、IsGreaterThanOrEqualTo、IsIn、IsNotIn等比较谓词and/or则组合成复合过滤树最终由各个 Embedding Store 实现翻译成各自的查询语法对 Valkey 而言即 Search 模块的过滤表达式。测试与验证该集成在 langchain4j-community 仓库中提供了集成测试ValkeyEmbeddingStoreIT覆盖了 store 的创建、向量写入、检索与过滤等核心链路。建议你在本地启动上述 Docker 容器后参考该集成测试的用例模式编写自己的冒烟测试验证「写入 → 检索 → 过滤」全流程后再接入业务代码。注意事项与最佳实践版本匹配请确认你的 Valkey 服务端版本不低于 9.1且具备 JSON 与 Search 模块valkey-bundle镜像已内置这两个模块维度一致性dimension必须严格等于 Embedding 模型的输出维度模型更换如从 384 维升级到 768 维时需同步调整并重建索引命名空间规划通过prefix如docs:、qa:与indexName隔离不同业务的数据避免相互干扰超时设置默认operationTimeoutSeconds为 60 秒在慢网络或集群环境下可适当调大过滤字段先行声明需要参与过滤的元数据字段必须通过metadataKeys或metadataConfig提前声明检索阶段才可使用对应 FilterAPI 可移植性由于遵循 EmbeddingStore 统一接口业务代码不绑定 Valkey 特性后续可平滑迁移到其他向量库。【免费下载链接】langchain4jLangChain4j is an idiomatic, open-source Java library for building LLM-powered applications on the JVM. It offers a unified API over popular LLM providers and vector stores, and makes implementing tool calling (including MCP support), agents and RAG easy. It integrates seamlessly with enterprise Java frameworks like Quarkus and Spring Boot.项目地址: https://gitcode.com/GitHub_Trending/la/langchain4j创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考