CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Quarkus extension deployment module for OpenAI integration with LangChain4j providing build-time processing and CDI bean generation

Overview
Eval results
Files

build-items.mddocs/

Build Items Reference

Build items are Quarkus extension APIs that enable communication between build processors during application build. This deployment module produces and consumes build items to integrate OpenAI models into the Quarkus ecosystem.

This reference is primarily for Quarkus extension authors who want to integrate with the OpenAI deployment module.

Capabilities

Build Items Produced

Build items created by this deployment module that other extensions can consume for integration and coordination.

Provider Candidate Build Items

Build items indicating OpenAI is available as a provider for various model types, allowing the core LangChain4j extension to select appropriate providers.

package io.quarkiverse.langchain4j.deployment.items;

/**
 * Build item indicating OpenAI is available as a chat model provider.
 * Produced during build to participate in provider selection.
 */
public final class ChatModelProviderCandidateBuildItem extends MultiBuildItem {

    private final String provider;

    /**
     * Create a chat model provider candidate.
     *
     * @param provider The provider name ("openai")
     */
    public ChatModelProviderCandidateBuildItem(String provider) {
        this.provider = provider;
    }

    /**
     * Get the provider name.
     *
     * @return The provider name
     */
    public String getProvider() {
        return provider;
    }
}

When Produced: When quarkus.langchain4j.openai.chat-model.enabled=true (default)

Similar Build Items:

  • EmbeddingModelProviderCandidateBuildItem - Embedding model provider candidate
  • ModerationModelProviderCandidateBuildItem - Moderation model provider candidate
  • ImageModelProviderCandidateBuildItem - Image model provider candidate

Usage by Other Extensions:

import io.quarkiverse.langchain4j.deployment.items.ChatModelProviderCandidateBuildItem;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.BuildProducer;
import java.util.List;

@BuildStep
void checkOpenAiAvailability(
        List<ChatModelProviderCandidateBuildItem> candidates,
        BuildProducer<MyCustomBuildItem> producer) {

    boolean hasOpenAi = candidates.stream()
        .anyMatch(c -> "openai".equals(c.getProvider()));

    if (hasOpenAi) {
        // Configure integration with OpenAI
        producer.produce(new MyCustomBuildItem());
    }
}

Feature Build Item

Build item registering the "langchain4j-openai" feature for tracking and display.

package io.quarkus.deployment.builditem;

/**
 * Build item representing a Quarkus feature.
 * Used for feature tracking and display in build output.
 */
public final class FeatureBuildItem extends SimpleBuildItem {

    private final String info;

    /**
     * Create a feature build item.
     *
     * @param info The feature name
     */
    public FeatureBuildItem(String info) {
        this.info = info;
    }

    public String getInfo() {
        return info;
    }
}

Feature Name: "langchain4j-openai"

Purpose: Appears in build output and feature lists, helping track which Quarkus extensions are active.

Service Provider Build Items

Build items registering SPI implementations for Java ServiceLoader mechanism and native image support.

package io.quarkus.deployment.builditem.nativeimage;

/**
 * Build item registering a service provider interface implementation.
 * Ensures SPI mechanism works in native images.
 */
public final class ServiceProviderBuildItem extends MultiBuildItem {

    private final String serviceInterface;
    private final String provider;

    /**
     * Create a service provider build item.
     *
     * @param serviceInterface The service interface (e.g., "dev.langchain4j.model.openai.spi.OpenAiChatModelBuilderFactory")
     * @param provider The provider implementation (e.g., "io.quarkiverse.langchain4j.openai.QuarkusOpenAiChatModelBuilderFactory")
     */
    public ServiceProviderBuildItem(String serviceInterface, String provider) {
        this.serviceInterface = serviceInterface;
        this.provider = provider;
    }

    public String getServiceInterface() {
        return serviceInterface;
    }

    public List<String> providers() {
        return Collections.singletonList(provider);
    }
}

Registered Service Providers:

  • OpenAiChatModelBuilderFactoryQuarkusOpenAiChatModelBuilderFactory
  • OpenAiStreamingChatModelBuilderFactoryQuarkusOpenAiStreamingChatModelBuilderFactory
  • OpenAiEmbeddingModelBuilderFactoryQuarkusOpenAiEmbeddingModelBuilderFactory
  • OpenAiModerationModelBuilderFactoryQuarkusOpenAiModerationModelBuilderFactory

Reflective Class Build Items

Build items registering classes that require reflection support in native images.

package io.quarkus.deployment.builditem.nativeimage;

/**
 * Build item registering a class for reflection in native image.
 * Ensures runtime reflection works in GraalVM native executables.
 */
public final class ReflectiveClassBuildItem extends MultiBuildItem {

    private final List<String> className;
    private final boolean methods;
    private final boolean fields;
    private final boolean constructors;

    /**
     * Create via builder pattern.
     */
    public static Builder builder(String... classNames) {
        return new Builder().classNames(classNames);
    }

    public static class Builder {
        public Builder methods(boolean methods);
        public Builder fields(boolean fields);
        public Builder constructors(boolean constructors);
        public ReflectiveClassBuildItem build();
    }
}

Registered Reflective Classes:

  • com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy - JSON serialization
  • dev.langchain4j.model.openai.internal.embedding.OpenAiEmbeddingDeserializer - Embedding deserialization

Synthetic Bean Build Items

Build items creating CDI beans programmatically without corresponding Java classes.

package io.quarkus.arc.deployment;

/**
 * Build item for creating synthetic CDI beans.
 * Allows programmatic bean definition without concrete classes.
 */
public final class SyntheticBeanBuildItem extends MultiBuildItem {

    /**
     * Configure a synthetic bean.
     *
     * @param beanType The bean type (e.g., DotName for ChatModel interface)
     * @return Bean configurator for fluent configuration
     */
    public static ExtendedBeanConfigurator configure(DotName beanType) {
        return new ExtendedBeanConfigurator(beanType);
    }

    public static class ExtendedBeanConfigurator {
        public ExtendedBeanConfigurator scope(Class<? extends Annotation> scope);
        public ExtendedBeanConfigurator defaultBean();
        public ExtendedBeanConfigurator unremovable();
        public ExtendedBeanConfigurator setRuntimeInit();
        public ExtendedBeanConfigurator addQualifier(AnnotationInstance qualifier);
        public ExtendedBeanConfigurator addInjectionPoint(Type type);
        public ExtendedBeanConfigurator createWith(Function<?, ?> creationFunction);
        public ExtendedBeanConfigurator supplier(Supplier<?> supplier);
        public SyntheticBeanBuildItem done();
    }
}

Generated Synthetic Beans:

For each selected OpenAI provider:

  • ChatModel - ApplicationScoped, default bean, runtime init, with ChatModelListener injection
  • StreamingChatModel - ApplicationScoped, default bean, runtime init, with ChatModelListener injection
  • EmbeddingModel - ApplicationScoped, default bean, unremovable, runtime init
  • ModerationModel - ApplicationScoped, default bean, runtime init
  • ImageModel - ApplicationScoped, default bean, runtime init

Named configurations add @ModelName(value) qualifier to beans.

Example Creation:

var builder = SyntheticBeanBuildItem
    .configure(CHAT_MODEL)
    .setRuntimeInit()
    .defaultBean()
    .scope(ApplicationScoped.class)
    .addInjectionPoint(ParameterizedType.create(
        DotNames.CDI_INSTANCE,
        new Type[] { ClassType.create(DotNames.CHAT_MODEL_LISTENER) },
        null))
    .createWith(recorder.chatModel(configName));

if (!NamedConfigUtil.isDefault(configName)) {
    builder.addQualifier(
        AnnotationInstance.builder(ModelName.class)
            .add("value", configName)
            .build());
}

beanProducer.produce(builder.done());

Dev UI Build Items (Development Mode Only)

Build items for Quarkus Development UI integration.

package io.quarkus.devui.spi.page;

/**
 * Build item for adding a card page to Dev UI.
 * Only produced in development mode.
 */
public final class CardPageBuildItem extends SimpleBuildItem {

    /**
     * Add build-time data available to Dev UI pages.
     */
    public void addBuildTimeData(String key, Object value);

    /**
     * Add a web component page to the card.
     */
    public void addPage(Page page);
}

Dev UI Pages Added:

  • Images Page: Testing image generation with DALL-E models
  • Moderation Page: Testing content moderation
package io.quarkus.devui.spi;

/**
 * Build item registering JSON RPC providers for Dev UI.
 */
public final class JsonRPCProvidersBuildItem extends MultiBuildItem {

    private final Class<?> providerClass;

    public JsonRPCProvidersBuildItem(Class<?> providerClass) {
        this.providerClass = providerClass;
    }

    public Class<?> getProviderClass() {
        return providerClass;
    }
}

Registered RPC Providers:

  • OpenAiImagesJsonRPCService - Image generation RPC service
  • OpenAiModerationModelsJsonRPCService - Moderation RPC service

Build Items Consumed

Build items consumed by this deployment module from other extensions.

Selected Provider Build Items

Build items indicating which model provider was selected by the core LangChain4j extension after evaluating all candidates.

package io.quarkiverse.langchain4j.deployment.items;

/**
 * Build item indicating the selected chat model provider.
 * Consumed to determine whether to generate OpenAI chat model beans.
 */
public final class SelectedChatModelProviderBuildItem extends SimpleBuildItem {

    private final String provider;
    private final String configName;

    public SelectedChatModelProviderBuildItem(String provider, String configName) {
        this.provider = provider;
        this.configName = configName;
    }

    /**
     * Get the selected provider name.
     *
     * @return Provider name (e.g., "openai")
     */
    public String getProvider() {
        return provider;
    }

    /**
     * Get the configuration name.
     *
     * @return Configuration name ("default" or named configuration)
     */
    public String getConfigName() {
        return configName;
    }
}

Similar Build Items:

  • SelectedEmbeddingModelCandidateBuildItem - Selected embedding model provider
  • SelectedModerationModelProviderBuildItem - Selected moderation model provider
  • SelectedImageModelProviderBuildItem - Selected image model provider

Usage:

import io.quarkiverse.langchain4j.deployment.items.SelectedChatModelProviderBuildItem;
import io.quarkiverse.langchain4j.openai.runtime.OpenAiRecorder;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.builditem.BuildProducer;
import org.jboss.jandex.DotName;
import java.util.List;

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void generateBeans(
        OpenAiRecorder recorder,
        List<SelectedChatModelProviderBuildItem> selectedChatItem,
        BuildProducer<SyntheticBeanBuildItem> beanProducer) {

    DotName CHAT_MODEL = DotName.createSimple("dev.langchain4j.model.chat.ChatLanguageModel");

    for (var selected : selectedChatItem) {
        if ("openai".equals(selected.getProvider())) {
            String configName = selected.getConfigName();
            // Generate CDI bean for this configuration
            var builder = SyntheticBeanBuildItem
                .configure(CHAT_MODEL)
                .createWith(recorder.chatModel(configName));
            beanProducer.produce(builder.done());
        }
    }
}

Shutdown Context Build Item

Build item for registering application shutdown handlers.

package io.quarkus.deployment.builditem;

/**
 * Build item providing access to shutdown context.
 * Used to register cleanup handlers that run on application shutdown.
 */
public final class ShutdownContextBuildItem extends SimpleBuildItem {

    private final ShutdownContext shutdownContext;

    public ShutdownContextBuildItem(ShutdownContext shutdownContext) {
        this.shutdownContext = shutdownContext;
    }

    public ShutdownContext getShutdownContext() {
        return shutdownContext;
    }
}

Usage:

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void cleanUp(OpenAiRecorder recorder, ShutdownContextBuildItem shutdown) {
    recorder.cleanUp(shutdown.getShutdownContext());
}

Build Processor Methods

Provider Candidate Registration

Build step that produces provider candidate build items based on configuration.

package io.quarkiverse.langchain4j.openai.deployment;

public class OpenAiProcessor {

    /**
     * Register OpenAI as a candidate provider for enabled model types.
     *
     * @param chatProducer Producer for chat model candidates
     * @param embeddingProducer Producer for embedding model candidates
     * @param moderationProducer Producer for moderation model candidates
     * @param imageProducer Producer for image model candidates
     * @param config Build-time configuration
     */
    @BuildStep
    public void providerCandidates(
            BuildProducer<ChatModelProviderCandidateBuildItem> chatProducer,
            BuildProducer<EmbeddingModelProviderCandidateBuildItem> embeddingProducer,
            BuildProducer<ModerationModelProviderCandidateBuildItem> moderationProducer,
            BuildProducer<ImageModelProviderCandidateBuildItem> imageProducer,
            LangChain4jOpenAiBuildConfig config) {

        if (config.chatModel().enabled().isEmpty() || config.chatModel().enabled().get()) {
            chatProducer.produce(new ChatModelProviderCandidateBuildItem("openai"));
        }
        // Similar for other model types
    }
}

Execution Phase: BUILD_TIME Purpose: Declare OpenAI as available provider

Bean Generation

Build step that creates synthetic CDI beans for selected providers.

/**
 * Generate CDI beans for selected OpenAI model providers.
 *
 * @param recorder Runtime recorder for creating model instances
 * @param selectedChatItem Selected chat model providers
 * @param selectedEmbedding Selected embedding model providers
 * @param selectedModeration Selected moderation model providers
 * @param selectedImage Selected image model providers
 * @param beanProducer Producer for synthetic beans
 */
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void generateBeans(
        OpenAiRecorder recorder,
        List<SelectedChatModelProviderBuildItem> selectedChatItem,
        List<SelectedEmbeddingModelCandidateBuildItem> selectedEmbedding,
        List<SelectedModerationModelProviderBuildItem> selectedModeration,
        List<SelectedImageModelProviderBuildItem> selectedImage,
        BuildProducer<SyntheticBeanBuildItem> beanProducer) {
    // Bean generation logic
}

Execution Phase: RUNTIME_INIT Purpose: Create injectable model beans

Native Image Support Registration

Build step that registers service providers and reflective classes.

/**
 * Register service providers and reflective classes for native image support.
 *
 * @param serviceProviderProducer Producer for service provider registrations
 * @param reflectiveClassProducer Producer for reflective class registrations
 */
@BuildStep
void nativeSupport(
        BuildProducer<ServiceProviderBuildItem> serviceProviderProducer,
        BuildProducer<ReflectiveClassBuildItem> reflectiveClassProducer) {

    serviceProviderProducer.produce(new ServiceProviderBuildItem(
        OpenAiChatModelBuilderFactory.class.getName(),
        QuarkusOpenAiChatModelBuilderFactory.class.getName()));

    reflectiveClassProducer.produce(
        ReflectiveClassBuildItem.builder(PropertyNamingStrategies.SnakeCaseStrategy.class)
            .build());
}

Execution Phase: BUILD_TIME Purpose: Enable native compilation

Cleanup Registration

Build step that registers shutdown handlers.

/**
 * Register cleanup handlers for application shutdown.
 *
 * @param recorder Runtime recorder
 * @param shutdown Shutdown context
 */
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
public void cleanUp(OpenAiRecorder recorder, ShutdownContextBuildItem shutdown) {
    recorder.cleanUp(shutdown.getShutdownContext());
}

Execution Phase: RUNTIME_INIT Purpose: Clean resource cleanup on shutdown

Extension Integration Examples

Checking OpenAI Availability

Other extensions can check if OpenAI is available:

import io.quarkiverse.langchain4j.deployment.items.ChatModelProviderCandidateBuildItem;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.BuildProducer;
import java.util.List;

@BuildStep
void integrateWithOpenAi(
        List<ChatModelProviderCandidateBuildItem> candidates,
        BuildProducer<MyFeatureBuildItem> producer) {

    boolean hasOpenAi = candidates.stream()
        .anyMatch(c -> "openai".equals(c.getProvider()));

    if (hasOpenAi) {
        // Enable OpenAI-specific features
        producer.produce(new MyFeatureBuildItem("openai-integration"));
    }
}

Consuming Selected Provider

React to OpenAI being selected as the provider:

import io.quarkiverse.langchain4j.deployment.items.SelectedChatModelProviderBuildItem;
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.BuildProducer;
import java.util.List;

@BuildStep
void onOpenAiSelected(
        List<SelectedChatModelProviderBuildItem> selected,
        BuildProducer<AdditionalBeanBuildItem> beanProducer) {

    for (var item : selected) {
        if ("openai".equals(item.getProvider())) {
            // Register additional beans or configuration
            beanProducer.produce(AdditionalBeanBuildItem.builder()
                .addBeanClass(OpenAiMetricsCollector.class)
                .build());
        }
    }
}

Adding Custom Listeners

Register chat model listeners that will be automatically injected:

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.BuildProducer;

@BuildStep
void registerListener(BuildProducer<AdditionalBeanBuildItem> producer) {
    producer.produce(AdditionalBeanBuildItem.builder()
        .addBeanClass(CustomChatModelListener.class)
        .setUnremovable()
        .build());
}

The listener will be automatically discovered and injected into OpenAI chat model beans.

Build Item Ordering

Build items flow through the build process in a specific order:

  1. Build-Time Configuration is loaded
  2. Provider Candidates are produced by all provider extensions
  3. Provider Selection happens in core LangChain4j extension
  4. Selected Provider Build Items are produced
  5. Bean Generation consumes selected providers and creates beans
  6. Service Provider Registration happens for native image
  7. Dev UI Registration happens in development mode
  8. Runtime Initialization executes recorded method calls
  9. Application Starts with all beans available

Extensions can hook into any phase by consuming appropriate build items.

Testing Build Items

When testing Quarkus extensions that integrate with OpenAI deployment module:

import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.pkg.builditem.NativeBuild;
import dev.langchain4j.model.openai.spi.OpenAiChatModelBuilderFactory;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertTrue;

@QuarkusTest
public class OpenAiIntegrationTest {

    @BuildStep(onlyIf = NativeBuild.class)
    void checkNativeImageSupport(
            List<ServiceProviderBuildItem> serviceProviders) {

        boolean hasOpenAiChatFactory = serviceProviders.stream()
            .anyMatch(sp -> sp.getServiceInterface()
                .equals(OpenAiChatModelBuilderFactory.class.getName()));

        assertTrue(hasOpenAiChatFactory, "OpenAI chat factory should be registered");
    }
}

Use Quarkus testing utilities to verify build items are produced and consumed correctly.

Install with Tessl CLI

npx tessl i tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-openai-deployment

docs

build-items.md

cdi-beans.md

configuration.md

dev-ui.md

index.md

runtime-components.md

tile.json