LangChain4j集成Chroma向量数据库实战:从零构建语义搜索应用

1次阅读
没有评论

共计 2808 个字符,预计需要花费 8 分钟才能阅读完成。

image.webp

背景与痛点

传统全文检索(如 Elasticsearch)基于关键词匹配,无法理解 ” 汽车 ” 和 ” 机动车 ” 的语义关联。当用户搜索 ” 省油的交通工具 ” 时,传统方案可能完全失效。向量数据库将文本转换为高维向量(如 384/768 维),通过余弦相似度等算法实现语义级搜索。

LangChain4j 集成 Chroma 向量数据库实战:从零构建语义搜索应用

技术选型对比

维度 Chroma Milvus Pinecone
部署复杂度 单机 Docker 一键启动 需要分布式集群 SaaS 云服务
Java SDK 成熟度 通过 LangChain4j 间接支持 官方 SDK 完善 需自行封装 REST 调用
延迟 (ms) 15-50 (本地网络) 20-80 30-100
最大 QPS 约 2000 (CPU 模式) 5000+ 按需扩展

实战步骤

1. Chroma 部署

docker pull chromadb/chroma
# CPU 模式
docker run -p 8000:8000 chromadb/chroma
# GPU 模式(需 NVIDIA 环境)docker run --gpus all -p 8000:8000 chromadb/chroma

关键参数说明:
--env PERSIST_DIRECTORY=/data 可设置持久化目录
--env ALLOW_RESET=true 允许通过 API 清空数据

2. LangChain4j 集成

Maven 依赖

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-chroma</artifactId>
    <version>0.22.0</version>
</dependency>

向量化配置(二选一)

// 方案 1:使用本地 HuggingFace 模型
EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();

// 方案 2:接入 OpenAI
EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder()
    .apiKey("sk-***")
    .modelName("text-embedding-3-small")
    .dimensions(512) // 显式指定维度
    .build();

3. 核心代码实现

数据写入

@RequiredArgsConstructor
public class ChromaService {
    private final EmbeddingModel embeddingModel;
    private final ChromaEmbeddingStore embeddingStore = new ChromaEmbeddingStore("http://localhost:8000");

    public void indexDocument(String docId, String text) {Embedding embedding = embeddingModel.embed(text).content();
        embeddingStore.add(docId, embedding, Metadata.from("source", "web-crawler"));
    }

    // 批量写入(推荐)public void bulkIndex(List<Document> docs) {List<Embedding> embeddings = embeddingModel.embedAll(docs.stream()
            .map(Document::text)
            .collect(Collectors.toList())).content();

        List<String> ids = docs.stream()
            .map(Document::id)
            .collect(Collectors.toList());

        embeddingStore.addAll(ids, embeddings, Collections.nCopies(docs.size(), Metadata.empty()));
    }
}

语义搜索

public List<ScoredDocument> semanticSearch(String query, int topK) {Embedding queryEmbedding = embeddingModel.embed(query).content();
    List<EmbeddingMatch<Metadata>> matches = embeddingStore.findRelevant(queryEmbedding, topK, 0.6);

    return matches.stream()
        .map(match -> new ScoredDocument(match.embeddingId(),
            match.score(), // 余弦相似度得分
            match.embedded().toString()
        ))
        .collect(Collectors.toList());
}

性能优化

写入优化

// 在 ChromaEmbeddingStore 初始化时配置
ChromaClientConfig config = ChromaClientConfig.builder()
    .baseUrl("http://localhost:8000")
    .connectTimeout(Duration.ofSeconds(10))
    .writeBatchSize(500) // 每批 500 条
    .maxConnections(20)  // 连接池大小
    .build();

查询优化

  1. Top- K 选择 :根据业务需求动态调整(建议 10-100)
  2. 距离阈值
  3. 余弦相似度:0.6-0.8 过滤低质量结果
  4. 欧氏距离:需根据向量维度调整

避坑指南

  1. 内存管理
  2. 单条文本向量化前检查长度(建议 <512 tokens)
  3. 分批处理 10 万 + 文档时,每批完成后手动调用 System.gc()

  4. 多线程安全

    // 使用 ThreadLocal 保证线程安全
    private static final ThreadLocal<ChromaClient> clientHolder = ThreadLocal.withInitial(() -> ChromaClient.builder().baseUrl("http://localhost:8000").build());

扩展应用

FAQ 机器人实现架构

flowchart LR
    A[用户问题] --> B[向量化]
    B --> C[Chroma 相似度检索]
    C --> D[Top3 候选答案]
    D --> E[LLM 生成最终回复]

推荐系统增强

  • 混合检索:结合向量搜索与业务规则过滤
  • 实时更新:监听 MySQL binlog 触发向量更新

测试数据参考

环境:MacBook Pro M1/16GB, Docker 4.0
– 100 万条 512 维向量
– 写入吞吐:约 1200 docs/s
– 查询延迟:平均 23ms(TopK=10)

通过合理配置,Chroma 在中等规模数据下完全可用。如需千万级数据,建议评估 Milvus 集群方案。

正文完
 0
评论(没有评论)