From f2bae0382c20c1602d0be3ab4841d26c047b929b Mon Sep 17 00:00:00 2001 From: aruo <40362743+zyongxin@users.noreply.github.com> Date: Sun, 5 Jul 2026 10:53:45 +0800 Subject: [PATCH] fix: align vectorstore live retrieval --- .../agent/service/VectorSearchService.java | 32 +++++++++++++++++-- src/main/resources/application.yml | 2 +- .../service/VectorSearchServiceTest.java | 26 +++++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/superbiz/agent/service/VectorSearchService.java b/src/main/java/com/superbiz/agent/service/VectorSearchService.java index a98d551..4b49a49 100644 --- a/src/main/java/com/superbiz/agent/service/VectorSearchService.java +++ b/src/main/java/com/superbiz/agent/service/VectorSearchService.java @@ -106,7 +106,7 @@ public class VectorSearchService { result.setMetadata(toJson(document.getMetadata())); result.setRawScore(document.getScore()); result.setScoreLabel("similarity"); - result.setScore(toCompatibleL2Distance(document.getScore())); + result.setScore(toCompatibleL2Distance(document)); results.add(result); } logger.info("Spring AI VectorStore search complete, candidates={}", results.size()); @@ -166,6 +166,14 @@ public class VectorSearchService { } } + private float toCompatibleL2Distance(Document document) { + Double distance = extractDistance(document.getMetadata()); + if (distance != null) { + return distance.floatValue(); + } + return toCompatibleL2Distance(document.getScore()); + } + private float toCompatibleL2Distance(Double similarity) { if (similarity == null) { return (float) maxL2Distance; @@ -174,6 +182,24 @@ public class VectorSearchService { return (float) ((1.0 - bounded) * maxL2Distance); } + private Double extractDistance(Map metadata) { + if (metadata == null) { + return null; + } + Object value = metadata.get("distance"); + if (value instanceof Number number) { + return number.doubleValue(); + } + if (value instanceof String text) { + try { + return Double.parseDouble(text); + } catch (NumberFormatException ignored) { + return null; + } + } + return null; + } + private String toJson(Map metadata) { if (metadata == null || metadata.isEmpty()) { return null; @@ -196,8 +222,8 @@ public class VectorSearchService { private String content; /** * Compatibility score used by existing lookup relevance normalization. - * SDK mode keeps L2 distance; VectorStore mode maps similarity into a - * L2-like distance using retrieval.normalization.max-l2-distance. + * SDK mode keeps L2 distance; VectorStore mode prefers the Milvus + * distance metadata and falls back to similarity mapping. */ private float score; private Double rawScore; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b921a3f..5ae16ca 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -98,7 +98,7 @@ spring: milvus: initialize-schema: false database-name: ${milvus.database} - collection-name: business_knowledge + collection-name: biz embedding-dimension: ${milvus.vector-dim} index-type: IVF_FLAT metric-type: L2 diff --git a/src/test/java/com/superbiz/agent/service/VectorSearchServiceTest.java b/src/test/java/com/superbiz/agent/service/VectorSearchServiceTest.java index a867fbb..0fb7cc6 100644 --- a/src/test/java/com/superbiz/agent/service/VectorSearchServiceTest.java +++ b/src/test/java/com/superbiz/agent/service/VectorSearchServiceTest.java @@ -67,6 +67,32 @@ class VectorSearchServiceTest { assertTrue(results.get(0).getMetadata().contains("spring.md")); } + @Test + void vectorStoreSearchUsesDistanceMetadataAsCompatibleScore() { + VectorStore vectorStore = mock(VectorStore.class); + ObjectProvider provider = mock(ObjectProvider.class); + when(provider.getIfAvailable()).thenReturn(vectorStore); + when(vectorStore.similaritySearch(any(SearchRequest.class))).thenReturn(List.of( + Document.builder() + .id("spring-doc") + .text("spring content") + .metadata(Map.of("distance", 0.5659486, "category", "api")) + .score(0.4340514) + .build() + )); + + VectorSearchService service = new VectorSearchService(); + setMode(service, "auto"); + setVectorStore(service, provider); + + List results = service.searchSimilarDocuments("query", 3, null); + + assertEquals(1, results.size()); + assertEquals("similarity", results.get(0).getScoreLabel()); + assertEquals(0.4340514, results.get(0).getRawScore(), 0.0001); + assertEquals(0.5659486f, results.get(0).getScore(), 0.0001); + } + @Test void autoModeFallsBackToSdkWhenVectorStoreFails() { VectorStore vectorStore = mock(VectorStore.class);