CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-agentic

Quarkus extension that integrates LangChain4j's agentic capabilities, enabling developers to build AI agent-based applications using declarative patterns with support for multiple agent types, agent-to-agent communication, and CDI integration.

Overview
Eval results
Files

resource-suppliers.mddocs/

Resource Suppliers

This document describes how to provide ChatModels, ChatMemory, Tools, ContentRetrievers, and other resources to agents via static supplier methods.

Capabilities

Chat Model Supplier

Provides a ChatModel for the agent to use.

/**
 * Supplies a ChatModel for the agent
 * Method must be static with no parameters
 *
 * @return ChatModel instance
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ChatModelSupplier {
}

// Usage
@ChatModelSupplier
static ChatModel chatModel() {
    return new OpenAiChatModel.builder()
        .apiKey(System.getenv("OPENAI_API_KEY"))
        .modelName("gpt-4")
        .temperature(0.7)
        .build();
}

Usage Example:

public interface MyAgent {
    @Agent(description = "Processes requests")
    String process(@V("input") String input);

    @ChatModelSupplier
    static ChatModel chatModel() {
        // OpenAI
        return new OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .modelName("gpt-4")
            .temperature(0.7)
            .maxTokens(1000)
            .build();
    }
}

// Alternative: Using Ollama
public interface OllamaAgent {
    @Agent
    String process(@V("input") String input);

    @ChatModelSupplier
    static ChatModel chatModel() {
        return OllamaChatModel.builder()
            .baseUrl("http://localhost:11434")
            .modelName("llama2")
            .temperature(0.7)
            .build();
    }
}

// Or inject from CDI (no @ChatModelSupplier needed)
// The extension will automatically use the default ChatModel bean
public interface AutoInjectedAgent {
    @Agent
    String process(@V("input") String input);
    // No @ChatModelSupplier - uses CDI-provided ChatModel
}

Chat Memory Supplier

Provides a ChatMemory instance for conversation history.

/**
 * Supplies a ChatMemory instance for the agent
 * Method must be static with no parameters
 *
 * @return ChatMemory instance
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ChatMemorySupplier {
}

// Usage
@ChatMemorySupplier
static ChatMemory chatMemory() {
    return MessageWindowChatMemory.withMaxMessages(10);
}

Usage Example:

public interface ConversationalAgent {
    @Agent(description = "Maintains conversation context")
    String chat(@V("message") String message);

    @ChatMemorySupplier
    static ChatMemory chatMemory() {
        // Window-based memory (keeps last N messages)
        return MessageWindowChatMemory.withMaxMessages(10);
    }

    @ChatModelSupplier
    static ChatModel chatModel() {
        return new OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .modelName("gpt-4")
            .build();
    }
}

// Alternative: Token-based memory
public interface TokenBasedMemoryAgent {
    @Agent
    String chat(@V("message") String message);

    @ChatMemorySupplier
    static ChatMemory chatMemory() {
        return TokenWindowChatMemory.withMaxTokens(1000, new OpenAiTokenizer());
    }

    @ChatModelSupplier
    static ChatModel chatModel() {
        return new OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .modelName("gpt-4")
            .build();
    }
}

Chat Memory Provider Supplier

Provides a ChatMemory that can be created per-user using a memory ID.

/**
 * Supplies a ChatMemoryProvider that creates ChatMemory per memory ID
 * Method must be static with one Object parameter
 *
 * @param memoryId - The memory identifier (typically user ID)
 * @return ChatMemory instance for that memory ID
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ChatMemoryProviderSupplier {
}

// Usage
@ChatMemoryProviderSupplier
static ChatMemory chatMemoryProvider(Object memoryId) {
    return MessageWindowChatMemory.withMaxMessages(10);
}

Usage Example:

public interface MultiUserAgent {
    @Agent(description = "Chat agent with per-user memory")
    String chat(@MemoryId String userId, @V("message") String message);

    @ChatMemoryProviderSupplier
    static ChatMemory chatMemoryProvider(Object memoryId) {
        // Create isolated memory for each user
        return MessageWindowChatMemory.withMaxMessages(10);
    }

    @ChatModelSupplier
    static ChatModel chatModel() {
        return new OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .modelName("gpt-4")
            .build();
    }
}

// Usage
@Inject
MultiUserAgent agent;

String response1 = agent.chat("user123", "Hello!");
String response2 = agent.chat("user456", "Hello!");  // Separate memory
String response3 = agent.chat("user123", "What did I just say?");  // Remembers "Hello!"

Tools Supplier

Provides tools (functions) that the agent can use.

/**
 * Supplies tools for the agent
 * Method must be static with no parameters
 * Return type must be Object or Object[]
 *
 * @return Tool object(s)
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ToolsSupplier {
}

// Usage - single tool
@ToolsSupplier
static Object tools() {
    return new CalculatorTool();
}

// Usage - multiple tools
@ToolsSupplier
static Object[] tools() {
    return new Object[] { new CalculatorTool(), new WeatherTool() };
}

Usage Example:

@ApplicationScoped
public class MathTools {
    @Tool("Adds two numbers")
    public int add(int a, int b) {
        return a + b;
    }

    @Tool("Multiplies two numbers")
    public int multiply(int a, int b) {
        return a * b;
    }

    @Tool("Calculates factorial")
    public long factorial(int n) {
        if (n <= 1) return 1;
        return n * factorial(n - 1);
    }
}

@ApplicationScoped
public class WebTools {
    @Tool("Fetches content from a URL")
    public String fetchUrl(String url) {
        // Implementation
        return "Content from " + url;
    }

    @Tool("Searches the web")
    public String search(String query) {
        // Implementation
        return "Search results for " + query;
    }
}

public interface AssistantAgent {
    @SystemMessage("You are a helpful assistant with access to math and web tools.")
    @UserMessage("{{request}}")
    @Agent(description = "General purpose assistant", outputKey = "response")
    String assist(@V("request") String request);

    @ToolsSupplier
    static Object[] tools() {
        return new Object[] { new MathTools(), new WebTools() };
    }

    @ChatModelSupplier
    static ChatModel chatModel() {
        return new OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .modelName("gpt-4")
            .build();
    }
}

Tool Provider Supplier

Provides a ToolProvider for dynamic tool resolution.

/**
 * Supplies a ToolProvider for the agent
 * Method must be static with no parameters
 *
 * @return ToolProvider instance
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ToolProviderSupplier {
}

// Usage
@ToolProviderSupplier
static ToolProvider toolProvider() {
    return new CustomToolProvider();
}

Usage Example:

public class DynamicToolProvider implements ToolProvider {
    @Override
    public Collection<ToolSpecification> provideTools(Object context) {
        // Dynamically determine which tools to provide based on context
        List<ToolSpecification> tools = new ArrayList<>();
        // Add tools based on context
        return tools;
    }
}

public interface DynamicAgent {
    @Agent(description = "Agent with dynamic tools")
    String process(@V("input") String input);

    @ToolProviderSupplier
    static ToolProvider toolProvider() {
        return new DynamicToolProvider();
    }

    @ChatModelSupplier
    static ChatModel chatModel() {
        return new OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .modelName("gpt-4")
            .build();
    }
}

Content Retriever Supplier

Provides a ContentRetriever for RAG (Retrieval Augmented Generation).

/**
 * Supplies a ContentRetriever for RAG
 * Method must be static with no parameters
 *
 * @return ContentRetriever instance
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ContentRetrieverSupplier {
}

// Usage
@ContentRetrieverSupplier
static ContentRetriever contentRetriever() {
    return new EmbeddingStoreContentRetriever(embeddingStore, embeddingModel);
}

Usage Example:

public interface KnowledgeBaseAgent {
    @SystemMessage("Answer questions using the provided knowledge base context.")
    @UserMessage("Question: {{question}}")
    @Agent(description = "Answers questions using knowledge base", outputKey = "answer")
    String answer(@V("question") String question);

    @ContentRetrieverSupplier
    static ContentRetriever contentRetriever() {
        // Set up embedding store
        EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
        EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();

        // Optionally populate the store
        // embeddingStore.add(...);

        return EmbeddingStoreContentRetriever.builder()
            .embeddingStore(embeddingStore)
            .embeddingModel(embeddingModel)
            .maxResults(5)
            .minScore(0.7)
            .build();
    }

    @ChatModelSupplier
    static ChatModel chatModel() {
        return new OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .modelName("gpt-4")
            .build();
    }
}

Retrieval Augmentor Supplier

Provides a RetrievalAugmentor for advanced RAG scenarios.

/**
 * Supplies a RetrievalAugmentor for advanced RAG
 * Method must be static with no parameters
 *
 * @return RetrievalAugmentor instance
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface RetrievalAugmentorSupplier {
}

// Usage
@RetrievalAugmentorSupplier
static RetrievalAugmentor retrievalAugmentor() {
    return DefaultRetrievalAugmentor.builder()
        .contentRetriever(contentRetriever)
        .build();
}

Usage Example:

public interface AdvancedRAGAgent {
    @Agent(description = "Advanced RAG with custom augmentation")
    String answer(@V("question") String question);

    @RetrievalAugmentorSupplier
    static RetrievalAugmentor retrievalAugmentor() {
        ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
            .embeddingStore(new InMemoryEmbeddingStore<>())
            .embeddingModel(new AllMiniLmL6V2EmbeddingModel())
            .build();

        return DefaultRetrievalAugmentor.builder()
            .contentRetriever(retriever)
            .contentAggregator(new ReRankingContentAggregator())
            .build();
    }

    @ChatModelSupplier
    static ChatModel chatModel() {
        return new OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .modelName("gpt-4")
            .build();
    }
}

Parallel Executor Supplier

Provides an Executor for parallel agent execution.

/**
 * Supplies an Executor for parallel agent execution
 * Method must be static with no parameters
 *
 * @return Executor instance
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ParallelExecutor {
}

// Usage
@ParallelExecutor
static Executor executor() {
    return Executors.newFixedThreadPool(4);
}

Usage Example:

public interface CustomParallelAgent {
    @ParallelAgent(
        outputKey = "results",
        subAgents = { Agent1.class, Agent2.class, Agent3.class, Agent4.class }
    )
    String processInParallel(@V("input") String input);

    @ParallelExecutor
    static Executor executor() {
        // Custom thread pool for parallel execution
        return Executors.newFixedThreadPool(
            8,
            new ThreadFactoryBuilder()
                .setNameFormat("agent-pool-%d")
                .setDaemon(true)
                .build()
        );
    }

    @ChatModelSupplier
    static ChatModel chatModel() {
        return new OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .modelName("gpt-4")
            .build();
    }
}

Human-in-the-Loop Response Supplier

Provides human response in human-in-the-loop scenarios.

/**
 * Supplies human response for human-in-the-loop scenarios
 * Method must be static
 * Return type must be String
 *
 * @return Human response string
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface HumanInTheLoopResponseSupplier {
}

// Usage
@HumanInTheLoopResponseSupplier
static String getHumanResponse() {
    // Fetch response from user interface, queue, etc.
    return "Human approval granted";
}

Usage Example:

public interface ApprovalAgent {
    @Agent(description = "Process with human approval")
    String processWithApproval(@V("request") String request);

    @HumanInTheLoop
    static void requestApproval(@V("request") String request, @V("proposedAction") String action) {
        System.out.println("Approval needed for: " + action);
        // Notify user, log request, etc.
    }

    @HumanInTheLoopResponseSupplier
    static String getHumanResponse() {
        // In production, this would fetch from a queue, UI, etc.
        // For example: return approvalQueue.poll(timeout);
        return "Approved";
    }

    @ChatModelSupplier
    static ChatModel chatModel() {
        return new OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .modelName("gpt-4")
            .build();
    }
}

Combining Multiple Suppliers

Agents can use multiple suppliers to configure different aspects.

Usage Example:

public interface FullyConfiguredAgent {
    @SystemMessage("You are a helpful assistant with tools and knowledge base access.")
    @UserMessage("{{question}}")
    @Agent(description = "Fully configured assistant", outputKey = "answer")
    String assist(@V("question") String question);

    @ChatModelSupplier
    static ChatModel chatModel() {
        return new OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .modelName("gpt-4")
            .temperature(0.7)
            .build();
    }

    @ChatMemorySupplier
    static ChatMemory chatMemory() {
        return MessageWindowChatMemory.withMaxMessages(10);
    }

    @ToolsSupplier
    static Object[] tools() {
        return new Object[] { new CalculatorTool(), new WebSearchTool() };
    }

    @ContentRetrieverSupplier
    static ContentRetriever contentRetriever() {
        EmbeddingStore<TextSegment> store = new InMemoryEmbeddingStore<>();
        EmbeddingModel model = new AllMiniLmL6V2EmbeddingModel();
        return new EmbeddingStoreContentRetriever(store, model);
    }
}

Install with Tessl CLI

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

docs

agent-definition.md

error-handling.md

index.md

lifecycle-control.md

memory-parameters.md

multi-agent-orchestration.md

resource-suppliers.md

runtime-support.md

scope-state.md

tile.json