diff --git a/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/ChatMemoryBean.java b/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/ChatMemoryBean.java deleted file mode 100644 index 8eb87ae96..000000000 --- a/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/ChatMemoryBean.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.quarkiverse.langchain4j.samples; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import jakarta.inject.Singleton; - -import dev.langchain4j.memory.ChatMemory; -import dev.langchain4j.memory.chat.MessageWindowChatMemory; -import io.quarkiverse.langchain4j.RemovableChatMemoryProvider; - -@Singleton -public class ChatMemoryBean implements RemovableChatMemoryProvider { - - private final Map memories = new ConcurrentHashMap<>(); - - @Override - public ChatMemory get(Object memoryId) { - return memories.computeIfAbsent(memoryId, id -> MessageWindowChatMemory.builder() - .maxMessages(20) - .id(memoryId) - .build()); - } - - @Override - public void remove(Object id) { - memories.remove(id); - } -} diff --git a/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/ChatMemoryProviderBean.java b/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/ChatMemoryProviderBean.java new file mode 100644 index 000000000..7aa437a6b --- /dev/null +++ b/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/ChatMemoryProviderBean.java @@ -0,0 +1,24 @@ +package io.quarkiverse.langchain4j.samples; + +import dev.langchain4j.memory.ChatMemory; +import dev.langchain4j.memory.chat.ChatMemoryProvider; +import dev.langchain4j.memory.chat.MessageWindowChatMemory; +import dev.langchain4j.store.memory.chat.ChatMemoryStore; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class ChatMemoryProviderBean implements ChatMemoryProvider { + + @Inject + ChatMemoryStore store; + + @Override + public ChatMemory get(Object memoryId) { + return MessageWindowChatMemory.builder() + .id(memoryId) + .maxMessages(20) + .chatMemoryStore(store) + .build(); + } +} diff --git a/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/ChatMemoryStoreProducer.java b/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/ChatMemoryStoreProducer.java new file mode 100644 index 000000000..353d7acf8 --- /dev/null +++ b/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/ChatMemoryStoreProducer.java @@ -0,0 +1,13 @@ +package io.quarkiverse.langchain4j.samples; + +import dev.langchain4j.store.memory.chat.ChatMemoryStore; +import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore; +import jakarta.enterprise.context.ApplicationScoped; + +public class ChatMemoryStoreProducer { + + @ApplicationScoped + ChatMemoryStore produceChatMemoryStore() { + return new InMemoryChatMemoryStore(); + } +} diff --git a/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/MySmallMemoryProvider.java b/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/MySmallMemoryProvider.java index a4afa028d..458bcbbf3 100644 --- a/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/MySmallMemoryProvider.java +++ b/docs/modules/ROOT/examples/io/quarkiverse/langchain4j/samples/MySmallMemoryProvider.java @@ -1,32 +1,23 @@ package io.quarkiverse.langchain4j.samples; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; - -import dev.langchain4j.memory.ChatMemory; import dev.langchain4j.memory.chat.ChatMemoryProvider; import dev.langchain4j.memory.chat.MessageWindowChatMemory; -import io.quarkiverse.langchain4j.RemovableChatMemoryProvider; +import dev.langchain4j.store.memory.chat.ChatMemoryStore; +import jakarta.inject.Inject; + +import java.util.function.Supplier; public class MySmallMemoryProvider implements Supplier { - @Override - public ChatMemoryProvider get() { - return new RemovableChatMemoryProvider() { - private final Map memories = new ConcurrentHashMap<>(); - @Override - public ChatMemory get(Object memoryId) { - return memories.computeIfAbsent(memoryId, id -> MessageWindowChatMemory.builder() - .maxMessages(20) - .id(memoryId) - .build()); - } + @Inject + ChatMemoryStore store; - @Override - public void remove(Object id) { - memories.remove(id); - } - }; + @Override + public ChatMemoryProvider get() { + return memoryId -> MessageWindowChatMemory.builder() + .id(memoryId) + .maxMessages(20) + .chatMemoryStore(store) + .build(); } } diff --git a/docs/modules/ROOT/pages/ai-services.adoc b/docs/modules/ROOT/pages/ai-services.adoc index 4cca74256..2f9d87a27 100644 --- a/docs/modules/ROOT/pages/ai-services.adoc +++ b/docs/modules/ROOT/pages/ai-services.adoc @@ -181,10 +181,18 @@ An example of such a bean is: [source,java] ---- -include::{examples-dir}/io/quarkiverse/langchain4j/samples/ChatMemoryBean.java[] +include::{examples-dir}/io/quarkiverse/langchain4j/samples/ChatMemoryProviderBean.java[] ---- -Notice that the messages are deleted when the scope terminates (as it will call the `close` method). +Additionally, it is important to configure a `ChatMemoryStore` which is responsible for actually storing the chat memory. +The following example shows how an application wide `InMemoryChatMemoryStore` can be used for this. + +[source,java] +---- +include::{examples-dir}/io/quarkiverse/langchain4j/samples/ChatMemoryStoreProducer.java[] +---- + +Notice that with this example, conversations are not deleted and thus accumulate over time. NOTE: It is recommended to have your chat memory beans implement `RemovableChatMemoryProvider` because the objects used as memory IDs are removed from the memory when the service goes out of scope.