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

安装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>
  2. 设置配置信息

    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

  3. 配置向量库

    @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;
    }

    }

  4. 使用向量库存储数据

    @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);
     }

    }

  5. 配置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();
     }

    }

  6. 配置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);
    }

  7. 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	  
相关推荐
秃头摸鱼侠42 分钟前
MySQL查询语句(续)
数据库·mysql
MuYiLuck1 小时前
【redis实战篇】第八天
数据库·redis·缓存
睡觉待开机1 小时前
6. MySQL基本查询
数据库·mysql
大熊猫侯佩2 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(三)
数据库·swiftui·swift
大熊猫侯佩2 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(二)
数据库·swiftui·swift
大熊猫侯佩2 小时前
用异步序列优雅的监听 SwiftData 2.0 中历史追踪记录(History Trace)的变化
数据库·swiftui·swift
大熊猫侯佩2 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(一)
数据库·swiftui·swift
Ares-Wang2 小时前
负载均衡LB》》HAproxy
运维·数据库·负载均衡
AI.NET 极客圈2 小时前
.NET 原生驾驭 AI 新基建实战系列(四):Qdrant ── 实时高效的向量搜索利器
数据库·人工智能·.net
weixin_470880263 小时前
MySQL体系架构解析(二):MySQL目录与启动配置全解析
数据库·mysql·面试·mysql体系架构·mysql bin目录