package com.superbiz.agent.service; import io.milvus.client.MilvusServiceClient; import io.milvus.grpc.SearchResults; import io.milvus.param.R; import io.milvus.param.dml.SearchParam; import io.milvus.response.SearchResultsWrapper; import lombok.Getter; import lombok.Setter; import com.superbiz.agent.constant.MilvusConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * 向量搜索服务 * 负责从 Milvus 中搜索相似向量 */ @Service public class VectorSearchService { private static final Logger logger = LoggerFactory.getLogger(VectorSearchService.class); @Autowired private MilvusServiceClient milvusClient; @Autowired private VectorEmbeddingService embeddingService; /** * 搜索相似文档 * * @param query 查询文本 * @param topK 返回最相似的K个结果 * @return 搜索结果列表 */ public List searchSimilarDocuments(String query, int topK) { try { logger.info("开始搜索相似文档, 查询: {}, topK: {}", query, topK); // 1. 将查询文本向量化 List queryVector = embeddingService.generateQueryVector(query); logger.debug("查询向量生成成功, 维度: {}", queryVector.size()); // 2. 构建搜索参数 SearchParam searchParam = SearchParam.newBuilder() .withCollectionName(MilvusConstants.MILVUS_COLLECTION_NAME) .withVectorFieldName("vector") .withVectors(Collections.singletonList(queryVector)) .withTopK(topK) .withMetricType(io.milvus.param.MetricType.L2) .withOutFields(List.of("id", "content", "metadata")) .withParams("{\"nprobe\":10}") .build(); // 3. 执行搜索 R searchResponse = milvusClient.search(searchParam); if (searchResponse.getStatus() != 0) { throw new RuntimeException("向量搜索失败: " + searchResponse.getMessage()); } // 4. 解析搜索结果 SearchResultsWrapper wrapper = new SearchResultsWrapper(searchResponse.getData().getResults()); List results = new ArrayList<>(); for (int i = 0; i < wrapper.getRowRecords(0).size(); i++) { SearchResult result = new SearchResult(); result.setId((String) wrapper.getIDScore(0).get(i).get("id")); result.setContent((String) wrapper.getFieldData("content", 0).get(i)); result.setScore(wrapper.getIDScore(0).get(i).getScore()); // 解析 metadata Object metadataObj = wrapper.getFieldData("metadata", 0).get(i); if (metadataObj != null) { result.setMetadata(metadataObj.toString()); } results.add(result); } logger.info("搜索完成, 找到 {} 个相似文档", results.size()); return results; } catch (Exception e) { logger.error("搜索相似文档失败", e); throw new RuntimeException("搜索失败: " + e.getMessage(), e); } } /** * 搜索结果类 */ @Setter @Getter public static class SearchResult { private String id; private String content; private float score; private String metadata; } }