安装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
-
在
pom.xml
中引入依赖<dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-milvus</artifactId> <version>${langchain4j.version}</version> </dependency>
-
设置配置信息
milvus:
host: 192.168.1.131
port: 19530langchain4j:
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 -
配置向量库
@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;
}}
-
使用向量库存储数据
@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); }
}
-
配置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(); }
}
-
配置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);
} -
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
注意事项
-
pom.xml
文件中的langchain4j-pinecone
与langchain4j-milvus
依赖了不同版本的gRPC,需要注释掉其中一种向量库 -
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