CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Quarkus deployment extension for LangChain4j integration providing build-time processing, BuildItem APIs, and configuration for integrating Large Language Models into Quarkus applications

Overview
Eval results
Files

processors.mddocs/

Processors API Reference

Processors contain @BuildStep annotated methods that execute during the Quarkus build process. This document covers all 12 processor classes in the deployment extension.

Understanding Processors

What is a Processor?

A processor is a class containing one or more @BuildStep methods. These methods:

  • Execute at build time in dependency order
  • Consume BuildItems as method parameters
  • Produce BuildItems via BuildProducer<T> parameters
  • Can use @Record to pass data to runtime
  • Can be conditional using onlyIf or onlyIfNot

BuildStep Method Pattern

@BuildStep
public void myBuildStep(
        // Input: Consume BuildItems
        List<SomeBuildItem> inputs,
        SingleBuildItem singleInput,

        // Output: Produce BuildItems
        BuildProducer<OutputBuildItem> output) {

    // Process inputs and produce outputs
    output.produce(new OutputBuildItem(...));
}

Recording Runtime Values

Use @Record to pass build-time data to runtime:

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
public void recordData(MyRecorder recorder, List<SomeBuildItem> items) {
    // Pass data to runtime via recorder
    recorder.recordSomething(items);
}

Core Processors

BeansProcessor

Package: io.quarkiverse.langchain4j.deployment

Main processor for model provider selection and CDI bean creation.

Key Build Steps

Feature Registration:

@BuildStep
FeatureBuildItem feature() {
    return new FeatureBuildItem("langchain4j");
}

Index Dependencies:

@BuildStep
void indexDependencies(BuildProducer<IndexDependencyBuildItem> producer) {
    producer.produce(new IndexDependencyBuildItem("dev.langchain4j", "langchain4j-core"));
    producer.produce(new IndexDependencyBuildItem("dev.langchain4j", "langchain4j"));
}

Provider Selection:

@BuildStep
public void handleProviders(
        BeanDiscoveryFinishedBuildItem beanDiscoveryFinished,
        List<ChatModelProviderCandidateBuildItem> chatCandidates,
        List<EmbeddingModelProviderCandidateBuildItem> embeddingCandidates,
        List<ImageModelProviderCandidateBuildItem> imageCandidates,
        List<ModerationModelProviderCandidateBuildItem> moderationCandidates,
        List<ScoringModelProviderCandidateBuildItem> scoringCandidates,
        List<RequestChatModelBeanBuildItem> requestChatModelBeans,
        LangChain4jBuildConfig buildConfig,
        BuildProducer<SelectedChatModelProviderBuildItem> selectedChat,
        BuildProducer<SelectedEmbeddingModelCandidateBuildItem> selectedEmbedding,
        BuildProducer<SelectedImageModelProviderBuildItem> selectedImage,
        BuildProducer<SelectedModerationModelProviderBuildItem> selectedModeration,
        BuildProducer<SelectedScoringModelProviderBuildItem> selectedScoring) {

    // Select providers based on:
    // 1. Injection points (bean usage)
    // 2. Configuration
    // 3. Explicit requests via RequestXXXBeanBuildItem
}

Purpose:

  • Registers the "langchain4j" feature
  • Indexes LangChain4j dependencies for Jandex
  • Selects model providers based on configuration and usage
  • Produces Selected*BuildItem instances for chosen providers

Usage Pattern: Extensions register provider candidates, then BeansProcessor selects winners and publishes selection BuildItems that extensions can consume to create actual beans.

AiServicesProcessor

Package: io.quarkiverse.langchain4j.deployment

Main processor for AI service registration, tool integration, and guardrails processing.

Key Build Steps

Service Discovery:

@BuildStep
void discover(
        CombinedIndexBuildItem indexBuildItem,
        BuildProducer<DeclarativeAiServiceBuildItem> producer) {

    // Scan for @RegisterAiService annotations
    // Produce DeclarativeAiServiceBuildItem for each
}

Service Creation:

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void create(
        List<DeclarativeAiServiceBuildItem> aiServices,
        List<ToolMethodBuildItem> tools,
        ToolsMetadataBuildItem toolsMetadata,
        AiServicesRecorder recorder,
        BuildProducer<GeneratedBeanBuildItem> generatedBeans) {

    // Generate CDI beans for AI services
    // Integrate tools
    // Configure guardrails
    // Wire up memory providers
}

Purpose:

  • Discovers @RegisterAiService annotated interfaces
  • Generates implementation classes for AI services
  • Integrates tools with AI services
  • Processes input/output guardrails
  • Configures prompt templates
  • Wires chat memory providers

Usage Pattern: Consumes DeclarativeAiServiceBuildItem and ToolMethodBuildItem to generate complete AI service implementations.

ToolProcessor

Package: io.quarkiverse.langchain4j.deployment

Discovers and validates tool methods, creates tool specifications.

Key Build Steps

Tool Discovery:

@BuildStep
void discover(
        CombinedIndexBuildItem index,
        BuildProducer<ToolMethodBuildItem> producer) {

    IndexView indexView = index.getIndex();

    // Find all methods annotated with @Tool
    for (AnnotationInstance annotation :
            indexView.getAnnotations(LangChain4jDotNames.TOOL)) {

        MethodInfo method = annotation.target().asMethod();

        // Create ToolMethodCreateInfo
        ToolMethodCreateInfo createInfo = analyzeToolMethod(method);

        producer.produce(new ToolMethodBuildItem(method, createInfo));
    }
}

Tool Validation:

@BuildStep
void validate(
        List<ToolMethodBuildItem> tools,
        ValidationPhaseBuildItem validationPhase,
        BuildProducer<ValidationErrorBuildItem> errors) {

    for (ToolMethodBuildItem tool : tools) {
        // Validate tool method signatures
        // Check parameter types
        // Verify return types
        // Report errors
    }
}

Tool Specification Creation:

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void createSpecs(
        List<ToolMethodBuildItem> tools,
        ToolsRecorder recorder,
        BuildProducer<ToolsMetadataBuildItem> metadata) {

    // Create ToolSpecification for each tool
    // Generate JSON schemas for parameters
    // Produce consolidated metadata
}

Purpose:

  • Discovers @Tool annotated methods
  • Validates tool method signatures
  • Creates ToolSpecification instances
  • Generates JSON schemas for tool parameters
  • Produces tool metadata for AI services

Usage Pattern: Extensions can consume ToolMethodBuildItem to customize tool behavior or add tool-related functionality.

ChatMemoryProcessor

Package: io.quarkiverse.langchain4j.deployment

Configures chat memory providers.

Key Build Steps

Memory Provider Creation:

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void createMemoryProvider(
        ChatMemoryBuildConfig config,
        ChatMemoryRecorder recorder,
        BuildProducer<SyntheticBeanBuildItem> syntheticBeans) {

    ChatMemoryBuildConfig.Type type = config.type();

    // Create appropriate ChatMemoryProvider bean
    syntheticBeans.produce(
        SyntheticBeanBuildItem
            .configure(ChatMemoryProvider.class)
            .defaultBean()
            .supplier(recorder.chatMemoryProviderSupplier(type))
            .done()
    );
}

Purpose:

  • Creates ChatMemoryProvider beans based on configuration
  • Supports MESSAGE_WINDOW and TOKEN_WINDOW memory types
  • Integrates with AI services for conversation memory

InProcessEmbeddingProcessor

Package: io.quarkiverse.langchain4j.deployment

Discovers and configures local (in-process) embedding models.

Key Build Steps

Model Discovery:

@BuildStep
void discover(
        CombinedIndexBuildItem index,
        BuildProducer<InProcessEmbeddingBuildItem> producer) {

    // Scan for in-process embedding model implementations
    // Produce InProcessEmbeddingBuildItem for each
}

Bean Generation:

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void generateBeans(
        List<InProcessEmbeddingBuildItem> models,
        InProcessEmbeddingRecorder recorder,
        BuildProducer<GeneratedBeanBuildItem> generatedBeans) {

    for (InProcessEmbeddingBuildItem model : models) {
        // Generate CDI bean for in-process embedding model
        // Configure ONNX runtime if needed
    }
}

Purpose:

  • Discovers local embedding model implementations
  • Generates beans for in-process models
  • Configures ONNX Runtime for model inference
  • Enables embeddings without external API calls

PromptProcessor

Package: io.quarkiverse.langchain4j.deployment

Processes structured prompts and templates.

Key Build Steps

Template Processing:

@BuildStep
void processTemplates(
        CombinedIndexBuildItem index,
        LangChain4jBuildConfig config,
        BuildProducer<ProcessedTemplateBuildItem> producer) {

    // Process @SystemMessage and @UserMessage templates
    // Validate template variables
    // Handle {response schema} placeholder based on config
}

Purpose:

  • Processes prompt templates from annotations
  • Validates template variable references
  • Handles response schema placeholders
  • Enables structured prompt engineering

GuardrailObservabilityProcessor

Package: io.quarkiverse.langchain4j.deployment

Configures observability for guardrail execution (metrics and tracing).

Key Build Steps

Metrics Registration:

@BuildStep
void registerMetrics(
        Capabilities capabilities,
        BuildProducer<MetricsBuildItem> metrics) {

    if (capabilities.isPresent(Capability.MICROMETER)) {
        // Register guardrail execution metrics
        // Track success/failure rates
        // Monitor execution times
    }
}

Purpose:

  • Enables metrics for guardrail execution
  • Integrates with Micrometer when available
  • Tracks guardrail performance and outcomes

ListenersProcessor

Package: io.quarkiverse.langchain4j.deployment

Registers chat model listeners for observability.

Key Build Steps

Listener Registration:

@BuildStep
void registerListeners(
        Capabilities capabilities,
        BuildProducer<AdditionalBeanBuildItem> beans) {

    // Register OpenTelemetry listeners if available
    if (capabilities.isPresent(Capability.OPENTELEMETRY)) {
        beans.produce(AdditionalBeanBuildItem.unremovableOf(
            OpenTelemetryChatModelListener.class
        ));
    }

    // Register Micrometer listeners if available
    if (capabilities.isPresent(Capability.MICROMETER)) {
        beans.produce(AdditionalBeanBuildItem.unremovableOf(
            MicrometerChatModelListener.class
        ));
    }
}

Purpose:

  • Registers ChatModelListener implementations
  • Enables OpenTelemetry tracing integration
  • Enables Micrometer metrics integration
  • Provides observability for AI interactions

Native Image Processors

OnnxRuntimeProcessor

Package: io.quarkiverse.langchain4j.deployment

Configures ONNX Runtime for native image builds.

Key Build Steps

JNI Configuration:

@BuildStep(onlyIf = NativeBuild.class)
void configureJni(
        RequireOnnxRuntimeBuildItem requireOnnx,
        BuildProducer<JniRuntimeAccessBuildItem> jniAccess) {

    // Register JNI classes for ONNX Runtime
    // Configure native library loading
}

Reflection Registration:

@BuildStep(onlyIf = NativeBuild.class)
void registerReflection(
        RequireOnnxRuntimeBuildItem requireOnnx,
        BuildProducer<ReflectiveClassBuildItem> reflection) {

    // Register classes used by ONNX Runtime via reflection
}

Runtime Initialization:

@BuildStep(onlyIf = NativeBuild.class)
void configureInitialization(
        RequireOnnxRuntimeBuildItem requireOnnx,
        BuildProducer<RuntimeInitializedClassBuildItem> runtimeInit) {

    // Configure classes to initialize at runtime
    // Required for JNI library loading
}

Purpose:

  • Configures ONNX Runtime for native image
  • Registers JNI access patterns
  • Sets up reflection configuration
  • Enables in-process embedding models in native builds

OpenNlpProcessor

Package: io.quarkiverse.langchain4j.deployment

Registers OpenNLP resources for native image.

Key Build Steps

Resource Registration:

@BuildStep(onlyIf = NativeBuild.class)
void registerResources(BuildProducer<NativeImageResourceBuildItem> resources) {
    // Register .bin files (OpenNLP models)
    resources.produce(new NativeImageResourceBuildItem("*.bin"));
}

Reflection Configuration:

@BuildStep(onlyIf = NativeBuild.class)
void registerReflection(BuildProducer<ReflectiveClassBuildItem> reflection) {
    // Register OpenNLP classes for reflection
}

Purpose:

  • Includes OpenNLP model files in native image
  • Configures reflection for OpenNLP classes
  • Enables text processing in native builds

DevServices Processors

DevServicesOllamaProcessor

Package: io.quarkiverse.langchain4j.deployment.devservice

Manages Ollama DevServices container lifecycle.

Build Step Conditions

@BuildSteps(onlyIfNot = IsNormal.class)
public class DevServicesOllamaProcessor {
    // Only runs in dev/test mode, not production
}

Key Build Steps

Container Startup:

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
DevServicesResultBuildItem startContainer(
        LangChain4jBuildConfig config,
        List<DevServicesChatModelRequiredBuildItem> chatModelRequests,
        List<DevServicesEmbeddingModelRequiredBuildItem> embeddingModelRequests,
        DevServicesRecorder recorder) {

    if (!config.devservices().enabled()) {
        return null;
    }

    // Start Ollama container
    // Pull requested models
    // Preload models if configured
    // Configure base URLs for providers
}

Purpose:

  • Starts Ollama container in dev/test mode
  • Automatically pulls required models
  • Configures model base URLs
  • Enables local development without external APIs

Usage Pattern: Extensions produce DevServicesChatModelRequiredBuildItem or DevServicesEmbeddingModelRequiredBuildItem to request DevServices support.

Dev UI Processors

LangChain4jDevUIProcessor

Package: io.quarkiverse.langchain4j.deployment.devui

Integrates with Quarkus Dev UI.

Key Build Steps

Card Registration:

@BuildStep(onlyIf = IsDevelopment.class)
void registerCards(
        List<DeclarativeAiServiceBuildItem> aiServices,
        List<ToolMethodBuildItem> tools,
        List<AdditionalDevUiCardBuildItem> additionalCards,
        BuildProducer<CardPageBuildItem> cards) {

    // Create main LangChain4j card
    CardPageBuildItem card = new CardPageBuildItem();

    // Add AI services section
    // Add tools section
    // Add additional custom cards

    cards.produce(card);
}

RPC Endpoints:

@BuildStep(onlyIf = IsDevelopment.class)
@Record(ExecutionTime.STATIC_INIT)
void createRpcEndpoints(
        DevUIRecorder recorder,
        BuildProducer<JsonRPCProvidersBuildItem> rpcProducers) {

    // Create RPC endpoints for Dev UI interactions
    // Enable testing AI services from UI
    // Provide model status information
}

Purpose:

  • Adds LangChain4j card to Dev UI
  • Displays AI services and tools
  • Enables testing from browser
  • Shows model configuration

OpenWebUIDevUIProcessor

Package: io.quarkiverse.langchain4j.deployment.devui

Manages Open WebUI container for Dev UI.

Key Build Steps

Container Management:

@BuildStep(onlyIf = IsDevelopment.class)
void manageContainer(
        LangChain4jBuildConfig config,
        BuildProducer<DevServicesResultBuildItem> devServices) {

    // Start Open WebUI container
    // Connect to Ollama DevServices
    // Provide web interface for model interaction
}

Purpose:

  • Starts Open WebUI container in dev mode
  • Provides web interface for AI interactions
  • Connects to local Ollama instance
  • Enables visual testing of models

BuildStep Patterns

Pattern: Conditional Execution

Run BuildSteps only in specific modes:

// Only in native builds
@BuildStep(onlyIf = NativeBuild.class)
void nativeOnly() { }

// Only in dev/test (not production)
@BuildStep(onlyIfNot = IsNormal.class)
void devTestOnly() { }

// Only in development mode
@BuildStep(onlyIf = IsDevelopment.class)
void devOnly() { }

Pattern: Multi-Phase BuildSteps

Separate BuildSteps for different execution phases:

// Build-time processing
@BuildStep
void buildTime(
        CombinedIndexBuildItem index,
        BuildProducer<MyBuildItem> producer) {
    // Analyze code, discover annotations
}

// Static initialization (before main())
@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void staticInit(MyRecorder recorder, List<MyBuildItem> items) {
    // Create runtime objects, configure system
}

// Runtime initialization (during startup)
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void runtimeInit(MyRecorder recorder) {
    // Initialize runtime services
}

Pattern: Consuming Multiple BuildItems

@BuildStep
void combine(
        List<DeclarativeAiServiceBuildItem> services,
        List<ToolMethodBuildItem> tools,
        ToolsMetadataBuildItem metadata,
        BuildProducer<CombinedResultBuildItem> output) {

    // Combine multiple sources
    Map<String, List<ToolMethodCreateInfo>> toolsByClass =
        metadata.getMetadata();

    for (DeclarativeAiServiceBuildItem service : services) {
        // Correlate services with tools
        List<ClassInfo> toolClasses = service.getToolClassInfos();
        // Process combination
    }
}

Pattern: Provider Registration and Selection

// Phase 1: Provider registration
@BuildStep
void registerProvider(BuildProducer<ChatModelProviderCandidateBuildItem> producer) {
    producer.produce(new ChatModelProviderCandidateBuildItem("my-provider"));
}

// Phase 2: Provider selection (in BeansProcessor)
// Produces SelectedChatModelProviderBuildItem

// Phase 3: Bean creation based on selection
@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void createBeans(
        List<SelectedChatModelProviderBuildItem> selected,
        MyRecorder recorder,
        BuildProducer<SyntheticBeanBuildItem> beans) {

    for (SelectedChatModelProviderBuildItem item : selected) {
        if ("my-provider".equals(item.getProvider())) {
            // Create beans for this provider
        }
    }
}

Creating a Custom Processor

Here's a complete example of a custom processor:

package com.example.deployment;

import io.quarkiverse.langchain4j.deployment.items.ChatModelProviderCandidateBuildItem;
import io.quarkiverse.langchain4j.deployment.items.SelectedChatModelProviderBuildItem;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;

import java.util.List;

public class MyCustomProcessor {

    private static final String PROVIDER_NAME = "my-provider";

    // Step 1: Register as a provider candidate
    @BuildStep
    void registerProvider(BuildProducer<ChatModelProviderCandidateBuildItem> producer) {
        producer.produce(new ChatModelProviderCandidateBuildItem(PROVIDER_NAME));
    }

    // Step 2: React to provider selection
    @BuildStep
    @Record(ExecutionTime.STATIC_INIT)
    void onProviderSelected(
            List<SelectedChatModelProviderBuildItem> selected,
            MyRecorder recorder,
            BuildProducer<SyntheticBeanBuildItem> beans) {

        for (SelectedChatModelProviderBuildItem item : selected) {
            if (PROVIDER_NAME.equals(item.getProvider())) {
                String configName = item.getConfigName();

                // Create chat model bean
                beans.produce(
                    SyntheticBeanBuildItem
                        .configure(ChatLanguageModel.class)
                        .supplier(recorder.createChatModel(configName))
                        .done()
                );
            }
        }
    }
}

Processor Execution Order

BuildSteps execute in dependency order. The typical flow is:

  1. Feature Registration (BeansProcessor)
  2. Index Dependencies (BeansProcessor)
  3. Provider Registration (Extension processors)
  4. Service Discovery (AiServicesProcessor)
  5. Tool Discovery (ToolProcessor)
  6. Provider Selection (BeansProcessor)
  7. Bean Creation (Extension processors based on selection)
  8. AI Service Creation (AiServicesProcessor)
  9. DevServices (DevServicesOllamaProcessor, dev/test only)
  10. Dev UI (LangChain4jDevUIProcessor, dev only)

Dependencies between BuildSteps are determined automatically based on BuildItem consumption and production.

Install with Tessl CLI

npx tessl i tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-core-deployment@1.7.0

docs

build-items.md

configuration.md

index.md

processors.md

utilities.md

tile.json