or run

tessl search
Log in

Version

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/io.quarkiverse.langchain4j/quarkus-langchain4j-core@1.5.x

docs

examples

edge-cases.mdreal-world-scenarios.md
index.md
tile.json

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

tessl install tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-core@1.5.0

Quarkus LangChain4j Core provides runtime integration for LangChain4j with the Quarkus framework, enabling declarative AI service creation through CDI annotations.

real-world-scenarios.mddocs/examples/

Real-World Scenarios

This document demonstrates complete, production-ready implementations of common AI service patterns.

Table of Contents

  • Customer Support Chatbot
  • Code Review Assistant
  • Document Analysis Service
  • Multi-Tenant AI Platform
  • Retrieval Augmented Generation (RAG)
  • Secure Data Access with Guardrails
  • Streaming Dashboard Assistant
  • Cost-Optimized Multi-Model Router

Customer Support Chatbot

A complete customer support bot with memory, tools, and error handling.

Service Interface

import io.quarkiverse.langchain4j.RegisterAiService;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;

@RegisterAiService(
    modelName = "gpt-3.5-turbo",
    tools = {OrderTool.class, KnowledgeBaseTool.class, TicketTool.class}
)
public interface CustomerSupportBot {
    
    @SystemMessage("""
        You are a helpful customer support agent.
        Be professional, empathetic, and concise.
        Use the available tools to look up orders, search knowledge base, or create tickets.
        """)
    String chat(@MemoryId String customerId, @UserMessage String message);
}

Tools Implementation

import dev.langchain4j.agent.tool.Tool;
import io.quarkiverse.langchain4j.guardrails.ToolInputGuardrails;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

@ApplicationScoped
public class OrderTool {
    
    @Inject
    OrderService orderService;
    
    @Tool("Look up order details by order ID")
    @ToolInputGuardrails(AuthorizationGuardrail.class)
    public String getOrderDetails(String orderId) {
        Order order = orderService.findById(orderId);
        if (order == null) {
            return "Order not found: " + orderId;
        }
        return String.format(
            "Order %s: Status=%s, Items=%d, Total=$%.2f, Estimated Delivery=%s",
            order.getId(), order.getStatus(), order.getItemCount(),
            order.getTotal(), order.getEstimatedDelivery()
        );
    }
    
    @Tool("Cancel an order")
    @ToolInputGuardrails({AuthorizationGuardrail.class, CancellationPolicyGuardrail.class})
    public String cancelOrder(String orderId, String reason) {
        try {
            orderService.cancel(orderId, reason);
            return "Order " + orderId + " has been cancelled successfully.";
        } catch (OrderException e) {
            return "Unable to cancel order: " + e.getMessage();
        }
    }
}

@ApplicationScoped
public class KnowledgeBaseTool {
    
    @Inject
    KnowledgeBaseService kb;
    
    @Tool("Search knowledge base for answers to common questions")
    public String searchKnowledgeBase(String query) {
        List<Article> articles = kb.search(query, 3);
        if (articles.isEmpty()) {
            return "No relevant articles found.";
        }
        return articles.stream()
            .map(a -> a.getTitle() + ": " + a.getSummary())
            .collect(Collectors.joining("\n\n"));
    }
}

@ApplicationScoped
public class TicketTool {
    
    @Inject
    TicketService ticketService;
    
    @Tool("Create a support ticket for complex issues")
    public String createTicket(String subject, String description, String priority) {
        Ticket ticket = ticketService.create(subject, description, priority);
        return String.format(
            "Ticket #%s created. A support specialist will respond within %s hours.",
            ticket.getId(), ticket.getSlaHours()
        );
    }
}

Guardrails

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

@ApplicationScoped
public class AuthorizationGuardrail implements ToolInputGuardrail {
    
    @Inject
    SecurityService security;
    
    @Override
    public ToolInputGuardrailResult validate(ToolInputGuardrailRequest request) {
        Object memoryId = request.memoryId();
        String orderId = request.argumentsAsJson().getString("orderId");
        
        if (!security.canAccessOrder(memoryId.toString(), orderId)) {
            return ToolInputGuardrailResult.failure(
                "You don't have permission to access this order."
            );
        }
        
        return ToolInputGuardrailResult.success();
    }
}

Usage

@Path("/support")
public class SupportResource {
    
    @Inject
    CustomerSupportBot bot;
    
    @POST
    @Path("/chat")
    public String chat(@QueryParam("customerId") String customerId, String message) {
        return bot.chat(customerId, message);
    }
}

Code Review Assistant

An AI assistant that reviews code with context-aware feedback.

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

@RegisterAiService(modelName = "gpt-4")
public interface CodeReviewer {
    
    @SystemMessage("""
        You are an expert code reviewer with deep knowledge of:
        - Clean code principles
        - Security best practices
        - Performance optimization
        - Design patterns
        
        Provide constructive, specific feedback with examples.
        Focus on: correctness, security, performance, maintainability.
        """)
    @UserMessage("""
        Review this {language} code:
        
        ```{language}
        {code}
        ```
        
        Focus areas: {focusAreas}
        """)
    String reviewCode(String language, String code, String focusAreas);
    
    @SeedMemory
    static List<ChatMessage> provideExamples() {
        return List.of(
            UserMessage.from("""
                Review this Java code:
                ```java
                public String process(String input) {
                    return input.toLowerCase();
                }
                ```
                Focus areas: null safety
                """),
            AiMessage.from("""
                **Issue**: Missing null check
                
                **Recommendation**: Add null validation:
                ```java
                public String process(String input) {
                    if (input == null) {
                        throw new IllegalArgumentException("input cannot be null");
                    }
                    return input.toLowerCase();
                }
                ```
                
                **Alternative**: Use Objects.requireNonNull() for concise null checking.
                """)
        );
    }
}

// Usage
@Inject CodeReviewer reviewer;

String feedback = reviewer.reviewCode(
    "java",
    userSubmittedCode,
    "security, performance"
);

Document Analysis Service

Extract and analyze information from documents.

import io.quarkiverse.langchain4j.RegisterAiService;
import io.quarkiverse.langchain4j.PdfUrl;
import io.quarkiverse.langchain4j.response.ResponseAugmenter;
import dev.langchain4j.service.UserMessage;

@RegisterAiService(modelName = "gpt-4")
public interface DocumentAnalyzer {
    
    @UserMessage("Summarize this document in 3-5 bullet points")
    @ResponseAugmenter(CitationAugmenter.class)
    String summarize(@PdfUrl String documentUrl);
    
    @UserMessage("Extract all dates, amounts, and parties from this contract")
    ContractData extractContractData(@PdfUrl String contractUrl);
    
    @UserMessage("Analyze sentiment and key themes in this report")
    AnalysisResult analyzeSentiment(@PdfUrl String reportUrl);
}

public record ContractData(
    List<String> parties,
    List<LocalDate> dates,
    List<BigDecimal> amounts,
    String summary
) {}

public record AnalysisResult(
    String sentiment,  // "positive", "negative", "neutral"
    List<String> keyThemes,
    double confidenceScore
) {}

// Response Augmenter adds citations
@ApplicationScoped
public class CitationAugmenter implements AiResponseAugmenter<String> {
    
    @Override
    public String augment(String response, ResponseAugmenterParams params) {
        String documentUrl = extractDocumentUrl(params);
        return response + "\n\n*Source: " + documentUrl + "*";
    }
    
    private String extractDocumentUrl(ResponseAugmenterParams params) {
        // Extract from params.variables() or params.userMessage()
        return params.variables().get("documentUrl").toString();
    }
}

Multi-Tenant AI Platform

Handle multiple tenants with isolated data and configurations.

import io.quarkiverse.langchain4j.RegisterAiService;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.UserMessage;

@RegisterAiService(
    tools = {TenantDataTool.class, TenantAnalyticsTool.class}
)
public interface TenantAssistant {
    String chat(@MemoryId TenantContext context, @UserMessage String message);
}

public record TenantContext(String tenantId, String userId) {
    @Override
    public boolean equals(Object o) {
        if (!(o instanceof TenantContext that)) return false;
        return tenantId.equals(that.tenantId) && userId.equals(that.userId);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(tenantId, userId);
    }
}

@ApplicationScoped
public class TenantDataTool {
    
    @Inject
    TenantService tenantService;
    
    @Tool("Query tenant-specific data")
    @ToolInputGuardrails(TenantIsolationGuardrail.class)
    public String queryData(String query, TenantContext context) {
        return tenantService.query(context.tenantId(), query);
    }
}

@ApplicationScoped
public class TenantIsolationGuardrail implements ToolInputGuardrail {
    
    @Override
    public ToolInputGuardrailResult validate(ToolInputGuardrailRequest request) {
        TenantContext context = (TenantContext) request.memoryId();
        
        // Ensure tenant can only access their own data
        if (requestAccessesOtherTenant(request, context.tenantId())) {
            return ToolInputGuardrailResult.fatal(
                "Tenant isolation violation detected",
                new SecurityException("Cross-tenant access attempt")
            );
        }
        
        return ToolInputGuardrailResult.success();
    }
}

// Custom Memory Provider for tenant isolation
@ApplicationScoped
public class TenantMemoryProvider implements ChatMemoryProvider, ChatMemoryRemovable {
    
    private final Map<TenantContext, ChatMemory> memories = new ConcurrentHashMap<>();
    
    @Override
    public ChatMemory get(Object memoryId) {
        TenantContext context = (TenantContext) memoryId;
        return memories.computeIfAbsent(context, 
            ctx -> MessageWindowChatMemory.withMaxMessages(100));
    }
    
    @Override
    public void remove(Object... ids) {
        for (Object id : ids) {
            memories.remove((TenantContext) id);
        }
    }
}

Retrieval Augmented Generation (RAG)

Enhance AI responses with knowledge from your data sources.

import dev.langchain4j.rag.RetrievalAugmentor;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.query.Query;
import dev.langchain4j.data.segment.TextSegment;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

@ApplicationScoped
public class ProductKnowledgeRetriever implements ContentRetriever {
    
    @Inject
    EmbeddingStore<TextSegment> embeddingStore;
    
    @Inject
    EmbeddingModel embeddingModel;
    
    @Override
    public List<Content> retrieve(Query query) {
        Embedding queryEmbedding = embeddingModel.embed(query.text()).content();
        
        List<EmbeddingMatch<TextSegment>> matches = embeddingStore.findRelevant(
            queryEmbedding,
            5,  // max results
            0.7  // min similarity score
        );
        
        return matches.stream()
            .map(match -> new Content(match.embedded().text()))
            .collect(Collectors.toList());
    }
}

@ApplicationScoped
@Produces
public class RAGConfiguration {
    
    @Inject
    ProductKnowledgeRetriever retriever;
    
    @Produces
    @ApplicationScoped
    public RetrievalAugmentor createAugmentor() {
        return DefaultRetrievalAugmentor.builder()
            .contentRetriever(retriever)
            .contentAggregator(new ReRankingContentAggregator())
            .build();
    }
}

@RegisterAiService(modelName = "gpt-4")
public interface ProductAssistant {
    // RAG automatically injects relevant product knowledge
    String answerProductQuestion(String question);
}

Secure Data Access with Guardrails

Comprehensive security validation for tool execution.

@ApplicationScoped
public class DatabaseTool {
    
    @Tool("Execute database query")
    @ToolInputGuardrails({
        SqlInjectionGuardrail.class,
        RateLimitGuardrail.class,
        AuthorizationGuardrail.class
    })
    @ToolOutputGuardrails({
        PiiRedactionGuardrail.class,
        DataVolumeGuardrail.class
    })
    public String query(String sql) {
        return database.execute(sql);
    }
    
    @HandleToolExecutionError
    public static String handleError(Throwable error, ToolErrorContext context) {
        if (error instanceof SQLException) {
            return "Database query failed. Please check your query syntax.";
        }
        return "An unexpected error occurred: " + error.getMessage();
    }
}

@ApplicationScoped
public class SqlInjectionGuardrail implements ToolInputGuardrail {
    
    private static final Pattern SQL_INJECTION_PATTERN = 
        Pattern.compile(".*(union|exec|execute|drop|delete|insert|update).*", 
                       Pattern.CASE_INSENSITIVE);
    
    @Override
    public ToolInputGuardrailResult validate(ToolInputGuardrailRequest request) {
        String sql = request.argumentsAsJson().getString("sql");
        
        if (SQL_INJECTION_PATTERN.matcher(sql).matches()) {
            return ToolInputGuardrailResult.fatal(
                "Potentially dangerous SQL detected",
                new SecurityException("SQL injection attempt")
            );
        }
        
        return ToolInputGuardrailResult.success();
    }
}

@ApplicationScoped
public class PiiRedactionGuardrail implements ToolOutputGuardrail {
    
    @Override
    public ToolOutputGuardrailResult validate(ToolOutputGuardrailRequest request) {
        if (request.isError()) {
            return ToolOutputGuardrailResult.success();
        }
        
        String result = request.resultText();
        String redacted = redactPii(result);
        
        if (!result.equals(redacted)) {
            ToolExecutionResult modified = ToolExecutionResult.builder()
                .text(redacted)
                .build();
            return ToolOutputGuardrailResult.successWith(modified);
        }
        
        return ToolOutputGuardrailResult.success();
    }
    
    private String redactPii(String text) {
        // Redact emails, SSNs, credit cards, etc.
        return text
            .replaceAll("\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b", "[EMAIL]")
            .replaceAll("\\b\\d{3}-\\d{2}-\\d{4}\\b", "[SSN]")
            .replaceAll("\\b\\d{4}[- ]?\\d{4}[- ]?\\d{4}[- ]?\\d{4}\\b", "[CARD]");
    }
}

Streaming Dashboard Assistant

Real-time streaming responses for interactive dashboards.

import io.smallrye.mutiny.Multi;
import io.quarkiverse.langchain4j.RegisterAiService;
import io.quarkiverse.langchain4j.response.ResponseAugmenter;

@RegisterAiService(
    modelName = "gpt-4",
    tools = {MetricsTool.class, ChartTool.class}
)
public interface DashboardAssistant {
    
    @ResponseAugmenter(StreamingFormatterAugmenter.class)
    Multi<String> analyzeMetrics(String query);
}

@ApplicationScoped
public class StreamingFormatterAugmenter implements AiResponseAugmenter<String> {
    
    @Override
    public Multi<String> augment(Multi<String> stream, ResponseAugmenterParams params) {
        return Multi.createFrom().concat(
            Multi.createFrom().item("πŸ“Š **Analysis:**\n\n"),
            stream.map(this::formatChunk),
            Multi.createFrom().item("\n\n---\n*Generated at " + 
                                   Instant.now() + "*")
        );
    }
    
    private String formatChunk(String chunk) {
        // Add markdown formatting, syntax highlighting, etc.
        return chunk;
    }
}

// Server-Sent Events endpoint
@Path("/dashboard")
public class DashboardResource {
    
    @Inject
    DashboardAssistant assistant;
    
    @GET
    @Path("/analyze")
    @Produces(MediaType.SERVER_SENT_EVENTS)
    public Multi<String> analyze(@QueryParam("query") String query) {
        return assistant.analyzeMetrics(query);
    }
}

Cost-Optimized Multi-Model Router

Intelligently route requests to cost-effective models.

import io.quarkiverse.langchain4j.ModelName;
import dev.langchain4j.model.chat.ChatModel;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class SmartRouter {
    
    @Inject
    Instance<ChatModel> models;
    
    @Inject
    ComplexityAnalyzer analyzer;
    
    @Inject
    CostEstimatorService costEstimator;
    
    public String route(String query) {
        int complexity = analyzer.analyze(query);
        String modelName = selectModel(complexity);
        
        ChatModel model = models.select(ModelName.Literal.of(modelName)).get();
        Response<AiMessage> response = model.generate(query);
        
        logCost(modelName, response);
        
        return response.content().text();
    }
    
    private String selectModel(int complexity) {
        if (complexity > 8) {
            return "gpt-4";  // Complex reasoning
        } else if (complexity > 5) {
            return "gpt-3.5-turbo";  // Moderate complexity
        } else {
            return "gpt-3.5-turbo-fast";  // Simple queries
        }
    }
    
    private void logCost(String modelName, Response<AiMessage> response) {
        TokenUsage usage = response.tokenUsage();
        Cost cost = costEstimator.estimate(modelName, 
                                          usage.inputTokenCount(),
                                          usage.outputTokenCount());
        logger.info("Request cost: {} (model: {})", cost, modelName);
    }
}

@ApplicationScoped
public class ComplexityAnalyzer {
    
    public int analyze(String query) {
        int score = 0;
        
        // Longer queries are typically more complex
        if (query.length() > 500) score += 3;
        else if (query.length() > 200) score += 2;
        else if (query.length() > 100) score += 1;
        
        // Keywords indicating complexity
        String lower = query.toLowerCase();
        if (lower.contains("analyze") || lower.contains("compare")) score += 2;
        if (lower.contains("calculate") || lower.contains("solve")) score += 2;
        if (lower.contains("why") || lower.contains("how")) score += 1;
        
        // Multiple questions = higher complexity
        long questionCount = query.chars().filter(ch -> ch == '?').count();
        score += (int) Math.min(questionCount, 3);
        
        return Math.min(score, 10);
    }
}

Best Practices Demonstrated

Each scenario demonstrates:

βœ“ Proper CDI integration - Using @ApplicationScoped and @Inject
βœ“ Security validation - Guardrails for authorization and input validation
βœ“ Error handling - @HandleToolExecutionError for graceful degradation
βœ“ Memory management - Per-user or per-tenant conversation history
βœ“ Tool design - Clear descriptions and parameter naming
βœ“ Cost optimization - Smart model selection based on complexity
βœ“ Streaming support - Progressive response delivery
βœ“ Response augmentation - Adding citations and formatting

Related Resources

  • Edge Cases and Advanced Scenarios
  • Quick Start Guide
  • Complete API Reference