From d03f10506af539a42124c9f5f8c8c5197e587b17 Mon Sep 17 00:00:00 2001 From: Raja Kolli Date: Tue, 24 Dec 2024 13:49:45 +0000 Subject: [PATCH] upgrade to SB 3.4 and polish observability --- rag/rag-springai-ollama-llm/pom.xml | 48 +++++++++++++------ .../config/RestClientBuilderConfig.java | 20 -------- .../service/AIChatService.java | 39 +++++++++------ .../src/main/resources/application.properties | 18 +++++-- .../src/main/resources/logback-spring.xml | 16 +++++++ .../config/TestcontainersConfiguration.java | 18 +++---- 6 files changed, 94 insertions(+), 65 deletions(-) delete mode 100644 rag/rag-springai-ollama-llm/src/main/java/com/learning/ai/llmragwithspringai/config/RestClientBuilderConfig.java create mode 100644 rag/rag-springai-ollama-llm/src/main/resources/logback-spring.xml diff --git a/rag/rag-springai-ollama-llm/pom.xml b/rag/rag-springai-ollama-llm/pom.xml index 3fd60de..1730d20 100644 --- a/rag/rag-springai-ollama-llm/pom.xml +++ b/rag/rag-springai-ollama-llm/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.3.6 + 3.4.1 com.learning.ai @@ -16,7 +16,8 @@ 21 - 1.0.0-M4 + 1.0.0-M5 + 2.10.0-alpha 2.43.0 @@ -39,11 +40,7 @@ org.springframework.ai - spring-ai-redis-store-spring-boot-starter - - - org.apache.commons - commons-pool2 + spring-ai-pgvector-store-spring-boot-starter org.springframework.ai @@ -56,7 +53,14 @@ org.springdoc springdoc-openapi-starter-webmvc-ui - 2.6.0 + 2.7.0 + + + + org.springframework.boot + spring-boot-devtools + runtime + true @@ -76,6 +80,17 @@ io.micrometer micrometer-registry-otlp + + net.ttddyy.observation + datasource-micrometer-spring-boot + 1.0.6 + + + io.opentelemetry.instrumentation + opentelemetry-logback-appender-1.0 + runtime + + org.springframework.boot spring-boot-starter-test @@ -97,16 +112,14 @@ test - com.redis.testcontainers - testcontainers-redis + org.testcontainers + grafana test - 1.6.4 org.testcontainers - grafana + postgresql test - 1.20.4 io.rest-assured @@ -124,6 +137,13 @@ pom import + + io.opentelemetry.instrumentation + opentelemetry-instrumentation-bom-alpha + ${otelInstrumentation.version} + pom + import + @@ -144,7 +164,7 @@ - 2.47.0 + 2.50.0 diff --git a/rag/rag-springai-ollama-llm/src/main/java/com/learning/ai/llmragwithspringai/config/RestClientBuilderConfig.java b/rag/rag-springai-ollama-llm/src/main/java/com/learning/ai/llmragwithspringai/config/RestClientBuilderConfig.java deleted file mode 100644 index 8adbc8d..0000000 --- a/rag/rag-springai-ollama-llm/src/main/java/com/learning/ai/llmragwithspringai/config/RestClientBuilderConfig.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.learning.ai.llmragwithspringai.config; - -import java.time.Duration; -import org.springframework.boot.web.client.ClientHttpRequestFactories; -import org.springframework.boot.web.client.ClientHttpRequestFactorySettings; -import org.springframework.boot.web.client.RestClientCustomizer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration(proxyBeanMethods = false) -public class RestClientBuilderConfig { - - @Bean - RestClientCustomizer restClientCustomizer() { - return restClientBuilder -> restClientBuilder.requestFactory( - ClientHttpRequestFactories.get(ClientHttpRequestFactorySettings.DEFAULTS - .withConnectTimeout(Duration.ofSeconds(60)) - .withReadTimeout(Duration.ofMinutes(5)))); - } -} diff --git a/rag/rag-springai-ollama-llm/src/main/java/com/learning/ai/llmragwithspringai/service/AIChatService.java b/rag/rag-springai-ollama-llm/src/main/java/com/learning/ai/llmragwithspringai/service/AIChatService.java index 481e7b0..addb5a4 100644 --- a/rag/rag-springai-ollama-llm/src/main/java/com/learning/ai/llmragwithspringai/service/AIChatService.java +++ b/rag/rag-springai-ollama-llm/src/main/java/com/learning/ai/llmragwithspringai/service/AIChatService.java @@ -3,10 +3,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.chat.client.ChatClient; -import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.vectorstore.SearchRequest; +import org.springframework.ai.chat.client.advisor.RetrievalAugmentationAdvisor; +import org.springframework.ai.chat.prompt.AssistantPromptTemplate; +import org.springframework.ai.rag.generation.augmentation.ContextualQueryAugmenter; +import org.springframework.ai.rag.retrieval.search.VectorStoreDocumentRetriever; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.stereotype.Service; @@ -22,26 +22,35 @@ public class AIChatService { isn't found in the DOCUMENTS section, simply state that you don't know the answer. DOCUMENTS: - {question_answer_context} + {query} """; private final ChatClient aiClient; - private final VectorStore vectorStore; public AIChatService(ChatClient.Builder builder, VectorStore vectorStore) { - this.aiClient = builder.build(); - this.vectorStore = vectorStore; + + var documentRetriever = VectorStoreDocumentRetriever.builder() + .vectorStore(vectorStore) + .similarityThreshold(0.50) + .build(); + + var queryAugmenter = ContextualQueryAugmenter.builder() + .promptTemplate(new AssistantPromptTemplate(template)) + .allowEmptyContext(true) + .build(); + + RetrievalAugmentationAdvisor retrievalAugmentationAdvisor = RetrievalAugmentationAdvisor.builder() + .documentRetriever(documentRetriever) + .queryAugmenter(queryAugmenter) + .build(); + this.aiClient = + builder.clone().defaultAdvisors(retrievalAugmentationAdvisor).build(); } public String chat(String query) { - ChatResponse aiResponse = aiClient.prompt() - .advisors(new QuestionAnswerAdvisor(vectorStore, SearchRequest.query(query), template)) - .user(query) - .call() - .chatResponse(); + String aiResponse = aiClient.prompt().user(query).call().content(); LOGGER.info("Response received from call :{}", aiResponse); - Generation generation = aiResponse.getResult(); - return (generation != null) ? generation.getOutput().getContent() : ""; + return aiResponse; } } diff --git a/rag/rag-springai-ollama-llm/src/main/resources/application.properties b/rag/rag-springai-ollama-llm/src/main/resources/application.properties index 6a0724c..75eda33 100644 --- a/rag/rag-springai-ollama-llm/src/main/resources/application.properties +++ b/rag/rag-springai-ollama-llm/src/main/resources/application.properties @@ -3,6 +3,7 @@ spring.application.name=rag-springai-ollama-llm spring.threads.virtual.enabled=true spring.mvc.problemdetails.enabled=true +spring.ai.ollama.init.pull-model-strategy=when_missing spring.ai.ollama.chat.options.model=mistral spring.ai.ollama.chat.options.temperature=0.3 spring.ai.ollama.chat.options.top-k=2 @@ -10,19 +11,28 @@ spring.ai.ollama.chat.options.top-p=0.2 spring.ai.ollama.embedding.options.model=nomic-embed-text -spring.ai.vectorstore.redis.index=vector_store -spring.ai.vectorstore.redis.prefix=ai -spring.ai.vectorstore.redis.initialize-schema=true +#PgVector +spring.ai.vectorstore.observations.include-query-response=true +spring.ai.vectorstore.pgvector.initialize-schema=true -spring.ai.ollama.baseUrl=http://localhost:11434 +spring.http.client.connect-timeout=PT1M +spring.http.client.read-timeout=PT5M spring.testcontainers.beans.startup=parallel ##Observability spring.ai.chat.observations.include-completion=true spring.ai.chat.observations.include-prompt=true +spring.ai.chat.client.observations.include-input=true management.endpoints.web.exposure.include=* management.metrics.tags.service.name=${spring.application.name} management.tracing.sampling.probability=1.0 management.otlp.tracing.endpoint=http://localhost:4318/v1/traces +management.otlp.logging.endpoint=http://localhost:4318/v1/logs + +logging.level.org.springframework.ai.rag=debug + +## only for development +spring.ai.vectorstore.pgvector.removeExistingVectorStoreTable=true +spring.ai.ollama.baseUrl=http://localhost:11434 diff --git a/rag/rag-springai-ollama-llm/src/main/resources/logback-spring.xml b/rag/rag-springai-ollama-llm/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..1e2ef31 --- /dev/null +++ b/rag/rag-springai-ollama-llm/src/main/resources/logback-spring.xml @@ -0,0 +1,16 @@ + + + + + + true + true + true + + + + + + + diff --git a/rag/rag-springai-ollama-llm/src/test/java/com/learning/ai/llmragwithspringai/config/TestcontainersConfiguration.java b/rag/rag-springai-ollama-llm/src/test/java/com/learning/ai/llmragwithspringai/config/TestcontainersConfiguration.java index 4c7deda..b718825 100644 --- a/rag/rag-springai-ollama-llm/src/test/java/com/learning/ai/llmragwithspringai/config/TestcontainersConfiguration.java +++ b/rag/rag-springai-ollama-llm/src/test/java/com/learning/ai/llmragwithspringai/config/TestcontainersConfiguration.java @@ -1,13 +1,11 @@ package com.learning.ai.llmragwithspringai.config; -import com.redis.testcontainers.RedisStackContainer; import java.io.IOException; import java.time.Duration; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Scope; -import org.springframework.test.context.DynamicPropertyRegistry; +import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.grafana.LgtmStackContainer; import org.testcontainers.ollama.OllamaContainer; import org.testcontainers.utility.DockerImageName; @@ -28,19 +26,15 @@ OllamaContainer ollama() throws IOException, InterruptedException { } @Bean - RedisStackContainer redisContainer(DynamicPropertyRegistry properties) { - RedisStackContainer redis = new RedisStackContainer( - RedisStackContainer.DEFAULT_IMAGE_NAME.withTag(RedisStackContainer.DEFAULT_TAG)); - properties.add("spring.ai.vectorstore.redis.uri", () -> "redis://%s:%d" - .formatted(redis.getHost(), redis.getMappedPort(6379))); - return redis; + @ServiceConnection + PostgreSQLContainer postgreSQLContainer() { + return new PostgreSQLContainer<>(DockerImageName.parse("pgvector/pgvector:pg17")); } @Bean - @Scope("singleton") - @ServiceConnection("otel/opentelemetry-collector-contrib") + @ServiceConnection LgtmStackContainer lgtmStackContainer() { - return new LgtmStackContainer(DockerImageName.parse("grafana/otel-lgtm").withTag("0.7.1")) + return new LgtmStackContainer(DockerImageName.parse("grafana/otel-lgtm").withTag("0.8.1")) .withStartupTimeout(Duration.ofMinutes(2)); } }