Quarkus extension that integrates Hugging Face language models with Quarkus applications through LangChain4j
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.
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
);
}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
);
}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);
}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
);
}The extension provides Jackson mixins for proper serialization of LangChain4j Hugging Face client types. These are registered automatically with the REST client's ObjectMapper.
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 {
}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 {
}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 {
}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
);
}The client factory implements the following architecture:
HuggingFaceClientFactory SPI@ClientHeaderParamThe client factory is used internally by QuarkusHuggingFaceChatModel and QuarkusHuggingFaceEmbeddingModel. Most users will not interact with it directly.
// 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);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=changeitThe @ClientHeaderParam annotation automatically injects the Bearer token into the Authorization header for all requests.
The HuggingFaceClientLogger provides security-focused logging with automatic sensitive data masking:
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.
All mixins are registered at build time, ensuring the extension works correctly in GraalVM native images without runtime reflection.
The REST client automatically handles HTTP errors and converts them to appropriate exceptions:
waitForModel=false)The extension integrates with the following LangChain4j Hugging Face client types:
dev.langchain4j.model.huggingface.client.TextGenerationRequest - Chat/generation requestdev.langchain4j.model.huggingface.client.EmbeddingRequest - Embedding requestdev.langchain4j.model.huggingface.client.Parameters - Generation parametersdev.langchain4j.model.huggingface.client.Options - Request optionsdev.langchain4j.model.huggingface.client.TextGenerationResponse - Generation responsefloat[] - Embedding vectordev.langchain4j.model.huggingface.client.HuggingFaceClient - Client interfaceTo 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());
}
}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.CustomHeadersFactoryInstall with Tessl CLI
npx tessl i tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-hugging-face@1.7.0