spring-ai icon indicating copy to clipboard operation
spring-ai copied to clipboard

RetrievalAugmentationAdvisor doesn't seem to be compatible with Azure AI Search

Open khauser opened this issue 6 months ago • 0 comments
trafficstars

Bug description I put test execution files like logs and junit-result files into an Azure AI Search vectorstore but the question "Analyze the test execution of testsuite 2450228." gives me an exception:

2025-04-25T16:47:39.098+02:00[0;39m [32m INFO[0;39m [35m17264[0;39m [2m--- [ai] [   ai-advisor-2] [0;39m[36mc.i.iste.ai.genai.ChatConfiguration     [0;39m [2m:[0;39m >>> [Retrieval] Extracted testSuiteId: 2450228
[2m2025-04-25T16:47:39.143+02:00[0;39m [32m INFO[0;39m [35m17264[0;39m [2m--- [ai] [   ai-advisor-2] [0;39m[36mc.i.iste.ai.genai.ChatConfiguration     [0;39m [2m:[0;39m >>> [Retrieval] Applying filter for testSuiteId: 2450228
[2m2025-04-25T16:47:39.719+02:00[0;39m [31mERROR[0;39m [35m17264[0;39m [2m--- [ai] [   ai-advisor-2] [0;39m[36mc.a.c.i.MethodHandleReflectiveInvoker   [0;39m [2m:[0;39m Missing required property/properties: message
[2m2025-04-25T16:47:39.719+02:00[0;39m [33m WARN[0;39m [35m17264[0;39m [2m--- [ai] [   ai-advisor-2] [0;39m[36mc.a.c.i.s.HttpResponseBodyDecoder       [0;39m [2m:[0;39m Failed to deserialize the error entity.
java.lang.IllegalStateException: Missing required property/properties: message
[2m2025-04-25T16:47:39.720+02:00[0;39m [31mERROR[0;39m [35m17264[0;39m [2m--- [ai] [   ai-advisor-2] [0;39m[36mc.a.s.d.implementation.util.Utility     [0;39m [2m:[0;39m Status code 400, "{"error":{"code":"","message":"Invalid expression: Could not find a property named 'meta_testSuiteId' on type 'search.document'.\r\nParameter name: $filter"}}"
[2m2025-04-25T16:47:39.722+02:00[0;39m [31mERROR[0;39m [35m17264[0;39m [2m--- [ai] [oundedElastic-5] [0;39m[36mo.s.ai.chat.model.MessageAggregator     [0;39m [2m:[0;39m Aggregation Error

java.lang.IllegalStateException: Stream processing failed
	at org.springframework.ai.chat.client.advisor.api.BaseAdvisor.lambda$aroundStream$1(BaseAdvisor.java:68) ~[spring-ai-client-chat-1.0.0-M7.jar:1.0.0-M7]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) ~[reactor-core-3.7.4.jar:3.7.4]
	at reactor.core.publisher.FluxMap$MapSubscriber.onError(FluxMap.java:134) ~[reactor-core-3.7.4.jar:3.7.4]
	at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onError(MonoFlatMapMany.java:205) ~[reactor-core-3.7.4.jar:3.7.4]
	at reactor.core.publisher.FluxMap$MapSubscriber.onError(FluxMap.java:134) ~[reactor-core-3.7.4.jar:3.7.4]
	at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114) ~[reactor-core-3.7.4.jar:3.7.4]
	at reactor.core.publisher.FluxSubscribeOnValue$ScheduledScalar.run(FluxSubscribeOnValue.java:181) ~[reactor-core-3.7.4.jar:3.7.4]
	at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68) ~[reactor-core-3.7.4.jar:3.7.4]
	at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28) ~[reactor-core-3.7.4.jar:3.7.4]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) ~[na:na]
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[na:na]
	at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Caused by: java.util.concurrent.CompletionException: com.azure.core.exception.HttpResponseException: Status code 400, "{"error":{"code":"","message":"Invalid expression: Could not find a property named 'meta_testSuiteId' on type 'search.document'.\r\nParameter name: $filter"}}"
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315) ~[na:na]
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320) ~[na:na]
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1770) ~[na:na]
	at io.micrometer.context.ContextSnapshot.lambda$wrap$0(ContextSnapshot.java:91) ~[context-propagation-1.1.2.jar:1.1.2]
	... 3 common frames omitted
Caused by: com.azure.core.exception.HttpResponseException: Status code 400, "{"error":{"code":"","message":"Invalid expression: Could not find a property named 'meta_testSuiteId' on type 'search.document'.\r\nParameter name: $filter"}}"
	at com.azure.core.implementation.http.rest.RestProxyBase.instantiateUnexpectedException(RestProxyBase.java:381) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.implementation.http.rest.SyncRestProxy.ensureExpectedStatus(SyncRestProxy.java:133) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.implementation.http.rest.SyncRestProxy.handleRestReturnType(SyncRestProxy.java:211) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.implementation.http.rest.SyncRestProxy.invoke(SyncRestProxy.java:86) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.implementation.http.rest.RestProxyBase.invoke(RestProxyBase.java:124) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.http.rest.RestProxy.invoke(RestProxy.java:95) ~[azure-core-1.55.3.jar:1.55.3]
	at jdk.proxy2/jdk.proxy2.$Proxy135.searchPostSync(Unknown Source) ~[na:na]
	at com.azure.search.documents.implementation.DocumentsImpl.searchPostWithResponse(DocumentsImpl.java:618) ~[azure-search-documents-11.6.1.jar:11.6.1]
	at com.azure.search.documents.SearchClient.lambda$search$4(SearchClient.java:808) ~[azure-search-documents-11.6.1.jar:11.6.1]
	at com.azure.search.documents.implementation.util.Utility.executeRestCallWithExceptionHandling(Utility.java:192) ~[azure-search-documents-11.6.1.jar:11.6.1]
	at com.azure.search.documents.SearchClient.search(SearchClient.java:807) ~[azure-search-documents-11.6.1.jar:11.6.1]
	at com.azure.search.documents.SearchClient.lambda$search$2(SearchClient.java:794) ~[azure-search-documents-11.6.1.jar:11.6.1]
	at com.azure.search.documents.SearchClient.lambda$search$3(SearchClient.java:795) ~[azure-search-documents-11.6.1.jar:11.6.1]
	at com.azure.search.documents.util.SearchPagedIterable.lambda$new$0(SearchPagedIterable.java:62) ~[azure-search-documents-11.6.1.jar:11.6.1]
	at com.azure.core.util.paging.ContinuablePagedByIteratorBase.requestPage(ContinuablePagedByIteratorBase.java:104) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.util.paging.ContinuablePagedByItemIterable$ContinuablePagedByItemIterator.<init>(ContinuablePagedByItemIterable.java:83) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.util.paging.ContinuablePagedByItemIterable.iterator(ContinuablePagedByItemIterable.java:58) ~[azure-core-1.55.3.jar:1.55.3]
	at java.base/java.lang.Iterable.spliterator(Iterable.java:101) ~[na:na]
	at com.azure.core.util.paging.ContinuablePagedIterable.stream(ContinuablePagedIterable.java:85) ~[azure-core-1.55.3.jar:1.55.3]
	at org.springframework.ai.vectorstore.azure.AzureVectorStore.doSimilaritySearch(AzureVectorStore.java:236) ~[spring-ai-azure-store-1.0.0-M7.jar:1.0.0-M7]
	at org.springframework.ai.vectorstore.observation.AbstractObservationVectorStore.lambda$similaritySearch$7(AbstractObservationVectorStore.java:126) ~[spring-ai-vector-store-1.0.0-M7.jar:1.0.0-M7]
	at io.micrometer.observation.Observation.observe(Observation.java:564) ~[micrometer-observation-1.14.5.jar:1.14.5]
	at org.springframework.ai.vectorstore.observation.AbstractObservationVectorStore.similaritySearch(AbstractObservationVectorStore.java:125) ~[spring-ai-vector-store-1.0.0-M7.jar:1.0.0-M7]
	at com.intershop.iste.ai.genai.ChatConfiguration.lambda$0(ChatConfiguration.java:224) ~[main/:na]
	at org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor.getDocumentsForQuery(RetrievalAugmentationAdvisor.java:147) ~[spring-ai-rag-1.0.0-M7.jar:1.0.0-M7]
	at org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor.lambda$before$0(RetrievalAugmentationAdvisor.java:124) ~[spring-ai-rag-1.0.0-M7.jar:1.0.0-M7]
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768) ~[na:na]
	... 4 common frames omitted
Caused by: java.io.IOException: java.lang.IllegalStateException: Missing required property/properties: message
	at com.azure.core.implementation.ReflectionSerializable.deserializeAsJsonSerializable(ReflectionSerializable.java:164) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.implementation.serializer.HttpResponseBodyDecoder.deserialize(HttpResponseBodyDecoder.java:169) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.implementation.serializer.HttpResponseBodyDecoder.deserializeBody(HttpResponseBodyDecoder.java:150) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.implementation.serializer.HttpResponseBodyDecoder.decodeByteArray(HttpResponseBodyDecoder.java:67) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.implementation.serializer.HttpResponseDecoder$HttpDecodedResponse.getDecodedBody(HttpResponseDecoder.java:93) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.implementation.http.rest.SyncRestProxy.ensureExpectedStatus(SyncRestProxy.java:131) ~[azure-core-1.55.3.jar:1.55.3]
	... 29 common frames omitted
Caused by: java.lang.IllegalStateException: Missing required property/properties: message
	at com.azure.search.documents.implementation.models.SearchError.lambda$fromJson$1(SearchError.java:122) ~[azure-search-documents-11.6.1.jar:11.6.1]
	at com.azure.json.JsonReader.readMapOrObject(JsonReader.java:554) ~[azure-json-1.5.0.jar:1.5.0]
	at com.azure.json.JsonReader.readObject(JsonReader.java:458) ~[azure-json-1.5.0.jar:1.5.0]
	at com.azure.search.documents.implementation.models.SearchError.fromJson(SearchError.java:88) ~[azure-search-documents-11.6.1.jar:11.6.1]
	at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) ~[na:na]
	at com.azure.core.implementation.MethodHandleReflectiveInvoker.invokeStatic(MethodHandleReflectiveInvoker.java:26) ~[azure-core-1.55.3.jar:1.55.3]
	at com.azure.core.implementation.ReflectionSerializable.deserializeAsJsonSerializable(ReflectionSerializable.java:159) ~[azure-core-1.55.3.jar:1.55.3]
	... 34 common frames omitted

[2m2025-04-25T16:47:39.724+02:00[0;39m [31mERROR[0;39m [35m17264[0;39m [2m--- [ai] [oundedElastic-5] [0;39m[36mo.s.ai.chat.model.MessageAggregator     [0;39m [2m:[0;39m Aggregation Error

Environment Please provide as many details as possible: Spring AI version, Java version, which vector store you use if any, etc

Steps to reproduce Here is my code for evaluation:

    @Bean
    AzureVectorStore vectorStore(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel)
    {
        var vectorStore = AzureVectorStore.builder(searchIndexClient, embeddingModel)
                                          .filterMetadataFields(
                                                          List.of(AzureVectorStore.MetadataField.int64("testSuiteId")));
        vectorStore.indexName("test-execution-logs");
        return vectorStore.build();
    }

    @Bean
    RetrievalAugmentationAdvisor retrievalAugmentationAdvisor(AzureVectorStore vectorStore)
    {
        ContextualQueryAugmenter queryAugmenter = ContextualQueryAugmenter.builder().allowEmptyContext(true).build();

        return RetrievalAugmentationAdvisor.builder().documentRetriever(query -> {
            log.info(">>> [Retrieval] Incoming user query: " + query.text());

            String userQueryText = query.text();
            Long extractedTestSuiteId = null;

            // 1. Testsuite-ID aus der Query extrahieren (Beispiel mit Regex)
            Matcher matcher = TEST_SUITE_ID_PATTERN.matcher(userQueryText);
            if (matcher.find())
            {
                try
                {
                    extractedTestSuiteId = Long.parseLong(matcher.group(1)); // Gruppe 1 enthält die Ziffern
                    log.info(">>> [Retrieval] Extracted testSuiteId: {}", extractedTestSuiteId);
                }
                catch(NumberFormatException e)
                {
                    log.warn(">>> [Retrieval] Found potential ID pattern but failed to parse as Long: {}",
                                    matcher.group(1));
                }
            }

            // 2. SearchRequest erstellen
            SearchRequest.Builder requestBuilder = SearchRequest.builder()
                                                                .query(userQueryText)
                                                                .topK(5)
                                                                .similarityThreshold(0.50);

            // 3. Filter hinzufügen, WENN eine ID extrahiert wurde
            if (extractedTestSuiteId != null)
            {
                var filterExpressionBuilder = new FilterExpressionBuilder();
                //Expression expression = filterExpressionBuilder.eq("testSuiteId", extractedTestSuiteId).build();
                var expression = "testSuiteId == " + extractedTestSuiteId;

                requestBuilder = requestBuilder.filterExpression(expression);
                log.info(">>> [Retrieval] Applying filter for testSuiteId: {}", extractedTestSuiteId);
            }
            else
            {
                log.info(">>> [Retrieval] No testSuiteId found in query, performing broad similarity search.");
            }
            SearchRequest request = requestBuilder.build();

            // 4. Suche mit dem (potenziell gefilterten) Request durchführen
            List<Document> docs = vectorStore.similaritySearch(request); // Direkter Aufruf am vectorStore

            // Logging der Ergebnisse (optional verbessert)
            if (docs.isEmpty())
            {
                log.info(">>> [Retrieval] No documents found for the query and filter criteria.");
            }
            else
            {
                log.info(">>> [Retrieval] Retrieved {} documents:", docs.size());
                docs.forEach(doc -> {
                    // Log auch Metadaten, um zu prüfen, ob der Filter funktionierte
                    log.info("  - [ID: {}, MetaTS: {}, File: {}] Snippet: {}", doc.getId(),
                                    doc.getMetadata().get("testSuiteId"), // Zeigt die ID des gefundenen Dokuments
                                    doc.getMetadata().get("fileName"),
                                    doc.getText().substring(0, Math.min(doc.getText().length(), 100)).replace('\n', ' ')
                                                    + "...");
                });
            }

            return docs; // Gibt die gefilterten oder ungefilterten Dokumente zurück
        }).queryAugmenter(queryAugmenter).build();
    }

    @Bean
    ChatClient chatClient(ChatMemory chatMemory, AzureOpenAiChatModel azureOpenAiChatModel,
                    RetrievalAugmentationAdvisor retrievalAugmentationAdvisor)
    {
        ChatClient.Builder builder = ChatClient.builder(azureOpenAiChatModel);

        // @formatter:off
        return builder
            .defaultAdvisors(
                // Chat memory helps us keep context when using the chatbot for up to 10 previous messages.
                retrievalAugmentationAdvisor,
                new MessageChatMemoryAdvisor(chatMemory, DEFAULT_CHAT_MEMORY_CONVERSATION_ID, 10), // CHAT MEMORY
                new SimpleLoggerAdvisor()
            )
            .defaultSystem(getSystemPrompt())
            //.defaultTools(isteAiDataProvider)
            //.defaultFunctions("getTestSuites", "getStrackTraceOverview")
            .build();
        // @formatter:on
    }

1.0.0-M7 is used:

ext {
    springAiVersion = '1.0.0-M7'

    vaadinVersion = '24.6.6'
    viritinVersion = '2.13.0'

    springCloudVersion = '2024.0.1'
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
        mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}"
        mavenBom "com.vaadin:vaadin-bom:$vaadinVersion"
    }
}

dependencies {
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-actuator'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-hateoas'

    implementation('com.vaadin:vaadin-spring-boot-starter')
    implementation group: 'com.vaadin', name: 'vaadin-lumo-theme', version: "${vaadinVersion}"
    implementation group: 'in.virit', name: 'viritin', version: "${viritinVersion}"

    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-jdbc'

    implementation(group: 'org.springframework.ai', name: 'spring-ai-starter-model-azure-openai')
    implementation group: 'org.springframework.ai', name: 'spring-ai-autoconfigure-model-azure-openai'

    implementation group: 'org.springframework.ai', name: 'spring-ai-starter-vector-store-azure'
    implementation group: 'org.springframework.ai', name: 'spring-ai-autoconfigure-vector-store-azure'

    implementation group: 'org.springframework.ai', name: 'spring-ai-rag'
    implementation group: 'org.springframework.ai', name: 'spring-ai-azure-store'

    implementation group: 'com.azure', name: 'azure-core-http-okhttp', version: "1.12.10"

Expected behavior I get an evaluation of the testexecution.

khauser avatar Apr 25 '25 15:04 khauser