CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-hugging-face

Quarkus extension that integrates Hugging Face language models with Quarkus applications through LangChain4j

Overview
Eval results
Files

client-factory.mddocs/

Client Factory

The QuarkusHuggingFaceClientFactory provides the infrastructure for creating Hugging Face REST clients with Quarkus-specific configuration. It handles REST client setup, Jackson serialization, and authentication for communication with Hugging Face inference endpoints.

Capabilities

QuarkusHuggingFaceClientFactory

Factory class for creating Hugging Face REST clients.

package io.quarkiverse.langchain4j.huggingface;

/**
 * Factory for creating Hugging Face clients with Quarkus REST client integration.
 * Implements dev.langchain4j.model.huggingface.spi.HuggingFaceClientFactory.
 */
public class QuarkusHuggingFaceClientFactory
    implements dev.langchain4j.model.huggingface.spi.HuggingFaceClientFactory {

    /**
     * Standard factory method from HuggingFaceClientFactory interface.
     * Not supported - use the Quarkus-specific create() method instead.
     *
     * @param input Factory input
     * @return Never returns normally
     * @throws UnsupportedOperationException Always thrown
     */
    public dev.langchain4j.model.huggingface.client.HuggingFaceClient create(
        dev.langchain4j.model.huggingface.spi.HuggingFaceClientFactory.Input input
    );

    /**
     * Creates a Hugging Face client with Quarkus-specific configuration.
     *
     * @param config Chat model builder configuration
     * @param input Factory input containing access token
     * @param url Target endpoint URI
     * @return Configured Hugging Face client instance
     */
    public dev.langchain4j.model.huggingface.client.HuggingFaceClient create(
        io.quarkiverse.langchain4j.huggingface.QuarkusHuggingFaceChatModel.Builder config,
        dev.langchain4j.model.huggingface.spi.HuggingFaceClientFactory.Input input,
        java.net.URI url
    );
}

QuarkusHuggingFaceClient

Quarkus-specific implementation of the Hugging Face client.

/**
 * Quarkus-specific Hugging Face client implementation.
 * Uses MicroProfile REST Client for HTTP communication.
 */
public static class QuarkusHuggingFaceClient
    implements dev.langchain4j.model.huggingface.client.HuggingFaceClient {

    /**
     * Creates a new Quarkus Hugging Face client.
     *
     * @param restApi REST API interface for making HTTP calls
     * @param token Authentication token
     */
    public QuarkusHuggingFaceClient(
        HuggingFaceRestApi restApi,
        String token
    );

    /**
     * Executes a chat/generation request.
     *
     * @param request Text generation request
     * @return Text generation response
     */
    public dev.langchain4j.model.huggingface.client.TextGenerationResponse chat(
        dev.langchain4j.model.huggingface.client.TextGenerationRequest request
    );

    /**
     * Generates text from a request.
     *
     * @param request Text generation request
     * @return Text generation response
     */
    public dev.langchain4j.model.huggingface.client.TextGenerationResponse generate(
        dev.langchain4j.model.huggingface.client.TextGenerationRequest request
    );

    /**
     * Generates embeddings for text.
     *
     * @param request Embedding request
     * @return List of embedding vectors (float arrays)
     */
    public java.util.List<float[]> embed(
        dev.langchain4j.model.huggingface.client.EmbeddingRequest request
    );
}

HuggingFaceClientLogger

Custom logger for Hugging Face REST client with security-focused logging that automatically masks sensitive data.

/**
 * Custom ClientLogger implementation for logging Hugging Face API requests and responses.
 * Automatically masks API keys and authorization tokens for security.
 * Nested class within QuarkusHuggingFaceClientFactory.
 */
class HuggingFaceClientLogger implements org.jboss.resteasy.reactive.client.api.ClientLogger {

    /**
     * Creates a new logger instance with configurable logging levels.
     *
     * @param logRequests true to enable request logging at INFO level
     * @param logResponses true to enable response logging at INFO level
     */
    public HuggingFaceClientLogger(boolean logRequests, boolean logResponses);

    /**
     * Logs an outgoing HTTP request.
     * Automatically masks Authorization header Bearer tokens and api-key headers.
     * Logs method, URL, headers, and body at INFO level.
     *
     * @param request HTTP client request
     * @param body Request body buffer
     * @param omitBody Whether to omit the body from logging
     */
    public void logRequest(
        io.vertx.core.http.HttpClientRequest request,
        io.vertx.core.buffer.Buffer body,
        boolean omitBody
    );

    /**
     * Logs an incoming HTTP response.
     * Logs status code, headers, and body at INFO level.
     *
     * @param response HTTP client response
     * @param redirect Whether this is a redirect response
     */
    public void logResponse(
        io.vertx.core.http.HttpClientResponse response,
        boolean redirect
    );

    /**
     * Sets the maximum body size for logging.
     *
     * @param bodySize Maximum body size in bytes
     */
    public void setBodySize(int bodySize);
}

HuggingFaceRestApi

MicroProfile REST Client interface for Hugging Face API communication.

package io.quarkiverse.langchain4j.huggingface;

/**
 * MicroProfile REST Client interface for Hugging Face inference API.
 * Configured with Jackson for JSON serialization and authentication headers.
 */
@jakarta.ws.rs.Path("")
@org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam(
    name = "Authorization",
    value = "Bearer {token}"
)
@jakarta.ws.rs.Consumes(jakarta.ws.rs.core.MediaType.APPLICATION_JSON)
@jakarta.ws.rs.Produces(jakarta.ws.rs.core.MediaType.APPLICATION_JSON)
public interface HuggingFaceRestApi {

    /**
     * Generates text using the Hugging Face model.
     *
     * @param request Text generation request with inputs and parameters
     * @param token Authentication token (injected into Authorization header)
     * @return List of text generation responses
     */
    @jakarta.ws.rs.POST
    java.util.List<dev.langchain4j.model.huggingface.client.TextGenerationResponse> generate(
        dev.langchain4j.model.huggingface.client.TextGenerationRequest request,
        @org.eclipse.microprofile.rest.client.annotation.NotBody String token
    );

    /**
     * Generates embeddings using the Hugging Face model.
     *
     * @param request Embedding request with inputs
     * @param token Authentication token (injected into Authorization header)
     * @return List of embedding vectors (float arrays)
     */
    @jakarta.ws.rs.POST
    java.util.List<float[]> embed(
        dev.langchain4j.model.huggingface.client.EmbeddingRequest request,
        @org.eclipse.microprofile.rest.client.annotation.NotBody String token
    );

    /**
     * Provides custom Jackson ObjectMapper for JSON serialization.
     * Registers mixins for proper serialization of LangChain4j types.
     *
     * @param defaultObjectMapper Default ObjectMapper from REST client
     * @return Customized ObjectMapper with mixins
     */
    @org.eclipse.microprofile.rest.client.annotation.ClientObjectMapper
    static com.fasterxml.jackson.databind.ObjectMapper objectMapper(
        com.fasterxml.jackson.databind.ObjectMapper defaultObjectMapper
    );
}

Jackson Serialization Mixins

The extension provides Jackson mixins for proper serialization of LangChain4j Hugging Face client types. These are registered automatically with the REST client's ObjectMapper.

ParametersMixin

package io.quarkiverse.langchain4j.huggingface.runtime.jackson;

/**
 * Jackson mixin for serializing Parameters objects.
 * Uses field-based serialization without getters/setters.
 */
@io.quarkus.jackson.JacksonMixin(dev.langchain4j.model.huggingface.client.Parameters.class)
@com.fasterxml.jackson.annotation.JsonAutoDetect(
    fieldVisibility = com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY,
    getterVisibility = com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE,
    setterVisibility = com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE
)
public abstract class ParametersMixin {
}

TextGenerationRequestMixin

package io.quarkiverse.langchain4j.huggingface.runtime.jackson;

/**
 * Jackson mixin for serializing TextGenerationRequest objects.
 * Uses field-based serialization without getters/setters.
 */
@io.quarkus.jackson.JacksonMixin(dev.langchain4j.model.huggingface.client.TextGenerationRequest.class)
@com.fasterxml.jackson.annotation.JsonAutoDetect(
    fieldVisibility = com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY,
    getterVisibility = com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE,
    setterVisibility = com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE
)
public abstract class TextGenerationRequestMixin {
}

OptionsMixin

package io.quarkiverse.langchain4j.huggingface.runtime.jackson;

/**
 * Jackson mixin for serializing Options objects.
 * Uses field-based serialization without getters/setters.
 */
@io.quarkus.jackson.JacksonMixin(dev.langchain4j.model.huggingface.client.Options.class)
@com.fasterxml.jackson.annotation.JsonAutoDetect(
    fieldVisibility = com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY,
    getterVisibility = com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE,
    setterVisibility = com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE
)
public abstract class OptionsMixin {
}

TextGenerationResponseMixin

package io.quarkiverse.langchain4j.huggingface.runtime.jackson;

/**
 * Jackson mixin for deserializing TextGenerationResponse objects.
 * Maps "generated_text" JSON field to constructor parameter.
 */
@io.quarkus.jackson.JacksonMixin(dev.langchain4j.model.huggingface.client.TextGenerationResponse.class)
public abstract class TextGenerationResponseMixin {

    /**
     * Constructor for deserializing JSON response.
     *
     * @param generatedText The generated text from the "generated_text" JSON field
     */
    @com.fasterxml.jackson.annotation.JsonCreator
    public TextGenerationResponseMixin(
        @com.fasterxml.jackson.annotation.JsonProperty("generated_text") String generatedText
    );
}

Architecture

The client factory implements the following architecture:

  1. Service Provider Interface (SPI): Implements LangChain4j's HuggingFaceClientFactory SPI
  2. REST Client Integration: Uses Quarkus MicroProfile REST Client for HTTP communication
  3. Jackson Serialization: Custom ObjectMapper with mixins for LangChain4j types
  4. Authentication: Automatic Bearer token injection via @ClientHeaderParam
  5. Native Compilation: Full GraalVM native image support through mixins

Usage

The client factory is used internally by QuarkusHuggingFaceChatModel and QuarkusHuggingFaceEmbeddingModel. Most users will not interact with it directly.

Internal Usage Example

// This happens internally when building a chat model
QuarkusHuggingFaceClientFactory factory = QuarkusHuggingFaceChatModel.CLIENT_FACTORY;

HuggingFaceClient client = factory.create(
    chatModelBuilder,
    new Input("hf_token"),
    URI.create("https://api-inference.huggingface.co/models/tiiuae/falcon-7b-instruct")
);

// Client is then used for API calls
TextGenerationResponse response = client.generate(request);

Custom REST Client Configuration

The REST client can be customized via Quarkus configuration:

# REST client timeout (separate from model timeout)
quarkus.rest-client."io.quarkiverse.langchain4j.huggingface.HuggingFaceRestApi".connect-timeout=5000
quarkus.rest-client."io.quarkiverse.langchain4j.huggingface.HuggingFaceRestApi".read-timeout=30000

# Proxy configuration
quarkus.rest-client."io.quarkiverse.langchain4j.huggingface.HuggingFaceRestApi".proxy-address=proxy.example.com:8080

# Trust store configuration for custom certificates
quarkus.rest-client."io.quarkiverse.langchain4j.huggingface.HuggingFaceRestApi".trust-store=/path/to/truststore.jks
quarkus.rest-client."io.quarkiverse.langchain4j.huggingface.HuggingFaceRestApi".trust-store-password=changeit

Key Features

Automatic Authentication

The @ClientHeaderParam annotation automatically injects the Bearer token into the Authorization header for all requests.

Secure Request Logging

The HuggingFaceClientLogger provides security-focused logging with automatic sensitive data masking:

  • Bearer Token Masking: Authorization headers with Bearer tokens are masked, showing only first 2 and last 2 characters (e.g., "Bearer sk-ab...xy")
  • API Key Masking: API key headers are masked to show only first 2 and last 2 characters
  • Configurable Logging: Separate control for request and response logging
  • INFO Level Logging: Logs at INFO level instead of DEBUG for better visibility
  • Complete Request Context: Logs method, URL, headers, and body for debugging

Field-Based Serialization

The Jackson mixins use field-based serialization, avoiding the need for getters and setters on LangChain4j client types. This ensures compatibility with the upstream library.

Native Image Support

All mixins are registered at build time, ensuring the extension works correctly in GraalVM native images without runtime reflection.

Error Handling

The REST client automatically handles HTTP errors and converts them to appropriate exceptions:

  • 401 Unauthorized: Invalid API key
  • 403 Forbidden: Access denied
  • 404 Not Found: Model not found
  • 503 Service Unavailable: Model not loaded (if waitForModel=false)

LangChain4j Types

The extension integrates with the following LangChain4j Hugging Face client types:

Request Types

  • dev.langchain4j.model.huggingface.client.TextGenerationRequest - Chat/generation request
  • dev.langchain4j.model.huggingface.client.EmbeddingRequest - Embedding request
  • dev.langchain4j.model.huggingface.client.Parameters - Generation parameters
  • dev.langchain4j.model.huggingface.client.Options - Request options

Response Types

  • dev.langchain4j.model.huggingface.client.TextGenerationResponse - Generation response
  • float[] - Embedding vector

Client Interface

  • dev.langchain4j.model.huggingface.client.HuggingFaceClient - Client interface

Advanced Configuration

Custom Jackson Modules

To add custom Jackson modules to the REST client:

import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.jackson.ObjectMapperCustomizer;
import jakarta.inject.Singleton;

@Singleton
public class HuggingFaceObjectMapperCustomizer implements ObjectMapperCustomizer {

    @Override
    public void customize(ObjectMapper objectMapper) {
        // Register custom modules
        objectMapper.registerModule(new MyCustomModule());
    }
}

Intercepting Requests

Use MicroProfile REST Client filters to intercept requests:

import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class CustomHeadersFactory implements ClientHeadersFactory {

    @Override
    public MultivaluedMap<String, String> update(
        MultivaluedMap<String, String> incomingHeaders,
        MultivaluedMap<String, String> clientOutgoingHeaders
    ) {
        // Add custom headers
        clientOutgoingHeaders.add("X-Custom-Header", "value");
        return clientOutgoingHeaders;
    }
}

Register the factory:

quarkus.rest-client."io.quarkiverse.langchain4j.huggingface.HuggingFaceRestApi".headers-factory=com.example.CustomHeadersFactory

Install with Tessl CLI

npx tessl i tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-hugging-face@1.7.0

docs

chat-model.md

client-factory.md

configuration.md

embedding-model.md

index.md

tile.json