langchain4j中使用milvus向量数据库做RAG增加索引

发布于:2025-05-13 ⋅ 阅读:(22) ⋅ 点赞:(0)

安装milvus向量数据库

官方网址 https://milvus.io/zh

使用docker安装milvus

mkdir -p /data/docker/milvus
cd /data/docker/milvus
wget https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh

#在docker中启动milvus
sh standalone_embed.sh start
docker ps -a

#停止、删除
sh standalone_embed.sh stop
sh standalone_embed.sh delete

浏览器访问
http://192.168.2.205:9091/webui/


在langchain中使用milvus

  1. pom.xml中引入依赖
	<dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-milvus</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>
  1. 设置配置信息
milvus:
  host: 192.168.1.131
  port: 19530

langchain4j:
  community:
    dashscope:
      chat-model:
        api-key: ${dashscope.key}
        model-name: qwen-max
      embedding-model:
        api-key: ${dashscope.key}
        model-name: text-embedding-v3
      streaming-chat-model:
        api-key: ${dashscope.key}
        model-name: qwen-plus
  1. 配置向量库
@Configuration
@Slf4j
public class EmbeddingStoreConfig {
    @Autowired
    private EmbeddingModel embeddingModel;

    @Value("${milvus.host}")
    private String host;
    @Value("${milvus.port}")
    private Integer port;

    @Bean
    public EmbeddingStore embeddingStore() {
        log.info("==========开始创建Milvus的Collection");
        MilvusEmbeddingStore store = MilvusEmbeddingStore.builder()
                .host(host)
                .port(port)
                .collectionName("langchain_01")
                .dimension(1024)
                .indexType(IndexType.FLAT)
                .metricType(MetricType.COSINE)
//                .username("username")
//                .password("password")
                .consistencyLevel(ConsistencyLevelEnum.EVENTUALLY)
                .autoFlushOnInsert(true)
                .idFieldName("id")
                .textFieldName("text")
                .metadataFieldName("metadata")
                .vectorFieldName("vector")
                .build();
        log.info("==========创建Milvus的Collection完成");
        return store;
    }

}
  1. 使用向量库存储数据
@SpringBootTest
public class EmbeddingTest {
    @Autowired
    private EmbeddingModel embeddingModel;
    @Autowired
    private EmbeddingStore embeddingStore;

    @Test
    public void testEmbeddingModel() {
        Response<Embedding> embed = embeddingModel.embed("你好");
        System.out.println("向量维度:" + embed.content().vector().length);
        System.out.println("向量输出:" + embed.toString());
    }

    /**
     * 将文本转换成向量,然后存储到pinecone中
     * <p>
     * 参考:
     * https://docs.langchain4j.dev/tutorials/embedding-stores
     */
    @Test
    public void testPineconeEmbeded() {
        //将文本转换成向量
        TextSegment segment1 = TextSegment.from("我喜欢羽毛球");
        Embedding embedding1 = embeddingModel.embed(segment1).content();
        //存入向量数据库
        embeddingStore.add(embedding1, segment1);
        TextSegment segment2 = TextSegment.from("今天天气很好");
        Embedding embedding2 = embeddingModel.embed(segment2).content();
        embeddingStore.add(embedding2, segment2);
    }

    /**
     * 相似度匹配
     */
    @Test
    public void embeddingSearch() {
        //提问,并将问题转成向量数据
        Embedding queryEmbedding = embeddingModel.embed("你最喜欢的运动是什么?").content();
        //创建搜索请求对象
        EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder()
                .queryEmbedding(queryEmbedding)
                .maxResults(1) //匹配最相似的一条记录
                //.minScore(0.8)
                .build();
        //根据搜索请求 searchRequest 在向量存储中进行相似度搜索
        EmbeddingSearchResult<TextSegment> searchResult =
                embeddingStore.search(searchRequest);
        //searchResult.matches():获取搜索结果中的匹配项列表。
        //.get(0):从匹配项列表中获取第一个匹配项
        EmbeddingMatch<TextSegment> embeddingMatch = searchResult.matches().get(0);
        //获取匹配项的相似度得分
        System.out.println(embeddingMatch.score()); // 0.8144288515898701
        //返回文本结果
        System.out.println(embeddingMatch.embedded().text());
    }

    @Test
    public void testUploadKnowledgeLibrary() {
        //使用FileSystemDocumentLoader读取指定目录下的知识库文档
        //并使用默认的文档解析器对文档进行解析
        Document document1 = FileSystemDocumentLoader.loadDocument("D:/knowledge/文档1.md");
        Document document2 = FileSystemDocumentLoader.loadDocument("D:/knowledge/文档2.md");
        Document document3 = FileSystemDocumentLoader.loadDocument("D:/knowledge/文档3.md");
        List<Document> documents = Arrays.asList(document1, document2, document3);
        //文本向量化并存入向量数据库:将每个片段进行向量化,得到一个嵌入向量
        EmbeddingStoreIngestor
                .builder()
                .embeddingStore(embeddingStore)
                .embeddingModel(embeddingModel)
                .build()
                .ingest(documents);
    }
}
  1. 配置Agent属性

@Configuration
public class AgentConfig {
    @Autowired
    private MongoChatMemoryStore mongoChatMemoryStore;
    @Autowired
    private EmbeddingStore embeddingStore;
    @Autowired
    private EmbeddingModel embeddingModel;

    @Bean
    public ChatMemoryProvider chatMemoryProviderXiaozhi() {
        return memoryId -> MessageWindowChatMemory.builder()
                .id(memoryId)
                .maxMessages(20)
                .chatMemoryStore(mongoChatMemoryStore)
                .build();
    }

    @Bean
    ContentRetriever contentRetriever() {
        // 创建一个 EmbeddingStoreContentRetriever 对象,用于从嵌入存储中检索内容
        return EmbeddingStoreContentRetriever
                .builder()
                // 设置用于生成嵌入向量的嵌入模型
                .embeddingModel(embeddingModel)
                // 指定要使用的嵌入存储
                .embeddingStore(embeddingStore)
                // 设置最大检索结果数量,这里表示最多返回 1 条匹配结果
                .maxResults(1)
                // 设置最小得分阈值,只有得分大于等于 0.8 的结果才会被返回
                .minScore(0.8)
                // 构建最终的 EmbeddingStoreContentRetriever 实例
                .build();
    }
}
  1. 配置AIService
@AiService(
        wiringMode = EXPLICIT,
//        chatModel = "qwenChatModel",
        streamingChatModel = "qwenStreamingChatModel",
        chatMemoryProvider = "chatMemoryProviderXiaozhi",
        tools = "appointmentTools",
        contentRetriever = "contentRetriever")
public interface Agent {
    @SystemMessage(fromResource = "zhaozhi-prompt-template.txt")
    Flux<String> chat(@MemoryId Long memoryId, @UserMessage String userMessage);
}
  1. Controller类
@RestController
@RequestMapping("/agent")
public class AgentController {
    @Autowired
    private Agent agent;

    @Operation(summary = "对话")
    @PostMapping(value = "/chat", produces = "text/stream;charset=utf-8")
    public Flux<String> chat(@RequestBody ChatForm chatForm) {
        return agent.chat(chatForm.getMemoryId(), chatForm.getMessage());
    }
}

源码地址:
https://gitee.com/galen.zhang/langchain-ai-demo/java-ai-langchain4j


注意事项

  1. pom.xml文件中的langchain4j-pineconelangchain4j-milvus依赖了不同版本的gRPC,需要注释掉其中一种向量库

  2. milvus 默认有速率限制,写向量库会出现错误

2025-05-13T14:34:50.404+08:00 ERROR 26656 --- [java-ai-langchain4j] [           main] i.m.client.AbstractMilvusGrpcClient      : FlushRequest failed, error code: 8, reason: request is rejected by grpc RateLimiter middleware, please retry later: rate limit exceeded[rate=0.1]
2025-05-13T14:34:50.405+08:00 ERROR 26656 --- [java-ai-langchain4j] [           main] i.m.client.AbstractMilvusGrpcClient      : FlushRequest failed! Exception:{}
io.milvus.exception.ServerException: request is rejected by grpc RateLimiter middleware, please retry later: rate limit exceeded[rate=0.1]

解决方法:
需要修改配置文件 /milvus/configs/milvus.yaml
quotaAndLimits.flushRate.collection.max 默认值是0.1,需要调高一些

quotaAndLimits.flushRate.collection.max = 10

下载配置文件
wget https://raw.githubusercontent.com/milvus-io/milvus/v2.5.11/configs/milvus.yaml

修改docker启动配置,挂载外部配置文件
vi standalone_embed.sh

增加一行 -v $(pwd)/milvus.yaml:/milvus/configs/milvus.yaml \

    sudo docker run -d \
        --name milvus-standalone \
        --security-opt seccomp:unconfined \
        -e ETCD_USE_EMBED=true \
        -e ETCD_DATA_DIR=/var/lib/milvus/etcd \
        -e ETCD_CONFIG_PATH=/milvus/configs/embedEtcd.yaml \
        -e COMMON_STORAGETYPE=local \
	-v $(pwd)/milvus.yaml:/milvus/configs/milvus.yaml \
        -v $(pwd)/volumes/milvus:/var/lib/milvus \
        -v $(pwd)/embedEtcd.yaml:/milvus/configs/embedEtcd.yaml \
        -v $(pwd)/user.yaml:/milvus/configs/user.yaml \
        -p 19530:19530 \
        -p 9091:9091 \
        -p 2379:2379 \
        --health-cmd="curl -f http://localhost:9091/healthz" \
        --health-interval=30s \
        --health-start-period=90s \
        --health-timeout=20s \
        --health-retries=3 \
        milvusdb/milvus:v2.5.11 \
        milvus run standalone  1> /dev/null

删除之前的容器,重新启动

sh standalone_embed.sh stop
sh standalone_embed.sh delete

sh standalone_embed.sh start	  

网站公告

今日签到

点亮在社区的每一天
去签到