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	  
相关推荐
火龙谷1 小时前
【nosql】有哪些非关系型数据库?
数据库·nosql
焱焱枫2 小时前
Oracle获取执行计划之10046 技术详解
数据库·oracle
qq_392397124 小时前
Redis常用操作
数据库·redis·wpf
一只fish5 小时前
MySQL 8.0 OCP 1Z0-908 题目解析(17)
数据库·mysql
花好月圆春祺夏安6 小时前
基于odoo17的设计模式详解---装饰模式
数据库·python·设计模式
A__tao6 小时前
SQL 转 Java 实体类工具
java·数据库·sql
m0_653031366 小时前
腾讯云认证考试报名 - TDSQL数据库交付运维专家(TCCE PostgreSQL版)
运维·数据库·腾讯云
小马哥编程7 小时前
【iSAQB软件架构】架构决策记录-ADR
数据库·架构·系统架构·设计规范
萧鼎7 小时前
深度探索 Py2neo:用 Python 玩转图数据库 Neo4j
数据库·python·neo4j
m0_653031368 小时前
腾讯云认证考试报名 - TDSQL数据库交付运维专家(TCCE MySQL版)
运维·数据库·腾讯云