CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-easy-rag

Easy RAG extension for Quarkus LangChain4j that dramatically simplifies implementing Retrieval Augmented Generation pipelines with automatic document ingestion and embedding store management

Overview
Eval results
Files

architecture.mddocs/

Architecture

The Easy RAG extension architecture is designed to provide a seamless RAG experience with minimal configuration while maintaining flexibility for advanced use cases. The extension integrates deeply with Quarkus's CDI system and LangChain4j's RAG framework.

Key Components

EasyRagIngestor

The document ingestion engine that handles the complete pipeline from raw documents to stored embeddings.

Responsibilities:

  • Load documents from filesystem or classpath
  • Parse documents using Apache Tika (supports PDF, DOCX, HTML, plain text, OCR images)
  • Split documents into segments using recursive text splitter
  • Generate embeddings for each segment via configured EmbeddingModel
  • Store embeddings in configured EmbeddingStore
  • Support embeddings reuse for development scenarios

Configuration-Driven: All behavior controlled through EasyRagConfig properties:

  • Document source path and type (filesystem/classpath)
  • File filtering patterns
  • Segment sizing (max size and overlap)
  • Ingestion strategy (ON, OFF, MANUAL)
  • Embeddings reuse settings

EasyRetrievalAugmentor

The retrieval component that implements LangChain4j's RetrievalAugmentor interface to provide RAG capabilities to AI services.

Responsibilities:

  • Convert user queries to embeddings using the configured EmbeddingModel
  • Search the EmbeddingStore for semantically similar document segments
  • Filter results based on max-results and min-score thresholds
  • Return relevant context to be injected into LLM prompts

Integration: Automatically used by @RegisterAiService annotated interfaces through LangChain4j's framework, requiring no explicit wiring by developers.

EasyRagManualIngestion

A simple CDI bean that provides programmatic control over ingestion timing.

Responsibilities:

  • Expose a single ingest() method for manual triggering
  • Validate that ingestion-strategy is set to MANUAL
  • Delegate to EasyRagIngestor for actual ingestion work

Use Cases:

  • Event-driven ingestion (e.g., when documents are uploaded)
  • Scheduled re-ingestion (e.g., nightly updates)
  • REST API triggered ingestion
  • Integration testing scenarios

EasyRagConfig

Configuration interface providing type-safe access to all Easy RAG settings.

Configuration Domains:

  • Document Source: Path, path type, pattern matching, recursion
  • Document Processing: Segment sizing and overlap configuration
  • Retrieval Behavior: Max results and min score thresholds
  • Ingestion Control: Strategy selection (ON/OFF/MANUAL)
  • Development Features: Embeddings reuse configuration

Injection: Available throughout the application via standard CDI injection, enabling runtime access to configuration values.

Design Patterns

Automatic CDI Bean Synthesis

The extension leverages Quarkus's build-time CDI bean synthesis to automatically provide beans when not explicitly defined by the user:

InMemoryEmbeddingStore:

  • Synthesized if no EmbeddingStore bean exists
  • Provides quick prototyping without additional configuration
  • Supports embeddings reuse for development scenarios
  • Can be replaced by adding a persistent store extension (Redis, Chroma, Infinispan)

EasyRetrievalAugmentor:

  • Synthesized if no RetrievalAugmentor bean exists
  • Automatically wired with EmbeddingModel and EmbeddingStore
  • Uses EasyRagConfig for retrieval parameters
  • Can be replaced by providing a custom RetrievalAugmentor bean

This pattern enables zero-configuration RAG while preserving full customization capabilities.

Bean Lifecycle and Wiring

Automatic Bean Creation: The extension automatically creates and wires beans when not explicitly provided:

  • InMemoryEmbeddingStore created if no EmbeddingStore bean exists
  • EasyRetrievalAugmentor created if no RetrievalAugmentor bean exists
  • All beans automatically wired via CDI injection

Bean Replacement: Provide your own bean to override automatic creation:

  • Add a persistent store extension → replaces InMemoryEmbeddingStore
  • Create custom RetrievalAugmentor bean → replaces EasyRetrievalAugmentor
  • All dependencies automatically rewired to your custom implementations

Ingestion Timing: Controlled via ingestion-strategy configuration:

  • ON: Automatic ingestion at application startup
  • OFF: No ingestion (for pre-populated stores)
  • MANUAL: Programmatic control via EasyRagManualIngestion bean

Integration with LangChain4j Framework

The extension seamlessly integrates with LangChain4j's RAG abstractions:

RetrievalAugmentor Integration:

  • EasyRetrievalAugmentor implements RetrievalAugmentor interface
  • Automatically discovered by @RegisterAiService processing
  • Augments prompts with retrieved context before LLM invocation
  • No explicit wiring required in AI service definitions

EmbeddingModel Integration:

  • Uses any available LangChain4j EmbeddingModel bean
  • Supports multiple providers (OpenAI, Ollama, in-process ONNX models)
  • Consistent API regardless of embedding provider

EmbeddingStore Integration:

  • Works with any LangChain4j EmbeddingStore implementation
  • Automatic detection and utilization
  • Seamless transition from in-memory to persistent stores

Component Interaction Flow

Ingestion Flow

1. Application Startup / Manual Trigger
   ↓
2. EasyRagIngestor.ingest() called
   ↓
3. Load documents from configured path
   ↓
4. Parse documents with Apache Tika
   ↓
5. Split into segments (recursive text splitter)
   ↓
6. Generate embeddings (via EmbeddingModel)
   ↓
7. Store embeddings (via EmbeddingStore)
   ↓
8. (Optional) Serialize to file for reuse

Retrieval Flow

1. User sends message to AI Service
   ↓
2. LangChain4j framework calls EasyRetrievalAugmentor.augment()
   ↓
3. Generate query embedding (via EmbeddingModel)
   ↓
4. Search for similar segments (via EmbeddingStore)
   ↓
5. Filter results (max-results, min-score)
   ↓
6. Return AugmentationResult with relevant segments
   ↓
7. LangChain4j injects segments into prompt
   ↓
8. Augmented prompt sent to LLM
   ↓
9. LLM generates context-aware response

Configuration Flow

1. Developer sets properties in application.properties
   ↓
2. Quarkus maps properties to EasyRagConfig interface
   ↓
3. EasyRagConfig injected into components
   ↓
4. Components read config at runtime
   ↓
5. Behavior adapts to configuration

Architectural Benefits

Simplicity

  • Minimal configuration required (just document path and embedding model)
  • Sensible defaults for all parameters
  • Automatic bean synthesis eliminates boilerplate

Flexibility

  • Every automatic behavior can be customized
  • Custom RetrievalAugmentor for advanced retrieval logic
  • Custom EmbeddingStore for specialized storage needs
  • Manual ingestion control for dynamic scenarios

Performance

  • Build-time CDI synthesis reduces runtime overhead
  • Embeddings reuse accelerates development cycles
  • Lazy evaluation and caching opportunities
  • Efficient similarity search via specialized stores

Integration

  • Native Quarkus extension following framework conventions
  • Seamless LangChain4j integration
  • Standard CDI patterns throughout
  • Compatible with Quarkus ecosystem (Dev UI, config, etc.)

Extension Points

Developers can extend or customize the architecture at multiple points:

Custom Document Processing

Provide custom document loaders or processors before ingestion:

@ApplicationScoped
public class CustomProcessor {
    @Inject
    EmbeddingModel embeddingModel;

    @Inject
    EmbeddingStore<TextSegment> embeddingStore;

    public void ingestWithCustomLogic(List<Document> docs) {
        // Custom processing
        List<Document> processed = preprocess(docs);

        // Standard ingestion
        EmbeddingStoreIngestor.builder()
            .embeddingModel(embeddingModel)
            .embeddingStore(embeddingStore)
            .build()
            .ingest(processed);
    }
}

Custom Retrieval Logic

Replace EasyRetrievalAugmentor with custom implementation:

@ApplicationScoped
public class CustomAugmentor implements RetrievalAugmentor {
    @Override
    public AugmentationResult augment(AugmentationRequest request) {
        // Custom retrieval logic
        // Query transformation, reranking, filtering, etc.
    }
}

Custom Embedding Store

Add extension for persistent store to replace in-memory default:

<dependency>
    <groupId>io.quarkiverse.langchain4j</groupId>
    <artifactId>quarkus-langchain4j-redis</artifactId>
</dependency>

Automatically detected and used without code changes.

Relationship to Quarkus and LangChain4j Ecosystems

Quarkus Integration

  • Standard Quarkus extension structure
  • Config via SmallRye Config
  • CDI for dependency injection
  • Build-time processing via Quarkus build steps
  • Dev UI integration for testing
  • Health checks and metrics (potential)

LangChain4j Integration

  • Implements LangChain4j interfaces (RetrievalAugmentor)
  • Uses LangChain4j abstractions (EmbeddingModel, EmbeddingStore)
  • Compatible with all LangChain4j embedding and chat model providers
  • Leverages LangChain4j document processing utilities
  • Integrates with @RegisterAiService framework

This tight integration with both ecosystems ensures the extension works seamlessly with existing Quarkus and LangChain4j applications while following best practices from both communities.

Install with Tessl CLI

npx tessl i tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-easy-rag@1.7.0

docs

architecture.md

configuration.md

document-ingestion.md

index.md

manual-ingestion.md

retrieval-augmentor.md

tile.json