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));
}
}