feat: add spring ai retrieval sidecar

This commit is contained in:
aruo
2026-07-05 03:22:03 +08:00
parent 5197712719
commit b9ec07de57
21 changed files with 944 additions and 0 deletions
@@ -0,0 +1,117 @@
package com.superbiz.agent.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.superbiz.agent.config.RagSidecarProperties;
import com.superbiz.agent.dto.ComparableRetrievalResult;
import com.superbiz.agent.dto.RetrievalComparisonCase;
import com.superbiz.agent.dto.RetrievalComparisonReport;
import com.superbiz.agent.dto.SidecarRetrievalResponse;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class RagRetrievalSidecarComparisonServiceTest {
@TempDir
Path tempDir;
@Test
void compareWritesSeparateSidecarReports() throws Exception {
VectorSearchService vectorSearchService = mock(VectorSearchService.class);
SpringAiVectorStoreSidecarService sidecarService = mock(SpringAiVectorStoreSidecarService.class);
RagSidecarProperties properties = new RagSidecarProperties();
RetrievalResultNormalizer normalizer = new RetrievalResultNormalizer(new ObjectMapper());
RagRetrievalSidecarComparisonService comparisonService = new RagRetrievalSidecarComparisonService(
vectorSearchService,
sidecarService,
normalizer,
properties,
new ObjectMapper()
);
VectorSearchService.SearchResult current = new VectorSearchService.SearchResult();
current.setId("current-1");
current.setMetadata("{\"_source\":\"current.md\",\"breadcrumb\":\"A\",\"category\":\"api\"}");
current.setContent("current content");
current.setScore(0.1f);
when(vectorSearchService.searchSimilarDocuments("timeout", 3, "api"))
.thenReturn(List.of(current));
when(sidecarService.search("timeout", 3, "api"))
.thenReturn(SidecarRetrievalResponse.builder()
.enabled(true)
.available(true)
.status("available")
.results(List.of(ComparableRetrievalResult.builder()
.path("sidecar")
.rank(1)
.source("sidecar.md")
.breadcrumb("B")
.scoreLabel("similarity")
.scoreValue(0.9)
.build()))
.build());
RetrievalComparisonReport report = comparisonService.compare(List.of(
RetrievalComparisonCase.builder()
.caseId("case-1")
.scenario("aiops")
.query("timeout")
.category("api")
.build()
), 3);
assertEquals(1, report.getCaseCount());
assertEquals("available", report.getSidecarStatus());
assertTrue(report.getResults().get(0).getDifferences().contains("top_source_differs"));
Path json = tempDir.resolve("sidecar.json");
Path markdown = tempDir.resolve("sidecar.md");
comparisonService.writeReports(report, json, markdown);
assertTrue(Files.readString(json).contains("\"sidecarStatus\""));
assertTrue(Files.readString(markdown).contains("RAG Sidecar Retrieval Comparison"));
}
@Test
void compareGoldenCasesLoadsExistingCaseShape() throws Exception {
VectorSearchService vectorSearchService = mock(VectorSearchService.class);
SpringAiVectorStoreSidecarService sidecarService = mock(SpringAiVectorStoreSidecarService.class);
RagRetrievalSidecarComparisonService comparisonService = new RagRetrievalSidecarComparisonService(
vectorSearchService,
sidecarService,
new RetrievalResultNormalizer(new ObjectMapper()),
new RagSidecarProperties(),
new ObjectMapper()
);
when(vectorSearchService.searchSimilarDocuments("query", 2, null)).thenReturn(List.of());
when(sidecarService.search("query", 2, null))
.thenReturn(SidecarRetrievalResponse.builder()
.enabled(false)
.available(false)
.status("disabled")
.results(List.of())
.build());
Path cases = tempDir.resolve("cases.json");
Files.writeString(cases, """
{
"topK": 2,
"cases": [
{"caseId": "case-1", "scenario": "chat", "query": "query"}
]
}
""");
RetrievalComparisonReport report = comparisonService.compareGoldenCases(cases);
assertEquals(1, report.getCaseCount());
assertEquals(2, report.getTopK());
assertEquals("disabled", report.getSidecarStatus());
}
}