CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-core

Core runtime module for Quarkus LangChain4j integration with declarative AI services, guardrails, and observability

Overview
Eval results
Files

memory.mddocs/

Memory Management

Memory management in Quarkus LangChain4j enables conversation context persistence and few-shot learning through example seeding. The module provides both declarative memory seeding via annotations and imperative memory removal utilities.

Core Imports

import io.quarkiverse.langchain4j.SeedMemory;
import io.quarkiverse.langchain4j.ChatMemoryRemover;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;

@SeedMemory Annotation

package io.quarkiverse.langchain4j;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SeedMemory {
}

Usage

Seeds chat memory with example interactions for few-shot prompting. The annotated method must:

  • Be static
  • Be declared on an @RegisterAiService interface
  • Return List<ChatMessage>
  • Take no parameters, OR take a single String parameter (the method name)
  • Return an even number of messages alternating between UserMessage and AiMessage

The seed messages are only added if the chat memory for the given memory ID doesn't exist or is empty.

import io.quarkiverse.langchain4j.RegisterAiService;
import io.quarkiverse.langchain4j.SeedMemory;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.AiMessage;
import java.util.List;

@RegisterAiService
public interface SentimentAnalyzer {
    Sentiment analyze(String text);
    
    @SeedMemory
    static List<ChatMessage> seedExamples() {
        return List.of(
            UserMessage.from("I love this product!"),
            AiMessage.from("POSITIVE"),
            UserMessage.from("This is terrible."),
            AiMessage.from("NEGATIVE"),
            UserMessage.from("It's okay, nothing special."),
            AiMessage.from("NEUTRAL")
        );
    }
}

Method-Specific Seeding

You can provide different seed examples for different methods by accepting the method name parameter:

@RegisterAiService
public interface MultiTaskService {
    Sentiment analyzeSentiment(String text);
    
    Category categorize(String text);
    
    @SeedMemory
    static List<ChatMessage> seed(String methodName) {
        if (methodName.equals("analyzeSentiment")) {
            return List.of(
                UserMessage.from("Great!"),
                AiMessage.from("POSITIVE"),
                UserMessage.from("Awful!"),
                AiMessage.from("NEGATIVE")
            );
        }
        if (methodName.equals("categorize")) {
            return List.of(
                UserMessage.from("Latest iPhone release"),
                AiMessage.from("TECHNOLOGY"),
                UserMessage.from("NBA finals game"),
                AiMessage.from("SPORTS")
            );
        }
        return List.of();
    }
}

ChatMemoryRemover Class

package io.quarkiverse.langchain4j;

import java.util.List;

public final class ChatMemoryRemover {
    public static void remove(Object aiService, Object memoryId);
    
    public static void remove(Object aiService, List<Object> memoryIds);
}

Methods

remove(Object, Object)

public static void remove(Object aiService, Object memoryId)

Removes chat memory for a single memory ID from the underlying ChatMemoryStore.

Parameters:

  • aiService: The bean implementing the AI service (annotated with @RegisterAiService)
  • memoryId: The memory ID to remove

Note: Automatically unwraps CDI proxies.

remove(Object, List)

public static void remove(Object aiService, List<Object> memoryIds)

Removes chat memory for multiple memory IDs from the underlying ChatMemoryStore.

Parameters:

  • aiService: The bean implementing the AI service (annotated with @RegisterAiService)
  • memoryIds: List of memory IDs to remove

Note: Automatically unwraps CDI proxies.

Usage Examples

Basic Memory Seeding

import io.quarkiverse.langchain4j.RegisterAiService;
import io.quarkiverse.langchain4j.SeedMemory;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.service.SystemMessage;
import java.util.List;

@RegisterAiService
public interface EmailClassifier {
    @SystemMessage("Classify emails as SPAM, IMPORTANT, or NORMAL")
    String classify(String emailContent);
    
    @SeedMemory
    static List<ChatMessage> seedClassificationExamples() {
        return List.of(
            UserMessage.from("You won a lottery! Click here now!"),
            AiMessage.from("SPAM"),
            UserMessage.from("Meeting with CEO tomorrow at 9am"),
            AiMessage.from("IMPORTANT"),
            UserMessage.from("Lunch plans with Sarah?"),
            AiMessage.from("NORMAL")
        );
    }
}

Removing Memory

import io.quarkiverse.langchain4j.ChatMemoryRemover;
import jakarta.inject.Inject;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class ChatService {
    @Inject
    AssistantService assistant;
    
    public void endUserSession(String userId) {
        // Remove chat history for this user
        ChatMemoryRemover.remove(assistant, userId);
    }
    
    public void clearMultipleUsers(List<String> userIds) {
        // Remove chat history for multiple users at once
        ChatMemoryRemover.remove(assistant, userIds);
    }
}

Complex Seeding Example

@RegisterAiService
public interface CodeReviewer {
    @SystemMessage("Review code and provide feedback on quality, bugs, and improvements")
    String reviewCode(String code);
    
    @SeedMemory
    static List<ChatMessage> seedReviewExamples() {
        return List.of(
            UserMessage.from("""
                public void process(String input) {
                    System.out.println(input.toLowerCase());
                }
                """),
            AiMessage.from("""
                Good: Simple and clear logic
                Issues: 
                - No null check on input (NullPointerException risk)
                - Side effect (printing) in a processing method
                Suggestion: Return the result and handle null
                """),
            
            UserMessage.from("""
                public int calculate(int a, int b) {
                    return a / b;
                }
                """),
            AiMessage.from("""
                Critical Issue: Division by zero when b=0
                Suggestion: Add validation or use Optional<Integer>
                """)
        );
    }
}

Method-Specific Seeding

@RegisterAiService
public interface LanguageProcessor {
    String translate(String text, String targetLanguage);
    
    String summarize(String text);
    
    @SeedMemory
    static List<ChatMessage> seed(String methodName) {
        return switch (methodName) {
            case "translate" -> List.of(
                UserMessage.from("Translate to French: Hello"),
                AiMessage.from("Bonjour"),
                UserMessage.from("Translate to Spanish: Goodbye"),
                AiMessage.from("Adiós")
            );
            case "summarize" -> List.of(
                UserMessage.from("Summarize: The quick brown fox jumps over the lazy dog. This is a test."),
                AiMessage.from("A sentence about a fox and a dog used for testing."),
                UserMessage.from("Summarize: Technology advances rapidly. Innovation drives change."),
                AiMessage.from("Technology and innovation create rapid change.")
            );
            default -> List.of();
        };
    }
}

Memory Management with User Sessions

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import io.quarkiverse.langchain4j.ChatMemoryRemover;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@ApplicationScoped
public class SessionManager {
    @Inject
    CustomerSupportService supportService;
    
    private final Map<String, Long> sessionTimestamps = new ConcurrentHashMap<>();
    
    public void startSession(String userId) {
        sessionTimestamps.put(userId, System.currentTimeMillis());
    }
    
    public void endSession(String userId) {
        ChatMemoryRemover.remove(supportService, userId);
        sessionTimestamps.remove(userId);
    }
    
    public void cleanupInactiveSessions(long maxIdleMillis) {
        long now = System.currentTimeMillis();
        List<String> inactiveUsers = sessionTimestamps.entrySet().stream()
            .filter(e -> now - e.getValue() > maxIdleMillis)
            .map(Map.Entry::getKey)
            .toList();
        
        if (!inactiveUsers.isEmpty()) {
            ChatMemoryRemover.remove(supportService, inactiveUsers);
            inactiveUsers.forEach(sessionTimestamps::remove);
        }
    }
}

Disabling Memory for Specific Services

// Service with no memory (stateless)
@RegisterAiService(
    chatMemoryProviderSupplier = RegisterAiService.NoChatMemoryProviderSupplier.class
)
public interface StatelessTranslator {
    String translate(String text, String targetLanguage);
}

Custom Memory Configuration

import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import java.util.function.Supplier;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

@ApplicationScoped
public class CustomChatMemoryProviderSupplier implements Supplier<ChatMemoryProvider> {
    @Inject
    ChatMemoryStore memoryStore;
    
    @Override
    public ChatMemoryProvider get() {
        return memoryId -> MessageWindowChatMemory.builder()
            .id(memoryId)
            .maxMessages(20) // Custom window size
            .chatMemoryStore(memoryStore)
            .build();
    }
}

@RegisterAiService(
    chatMemoryProviderSupplier = CustomChatMemoryProviderSupplier.class
)
public interface CustomMemoryService {
    String chat(String message);
}

Multi-User Cleanup

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import io.quarkiverse.langchain4j.ChatMemoryRemover;
import java.util.List;

@ApplicationScoped
public class UserManagementService {
    @Inject
    ChatService chatService;
    
    public void deleteUserAccount(String userId) {
        // Clean up user data
        deleteUserData(userId);
        
        // Remove chat history
        ChatMemoryRemover.remove(chatService, userId);
    }
    
    public void bulkDeleteAccounts(List<String> userIds) {
        // Clean up data for all users
        userIds.forEach(this::deleteUserData);
        
        // Remove all chat histories in one call
        ChatMemoryRemover.remove(chatService, userIds);
    }
}

Memory Configuration

Configure chat memory behavior in application.properties:

# Maximum messages to keep in memory window
quarkus.langchain4j.chat-memory.memory-window.max-messages=10

# Memory store type (in-memory by default)
# Provide custom ChatMemoryStore bean for persistent storage

Notes

  • Memory Seeding: Only applied when memory is empty or doesn't exist
  • Message Format: Seed messages must alternate between UserMessage and AiMessage
  • Even Count: Seed method must return an even number of messages
  • Scope Considerations: When using non-request scopes for AI services, carefully manage memory to avoid leaks
  • CDI Proxy Unwrapping: ChatMemoryRemover automatically handles CDI proxy unwrapping
  • Memory IDs: Typically correspond to user IDs or session IDs for conversation tracking

Install with Tessl CLI

npx tessl i tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-core

docs

ai-services.md

authentication.md

cost-estimation.md

guardrails.md

index.md

media-content.md

memory.md

observability.md

response-augmentation.md

tools.md

tile.json