Skip to content

向量存储

嵌入模型选择

嵌入模型用于将文本转换为向量表示。LangChain 4J 支持多种嵌入模型:

OpenAI 嵌入模型

java
import dev.langchain4j.embedding.openai.OpenAiEmbeddingModel;
import dev.langchain4j.embedding.EmbeddingModel;

// 创建 OpenAI 嵌入模型
EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder()
        .apiKey(System.getenv("OPENAI_API_KEY"))
        .modelName("text-embedding-ada-002")
        .build();

// 生成嵌入
List<Double> embedding = embeddingModel.embed("这是一段文本");
System.out.println("嵌入向量维度:" + embedding.size());

Hugging Face 嵌入模型

java
import dev.langchain4j.embedding.huggingface.HuggingFaceEmbeddingModel;

// 创建 Hugging Face 嵌入模型
EmbeddingModel embeddingModel = HuggingFaceEmbeddingModel.builder()
        .accessToken(System.getenv("HUGGING_FACE_ACCESS_TOKEN"))
        .modelId("sentence-transformers/all-MiniLM-L6-v2")
        .build();

// 生成嵌入
List<Double> embedding = embeddingModel.embed("这是一段文本");
System.out.println("嵌入向量维度:" + embedding.size());

本地嵌入模型

java
import dev.langchain4j.embedding.local.LocalEmbeddingModel;

// 创建本地嵌入模型
EmbeddingModel embeddingModel = LocalEmbeddingModel.builder()
        .modelPath("path/to/model")
        .build();

// 生成嵌入
List<Double> embedding = embeddingModel.embed("这是一段文本");
System.out.println("嵌入向量维度:" + embedding.size());

向量数据库集成

LangChain 4J 支持多种向量数据库:

Chroma 集成

java
import dev.langchain4j.store.embedding.chroma.ChromaEmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStore;

// 创建 Chroma 嵌入存储
EmbeddingStore embeddingStore = ChromaEmbeddingStore.builder()
        .baseUrl("http://localhost:8000")
        .collectionName("documents")
        .build();

Pinecone 集成

java
import dev.langchain4j.store.embedding.pinecone.PineconeEmbeddingStore;

// 创建 Pinecone 嵌入存储
EmbeddingStore embeddingStore = PineconeEmbeddingStore.builder()
        .apiKey(System.getenv("PINECONE_API_KEY"))
        .environment("gcp-starter")
        .indexName("documents")
        .build();

Milvus 集成

java
import dev.langchain4j.store.embedding.milvus.MilvusEmbeddingStore;

// 创建 Milvus 嵌入存储
EmbeddingStore embeddingStore = MilvusEmbeddingStore.builder()
        .host("localhost")
        .port(19530)
        .collectionName("documents")
        .build();

FAISS 集成

java
import dev.langchain4j.store.embedding.faiss.FaissEmbeddingStore;

// 创建 FAISS 嵌入存储
EmbeddingStore embeddingStore = FaissEmbeddingStore.builder()
        .indexPath("path/to/index")
        .build();

相似度搜索

基本搜索

java
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingMatch;

// 添加文档到存储
embeddingStore.add("文档1内容", "文档1");
embeddingStore.add("文档2内容", "文档2");
embeddingStore.add("文档3内容", "文档3");

// 搜索相似文档
List<EmbeddingMatch> matches = embeddingStore.findRelevant("查询文本", 3);

for (EmbeddingMatch match : matches) {
    System.out.println("相似度:" + match.score());
    System.out.println("文档内容:" + match.embedded().text());
}

高级搜索

java
// 高级搜索配置
List<EmbeddingMatch> matches = embeddingStore.findRelevant(
        "查询文本", 
        3, // 返回的结果数量
        0.7 // 相似度阈值
);

检索增强生成 (RAG)

基本 RAG

java
import dev.langchain4j.retriever.EmbeddingStoreRetriever;
import dev.langchain4j.chain.rag.RetrievalAugmentedGenerationChain;
import dev.langchain4j.model.openai.OpenAiChatModel;

// 创建检索器
EmbeddingStoreRetriever retriever = EmbeddingStoreRetriever.builder()
        .embeddingStore(embeddingStore)
        .embeddingModel(embeddingModel)
        .maxResults(3)
        .minScore(0.7)
        .build();

// 创建模型
OpenAiChatModel model = OpenAiChatModel.builder()
        .apiKey(System.getenv("OPENAI_API_KEY"))
        .build();

// 创建 RAG 链
RetrievalAugmentedGenerationChain ragChain = RetrievalAugmentedGenerationChain.builder()
        .retriever(retriever)
        .model(model)
        .build();

// 执行 RAG
String response = ragChain.run("查询问题");
System.out.println("RAG 响应:" + response);

高级 RAG

java
// 高级 RAG 配置
RetrievalAugmentedGenerationChain ragChain = RetrievalAugmentedGenerationChain.builder()
        .retriever(retriever)
        .model(model)
        .promptTemplate(PromptTemplate.from("根据以下信息回答问题:\n{information}\n\n问题:{question}"))
        .build();

// 执行 RAG
String response = ragChain.run("查询问题");
System.out.println("RAG 响应:" + response);

自定义向量存储

您可以通过实现 EmbeddingStore 接口来创建自定义向量存储:

基本自定义存储

java
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.data.segment.TextSegment;

public class CustomEmbeddingStore implements EmbeddingStore {
    private final Map<String, List<Double>> embeddings = new HashMap<>();
    private final Map<String, String> texts = new HashMap<>();
    
    @Override
    public void add(String text, String id) {
        // 生成嵌入并存储
        List<Double> embedding = generateEmbedding(text);
        embeddings.put(id, embedding);
        texts.put(id, text);
    }
    
    @Override
    public List<EmbeddingMatch> findRelevant(String text, int maxResults) {
        // 生成查询嵌入
        List<Double> queryEmbedding = generateEmbedding(text);
        
        // 计算相似度
        List<EmbeddingMatch> matches = new ArrayList<>();
        for (Map.Entry<String, List<Double>> entry : embeddings.entrySet()) {
            double similarity = calculateSimilarity(queryEmbedding, entry.getValue());
            TextSegment segment = TextSegment.from(texts.get(entry.getKey()));
            EmbeddingMatch match = EmbeddingMatch.from(similarity, segment);
            matches.add(match);
        }
        
        // 按相似度排序并返回
        matches.sort(Comparator.comparing(EmbeddingMatch::score).reversed());
        return matches.stream().limit(maxResults).collect(Collectors.toList());
    }
    
    private List<Double> generateEmbedding(String text) {
        // 实现嵌入生成逻辑
        return new ArrayList<>();
    }
    
    private double calculateSimilarity(List<Double> embedding1, List<Double> embedding2) {
        // 实现相似度计算逻辑
        return 0.0;
    }
}

高级自定义存储

java
public class DatabaseEmbeddingStore implements EmbeddingStore {
    private final DataSource dataSource;
    
    public DatabaseEmbeddingStore(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    @Override
    public void add(String text, String id) {
        // 存储到数据库
        try (Connection conn = dataSource.getConnection()) {
            String sql = "INSERT INTO embeddings (id, text, embedding) VALUES (?, ?, ?)";
            try (PreparedStatement stmt = conn.prepareStatement(sql)) {
                stmt.setString(1, id);
                stmt.setString(2, text);
                stmt.setString(3, embeddingToString(generateEmbedding(text)));
                stmt.executeUpdate();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    
    @Override
    public List<EmbeddingMatch> findRelevant(String text, int maxResults) {
        // 从数据库查询并计算相似度
        List<EmbeddingMatch> matches = new ArrayList<>();
        List<Double> queryEmbedding = generateEmbedding(text);
        
        try (Connection conn = dataSource.getConnection()) {
            String sql = "SELECT id, text, embedding FROM embeddings";
            try (PreparedStatement stmt = conn.prepareStatement(sql)) {
                try (ResultSet rs = stmt.executeQuery()) {
                    while (rs.next()) {
                        String id = rs.getString("id");
                        String storedText = rs.getString("text");
                        List<Double> storedEmbedding = stringToEmbedding(rs.getString("embedding"));
                        
                        double similarity = calculateSimilarity(queryEmbedding, storedEmbedding);
                        TextSegment segment = TextSegment.from(storedText);
                        EmbeddingMatch match = EmbeddingMatch.from(similarity, segment);
                        matches.add(match);
                    }
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        
        matches.sort(Comparator.comparing(EmbeddingMatch::score).reversed());
        return matches.stream().limit(maxResults).collect(Collectors.toList());
    }
    
    private List<Double> generateEmbedding(String text) {
        // 实现嵌入生成逻辑
        return new ArrayList<>();
    }
    
    private double calculateSimilarity(List<Double> embedding1, List<Double> embedding2) {
        // 实现相似度计算逻辑
        return 0.0;
    }
    
    private String embeddingToString(List<Double> embedding) {
        // 实现嵌入转字符串逻辑
        return "";
    }
    
    private List<Double> stringToEmbedding(String embeddingString) {
        // 实现字符串转嵌入逻辑
        return new ArrayList<>();
    }
}

最佳实践

  1. 选择合适的嵌入模型

    • 考虑模型的性能和准确性
    • 对于特定领域,使用领域特定的嵌入模型
    • 平衡模型大小和性能
  2. 选择合适的向量数据库

    • 根据数据规模选择合适的数据库
    • 考虑部署环境和成本
    • 评估数据库的查询性能
  3. 优化嵌入存储

    • 批量添加文档以提高性能
    • 定期优化索引
    • 监控存储使用情况
  4. 优化相似度搜索

    • 设置合理的相似度阈值
    • 限制返回结果数量
    • 使用过滤条件减少搜索空间
  5. RAG 优化

    • 调整检索参数以提高相关性
    • 优化提示词以提高生成质量
    • 考虑多步检索策略
  6. 性能考虑

    • 缓存频繁使用的嵌入
    • 使用并行处理提高批量操作速度
    • 监控和优化查询性能
  7. 扩展性

    • 设计可扩展的存储架构
    • 考虑数据增长和查询负载
    • 实现数据分片和负载均衡