CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Quarkus extension deployment module for integrating Ollama LLM models with Quarkus applications through the LangChain4j framework

Overview
Eval results
Files

architecture.mddocs/

Architecture

The Quarkus LangChain4j Ollama Deployment module is a complex Quarkus extension that operates during the application build phase. This document describes the overall architecture, key components, and how they interact within the Quarkus build chain.

Overview

As a Quarkus deployment module, this extension participates in the Quarkus build process through annotated build step methods. The architecture follows the standard Quarkus extension pattern with clear separation between build-time (deployment) and runtime concerns.

Architecture Diagram

┌─────────────────────────────────────────────────────────────────┐
│                     Quarkus Build Process                       │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│             Ollama Deployment Module (Build Time)               │
│                                                                 │
│  ┌──────────────────┐  ┌─────────────────────────────────┐   │
│  │ OllamaProcessor  │  │ OllamaDevServicesProcessor      │   │
│  │                  │  │                                 │   │
│  │ • Feature        │  │ • Container Management         │   │
│  │ • Indexing       │  │ • Lifecycle Control            │   │
│  │ • Native Support │  │ • Configuration Injection      │   │
│  │ • Providers      │  │                                │   │
│  │ • Bean Creation  │  └─────────────────────────────────┘   │
│  └──────────────────┘                                         │
│           │                        │                           │
│           │                        ▼                           │
│           │         ┌──────────────────────────────┐          │
│           │         │  OllamaContainer             │          │
│           │         │  (Testcontainers wrapper)    │          │
│           │         └──────────────────────────────┘          │
│           │                                                    │
│           ▼                                                    │
│  ┌──────────────────────────────────────────┐                │
│  │  OllamaRecorder (Runtime Recorder)       │                │
│  │  • chatModel(configName)                 │                │
│  │  • streamingChatModel(configName)        │                │
│  │  • embeddingModel(configName)            │                │
│  └──────────────────────────────────────────┘                │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                  Runtime Module (Application)                   │
│                                                                 │
│  ┌──────────────────┐  ┌──────────────────┐                   │
│  │  ChatModel Bean  │  │ EmbeddingModel   │                   │
│  │  (Synthetic CDI) │  │ Bean             │                   │
│  └──────────────────┘  └──────────────────┘                   │
│           │                      │                             │
│           └──────────┬───────────┘                             │
│                      ▼                                         │
│         ┌─────────────────────────┐                           │
│         │  Application Code       │                           │
│         │  (@Inject models)       │                           │
│         └─────────────────────────┘                           │
└─────────────────────────────────────────────────────────────────┘

Key Components

Build-Time Processors

The extension contains three main processor classes that participate in the build chain:

OllamaProcessor

Package: io.quarkiverse.langchain4j.ollama.deployment

Responsibility: Core build-time processing for Ollama integration

Build Steps:

  1. Feature registration
  2. Dependency indexing
  3. Native image configuration
  4. Provider candidate registration
  5. Implicit configuration detection
  6. DevServices requirement detection
  7. Synthetic bean generation
  8. JSON-B deprioritization

Key Interactions:

  • Consumes configuration to determine model enablement
  • Produces provider candidates for selection mechanism
  • Produces DevServices requirements
  • Produces synthetic bean definitions
  • Uses OllamaRecorder to defer bean creation to runtime

OllamaDevServicesProcessor

Package: io.quarkiverse.langchain4j.ollama.deployment.devservices

Responsibility: DevServices container lifecycle management

Build Steps:

  1. Feature registration
  2. Container startup and configuration

Key Interactions:

  • Consumes DevServices requirements from OllamaProcessor
  • Manages OllamaContainer lifecycle
  • Produces DevServices configuration for runtime injection
  • Registers shutdown hooks for cleanup

Conditions:

  • Only runs in development/test modes (not production)
  • Only runs if DevServices are enabled
  • Only runs if Docker is available

OllamaDevUiProcessor

Package: io.quarkiverse.langchain4j.ollama.deployment.devui

Responsibility: Dev UI integration

Build Steps:

  1. Register Open WebUI card

Key Interactions:

  • Produces Dev UI card for Quarkus Dev UI
  • Only active in development mode

Configuration System

Build-Time Configuration:

  • LangChain4jOllamaOpenAiBuildConfig - Root configuration
  • ChatModelBuildConfig - Chat model enablement
  • EmbeddingModelBuildConfig - Embedding model enablement
  • OllamaDevServicesBuildConfig - DevServices settings

Configuration Phase: BUILD_TIME - Read during application build

Configuration Processing Flow:

  1. Quarkus reads configuration from application.properties
  2. SmallRye Config maps properties to typed interfaces
  3. Processors receive configuration through dependency injection
  4. Configuration determines which build items are produced

DevServices Architecture

Purpose: Automatic Ollama container provisioning for development

Components:

  1. OllamaDevServicesProcessor: Lifecycle coordinator

    • Detects if DevServices should start
    • Manages container lifecycle
    • Handles configuration changes
    • Injects runtime configuration
  2. OllamaContainer: Testcontainers wrapper

    • Extends org.testcontainers.ollama.OllamaContainer
    • Configures container with proper image, port, volumes
    • Provides configuration extraction methods
    • Handles shared network integration

Lifecycle Flow:

Start → Check Conditions → Check Existing Instance →
Compare Config → Start Container → Inject Config →
Register Cleanup → Running → Shutdown

Activation Conditions:

  • Not production mode
  • DevServices enabled in configuration
  • Docker available
  • Base URL not configured OR points to localhost
  • Ollama not already running on localhost:11434
  • At least one model selected Ollama provider

State Management:

  • Uses static volatile fields for cross-reload persistence
  • Configuration comparison triggers restart on changes
  • Cleanup hooks registered with ClassLoader

Build Chain Integration

Build Item Flow:

Configuration → Provider Candidates → Provider Selection →
DevServices Requirements → DevServices Startup →
Bean Generation → Runtime Initialization

Key Build Items:

  1. Provider Registration:

    • ChatModelProviderCandidateBuildItem
    • EmbeddingModelProviderCandidateBuildItem
    • ImplicitlyUserConfiguredChatProviderBuildItem
  2. Provider Selection (External):

    • SelectedChatModelProviderBuildItem
    • SelectedEmbeddingModelCandidateBuildItem
  3. DevServices:

    • DevServicesChatModelRequiredBuildItem
    • DevServicesEmbeddingModelRequiredBuildItem
    • DevServicesOllamaConfigBuildItem
    • DevServicesResultBuildItem
  4. Bean Generation:

    • SyntheticBeanBuildItem

Build Step Dependencies:

  • Quarkus automatically orders build steps based on consumed/produced build items
  • Build steps with no dependencies can run in parallel
  • Build steps with dependencies run in topological order

Synthetic Bean Generation

Pattern: Recorder Pattern

Build-Time:

  1. OllamaProcessor.generateBeans() build step executes
  2. For each selected model, creates SyntheticBeanBuildItem
  3. Calls recorder methods to get bean creation functions
  4. Functions are serialized into application bytecode

Runtime Initialization:

  1. Quarkus runtime initialization phase begins
  2. Bean creation functions are invoked
  3. Recorder accesses runtime configuration
  4. Model clients are instantiated and configured
  5. Beans are registered with Arc (CDI container)

Bean Types Created:

  • ChatModel - Standard chat interface
  • StreamingChatModel - Streaming chat interface
  • EmbeddingModel - Text embedding interface

Bean Characteristics:

  • Scope: @ApplicationScoped
  • Removability: EmbeddingModel is unremovable
  • Qualifiers: @ModelName(configName) for named configurations
  • Injection Points: Chat models inject Instance<ChatModelListener>

Native Image Support

Reflection Configuration:

  • Request/response classes registered for Jackson serialization
  • Service providers registered for SPI mechanism
  • Custom serializers/deserializers registered

Why Needed:

  • GraalVM native compilation uses static analysis
  • Reflection breaks static analysis
  • Explicit registration required for dynamic access

Configured Classes:

  • OllamaChatRequest - Full hierarchy with nested types
  • OllamaChatResponse - Full hierarchy with nested types
  • FormatSerializer - Constructor reflection only
  • OllamaDateDeserializer - Constructor reflection only
  • All ConfigSourceInterceptor implementations - Service providers

Runtime Module Interaction

Separation of Concerns:

Deployment Module (this module):

  • Build-time processing only
  • Configuration validation
  • Bean definition creation
  • DevServices management
  • Native image configuration

Runtime Module (quarkus-langchain4j-ollama):

  • Runtime bean creation
  • HTTP client configuration
  • API interaction
  • Model implementation
  • Configuration mapping

Communication:

  • Deployment module references runtime classes for type information
  • Recorder bridges build-time and runtime
  • Configuration is shared through Quarkus config system

Build Step Execution Order

Typical execution sequence:

  1. Early Steps (Parallel):

    • OllamaProcessor.feature()
    • OllamaProcessor.indexUpstreamOllamaModule()
    • OllamaDevServicesProcessor.feature()
  2. Configuration Steps:

    • OllamaProcessor.nativeSupport()
    • OllamaProcessor.providerCandidates()
    • OllamaProcessor.implicitlyConfiguredProviders()
  3. Provider Selection (External to this module)

  4. DevServices Steps (Conditional):

    • OllamaProcessor.devServicesSupport()
    • OllamaDevServicesProcessor.startOllamaDevService()
  5. Bean Generation:

    • OllamaProcessor.generateBeans()
  6. Finalization:

    • OllamaProcessor.deprioritizeJsonb()
    • OllamaDevUiProcessor.registerOpenWebUiCard()

Configuration Flow

Build-Time Configuration Flow

application.properties → SmallRye Config →
Build Config Interfaces → Processor Build Steps →
Build Items → Provider Selection

Runtime Configuration Flow

application.properties → SmallRye Config →
Runtime Config Interfaces → OllamaRecorder →
Model Client Instantiation

DevServices Configuration Injection

Container Started → Extract Config →
Inject base-url Properties → Runtime Config →
Model Clients Use Injected URLs

Extension Points

The deployment module provides several extension points:

Custom Beans

Applications can override default beans:

@ApplicationScoped
@Priority(APPLICATION + 10)
public class CustomChatModel implements ChatModel {
    // Custom implementation
}

Chat Model Listeners

Applications can provide listeners for chat events:

@ApplicationScoped
public class MyChatListener implements ChatModelListener {
    // Listen to chat events
}

Configuration Customization

Named configurations allow multiple Ollama instances:

quarkus.langchain4j.ollama.instance1.base-url=http://ollama1:11434
quarkus.langchain4j.ollama.instance2.base-url=http://ollama2:11434

Thread Safety

Build-Time

Build steps are single-threaded within the Quarkus build process. No synchronization needed.

DevServices State

Static volatile fields in OllamaDevServicesProcessor:

  • devService - Currently running container
  • cfg - Current configuration
  • first - First run flag

Marked volatile for visibility across hot-reload scenarios in development mode.

Runtime Beans

Model beans are @ApplicationScoped singletons:

  • Thread-safe by design
  • HTTP client handles concurrent requests
  • No shared mutable state

Performance Considerations

Build-Time

  • Jandex indexing minimizes classpath scanning
  • Provider selection happens once per build
  • Reflection configuration precomputed

DevServices

  • Container reuse across rebuilds (if config unchanged)
  • Shared network reduces resource usage
  • Model caching via volume mount

Runtime

  • Connection pooling in HTTP client
  • Singleton beans avoid instantiation overhead
  • Lazy initialization where appropriate

Error Handling

Build-Time Errors

  • Configuration validation at build time
  • Clear error messages for misconfiguration
  • Fail-fast approach prevents runtime issues

DevServices Errors

  • Docker unavailable: Skip DevServices, continue build
  • Container startup failure: Propagate error, fail build
  • Configuration errors: Validation at build time

Runtime Errors

  • Connection errors: Propagate to application
  • Model errors: Propagate through LangChain4j API
  • Configuration errors: Fail at startup

Debugging

Build-Time Debugging

Enable Quarkus build logging:

mvn clean install -X

DevServices Debugging

Check DevServices logs:

docker logs <container-id>

View DevServices state in Dev UI:

  • Navigate to http://localhost:8080/q/dev
  • Check "Configuration" section

Runtime Debugging

Enable HTTP client logging:

quarkus.log.category."dev.langchain4j.model.ollama".level=DEBUG

Testing Strategy

Unit Testing

  • Test processors with mock build items
  • Test configuration mapping
  • Test helper methods

Integration Testing

  • Test with actual Quarkus application
  • Test DevServices container startup
  • Test model bean injection and usage

Native Image Testing

mvn clean package -Pnative
./target/app-runner

Design Patterns

Patterns Used

  1. Builder Pattern: SyntheticBeanBuildItem.configure()
  2. Factory Pattern: OllamaRecorder bean creation
  3. Strategy Pattern: Provider selection mechanism
  4. Observer Pattern: ChatModelListener injection
  5. Proxy Pattern: Synthetic bean creation
  6. Singleton Pattern: @ApplicationScoped beans

Quarkus-Specific Patterns

  1. Build Item Pattern: Communication between build steps
  2. Recorder Pattern: Bridge build-time and runtime
  3. Conditional Build Steps: onlyIf, onlyIfNot
  4. Synthetic Beans: Programmatic bean creation

Dependencies

Compile Dependencies

  • quarkus-arc-deployment - CDI support
  • quarkus-rest-client-jackson-deployment - REST client
  • quarkus-qute-deployment - Templating
  • quarkus-langchain4j-core-deployment - Core LangChain4j
  • quarkus-langchain4j-ollama - Runtime module
  • testcontainers-ollama - DevServices container

Optional Dependencies

  • quarkus-devservices-deployment - DevServices support
  • quarkus-devui-spi - Dev UI integration

Security Considerations

DevServices

  • Containers run with Docker daemon privileges
  • Bind mounts may expose local filesystem
  • Network access to localhost only by default

Configuration

  • Sensitive configuration should use config sources
  • Base URLs may contain credentials (use secrets)
  • API keys should never be hardcoded

Native Image

  • Reflection increases attack surface
  • Minimize reflective access
  • Only register necessary classes

Future Architecture Considerations

Scalability

  • Multiple model instances supported via named configs
  • Load balancing handled at application level
  • Connection pooling in HTTP client

Extensibility

  • New model types can be added
  • Custom processors can extend functionality
  • Provider mechanism allows alternatives

Maintainability

  • Clear separation of build-time and runtime
  • Comprehensive documentation
  • Type-safe configuration
  • Explicit build item contracts

Related Documentation

  • Build-Time Configuration - Configuration interfaces and properties
  • DevServices Configuration - DevServices lifecycle and container management
  • Build Step Processing - Detailed build step documentation
  • Synthetic Bean Generation - Bean creation and injection
  • Native Image Support - GraalVM configuration

Install with Tessl CLI

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

docs

architecture.md

build-step-processing.md

build-time-configuration.md

devservices.md

index.md

native-image-support.md

runtime-configuration.md

runtime-model-types.md

synthetic-beans.md

tile.json