Quarkus LangChain4j
repository·main·Indexed 43 days ago
https://github.com/quarkiverse/quarkus-langchain4jExtensions that facilitate seamless integration between the Quarkus framework and the LangChain4j library, enabling developers to incorporate Large Language Models (LLMs) into Quarkus applications. Features include declarative AI services, support for OpenAI GPTs, Hugging Faces, and Ollama, document store integration with Redis, Chroma, and Infinispan, GraalVM native compilation support, and integrated observability.
What's inside Quarkus LangChain4j
- This sample demonstrates how to perform comprehensive evaluation testing for AI-powered chatbots using the Quarkus LangChain4j evaluation framework. It covers multiple testing paradigms including programmatic, declarative, and AI-driven approaches.
Overview of Quarkus LangChain4j features
mainQuarkus LangChain4j provides seamless integration between Quarkus and LangChain4j, allowing you to incorporate Large Language Models (LLMs) into your applications with the following capabilities:
- Declarative AI services: Define AI services using interfaces.
- Diverse LLM Integration: Support for OpenAI GPTs, Hugging Faces, Ollama, and more.
- Tool & Embedding Support: Use LLMs with external tools and embedding models.
- Document Store Integration: Connect to stores like Redis, Chroma, and Infinispan.
- Quarkus Native Support: Compatible with GraalVM native compilation.
- Observability: Integrated with the Quarkus observability stack (metrics, tracing).
- Pluggable Auth: Support for various authentication providers.
Overview of Quarkus LangChain4j
mainQuarkus LangChain4j is an extension that integrates Large Language Models (LLMs) into Quarkus applications using a declarative, developer-friendly API. It is built on top of the LangChain4j library but provides an opinionated, enterprise-grade integration tailored for the Quarkus ecosystem.
Key Capabilities:
- Declarative AI Services: Use Java interfaces and annotations to call LLMs with minimal boilerplate.
- Optimized for Quarkus: Fast startup, native-image ready, and low footprint.
- Advanced AI Patterns: Support for tool calling (function calling), agentic patterns, and chat memory for multi-turn interactions.
- RAG Support: Easy integration with vector stores like Redis, Chroma, and Infinispan for Retrieval-Augmented Generation.
- Built-in Observability: Integrated logs, metrics, and tracing.
- Developer Experience: Includes Dev UI for visual introspection and Dev Services for automatic embedding stores and model serving.
Use Milvus as an embedding store in Quarkus LangChain4j
mainThe
quarkus-langchain4j-milvusextension allows you to use Milvus as a vector database for storing and retrieving embedded documents in RAG (Retrieval-Augmented Generation) applications. It supports approximate nearest neighbor (ANN) search usingCOSINE,L2(Euclidean), orIP(Inner Product) distance metrics. The extension automatically handles collection and schema initialization via gRPC.include::{examples-dir}/io/quarkiverse/langchain4j/samples/IngestorExampleWithMilvus.java[]A2A Agent Discovery via Apicurio Registry
mainThis sample demonstrates dynamic Agent-to-Agent (A2A) discovery using Apicurio Registry as a centralized store for agent cards.
In this pattern, a 'Classifier' agent (using a local LLM) receives a request and determines which specialized agent should handle it. Instead of using hardcoded URLs or compile-time dependencies, the system discovers specialized agents (e.g., billing, technical, shipping) at runtime by querying the Apicurio Registry for artifacts of type
AGENT_CARD. These agents are then accessed via the@RegistryAgentannotation, which acts as an A2A client.Customer Request │ ▼ ┌──────────────┐ ┌───────────────────┐ │ Classifier │────▶│ Apicurio Registry │ │ (local LLM) │ │ ┌─────────────┐ │ └──────────────┘ │ │billing-agent│ │ │ │ │tech-agent │ │ ▼ │ │ship-agent │ │ ┌──────────────┐ │ └─────────────┘ │ │ @RegistryAgent│◀───│ AGENT_CARD │ │ (A2A client) │ └───────────────────┘ └──────────────┘What is Semantic Compression and when to use it
mainSemantic compression is a strategy to manage long chat histories by using an LLM to summarize messages in place, rather than simply truncating or evicting them. This approach preserves critical context (names, dates, action items) while staying within the model's token limits.
Key Benefits
- Prevents Token-Limit Errors: Avoids failed requests caused by exceeding the model's context window.
- Reduces Cost and Latency: Shortens prompts, which lowers API costs and improves response times.
Implementation Strategy
In Quarkus LangChain4j, you implement semantic compression by providing a custom
ChatMemoryStoreCDI bean. This bean wraps an existing memory store, monitors the history length or token count against a threshold, and triggers a summarization model when the threshold is exceeded. The summary is then embedded into a system message to maintain continuity.Warning: Semantic compression only applies to textual chat memories. Do not use this strategy for vision or other non-text data.
Configure multiple named Neo4j embedding stores
mainYou can manage embeddings for different domains by configuring multiple named stores. Each store can have its own dimension, label, index name, and database.
Important Isolation Rules:
- All named stores share the same
org.neo4j.driver.Driverand connect to the same Neo4j instance. - To keep data isolated within a single database (Neo4j Community Edition), use a distinct
label,index-name, andembedding-propertyper store. - To use different databases, you must have Neo4j Enterprise Edition. On Community Edition, you must set
database-nametoneo4j.
Configuration Example: To configure a store named
products:quarkus.langchain4j.neo4j.products.database-name=neo4j quarkus.langchain4j.neo4j.products.dimension=1536 quarkus.langchain4j.neo4j.products.label=Product quarkus.langchain4j.neo4j.products.index-name=product_vectorInjection: Use the
@EmbeddingStoreNamequalifier to inject a specific named store:@Inject @EmbeddingStoreName("products") EmbeddingStore<TextSegment> productsStore;Disabling Stores:
- Disable the default store:
quarkus.langchain4j.neo4j.default-store-enabled=false - Skip a specific named store at build time:
quarkus.langchain4j.neo4j.<store-name>.enabled=false
- All named stores share the same
Ensure consistency between Ingestion and Augmentation pipelines
mainFor successful RAG, your query-time augmentation pipeline must be compatible with your ingestion pipeline. If these do not match, retrieval accuracy will fail.
Requirements for consistency:
- Embedding Model: The model used for ingestion must be identical to the one used for query-time augmentation.
- Content Format: Text segments and metadata must match what the retriever expects.
- Vector Store: The schema and content format must be consistent; changing them requires re-ingesting all documents.
- Metadata: Any metadata used for ranking or filtering must be consistent with what was stored during ingestion.
Understand Secure MCP Authentication and Permissions
mainThe Secure MCP implementation uses the Streamable HTTP transport protocol and relies on GitHub OAuth2 for identity.
Authentication Flow
- Client Login: The MCP Client (a Quarkus application) initiates a GitHub OAuth2 authorization code flow.
- Token Propagation: The client acquires a GitHub access token and propagates it as a Bearer token in HTTP requests to the MCP server.
- Server Validation: The Quarkus MCP server validates the bearer token.
Authorization and Permissions
Access to MCP tools is restricted by permissions. Specifically, the MCP server endpoint for tools requires the
read:namepermission.How permissions are granted:
- The MCP server augments the identity derived from the GitHub bearer token.
- It checks a database for a record matching the GitHub account name that possesses the
read:namepermission. - If a match is found, the permission is added to the security identity.
Understand the Data Ingestion and RAG processes
mainRetrieval Augmented Generation (RAG) in Quarkus LangChain4j is split into two distinct phases:
- The Data Ingestion Process: This involves collecting, cleaning, and transforming data (like CSVs or text files) into vectorized documents that are stored in a database (e.g., Redis or Chroma).
- The RAG Process: When a user interacts with the LLM, the system seeks relevant documents from the database and passes them to the model to augment its response.
Embeddings (numerical vectors) are used during the RAG process to efficiently compute the similarity between user queries and stored documents.
Implement output guardrails
mainSince LLMs can generate harmful, inappropriate, or incorrectly formatted responses, you should implement guardrails to validate model output before it is used by your application. Common strategies include:
- Format Validation: Ensure outputs (like JSON) are well-formed and conform to your expected schema.
- Content Moderation: Use moderation models or keyword filtering to detect harmful or undesirable content.
- Tool-Use Validation: If the LLM is intended to call tools or functions, validate that the requested tool and its parameters are legitimate and safe to execute.
Configure multiple named PGVector stores
mainYou can configure multiple named stores, each backed by a different datasource. This is useful for managing embeddings for different domains or tenants in separate databases.
To configure a named store, use the pattern
quarkus.langchain4j.pgvector.<name>.<property>.If you only want to use named stores and not the default one, disable the default store using
quarkus.langchain4j.pgvector.default-store-enabled=false.quarkus.langchain4j.pgvector.products.dimension=1536 quarkus.langchain4j.pgvector.products.datasource=products-ds quarkus.langchain4j.pgvector.products.table=product_embeddings