Repository: debezium/debezium.github.io
Pull request #1133: Blogpost about Debezium in RAG scenarion
Author: login: jpechane
Created: 2025-05-20T04:59:10Z | Merged: 2025-05-30T00:45:36Z



Diff:
diff --git a/_posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc b/_posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
new file mode 100644
index 00000000000..3b483d99177
--- /dev/null
+++ b/_posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
@@ -0,0 +1,449 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that is optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Internally, our application uses the Milvus embedding store for LangChain4j, so we retain the following https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[default Milvus collection structure]:
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a https://github.com/langchain4j/langchain4j/issues/2834[known issue] in the module that causes an application failure when the store is empty.
+To work around the issue, we store a dummy document in the database (and thus in Milvus).
+
+== AI Application
+
+The AI application interacts with the LLM and extends the prompt based on similarities in the  embeddings in the prompt and in the data that it loads from the Milvus store.
+
+The demo application is command-line driven, and is written using the https://quarkus.io/[Quarkus framework].
+For AI features, the application uses the Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically the open-source https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and the https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Debezium Chat class].
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrievalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+You use https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties] to configure the module.
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the `pass:[@RegisterAiService]` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrievalAugmentor.java[MilvusRetrievalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrievalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrievalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class queries the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class also provides the `RetrievalAugmentorDecorator`, which logs details of the augmentation operation.
+
+You also use https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties] to configure the Milvus embedding store, as shown in the following example:
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# The following two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of the following two components:
+
+* A https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[Docker Compose configuration file] that starts all of the services.
+* A https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[Java CLI application] in the client directory that emulates both the data pipeline and the AI application.
+
+=== Starting the deployment
+
+In *Terminal 1*, enter the following command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The preceding command extends the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not included by default).
+The command also starts the PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and Ollama (`ollama`) containers.
+
+In *Terminal 2*, enter the following command to start the Granite LLM model:
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact, we selected the paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) to represent knowledge that is new to the application.
+This paper was published in February 2025, after cut-off date, and it contains the very specific keyword, `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When we ask the model this question multiple times it provides different and unrelated responses.
+
+=== Data pipeline
+
+We'll run the remaining portions of the demo in *Terminal 3*, using a Java application.
+The application is built with Maven, so we begin by running the following commands:
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+Now, we initialize the Milvus store with the collection and a dummy record (as per the known issue mentioned earlier).
+The record is not inserted directly.
+Instead, a new row is written into the PostgreSQL source table, and that row is then ingested into Milvus via Debezium.
+Enter the following command:
+
+`$ java -jar target/quarkus-app/quarkus-run.jar init`
+
+The command returns the following output (portions of the log are removed for improved readability and clarity):
+
+----
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Next, enter the following command to verify that the Milvus store contains only single (dummy) document.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can enter the following command to check whether the model is still hallucinating:
+
+
+`$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words`
+
+The model responds with the following output:
+
+----
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrievalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrievalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it is among the top three matching documents.
+
+The data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into a PostgreSQL table.
+Debezium Server should propagate the document into the Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+The Milvus store now contains the document about the IterQR framework.
+Note that, by default, we truncate the document to 512 characters so that the demo can be used on computers that do not have a GPU.
+This behavior is controlled by the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now, if you repeat the query, the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrievalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrievalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+The preceding log shows the following changes:
+
+* The response is augmented with the arXiv document.
+* The answer corresponds to the new fact.
+
+But if you query the model in *Terminal 2* again, you receive the hallucinated answer, because it does not have access to augmenting facts.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR) is an efficient, iterative algorithm for large-scale linear 
+regression that leverages quantization and ridge regression to reduce computational complexity while 
+maintaining accuracy, offering a scalable approach for managing extensive datasets.
+----
+
+As a final step, let's test whether the knowledge can be forgotten.
+The data pipeline deletes the document from the PostgreSQL database.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar delete-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:40:02,797 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+...
+
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+...
+2025-05-20 06:40:44,373 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:40:44,665 INFO  [io.deb.exa.air.MilvusRetrievalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:40:51,957 INFO  [io.deb.exa.air.MilvusRetrievalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:41:01,424 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR (iterQR) is an algorithm for approximate singular value decomposition, efficiently computing sparse solutions to linear systems through iterative updates of the matrix representation.
+...
+----
+
+After we remove the document, we observe the following results:
+
+* Debezium Server captures the delete operation and removes the document from the Milvus store.
+* The chat query is not augmented.
+* The reply is again hallucinated.
+
+=== Stopping the demo
+
+To end the demo deployment, enter the following command:
+
+----
+$ docker-compose down
+----
+
+The preceding command terminates the containers in all terminals.
+
+== Conclusion
+
+*Debezium enables organizations to plug their existing databases directly into modern Retrieval-Augmented Generation (RAG) pipelines — with zero modifications to source applications.*
+That means all the innovation, experimentation, and AI development can happen in parallel, without interfering with established processes, compliance controls, or legacy architecture.
+
+This blogpost describes how Debezium 3.1 can be integrated into AI workflows, particularly those using Retrieval-Augmented Generation (RAG).
+Debezium captures real-time changes from a database and feeds them into vector databases.
+These updates are essential for keeping AI systems current with fresh, domain-specific data.
+The example setup involves PostgreSQL, Debezium Server, Milvus, and Granite LLM (with embeddings).
+This architecture enables you to deploy intelligent applications that respond with accurate, up-to-date information.
+
+Turn your company’s data into a competitive advantage — without rewriting a single line of production code.
diff --git a/assets/images/2025-05-22-debezium-as-part-of-your-ai-solution/overview.excalidraw b/assets/images/2025-05-22-debezium-as-part-of-your-ai-solution/overview.excalidraw
new file mode 100644
index 00000000000..01e5a19c8bf
--- /dev/null
+++ b/assets/images/2025-05-22-debezium-as-part-of-your-ai-solution/overview.excalidraw
@@ -0,0 +1,1055 @@
+{
+  "type": "excalidraw",
+  "version": 2,
+  "source": "https://excalidraw.com",
+  "elements": [
+    {
+      "id": "M_DlWBWMrQdBuDXFIHUBT",
+      "type": "rectangle",
+      "x": 1036.4134342158213,
+      "y": -58.66666666666674,
+      "width": 161,
+      "height": 68,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [
+        "WqG27CGkQgSBUuQ8l3JQe"
+      ],
+      "frameId": null,
+      "index": "aFV",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 2132489523,
+      "version": 162,
+      "versionNonce": 2129370035,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "mkZCxpD49JcCH9d1Osn7A"
+        },
+        {
+          "id": "D2HKrAj5bWPS6mYU66VkS",
+          "type": "arrow"
+        },
+        {
+          "id": "ry0fBcluJ3roJE5CyN5Dw",
+          "type": "arrow"
+        }
+      ],
+      "updated": 1747658907916,
+      "link": null,
+      "locked": false
+    },
+    {
+      "id": "mkZCxpD49JcCH9d1Osn7A",
+      "type": "text",
+      "x": 1059.1034976923838,
+      "y": -37.16666666666674,
+      "width": 115.619873046875,
+      "height": 25,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [
+        "WqG27CGkQgSBUuQ8l3JQe"
+      ],
+      "frameId": null,
+      "index": "aG",
+      "roundness": null,
+      "seed": 2044131251,
+      "version": 99,
+      "versionNonce": 285453651,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747658907916,
+      "link": null,
+      "locked": false,
+      "text": "PostgreSQL",
+      "fontSize": 20,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "M_DlWBWMrQdBuDXFIHUBT",
+      "originalText": "PostgreSQL",
+      "autoResize": true,
+      "lineHeight": 1.25
+    },
+    {
+      "id": "ry0fBcluJ3roJE5CyN5Dw",
+      "type": "arrow",
+      "x": 1202.4134342158213,
+      "y": -24.659866666666744,
+      "width": 161.66666666666674,
+      "height": 1.1368683772161603e-13,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aK",
+      "roundness": null,
+      "seed": 751577171,
+      "version": 223,
+      "versionNonce": 1621144723,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747658907918,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          161.66666666666674,
+          1.1368683772161603e-13
+        ]
+      ],
+      "lastCommittedPoint": null,
+      "startBinding": {
+        "elementId": "M_DlWBWMrQdBuDXFIHUBT",
+        "focus": 0,
+        "gap": 6,
+        "fixedPoint": [
+          1.031055900621118,
+          0.5001
+        ]
+      },
+      "endBinding": {
+        "elementId": "7Bfsdo9XiEbmjmagbBhUI",
+        "focus": 0.00019434686534337776,
+        "gap": 6,
+        "fixedPoint": [
+          -0.031055900621118012,
+          0.5001
+        ]
+      },
+      "startArrowhead": null,
+      "endArrowhead": "arrow",
+      "elbowed": true,
+      "fixedSegments": null,
+      "startIsSpecial": null,
+      "endIsSpecial": null
+    },
+    {
+      "id": "7Bfsdo9XiEbmjmagbBhUI",
+      "type": "rectangle",
+      "x": 1369.080100882488,
+      "y": -58.66666666666663,
+      "width": 244.33333333333317,
+      "height": 68,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [
+        "407QHNpSlssVp9kYG_ASF"
+      ],
+      "frameId": null,
+      "index": "aKV",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 209109501,
+      "version": 158,
+      "versionNonce": 1615596883,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "id": "ry0fBcluJ3roJE5CyN5Dw",
+          "type": "arrow"
+        },
+        {
+          "id": "uYWBFbHcThd1enNQ_xJcG",
+          "type": "arrow"
+        }
+      ],
+      "updated": 1747658900827,
+      "link": null,
+      "locked": false
+    },
+    {
+      "id": "gcqcLiIvY-Aww20iBIZIU",
+      "type": "text",
+      "x": 1414.4134342158213,
+      "y": -32.66666666666663,
+      "width": 157.61985778808594,
+      "height": 25,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [
+        "407QHNpSlssVp9kYG_ASF"
+      ],
+      "frameId": null,
+      "index": "aL",
+      "roundness": null,
+      "seed": 1763791005,
+      "version": 146,
+      "versionNonce": 37312659,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "id": "wkeEjv_kGRPixsfX2WEx2",
+          "type": "arrow"
+        }
+      ],
+      "updated": 1747658957544,
+      "link": null,
+      "locked": false,
+      "text": "Debezium Server",
+      "fontSize": 20,
+      "fontFamily": 5,
+      "textAlign": "left",
+      "verticalAlign": "top",
+      "containerId": null,
+      "originalText": "Debezium Server",
+      "autoResize": true,
+      "lineHeight": 1.25
+    },
+    {
+      "id": "lnzmcjkWQOxiXadPSxyJP",
+      "type": "rectangle",
+      "x": 1373.7467675491544,
+      "y": 128,
+      "width": 244.33333333333317,
+      "height": 68,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aM",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 733233149,
+      "version": 53,
+      "versionNonce": 374640595,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "5XHtPr53ZVPtL-N9b2oMN"
+        },
+        {
+          "id": "mYgrg2F8NbIWoN_vlR6oL",
+          "type": "arrow"
+        },
+        {
+          "id": "wkeEjv_kGRPixsfX2WEx2",
+          "type": "arrow"
+        }
+      ],
+      "updated": 1747658957544,
+      "link": null,
+      "locked": false
+    },
+    {
+      "id": "5XHtPr53ZVPtL-N9b2oMN",
+      "type": "text",
+      "x": 1467.4034625971685,
+      "y": 149.5,
+      "width": 57.01994323730469,
+      "height": 25,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aMV",
+      "roundness": null,
+      "seed": 1572106259,
+      "version": 52,
+      "versionNonce": 1484557427,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747658944945,
+      "link": null,
+      "locked": false,
+      "text": "Milvus",
+      "fontSize": 20,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "lnzmcjkWQOxiXadPSxyJP",
+      "originalText": "Milvus",
+      "autoResize": true,
+      "lineHeight": 1.25
+    },
+    {
+      "id": "a4Ma2KCRG9b5HthUHmTok",
+      "type": "ellipse",
+      "x": 1124.413434215821,
+      "y": 304,
+      "width": 115,
+      "height": 61.66666666666674,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aO",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 1980902173,
+      "version": 327,
+      "versionNonce": 1925199357,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "gwg6X31UI4clZ4OeJxbLu"
+        },
+        {
+          "id": "2mzFSsm3kWCU2XrDRBeRs",
+          "type": "arrow"
+        }
+      ],
+      "updated": 1747659000134,
+      "link": null,
+      "locked": false
+    },
+    {
+      "id": "gwg6X31UI4clZ4OeJxbLu",
+      "type": "text",
+      "x": 1159.534815965075,
+      "y": 322.5308742467481,
+      "width": 44.43995666503906,
+      "height": 25,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aP",
+      "roundness": null,
+      "seed": 1496371,
+      "version": 270,
+      "versionNonce": 1808265715,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747659000135,
+      "link": null,
+      "locked": false,
+      "text": "User",
+      "fontSize": 20,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "a4Ma2KCRG9b5HthUHmTok",
+      "originalText": "User",
+      "autoResize": true,
+      "lineHeight": 1.25
+    },
+    {
+      "id": "RSAYRCBbHCbAeIR4mXWI6",
+      "type": "rectangle",
+      "x": 1711.0801008824878,
+      "y": 299,
+      "width": 221.66666666666674,
+      "height": 85,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aQ",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 1812038003,
+      "version": 196,
+      "versionNonce": 173972157,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "XNQe---gMRTXfTmd4pWGf"
+        },
+        {
+          "id": "bS9F31I2TXlZsnCMTiMhG",
+          "type": "arrow"
+        }
+      ],
+      "updated": 1747659000135,
+      "link": null,
+      "locked": false
+    },
+    {
+      "id": "XNQe---gMRTXfTmd4pWGf",
+      "type": "text",
+      "x": 1791.5934574091807,
+      "y": 329,
+      "width": 60.63995361328125,
+      "height": 25,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aR",
+      "roundness": null,
+      "seed": 941537971,
+      "version": 168,
+      "versionNonce": 1733579059,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747659000135,
+      "link": null,
+      "locked": false,
+      "text": "Ollama",
+      "fontSize": 20,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "RSAYRCBbHCbAeIR4mXWI6",
+      "originalText": "Ollama",
+      "autoResize": true,
+      "lineHeight": 1.25
+    },
+    {
+      "id": "rvIq43g770jt-Y00CixDx",
+      "type": "rectangle",
+      "x": 1389.413434215821,
+      "y": 299,
+      "width": 221.66666666666674,
+      "height": 85,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aS",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 1546679123,
+      "version": 146,
+      "versionNonce": 599445373,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "hXS2zRPTUockqUxzAuVoA"
+        },
+        {
+          "id": "2mzFSsm3kWCU2XrDRBeRs",
+          "type": "arrow"
+        },
+        {
+          "id": "bS9F31I2TXlZsnCMTiMhG",
+          "type": "arrow"
+        },
+        {
+          "id": "mYgrg2F8NbIWoN_vlR6oL",
+          "type": "arrow"
+        }
+      ],
+      "updated": 1747659000135,
+      "link": null,
+      "locked": false
+    },
+    {
+      "id": "hXS2zRPTUockqUxzAuVoA",
+      "type": "text",
+      "x": 1421.776850251791,
+      "y": 329,
+      "width": 156.93983459472656,
+      "height": 25,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aSV",
+      "roundness": null,
+      "seed": 936080797,
+      "version": 158,
+      "versionNonce": 1946460083,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747659000136,
+      "link": null,
+      "locked": false,
+      "text": "Chat application",
+      "fontSize": 20,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "rvIq43g770jt-Y00CixDx",
+      "originalText": "Chat application",
+      "autoResize": true,
+      "lineHeight": 1.25
+    },
+    {
+      "id": "2mzFSsm3kWCU2XrDRBeRs",
+      "type": "arrow",
+      "x": 1244.413434215821,
+      "y": 334.83950000000004,
+      "width": 140.00000000000023,
+      "height": 3.410605131648481e-13,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aV",
+      "roundness": null,
+      "seed": 448511549,
+      "version": 516,
+      "versionNonce": 870099197,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747659000137,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          140.00000000000023,
+          3.410605131648481e-13
+        ]
+      ],
+      "lastCommittedPoint": null,
+      "startBinding": {
+        "elementId": "a4Ma2KCRG9b5HthUHmTok",
+        "focus": 0,
+        "gap": 6,
+        "fixedPoint": [
+          1.0434782608695652,
+          0.5001
+        ]
+      },
+      "endBinding": {
+        "elementId": "rvIq43g770jt-Y00CixDx",
+        "focus": 0.15671764705881133,
+        "gap": 4.999999999999773,
+        "fixedPoint": [
+          -0.022556390977442574,
+          0.42164117647059274
+        ]
+      },
+      "startArrowhead": null,
+      "endArrowhead": "arrow",
+      "elbowed": true,
+      "fixedSegments": null,
+      "startIsSpecial": null,
+      "endIsSpecial": null
+    },
+    {
+      "id": "bS9F31I2TXlZsnCMTiMhG",
+      "type": "arrow",
+      "x": 1611.4134342158213,
+      "y": 335.66666666666674,
+      "width": 95,
+      "height": 5,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aW",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 1565220819,
+      "version": 392,
+      "versionNonce": 1923627155,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747659000277,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          95,
+          5
+        ]
+      ],
+      "lastCommittedPoint": null,
+      "startBinding": {
+        "elementId": "rvIq43g770jt-Y00CixDx",
+        "focus": -0.24174228675135886,
+        "gap": 1
+      },
+      "endBinding": {
+        "elementId": "RSAYRCBbHCbAeIR4mXWI6",
+        "focus": -0.10852994555354123,
+        "gap": 4.666666666666515
+      },
+      "startArrowhead": null,
+      "endArrowhead": "arrow",
+      "elbowed": false
+    },
+    {
+      "id": "mYgrg2F8NbIWoN_vlR6oL",
+      "type": "arrow",
+      "x": 1493.9901799243146,
+      "y": 298.30484531418267,
+      "width": 0.8484030406118563,
+      "height": 102.03149979070326,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aX",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 1869315389,
+      "version": 273,
+      "versionNonce": 548624915,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747659000136,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          -0.8484030406118563,
+          -102.03149979070326
+        ]
+      ],
+      "lastCommittedPoint": null,
+      "startBinding": {
+        "elementId": "rvIq43g770jt-Y00CixDx",
+        "focus": -0.05303461724082109,
+        "gap": 1.897051322909931
+      },
+      "endBinding": {
+        "elementId": "lnzmcjkWQOxiXadPSxyJP",
+        "focus": 0.024946029393651092,
+        "gap": 1
+      },
+      "startArrowhead": null,
+      "endArrowhead": "arrow",
+      "elbowed": false
+    },
+    {
+      "id": "yRIFZTIIs5nH8HI0F3_8N",
+      "type": "ellipse",
+      "x": 796.9134342158213,
+      "y": -65.16666666666663,
+      "width": 115,
+      "height": 61.66666666666674,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [
+        "dJKk3cvY-gQBc1V4dEiI3"
+      ],
+      "frameId": null,
+      "index": "aXV",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 560217373,
+      "version": 296,
+      "versionNonce": 1233910333,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "XiP5YiuvUg1zph8SS2URP"
+        },
+        {
+          "id": "D2HKrAj5bWPS6mYU66VkS",
+          "type": "arrow"
+        }
+      ],
+      "updated": 1747658915815,
+      "link": null,
+      "locked": false
+    },
+    {
+      "id": "XiP5YiuvUg1zph8SS2URP",
+      "type": "text",
+      "x": 832.0348159650753,
+      "y": -46.6357924199185,
+      "width": 44.43995666503906,
+      "height": 25,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [
+        "dJKk3cvY-gQBc1V4dEiI3"
+      ],
+      "frameId": null,
+      "index": "aY",
+      "roundness": null,
+      "seed": 2138607997,
+      "version": 239,
+      "versionNonce": 32221853,
+      "isDeleted": false,
+      "boundElements": [],
+      "updated": 1747658915815,
+      "link": null,
+      "locked": false,
+      "text": "User",
+      "fontSize": 20,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "yRIFZTIIs5nH8HI0F3_8N",
+      "originalText": "User",
+      "autoResize": true,
+      "lineHeight": 1.25
+    },
+    {
+      "id": "D2HKrAj5bWPS6mYU66VkS",
+      "type": "arrow",
+      "x": 912.8491589482326,
+      "y": -32.841494859304696,
+      "width": 116.92893811811518,
+      "height": 6.326117690664887,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "aa",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 127300957,
+      "version": 165,
+      "versionNonce": 129388285,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747658915816,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          116.92893811811518,
+          6.326117690664887
+        ]
+      ],
+      "lastCommittedPoint": null,
+      "startBinding": {
+        "elementId": "yRIFZTIIs5nH8HI0F3_8N",
+        "focus": -0.05685534591195127,
+        "gap": 1
+      },
+      "endBinding": {
+        "elementId": "M_DlWBWMrQdBuDXFIHUBT",
+        "focus": -0.053370267774701344,
+        "gap": 7.3333333333332575
+      },
+      "startArrowhead": null,
+      "endArrowhead": "arrow",
+      "elbowed": false
+    },
+    {
+      "id": "wkeEjv_kGRPixsfX2WEx2",
+      "type": "arrow",
+      "x": 1486.0801008824878,
+      "y": 9,
+      "width": 6.6666666666667425,
+      "height": 110,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "ab",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 966037981,
+      "version": 42,
+      "versionNonce": 1632030259,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747658957544,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          6.6666666666667425,
+          110
+        ]
+      ],
+      "lastCommittedPoint": null,
+      "startBinding": {
+        "elementId": "gcqcLiIvY-Aww20iBIZIU",
+        "focus": 0.11199218869649269,
+        "gap": 14
+      },
+      "endBinding": {
+        "elementId": "lnzmcjkWQOxiXadPSxyJP",
+        "focus": -0.004512745456757362,
+        "gap": 9
+      },
+      "startArrowhead": null,
+      "endArrowhead": "arrow",
+      "elbowed": false
+    },
+    {
+      "id": "o_5TOuqh1bjgcwon-vm1x",
+      "type": "rectangle",
+      "x": 722.7467675491546,
+      "y": -109.33333333333331,
+      "width": 953.3333333333333,
+      "height": 160.00000000000006,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "dotted",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "ac",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 1185019805,
+      "version": 160,
+      "versionNonce": 1286254237,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747658988281,
+      "link": null,
+      "locked": false
+    },
+    {
+      "id": "QEscc245x4KPikVQoiNIn",
+      "type": "rectangle",
+      "x": 1062.7467675491548,
+      "y": 257.33333333333337,
+      "width": 953.3333333333333,
+      "height": 160.00000000000006,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "dotted",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "ad",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 1943272819,
+      "version": 232,
+      "versionNonce": 1279348093,
+      "isDeleted": false,
+      "boundElements": [],
+      "updated": 1747659009480,
+      "link": null,
+      "locked": false
+    },
+    {
+      "id": "I2U8f-O2en_A5T0xQKBuA",
+      "type": "text",
+      "x": 737.7467675491546,
+      "y": -148.99999999999994,
+      "width": 175.61671447753906,
+      "height": 35,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "dotted",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "ae",
+      "roundness": null,
+      "seed": 1629475389,
+      "version": 70,
+      "versionNonce": 533778323,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1747659080383,
+      "link": null,
+      "locked": false,
+      "text": "Data pipeline",
+      "fontSize": 28,
+      "fontFamily": 5,
+      "textAlign": "left",
+      "verticalAlign": "top",
+      "containerId": null,
+      "originalText": "Data pipeline",
+      "autoResize": true,
+      "lineHeight": 1.25
+    },
+    {
+      "id": "avSCHaqwTvSSl1Oxv46PC",
+      "type": "text",
+      "x": 1068.2717436437183,
+      "y": 216.16666666666674,
+      "width": 188.80479431152344,
+      "height": 35,
+      "angle": 0,
+      "strokeColor": "#1e1e1e",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "dotted",
+      "roughness": 2,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "af",
+      "roundness": null,
+      "seed": 1071383613,
+      "version": 170,
+      "versionNonce": 1308599453,
+      "isDeleted": false,
+      "boundElements": [],
+      "updated": 1747659073031,
+      "link": null,
+      "locked": false,
+      "text": "AI application",
+      "fontSize": 28,
+      "fontFamily": 5,
+      "textAlign": "left",
+      "verticalAlign": "top",
+      "containerId": null,
+      "originalText": "AI application",
+      "autoResize": true,
+      "lineHeight": 1.25
+    }
+  ],
+  "appState": {
+    "gridSize": 20,
+    "gridStep": 5,
+    "gridModeEnabled": false,
+    "viewBackgroundColor": "#ffffff"
+  },
+  "files": {}
+}
\ No newline at end of file
diff --git a/assets/images/2025-05-22-debezium-as-part-of-your-ai-solution/overview.png b/assets/images/2025-05-22-debezium-as-part-of-your-ai-solution/overview.png
new file mode 100644
index 00000000000..8b03faf2f3f
Binary files /dev/null and b/assets/images/2025-05-22-debezium-as-part-of-your-ai-solution/overview.png differ


Reviews:
user: login: roldanbob
body: I reviewed about a third of the document (through L115) and added comments. Now that I'm getting a sense of what its all about, I should be able make faster progress through the rest of it on Wednesday.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T22:56:35Z
user: login: Naros
body: Bob caught a lot already, but here are a few I found just skimming.
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-21T05:18:08Z
user: login: jpechane
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T06:08:36Z
user: login: jpechane
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T06:11:05Z
user: login: vjuranek
body: Really nice blog post!

As a final comment, I'd consider adding some marketing pitch at the beginning or at the end of the blog post, that thanks to Debezium existing company databases can be involved in modern AI RAG pipelines without any need to modify them (which is usually very hard or impossible) and all the innovation in the company can happen in parallel to existing processes and workflows.
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-21T10:43:33Z
user: login: roldanbob
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T16:32:08Z
user: login: jpechane
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T08:01:42Z
user: login: jpechane
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T08:10:22Z
user: login: vjuranek
body: Really nice blog post!
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-26T08:38:23Z
user: login: mfvitale
body: Very nice read!
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-26T10:32:43Z
user: login: Naros
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-30T00:45:30Z

Review comments:
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
title: "Debezium as part of your AI solution"
```
created_at: 2025-05-20T13:12:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
```
created_at: 2025-05-20T13:14:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: The referenced 3.1.1 blog post doesn't really provide additional detail about either the Embeddings SMT or the Milvus sink. The https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1.0 blog post] mentions the Milvus sink for Debezium Server, and the LangChain4j based Embeddings Transformation. Should the link target that post instead?
created_at: 2025-05-20T16:49:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
```
created_at: 2025-05-20T16:56:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
```
created_at: 2025-05-20T17:00:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
```
created_at: 2025-05-20T17:03:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
```
created_at: 2025-05-20T17:04:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
```
created_at: 2025-05-20T17:07:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
```
created_at: 2025-05-20T17:07:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
```
created_at: 2025-05-20T17:08:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
* A PostgreSQL database for data storage
* Milvus vector database
* Debezium Server to feed Milvus from PostgreSQL
* A local https://ollama.com/[Ollama] hosted LLM
* A Java application that interacts with the LLM and uses RAG to provide prompt context
```
created_at: 2025-05-20T17:10:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
```
created_at: 2025-05-20T20:20:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
```
created_at: 2025-05-20T20:24:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
```
created_at: 2025-05-20T20:25:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
```
created_at: 2025-05-20T20:29:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
A vector database and fast vector retrieval is the heart of any RAG solution.
```
created_at: 2025-05-20T20:29:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
```
created_at: 2025-05-20T20:30:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
```
created_at: 2025-05-20T20:50:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
```
created_at: 2025-05-20T20:56:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
```
created_at: 2025-05-20T21:49:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
```
created_at: 2025-05-20T21:51:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
A typical deployment of Milvus sink uses the following workflow:
```
created_at: 2025-05-20T21:51:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
* The Debezium connector captures changes from a source database.
* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
* Milvus sink writes the vector data into Milvus.
* Milvus stores and indexes the vectors for fast similarity search.
```
created_at: 2025-05-20T21:53:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
```
created_at: 2025-05-20T22:25:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Let's go step-by-step through the details and internals of the application so you can easily build your own.
```
created_at: 2025-05-20T22:26:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The application architecture consists of the following two flows, which share a common Milvus instance:

* Data pipeline
* AI application

```
created_at: 2025-05-20T22:28:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
```
created_at: 2025-05-20T22:32:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
```
created_at: 2025-05-20T22:35:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
```
created_at: 2025-05-20T22:35:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
```
created_at: 2025-05-20T22:36:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
```
created_at: 2025-05-20T22:41:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
```
created_at: 2025-05-20T22:42:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Upon user request, the application downloads documents in text form and stores them in the table.
```
created_at: 2025-05-20T22:43:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
```
created_at: 2025-05-20T22:45:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
```
created_at: 2025-05-20T22:47:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
In our environment, we run a local LLM that is based on the Ollama LLM framework.
```
created_at: 2025-05-20T22:47:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
```
created_at: 2025-05-20T22:49:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
```
created_at: 2025-05-20T22:50:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
```
created_at: 2025-05-20T22:51:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
```
created_at: 2025-05-20T22:52:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
```
created_at: 2025-05-21T04:59:34Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
```
created_at: 2025-05-21T05:01:21Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
```
created_at: 2025-05-21T05:01:44Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
```
created_at: 2025-05-21T05:02:22Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
```
created_at: 2025-05-21T05:03:28Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
```
created_at: 2025-05-21T05:03:53Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute command and wait for the containers to start.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
In *Terminal 1* execute the command and wait for the containers to start.
```
created_at: 2025-05-21T05:04:17Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend standard Debezium Server image with `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
```
created_at: 2025-05-21T05:04:35Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend standard Debezium Server image with `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute command
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
In *Terminal 2* execute this command to start the Granite LLM model.
```
created_at: 2025-05-21T05:04:50Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend standard Debezium Server image with `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute command
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+to start Granite LLM model.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion

```
created_at: 2025-05-21T05:05:15Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend standard Debezium Server image with `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute command
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+to start Granite LLM model.
+We need to make sure that we are testing the application with fact that model is unaware of.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
We need to make sure that we are testing the application with facts that the model is unaware of.
```
created_at: 2025-05-21T05:05:33Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend standard Debezium Server image with `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute command
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+to start Granite LLM model.
+We need to make sure that we are testing the application with fact that model is unaware of.
+First we will check what is model's cut off date (what are the latest data that model seen).
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
First, we will check the model's cut-off date (what's the latest data the model has seen).
```
created_at: 2025-05-21T05:06:04Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend standard Debezium Server image with `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute command
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+to start Granite LLM model.
+We need to make sure that we are testing the application with fact that model is unaware of.
+First we will check what is model's cut off date (what are the latest data that model seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using Java application.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
The rest of the demo will be executed in *Terminal 3* using a Java application.
```
created_at: 2025-05-21T05:06:32Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend standard Debezium Server image with `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute command
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+to start Granite LLM model.
+We need to make sure that we are testing the application with fact that model is unaware of.
+First we will check what is model's cut off date (what are the latest data that model seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the built application will be invoked with command `java -jar target/quarkus-app/quarkus-run.jar`.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
```
created_at: 2025-05-21T05:06:57Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend standard Debezium Server image with `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute command
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+to start Granite LLM model.
+We need to make sure that we are testing the application with fact that model is unaware of.
+First we will check what is model's cut off date (what are the latest data that model seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the built application will be invoked with command `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step it is necessary to initialize Milvus store with the collection and dummy record (see discussion above about known issue).
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
```
created_at: 2025-05-21T05:07:37Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend standard Debezium Server image with `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute command
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+to start Granite LLM model.
+We need to make sure that we are testing the application with fact that model is unaware of.
+First we will check what is model's cut off date (what are the latest data that model seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the built application will be invoked with command `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step it is necessary to initialize Milvus store with the collection and dummy record (see discussion above about known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+Model reply is clearly unrelated to the real framework.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
The model's reply is clearly unrelated to the real framework.
```
created_at: 2025-05-21T05:15:28Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend standard Debezium Server image with `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute command
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+to start Granite LLM model.
+We need to make sure that we are testing the application with fact that model is unaware of.
+First we will check what is model's cut off date (what are the latest data that model seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the built application will be invoked with command `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step it is necessary to initialize Milvus store with the collection and dummy record (see discussion above about known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+Model reply is clearly unrelated to the real framework.
+Log lines emitted by `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
```
created_at: 2025-05-21T05:16:03Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search over these vectors, you can build AI-driven applications with up-to-date, domain-specific knowledge.
+
+Let's describe the problem we are aiming to solve.
+
+Our organization introduces new AI-driven application backed by an LLM.
+The model needs to be extended with the internal company knowledge that is stored in text documents in PostgreSQL database.
+Whenever user interacts with AI the local knowledge must be taken into consideration.
+Also the knowledge is constantly changing, new documents are added, existing documents are updated and sometimes some of the documents are withdrawn due to regulatory requirements.
+
+The common solution to this problem is Retrieval-Augmented Generation (RAG).
+This post will demostrate how to build CDC fed RAG system using
+
+* PostgreSQL as data storage
+* Milvus vector database
+* Debezium Server feeding Milvus from PostgreSQL
+* Local https://ollama.com/[Ollama] hosted LLM
+* Java application interacting with LLM and using RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is one of Debezium flavours that allows you to stream change events from databases to various sinks without the need to stand up a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them where you need them.
+It is also possible to use Kafka Connect single message transformations as a part of its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any use case needing fast vector retrieval, Milvus is built for that.
+Vector database and fast vector retrieval are in the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations the data that can be used for tasks like similarity search or clustering.
+Prompt context is extended according to similarity of stored data with requested prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+This approach keeps your AI models in sync with operational data and offloads similarity search to a system built for it.
+
+=== How Debezium Milvus Sink Works
+
+The typical deployment of Milvus sink can be described with this workflow
+
+* Debezium Connector captures changes from the source database
+* If the source database does not contain a field with embedding then https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings
+* Milvus sink writes the vector data into Milvus
+* Milvus stores and indexes the vectors for fast similarity search
+
+== Example application
+
+This blogpost is built around https://github.com/debezium/debezium-examples/tree/main/ai-rag[ai-rag] example application.
+We are going step-by-step through the details and internals of the application so you can easily built your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The architecture identifies two different flows
+
+* Data pipeline
+* AI application
+
+that share common Milvus instance.
+Data pipeline is responsible for ingesting data into Milvus and AI application queries it.
+
+=== Data pipeline
+
+Our source of the documents is https://arxiv.org/[arXiv], service that provides scholarly articles for download in different formats.
+The test application downloads requested article based on its identifier and stores it in PostgreSQL table.
+
+The table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The table has enabled full replica identity which means that original state of the database row will be available in update and delete messages.
+This is not required for our demo but can be useful for different implementations.
+
+Upon user request the application will download the document in text form and store it in the table.
+The document identifier will be used as the `id`, the textual representation of the article as `text` and JSON metadata `{"id:" "<document id>"}` in metadata.
+There is no column with embeddings so Debezium is responsible for calculation.
+
+We run LLM locally in Ollama LLM framework.
+As the model itself we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], that is text-only model optimized for also for RAG.
+It is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models] but the application is not limited to it and can use an arbitrary one.
+
+Debezium Server links together PostgreSQL store with Milvus.
+As embeddings were not provided, they are calculated using https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[FieldToEmbedding] SMT and stored in the field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is a command-line written using https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled via `retrievalAugmentor` parameter of `@RegisterAiService` and is implemented in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+`EmbeddingStoreContentRetriever` is responsible for querying the Milvus vector database and it enhances prompt context with the 3 most similar documents.
+The class itself also provides `RetrievalAugmentorDecorator` which logs the detail of augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend standard Debezium Server image with `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute command
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+to start Granite LLM model.
+We need to make sure that we are testing the application with fact that model is unaware of.
+First we will check what is model's cut off date (what are the latest data that model seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the built application will be invoked with command `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step it is necessary to initialize Milvus store with the collection and dummy record (see discussion above about known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+Model reply is clearly unrelated to the real framework.
+Log lines emitted by `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
+
+* The query was augmented with the arXiv document
+* The answer corresponds to the new fact
+
+But if you query the model in *Terminal 2* again then you will receive hallucinated answer as it does not have access to augmenting facts.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR) is an efficient, iterative algorithm for large-scale linear 
+regression that leverages quantization and ridge regression to reduce computational complexity while 
+maintaining accuracy, offering a scalable approach for managing extensive datasets.
+----
+
+As a final step we are going to test if the knowledge can be forgotten.
+The data pipeline deletes the document from PostgreSQL database.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar delete-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:40:02,797 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+...
+
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+...
+2025-05-20 06:40:44,373 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:40:44,665 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:40:51,957 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:41:01,424 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR (iterQR) is an algorithm for approximate singular value decomposition, efficiently computing sparse solutions to linear systems through iterative updates of the matrix representation.
+...
+----
+
+As the result of the document removal
+
+* Debezium Server captures the delete operation and removes document from Milvus store
+* Chat query is not augmented
+* Reply is again hallucinated
+
+=== Stop demo
+
+A the end the demo deployment is dropped via
+
+----
+$ docker-compose down
+----
+
+that will terminate containers in all terminals.
+
+== Conclusion
+
+This blogpost explains how Debezium 3.1 can be integrated into AI workflows, particularly those using Retrieval-Augmented Generation (RAG).
+Debezium captures real-time changes in databases and feeds them into vector databases.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: Naros
body: ```suggestion
Debezium captures real-time changes from a database and feeds them into vector databases.
```
created_at: 2025-05-21T05:17:27Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: jpechane
body: ```suggestion
You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
```
created_at: 2025-05-21T06:08:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,440 @@
+---
+layout: post
+title: "Debezium as Part of Your AI Solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One of the questions we recently encounter is how to effectively integrate change data capture (CDC) with AI workloads — particularly for use cases where organization knowledge is not publicly available.
+With the release of Debezium 3.1, new AI-focused features such as the Embeddings SMT and the Milvus Sink make this scenario reality.
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/24/debezium-3-1-1-final-released/[Debezium 3.1 release notes].
+
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: jpechane
body: Thanks! That was an oversight on my part.
created_at: 2025-05-21T06:11:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: vjuranek
body: ```suggestion
For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that is optimized for RAG.
```
created_at: 2025-05-21T10:17:40Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: vjuranek
body: `@RegisterAiService` is not rendered correctly as code, but not sure what's wrong here, probably something antora specific as plain asciidoc renders it correctly.
created_at: 2025-05-21T10:25:09Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Internally, our application uses the Milvus embedding store for LangChain4j, so we retain the following https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[default Milvus collection structure]:
```
created_at: 2025-05-21T14:58:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
There is a https://github.com/langchain4j/langchain4j/issues/2834[known issue] in the module that causes an application failure when the store is empty.
```
created_at: 2025-05-21T14:59:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
To work around the issue, we store a dummy document in the database (and thus in Milvus).
```
created_at: 2025-05-21T15:04:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The AI application interacts with the LLM and extends the prompt based on similarities in the  embeddings in the prompt and in the data that it loads from the Milvus store.
```
This sentence is unclear. I tried to detangle it, but I'm not sure my interpretation is correct.
created_at: 2025-05-21T15:11:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The demo application is command-line driven, and is written using the https://quarkus.io/[Quarkus framework].
```
created_at: 2025-05-21T15:13:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
For AI features, the application uses the Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically the open-source https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and the https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
```
created_at: 2025-05-21T15:17:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Debezium Chat class].
```
created_at: 2025-05-21T15:18:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
You use https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties] to configure the module.
```
created_at: 2025-05-21T15:19:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
To enable RAG, you use the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation.
RAG is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrievalAugmentor bean].
```
FWIW, retrieval is misspelled with an extra `a`. But the misspelling is in the code, so the URL works as-is. 
In the code that follows, there are inconsistencies in the spelling.
created_at: 2025-05-21T15:34:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: Retrieaval vs. Retrieval
created_at: 2025-05-21T15:36:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The `EmbeddingStoreContentRetriever` class queries the Milvus vector database and enhances the prompt context with the three most similar documents.
```
created_at: 2025-05-21T15:37:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The class also provides the `RetrievalAugmentorDecorator`, which logs details of the augmentation operation.
```
created_at: 2025-05-21T15:38:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
You also use https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties] to configure the Milvus embedding store, as shown in the following example:
```
created_at: 2025-05-21T15:39:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
# The following two settings are not supported by the current version of Quarkus Langchain4j extension
```
created_at: 2025-05-21T15:40:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The demo is composed of the following two components:
```
created_at: 2025-05-21T15:42:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
* A https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[Docker Compose configuration file] that starts all of the services.
```
created_at: 2025-05-21T15:44:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
* A https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[Java CLI application] in the client directory that emulates both the data pipeline and the AI application.
```
created_at: 2025-05-21T15:46:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
=== Starting the deployment
```
created_at: 2025-05-21T15:46:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
In *Terminal 1*, enter the following command and wait for the containers to start.
```
created_at: 2025-05-21T15:48:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The preceding command extends the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not included by default).
```
created_at: 2025-05-21T15:48:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The command also starts the PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and Ollama (`ollama`) containers.
```
created_at: 2025-05-21T15:49:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
In *Terminal 2*, enter the following command to start the Granite LLM model:
```
created_at: 2025-05-21T15:51:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Based on that fact, we selected the paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) to represent knowledge that is new to the application.
```
created_at: 2025-05-21T15:54:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
This paper was published in February 2025, after cut-off date, and it contains the very specific keyword, `IterQR`.
```
created_at: 2025-05-21T15:56:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
When we ask the model this question multiple times it provides different and unrelated responses.
```
created_at: 2025-05-21T15:58:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
We'll run the remaining portions of the demo in *Terminal 3*, using a Java application.
```
created_at: 2025-05-21T15:59:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The application is built with Maven, so we begin by running the following commands:
```
created_at: 2025-05-21T16:01:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
```
created_at: 2025-05-21T16:02:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Now, we initialize the Milvus store with the collection and a dummy record (as per the known issue mentioned earlier).
```
created_at: 2025-05-21T16:03:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The record is not inserted directly.
Instead, a new row is written into the PostgreSQL source table, and that row is then ingested into Milvus via Debezium.
```
created_at: 2025-05-21T16:04:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Enter the following command:

`$ java -jar target/quarkus-app/quarkus-run.jar init`

The command returns the following output (portions of the log are removed for improved readability and clarity):

```
created_at: 2025-05-21T16:08:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
----
...
```
created_at: 2025-05-21T16:08:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Next, enter the following command to verify that the Milvus store contains only single (dummy) document.
```
created_at: 2025-05-21T16:09:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
We can enter the following command to check whether the model is still hallucinating:
```
created_at: 2025-05-21T16:11:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion

`$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words`

The model responds with the following output:

----
2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
----
```
created_at: 2025-05-21T16:12:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
It is the dummy record from the store and as such it will be always added if it is among the top three matching documents.
```
created_at: 2025-05-21T16:14:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The data pipeline now processes a new domain fact (arXiv document).
```
created_at: 2025-05-21T16:14:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Document is downloaded from the server in textual form and inserted into a PostgreSQL table.
```
created_at: 2025-05-21T16:14:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Debezium Server should propagate the document into the Milvus store.
```
created_at: 2025-05-21T16:15:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The Milvus store now contains the document about the IterQR framework.
```
created_at: 2025-05-21T16:15:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Note that, by default, we truncate the document to 512 characters so that the demo can be used on computers that do not have a GPU.
```
created_at: 2025-05-21T16:18:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
This behavior is controlled by the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
```
created_at: 2025-05-21T16:18:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
Now, if you repeat the query, the answer should be relevant to the real description.
```
created_at: 2025-05-21T16:19:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The preceding log shows the following changes:
```
created_at: 2025-05-21T16:19:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
+
+* The query was augmented with the arXiv document
+* The answer corresponds to the new fact
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
* The response is augmented with the arXiv document.
* The answer corresponds to the new fact.
```
created_at: 2025-05-21T16:22:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
+
+* The query was augmented with the arXiv document
+* The answer corresponds to the new fact
+
+But if you query the model in *Terminal 2* again then you will receive hallucinated answer as it does not have access to augmenting facts.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
But if you query the model in *Terminal 2* again, you receive the hallucinated answer, because it does not have access to augmenting facts.
```
created_at: 2025-05-21T16:23:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
+
+* The query was augmented with the arXiv document
+* The answer corresponds to the new fact
+
+But if you query the model in *Terminal 2* again then you will receive hallucinated answer as it does not have access to augmenting facts.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR) is an efficient, iterative algorithm for large-scale linear 
+regression that leverages quantization and ridge regression to reduce computational complexity while 
+maintaining accuracy, offering a scalable approach for managing extensive datasets.
+----
+
+As a final step we are going to test if the knowledge can be forgotten.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
As a final step, let's test whether the knowledge can be forgotten.
```
created_at: 2025-05-21T16:23:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
+
+* The query was augmented with the arXiv document
+* The answer corresponds to the new fact
+
+But if you query the model in *Terminal 2* again then you will receive hallucinated answer as it does not have access to augmenting facts.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR) is an efficient, iterative algorithm for large-scale linear 
+regression that leverages quantization and ridge regression to reduce computational complexity while 
+maintaining accuracy, offering a scalable approach for managing extensive datasets.
+----
+
+As a final step we are going to test if the knowledge can be forgotten.
+The data pipeline deletes the document from PostgreSQL database.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The data pipeline deletes the document from the PostgreSQL database.
```
created_at: 2025-05-21T16:24:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
+
+* The query was augmented with the arXiv document
+* The answer corresponds to the new fact
+
+But if you query the model in *Terminal 2* again then you will receive hallucinated answer as it does not have access to augmenting facts.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR) is an efficient, iterative algorithm for large-scale linear 
+regression that leverages quantization and ridge regression to reduce computational complexity while 
+maintaining accuracy, offering a scalable approach for managing extensive datasets.
+----
+
+As a final step we are going to test if the knowledge can be forgotten.
+The data pipeline deletes the document from PostgreSQL database.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar delete-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:40:02,797 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+...
+
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+...
+2025-05-20 06:40:44,373 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:40:44,665 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:40:51,957 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:41:01,424 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR (iterQR) is an algorithm for approximate singular value decomposition, efficiently computing sparse solutions to linear systems through iterative updates of the matrix representation.
+...
+----
+
+As the result of the document removal
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
After we remove the document, we observe the following results:
```
created_at: 2025-05-21T16:25:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
+
+* The query was augmented with the arXiv document
+* The answer corresponds to the new fact
+
+But if you query the model in *Terminal 2* again then you will receive hallucinated answer as it does not have access to augmenting facts.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR) is an efficient, iterative algorithm for large-scale linear 
+regression that leverages quantization and ridge regression to reduce computational complexity while 
+maintaining accuracy, offering a scalable approach for managing extensive datasets.
+----
+
+As a final step we are going to test if the knowledge can be forgotten.
+The data pipeline deletes the document from PostgreSQL database.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar delete-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:40:02,797 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+...
+
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+...
+2025-05-20 06:40:44,373 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:40:44,665 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:40:51,957 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:41:01,424 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR (iterQR) is an algorithm for approximate singular value decomposition, efficiently computing sparse solutions to linear systems through iterative updates of the matrix representation.
+...
+----
+
+As the result of the document removal
+
+* Debezium Server captures the delete operation and removes document from Milvus store
+* Chat query is not augmented
+* Reply is again hallucinated
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
* Debezium Server captures the delete operation and removes the document from the Milvus store.
* The chat query is not augmented.
* The reply is again hallucinated.
```
created_at: 2025-05-21T16:26:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
+
+* The query was augmented with the arXiv document
+* The answer corresponds to the new fact
+
+But if you query the model in *Terminal 2* again then you will receive hallucinated answer as it does not have access to augmenting facts.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR) is an efficient, iterative algorithm for large-scale linear 
+regression that leverages quantization and ridge regression to reduce computational complexity while 
+maintaining accuracy, offering a scalable approach for managing extensive datasets.
+----
+
+As a final step we are going to test if the knowledge can be forgotten.
+The data pipeline deletes the document from PostgreSQL database.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar delete-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:40:02,797 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+...
+
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+...
+2025-05-20 06:40:44,373 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:40:44,665 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:40:51,957 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:41:01,424 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR (iterQR) is an algorithm for approximate singular value decomposition, efficiently computing sparse solutions to linear systems through iterative updates of the matrix representation.
+...
+----
+
+As the result of the document removal
+
+* Debezium Server captures the delete operation and removes document from Milvus store
+* Chat query is not augmented
+* Reply is again hallucinated
+
+=== Stop demo
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
=== Stopping the demo
```
created_at: 2025-05-21T16:26:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
+
+* The query was augmented with the arXiv document
+* The answer corresponds to the new fact
+
+But if you query the model in *Terminal 2* again then you will receive hallucinated answer as it does not have access to augmenting facts.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR) is an efficient, iterative algorithm for large-scale linear 
+regression that leverages quantization and ridge regression to reduce computational complexity while 
+maintaining accuracy, offering a scalable approach for managing extensive datasets.
+----
+
+As a final step we are going to test if the knowledge can be forgotten.
+The data pipeline deletes the document from PostgreSQL database.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar delete-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:40:02,797 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+...
+
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+...
+2025-05-20 06:40:44,373 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:40:44,665 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:40:51,957 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:41:01,424 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR (iterQR) is an algorithm for approximate singular value decomposition, efficiently computing sparse solutions to linear systems through iterative updates of the matrix representation.
+...
+----
+
+As the result of the document removal
+
+* Debezium Server captures the delete operation and removes document from Milvus store
+* Chat query is not augmented
+* Reply is again hallucinated
+
+=== Stop demo
+
+A the end the demo deployment is dropped via
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
To end the demo deployment, enter the following command:
```
created_at: 2025-05-21T16:26:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
+
+* The query was augmented with the arXiv document
+* The answer corresponds to the new fact
+
+But if you query the model in *Terminal 2* again then you will receive hallucinated answer as it does not have access to augmenting facts.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR) is an efficient, iterative algorithm for large-scale linear 
+regression that leverages quantization and ridge regression to reduce computational complexity while 
+maintaining accuracy, offering a scalable approach for managing extensive datasets.
+----
+
+As a final step we are going to test if the knowledge can be forgotten.
+The data pipeline deletes the document from PostgreSQL database.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar delete-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:40:02,797 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+...
+
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+...
+2025-05-20 06:40:44,373 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:40:44,665 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:40:51,957 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:41:01,424 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR (iterQR) is an algorithm for approximate singular value decomposition, efficiently computing sparse solutions to linear systems through iterative updates of the matrix representation.
+...
+----
+
+As the result of the document removal
+
+* Debezium Server captures the delete operation and removes document from Milvus store
+* Chat query is not augmented
+* Reply is again hallucinated
+
+=== Stop demo
+
+A the end the demo deployment is dropped via
+
+----
+$ docker-compose down
+----
+
+that will terminate containers in all terminals.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
The preceding command terminates the containers in all terminals.
```
created_at: 2025-05-21T16:30:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
+
+* The query was augmented with the arXiv document
+* The answer corresponds to the new fact
+
+But if you query the model in *Terminal 2* again then you will receive hallucinated answer as it does not have access to augmenting facts.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR) is an efficient, iterative algorithm for large-scale linear 
+regression that leverages quantization and ridge regression to reduce computational complexity while 
+maintaining accuracy, offering a scalable approach for managing extensive datasets.
+----
+
+As a final step we are going to test if the knowledge can be forgotten.
+The data pipeline deletes the document from PostgreSQL database.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar delete-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:40:02,797 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+...
+
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+...
+2025-05-20 06:40:44,373 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:40:44,665 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:40:51,957 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:41:01,424 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR (iterQR) is an algorithm for approximate singular value decomposition, efficiently computing sparse solutions to linear systems through iterative updates of the matrix representation.
+...
+----
+
+As the result of the document removal
+
+* Debezium Server captures the delete operation and removes document from Milvus store
+* Chat query is not augmented
+* Reply is again hallucinated
+
+=== Stop demo
+
+A the end the demo deployment is dropped via
+
+----
+$ docker-compose down
+----
+
+that will terminate containers in all terminals.
+
+== Conclusion
+
+This blogpost explains how Debezium 3.1 can be integrated into AI workflows, particularly those using Retrieval-Augmented Generation (RAG).
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
This blogpost describes how Debezium 3.1 can be integrated into AI workflows, particularly those using Retrieval-Augmented Generation (RAG).
```
created_at: 2025-05-21T16:30:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
+
+[source,java]
+----
+@ApplicationScoped
+public class MilvusRetrieavalAugmentor implements Supplier<RetrievalAugmentor> {
+
+    private final RetrievalAugmentor augmentor;
+
+    MilvusRetrieavalAugmentor(MilvusEmbeddingStore store, EmbeddingModel model) {
+        EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
+                .embeddingModel(model)
+                .embeddingStore(store)
+                .maxResults(3)
+                .build();
+        augmentor = new RetrievalAugmentorDecorator(DefaultRetrievalAugmentor
+                .builder()
+                .contentRetriever(contentRetriever)
+                .build());
+    }
+
+    @Override
+    public RetrievalAugmentor get() {
+        return augmentor;
+    }
+
+    private class RetrievalAugmentorDecorator implements RetrievalAugmentor {
+
+        private final RetrievalAugmentor delegate;
+
+        public RetrievalAugmentorDecorator(RetrievalAugmentor delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public AugmentationResult augment(AugmentationRequest augmentationRequest) {
+            Log.infof("Requested augmentation of %s", augmentationRequest.chatMessage());
+            final var result = delegate.augment(augmentationRequest);
+            Log.infof("Result of augmentation is %s", result.contents());
+            return result;
+        }
+    }
+}
+----
+
+The `EmbeddingStoreContentRetriever` class is responsible for querying the Milvus vector database and enhances the prompt context with the three most similar documents.
+The class itself also provides the `RetrievalAugmentorDecorator`, which logs the detail of the augmentation operation.
+
+The Milvus embedding store is again configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.milvus.host=localhost
+quarkus.langchain4j.milvus.port=19530
+quarkus.langchain4j.milvus.create-collection=false
+quarkus.langchain4j.milvus.collection-name=demo_ai_documents
+
+# These two settings are not supported by the current version of Quarkus Langchain4j extension
+# Also field with text cannot be overriden and is default text
+quarkus.langchain4j.milvus.primary-field=id
+quarkus.langchain4j.milvus.vector-field=vector
+----
+
+== Demo
+
+The demo is composed of two components
+
+* Docker Compose configuration https://github.com/debezium/debezium-examples/blob/main/ai-rag/docker-compose.yml[file] that starts all services.
+* Java CLI application in https://github.com/debezium/debezium-examples/tree/main/ai-rag/client[client] directory that emulates both data pipeline and AI application.
+
+=== Start deployment
+
+In *Terminal 1* execute the command and wait for the containers to start.
+
+----
+$ docker-compose up --build
+----
+
+The command will extend the standard Debezium Server image with the `debezium-ai-embeddings-ollama` module (the AI embeddings modules are not by default included).
+PostgreSQL (`postgres`), Milvus (`milvus`), Debezium Server (`debezium-server`) and ollama (`ollama`) containers are started.
+
+In *Terminal 2* execute this command to start the Granite LLM model.
+
+----
+$ docker exec -it ollama ollama run granite3.1-dense:2b
+----
+
+We need to make sure that we are testing the application with facts that the model is unaware of.
+First, we will check the model's cut-off date (what's the latest data the model has seen).
+
+----
+>>> What is your cut off date?
+My knowledge cut off date is April 2024. I can provide information and answer questions based on data up to 
+that point. For more recent events or discoveries, I'm unable to include those details in my responses as 
+they weren't available at the time of my training data. If you have any questions within this timeframe, 
+feel free to ask!
+----
+
+Based on that fact we selected paper https://arxiv.org/abs/2504.05309v1[2504.05309v1] (IterQR: An Iterative Framework for LLM-based Query Rewrite in e-Commercial Search System) as the sample of the new knowledge.
+It was published in February 2025 so after cut off date and contains very specific keyword - `IterQR`.
+We will test the model by asking about the framework.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR), a scalable method for large-scale regression, iteratively 
+refines coefficients via quantization and ridge regression techniques to minimize computational complexity 
+while maintaining accuracy.
+----
+
+The answer is completely unrelated to the framework and exhibits traits of https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)[hallucination].
+The model does not know about the fact so it invents its own without any connection to reality.
+When model is asked multiple times it will provide different and unrelated descriptions.
+
+=== Data pipeline
+
+The rest of the demo will be executed in *Terminal 3* using a Java application.
+The application is built via Maven so execute
+
+----
+$ cd client
+$ ./mvnw clean install
+----
+
+and the build the application. To start the application, run `java -jar target/quarkus-app/quarkus-run.jar`.
+
+As the very first step, it is necessary to initialize the Milvus store with the collection and a dummy record (see discussion above about the known issue).
+The record is not inserted directly but a new row is written into the PostgreSQL source table that is then ingested into Milvus via Debezium.
+(Parts of the log are removed for readability and clarity purposes)
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar init
+
+...
+2025-05-20 06:05:10,712 INFO  [io.deb.exa.air.MilvusStore] (main) Created collection 'demo_ai_documents' with schema: CreateCollectionReq.CollectionSchema(fieldSchemaList=[CreateCollectionReq.FieldSchema(name=id, description=, dataType=VarChar, maxLength=64, dimension=null, isPrimaryKey=true, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=metadata, description=, dataType=JSON, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=true, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=text, description=, dataType=VarChar, maxLength=65535, dimension=null, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null), CreateCollectionReq.FieldSchema(name=vector, description=, dataType=FloatVector, maxLength=65535, dimension=2048, isPrimaryKey=false, isPartitionKey=false, isClusteringKey=false, autoID=false, elementType=null, maxCapacity=null, isNullable=false, defaultValue=null, enableAnalyzer=null, analyzerParams=null, enableMatch=null)], enableDynamicField=false, functionList=[])
+...
+----
+
+Let's verify that there is only single (dummy) document in Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:08:08,213 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+2025-05-20 06:08:08,217 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], text=permanent, id=permanent}
+...
+----
+
+=== Application pipeline
+
+The data pipeline is established but there is no domain specific knowledge available yet.
+We can check that model is still hallucinating.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:15:13,140 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:15:13,465 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:15:21,521 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:15:30,117 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR factorization, a permanent matrix method, breaks down data into orthogonal matrices for efficient computations.
+----
+
+The model's reply is clearly unrelated to the real framework.
+The log of `RetrievalAugmentorDecorator` shows the impact of augmentation on the message sent to the chat.
+Document `permanent` was added to the message.
+It is the dummy record from the store and as such it will be always added if it gets into top 3 matching documents.
+
+Data pipeline now processes a new domain fact (arXiv document).
+Document is downloaded from the server in textual form and inserted into PostgreSQL table.
+Debezium Server should propagate the document into Milvus store.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar insert-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:25:00,203 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 2
+2025-05-20 06:25:00,206 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"2504.05309v1"}, vector=[...], id=2504.05309v1, text=# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr}
+2025-05-20 06:25:00,240 INFO  [io.deb.exa.air.MilvusStore] (main) Document: {metadata={"id":"permanent"}, vector=[...], id=permanent, text=permanent}...
+----
+
+Milvus store now contains the document about IterQR framework.
+Please note that by default we cut the document to 512 characters to make demo usable even on computers without GPU.
+This behaviour is controlled by https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/DocumentDatabase.java[DocumentDatabase] class and configuration property `debezium.rag.demo.document.truncate`.
+
+Now if the query is repeated the answer should be relevant to the real description.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+2025-05-20 06:30:36,703 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:30:37,014 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:30:44,775 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "# Title
+IterQR: An Iterative Framework for LLM-based Query Rewrite in
+  e-Commercial Search System
+
+# Authors
+Shangyu Chen, Xinyu Jia, Yingfei Zhang, Shuai Zhang, Xiang Li, Wei Lin
+
+# Abstract
+The essence of modern e-Commercial search system lies in matching user's
+intent and available candidates depending on user's query, providing
+personalized and precise service. However, user's query may be incorrect due to
+ambiguous input and typo, leading to inaccurate search. These cases may be
+released by query rewr" metadata = {id=2504.05309v1} }, metadata = {SCORE=0.5339204333722591, EMBEDDING_ID=2504.05309v1} }, DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:31:08,067 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: IterQR is an iterative framework for enhancing e-Commercial search system precision, addressing user query errors via continuous iterations of candidate selection based on language model outputs.
+----
+
+From the log you can see that:
+
+* The query was augmented with the arXiv document
+* The answer corresponds to the new fact
+
+But if you query the model in *Terminal 2* again then you will receive hallucinated answer as it does not have access to augmenting facts.
+
+----
+>>> Describe IterQR framework in 20 words.
+Iterative Quantized Ridge Regression (IterQR) is an efficient, iterative algorithm for large-scale linear 
+regression that leverages quantization and ridge regression to reduce computational complexity while 
+maintaining accuracy, offering a scalable approach for managing extensive datasets.
+----
+
+As a final step we are going to test if the knowledge can be forgotten.
+The data pipeline deletes the document from PostgreSQL database.
+
+----
+$ java -jar target/quarkus-app/quarkus-run.jar delete-document 2504.05309v1
+
+$ java -jar target/quarkus-app/quarkus-run.jar list-milvus
+
+...
+2025-05-20 06:40:02,797 INFO  [io.deb.exa.air.MilvusStore] (main) Milvus list results size: 1
+...
+
+$ java -jar target/quarkus-app/quarkus-run.jar query-chat Describe IterQR framework in 20 words
+
+...
+2025-05-20 06:40:44,373 INFO  [io.deb.exa.air.RagCommand] (main) Sending query: Describe IterQR framework in 20 words
+2025-05-20 06:40:44,665 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Requested augmentation of UserMessage { name = null contents = [TextContent { text = "Describe IterQR framework in 20 words" }] }
+2025-05-20 06:40:51,957 INFO  [io.deb.exa.air.MilvusRetrieavalAugmentor$RetrievalAugmentorDecorator] (main) Result of augmentation is [DefaultContent { textSegment = TextSegment { text = "permanent" metadata = {id=permanent} }, metadata = {SCORE=0.5046951323747635, EMBEDDING_ID=permanent} }]
+2025-05-20 06:41:01,424 INFO  [io.deb.exa.air.RagCommand] (main) Chat reply: Iterative QR (iterQR) is an algorithm for approximate singular value decomposition, efficiently computing sparse solutions to linear systems through iterative updates of the matrix representation.
+...
+----
+
+As the result of the document removal
+
+* Debezium Server captures the delete operation and removes document from Milvus store
+* Chat query is not augmented
+* Reply is again hallucinated
+
+=== Stop demo
+
+A the end the demo deployment is dropped via
+
+----
+$ docker-compose down
+----
+
+that will terminate containers in all terminals.
+
+== Conclusion
+
+This blogpost explains how Debezium 3.1 can be integrated into AI workflows, particularly those using Retrieval-Augmented Generation (RAG).
+Debezium captures real-time changes from a database and feeds them into vector databases.
+These updates are essential for keeping AI systems current with fresh, domain-specific data.
+The example setup involves PostgreSQL, Debezium Server, Milvus, and Granite LLM (with embeddings).
+This architecture enables intelligent applications that respond with accurate, up-to-date information.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: roldanbob
body: ```suggestion
This architecture enables you to deploy intelligent applications that respond with accurate, up-to-date information.
```
created_at: 2025-05-21T16:31:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: jpechane
body: @roldanbob I fixed the example sources and reflected it in the blogpost too.
created_at: 2025-05-22T08:01:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,438 @@
+---
+layout: post
+title: "Debezium as part of your AI solution"
+date: 2025-05-19
+tags: [ demo, ai, rag ]
+author: jpechane
+---
+
+One question that we encountered recently is how to effectively integrate change data capture (CDC) with AI workloads — particularly for scenarios in which critical organizational knowledge is not publicly available.
+To help you to take advantage of your internal data, Debezium 3.1 introduces AI-focused features such as the Embeddings SMT and the Milvus sink, which you can combine to supply inputs to an LLM.  
+You can read more about these enhancements in the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/[Debezium 3.1 release notes].
+
++++<!-- more -->+++
+
+:imagesdir: /assets/images/2025-05-22-debezium-as-part-of-your-ai-solution
+
+== Introduction
+
+In this post, we'll show how Debezium, Milvus, and Ollama can work together to form a Retrieval-Augmented Generation (RAG) pipeline.
+By capturing changes from a relational database, enriching them with vector embeddings, and enabling similarity search across these vectors, you can build AI-driven applications that are powered by up-to-date, domain-specific knowledge.
+
+Let's look at an example that illustrates how you can use Debezium to enrich your AI applications with knowledge captured from experts within your organization.
+
+Suppose that our organization introduces a new AI-driven application that is backed by an LLM.
+To enrich and extend the language model, we want to take advantage of internal organizational knowledge that is stored in text documents in a PostgreSQL database.
+Whenever users within the organization interact with the AI application, we want to make sure that its responses are informed by the most current local knowledge.
+Because the local knowledge that is stored in the PostgreSQL database is in constant flux, with documents being added, updated, or withdrawn to comply with regulatory requirements, we need a solution that has the agility to keep up with these changes. 
+
+The common solution to address this problem is to implement Retrieval-Augmented Generation (RAG).
+This post demonstrates how to use Debezium to build a CDC-fed RAG system that uses the following components:
+
+* A PostgreSQL database for data storage
+* Milvus vector database
+* Debezium Server to feed Milvus from PostgreSQL
+* A local https://ollama.com/[Ollama] hosted LLM
+* A Java application that interacts with the LLM and uses RAG to provide prompt context
+
+== What is RAG (Retrieval-Augmented Generation)?
+
+Retrieval-Augmented Generation (RAG) is an AI technique that combines information retrieval with generative models to produce more accurate and contextually relevant responses.
+Instead of relying solely on a model's internal knowledge, RAG pipelines retrieve relevant documents or data from an external source (like a vector database) and use that information to enrich the model's responses.
+In our scenario, Debezium, Milvus, and Ollama work together to form a RAG workflow: data changes are captured and vectorized, stored in Milvus, and then retrieved to augment LLM outputs with up-to-date, domain-specific information.
+
+== What is Debezium Server?
+
+https://debezium.io/documentation/reference/3.1/operations/debezium-server.html[Debezium Server] is a Debezium implementation that you can use to stream change events from databases to various sinks without the need to deploy a Kafka cluster.
+It provides a lightweight way to consume CDC events and forward them to destinations from which they can be consumed by other applications.
+Debezium Server also supports the use of Kafka Connect single message transformations within its processing pipeline.
+
+== What is Milvus?
+
+Milvus is a specialized vector database designed for similarity search and AI-heavy workloads.
+Whether it's product recommendations, image search, or any other use case that relies on fast vector retrieval, Milvus is built for that.
+A vector database and fast vector retrieval is the heart of any RAG solution.
+The vector database stores so called *embeddings* - vector representations of the data that can be used for tasks like similarity search or clustering.
+Based on similarities between a prompt and the stored data, the AI application extends the context of the prompt.
+
+=== Why Milvus as a Sink?
+
+For applications where you need up-to-date vector representations of your data, pushing changes from a transactional database into Milvus makes a lot of sense.
+By using Milvus, not only can you keep your AI models in sync with operational data, you can also offload similarity search to a system that is built for it.
+
+=== How Debezium Milvus Sink Works
+
+A typical deployment of Milvus sink uses the following workflow:
+
+* The Debezium connector captures changes from a source database.
+* If the source database does not contain a field with embeddings, then the https://debezium.io/blog/2025/04/02/debezium-3-1-final-released/#new-features-and-improvements-ai[FieldToEmbedding SMT] is used to enrich change events with vector embeddings.
+* Milvus sink writes the vector data into Milvus.
+* Milvus stores and indexes the vectors for fast similarity search.
+
+== Example application
+
+This blogpost is based on the https://github.com/debezium/debezium-examples/tree/main/ai-rag[Debezium ai-rag] example application.
+Let's go step-by-step through the details and internals of the application so you can easily build your own.
+
+image::overview.png[image,caption="Figure 1: Architecture",width=800,role=centered-image]
+
+The application architecture consists of the following two flows, which share a common Milvus instance:
+
+* Data pipeline
+* AI application
+
+The data pipeline ingests data into Milvus, while the AI application queries Milvus to find similarities in the data.
+
+=== Data pipeline
+
+Our organization sources documents in an https://arxiv.org/[arXiv service] that provides scholarly articles for download in different formats.
+The test application downloads a requested article based on its identifier and stores it in a PostgreSQL table.
+
+The PostgreSQL table is created with the following https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-postgres/ai-sample-data.sql[DDL]:
+[source,sql]
+----
+CREATE TABLE documents (
+  id VARCHAR(64) PRIMARY KEY,
+  metadata JSON,
+  text TEXT
+);
+ALTER TABLE documents REPLICA IDENTITY FULL;
+----
+
+The replica identity of the table is set to `FULL`, so Debezium preserves the original state of a row in update and delete messages.
+Our demo doesn't require preservation of the original row state, but being able to refer back to the original state is useful for some implementations.
+
+Upon user request, the application downloads documents in text form and stores them in the table.
+Debezium stores the document identifier in the `id` field of the event; the textual representation of the article in the `text` field; and JSON metadata `{"id:" "<document id>"}` in metadata.
+The table does not provide a column with embeddings, so Debezium must use its `FieldToEmbedding` SMT (described later) to calculate them.
+
+In our environment, we run a local LLM that is based on the Ollama LLM framework.
+For the model, we selected https://ollama.com/library/granite3.1-dense:2b[granite3.1-dense:2b], a text-only model that optimized for RAG.
+Our model is one of large family of open-source https://huggingface.co/ibm-granite[IBM Granite models], but the application is not limited to it and can use an arbitrary model.
+
+Debezium Server provides an interface between the PostgreSQL store and the Milvus sink.
+Because embeddings are not provided, we can use the https://github.com/debezium/debezium-examples/blob/main/ai-rag/config-server/application.properties#L16[Debezium FieldToEmbedding SMT] to calculate them and store them a field named `vector`.
+
+Our application uses LangChain4j Milvus store module internally so we will keep the default collection structure https://github.com/langchain4j/langchain4j/blob/main/langchain4j-milvus/src/main/java/dev/langchain4j/store/embedding/milvus/MilvusEmbeddingStore.java[expected by it]
+
+* `id` - `VarChar`
+* `metadata` - `JSON`
+* `text` -`VarChar`
+* `vector` - `FloatVector`
+
+There is a known https://github.com/langchain4j/langchain4j/issues/2834[issue] in the module that causes an application failure when the store is empty.
+We are going to store one dummy document in the database (and thus in Milvus) to work around it.
+
+== AI Application
+
+The AI application is the application that interacts with LLM and extends the prompt with data loaded from Milvus stored base on the data and prompt embeddings similarity.
+
+The demo application is command-line driven, written using the https://quarkus.io/[Quarkus framework].
+For AI features it uses Quarkus https://docs.quarkiverse.io/quarkus-langchain4j/dev/index.html[LangChain4j extension], specifically https://docs.quarkiverse.io/quarkus-langchain4j/dev/ollama.html[Ollama LLM] and https://docs.quarkiverse.io/quarkus-langchain4j/dev/milvus-store.html[Milvus Store] for RAG.
+
+The AI service is registered via the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/Chat.java[Chat] class.
+
+[source,java]
+----
+package io.debezium.examples.airag;
+
+import dev.langchain4j.service.SystemMessage;
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+
+@RegisterAiService(retrievalAugmentor = MilvusRetrieavalAugmentor.class)
+public interface Chat {
+
+    @SystemMessage("You are an expert that provides short summaries.")
+    String chat(@UserMessage String message);
+}
+----
+
+The module itself is configured in https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/resources/application.properties[application.properties].
+
+----
+quarkus.langchain4j.ollama.base-url=http://localhost:11434
+quarkus.langchain4j.ollama.chat-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.embedding-model.model-id=granite3.1-dense:2b
+quarkus.langchain4j.ollama.timeout=120s
+----
+
+RAG is enabled using the `retrievalAugmentor` parameter on the`@RegisterAiService` annotation and is implemented in the https://github.com/debezium/debezium-examples/blob/main/ai-rag/client/src/main/java/io/debezium/examples/airag/MilvusRetrieavalAugmentor.java[MilvusRetrieavalAugmentor] bean.
path: _posts/2025-05-22-debezium-as-part-of-your-ai-solution.adoc
user: login: jpechane
body: Fixed
created_at: 2025-05-22T08:10:22Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-20T04:59:19Z
body: 🎊 PR Preview has been successfully built and deployed to https://debezium-debezium-github-io-preview-pr-1133.surge.sh

<img width="300" src="https://user-images.githubusercontent.com/507615/90250366-88233900-de6e-11ea-95a5-84f0762ffd39.png">
<!-- Sticky Pull Request Comment -->
<!-- Sticky Pull Request Comment -->
author_association: NONE
user: login: jpechane
created_at: 2025-05-21T06:12:27Z
body: @Naros I merged the suggestions so it is up to you to start prinitng machine (with correct publication date) :-)
author_association: CONTRIBUTOR
user: login: jpechane
created_at: 2025-05-21T06:12:45Z
body: @roldanbob @Naros Thanks a lot for the review!
author_association: CONTRIBUTOR
user: login: Naros
created_at: 2025-05-21T09:33:12Z
body: @jpechane I'll wait for @roldanbob to do the remainder of the document today, then we'll start the :printer: 
author_association: MEMBER
user: login: jpechane
created_at: 2025-05-22T08:18:19Z
body: @vjuranek I updated Conclusion with a marketing blurb, can you please check it?
author_association: CONTRIBUTOR
user: login: jpechane
created_at: 2025-05-28T05:23:09Z
body: @Naros Can we publish it now?
author_association: CONTRIBUTOR