CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-dev-langchain4j--langchain4j-agentic

LangChain4j Agentic Framework provides a comprehensive Java library for building multi-agent AI systems with support for workflow orchestration, supervisor agents, planning-based execution, declarative configuration, agent-to-agent communication, and human-in-the-loop workflows.

Overview
Eval results
Files

supervisor.mddocs/workflows/

Supervisor Agents

Autonomous LLM-based orchestration that dynamically selects and coordinates sub-agents to accomplish complex tasks.

Overview

Supervisor agents enable:

  • Autonomous agent selection and coordination
  • Dynamic workflow planning based on task requirements
  • Context-aware decision making
  • Flexible orchestration without fixed workflows

Factory Methods

static SupervisorAgentService<SupervisorAgent> supervisorBuilder();
static <T> SupervisorAgentService<T> supervisorBuilder(Class<T> agentServiceClass);

Quick Start:

SupervisorAgent supervisor = AgenticServices.supervisorBuilder()
    .chatModel(chatModel)
    .subAgents(researchAgent, analysisAgent, writingAgent)
    .maxAgentsInvocations(10)
    .build();

Object result = supervisor.invoke("Create a comprehensive report on AI trends");

Configuration

Required Settings

SupervisorAgentService<T> chatModel(dev.langchain4j.model.chat.ChatModel chatModel);
SupervisorAgentService<T> subAgents(Object... agents);

The ChatModel is used by the supervisor to make autonomous decisions about which agents to invoke.

Context Strategy

SupervisorAgentService<T> contextGenerationStrategy(SupervisorContextStrategy strategy);

enum SupervisorContextStrategy {
    CHAT_MEMORY,    // Use conversation history only
    INVOCATIONS,    // Use agent invocation history only
    FULL            // Use both (default)
}

Examples:

// Use full context (conversation + invocations)
.contextGenerationStrategy(SupervisorContextStrategy.FULL)

// Use only invocation history
.contextGenerationStrategy(SupervisorContextStrategy.INVOCATIONS)

// Use only conversation history
.contextGenerationStrategy(SupervisorContextStrategy.CHAT_MEMORY)

Response Strategy

SupervisorAgentService<T> responseStrategy(SupervisorResponseStrategy strategy);

enum SupervisorResponseStrategy {
    LAST,      // Return last agent's response
    SUMMARY    // Generate comprehensive summary
}

Examples:

// Return last agent's response
.responseStrategy(SupervisorResponseStrategy.LAST)

// Generate summary of all agent outputs
.responseStrategy(SupervisorResponseStrategy.SUMMARY)

Invocation Limits

SupervisorAgentService<T> maxAgentsInvocations(int maxInvocations);

Control maximum number of agent invocations to prevent infinite loops:

.maxAgentsInvocations(15)  // Allow up to 15 agent invocations

Request Generation

SupervisorAgentService<T> requestGenerator(Function<AgenticScope, String> requestGenerator);

Customize the request sent to the supervisor LLM:

.requestGenerator(scope -> {
    String userInput = (String) scope.readState("user_input");
    String priority = (String) scope.readState("priority", "normal");

    return String.format(
        "Task: %s (Priority: %s). Coordinate agents to complete efficiently.",
        userInput,
        priority
    );
})

Supervisor Context

SupervisorAgentService<T> supervisorContext(String context);

Provide additional context to guide the supervisor's decision-making:

.supervisorContext(
    "You are an expert project manager coordinating specialists. " +
    "Always start with research agent to gather information. " +
    "Only invoke writing agent after analysis is complete. " +
    "Aim to complete tasks in minimum number of steps."
)

How It Works

  1. Request Generation: Supervisor receives initial task
  2. Context Provision: Supervisor gets context (conversation and/or invocations)
  3. Agent Selection: LLM decides which sub-agent(s) to invoke next
  4. Invocation: Selected agent(s) are executed
  5. Result Processing: Outputs are added to AgenticScope
  6. Iteration: Steps 2-5 repeat until task complete or max invocations reached
  7. Response Generation: Final response created based on response strategy

Common Patterns

Multi-Specialist Coordination

// Define specialized agents
UntypedAgent researcher = AgenticServices.agentBuilder()
    .chatModel(chatModel)
    .name("researcher")
    .description("Searches and gathers information on topics")
    .tools(searchTool)
    .outputKey("research_data")
    .build();

UntypedAgent analyzer = AgenticServices.agentBuilder()
    .chatModel(chatModel)
    .name("analyzer")
    .description("Analyzes data and identifies patterns")
    .outputKey("analysis")
    .build();

UntypedAgent validator = AgenticServices.agentBuilder()
    .chatModel(chatModel)
    .name("validator")
    .description("Validates findings for accuracy")
    .outputKey("validation")
    .build();

// Create supervisor
SupervisorAgent supervisor = AgenticServices.supervisorBuilder()
    .chatModel(chatModel)
    .name("research-supervisor")
    .description("Coordinates research, analysis, and validation")
    .subAgents(researcher, analyzer, validator)
    .maxAgentsInvocations(10)
    .contextGenerationStrategy(SupervisorContextStrategy.FULL)
    .responseStrategy(SupervisorResponseStrategy.SUMMARY)
    .supervisorContext(
        "You coordinate a research team. First gather information, " +
        "then analyze it, and finally validate the findings."
    )
    .build();

// Supervisor autonomously determines agent invocation order
Object result = supervisor.invoke("Research the impact of AI on healthcare");

Customer Support System

interface CustomerSupportSystem {
    @SupervisorAgent(
        name = "support-coordinator",
        description = "Coordinates specialists to resolve customer issues",
        subAgents = {TechnicalAgent.class, BillingAgent.class, ProductAgent.class},
        maxAgentsInvocations = 15,
        contextStrategy = SupervisorContextStrategy.FULL,
        responseStrategy = SupervisorResponseStrategy.SUMMARY
    )
    String handleCustomerIssue(String customerQuery);

    @ChatModelSupplier
    default dev.langchain4j.model.chat.ChatModel chatModel() {
        return yourChatModelInstance;
    }

    @SupervisorRequest
    default String generateRequest(AgenticScope scope) {
        String query = (String) scope.readState("user_input");
        return "Help resolve this customer issue: " + query;
    }
}

Custom Output

SupervisorAgent supervisor = AgenticServices.supervisorBuilder()
    .chatModel(chatModel)
    .subAgents(researcher, analyzer, writer)
    .output(scope -> {
        List<AgentInvocation> invocations = scope.agentInvocations();

        return Map.of(
            "final_result", scope.readState("final_output"),
            "research_data", scope.readState("research_data"),
            "analysis", scope.readState("analysis"),
            "total_invocations", invocations.size(),
            "agents_used", invocations.stream()
                .map(AgentInvocation::agentName)
                .distinct()
                .collect(Collectors.toList())
        );
    })
    .build();

Declarative API

Example:

interface ProjectManagementSystem {
    @SupervisorAgent(
        name = "project-orchestrator",
        description = "Manages project tasks by coordinating team agents",
        subAgents = {
            PlanningAgent.class,
            DevelopmentAgent.class,
            TestingAgent.class,
            DeploymentAgent.class
        },
        maxAgentsInvocations = 20,
        contextStrategy = SupervisorContextStrategy.FULL,
        responseStrategy = SupervisorResponseStrategy.SUMMARY
    )
    String manageProject(String projectDescription);

    @ChatModelSupplier
    default dev.langchain4j.model.chat.ChatModel getChatModel() {
        return chatModelInstance;
    }
}

Error Handling

SupervisorAgent supervisor = AgenticServices.supervisorBuilder()
    .chatModel(chatModel)
    .subAgents(agent1, agent2, agent3)
    .errorHandler(errorContext -> {
        Throwable error = errorContext.error();
        AgenticScope scope = errorContext.agenticScope();

        System.err.println("Supervisor error: " + error.getMessage());

        int invocationCount = scope.agentInvocations().size();

        if (invocationCount < 3) {
            return new ErrorRecoveryResult("Partial result", true);
        } else {
            return new ErrorRecoveryResult(null, false);
        }
    })
    .build();

Memory and Chat History

Configure chat memory for conversation-aware supervision:

SupervisorAgent supervisor = AgenticServices.supervisorBuilder()
    .chatModel(chatModel)
    .chatMemoryProvider(chatMemoryProvider)
    .subAgents(agent1, agent2, agent3)
    .contextGenerationStrategy(SupervisorContextStrategy.FULL)
    .build();

Performance Considerations

  • Max Invocations: Set appropriate limits to prevent excessive LLM calls
  • Context Strategy: INVOCATIONS is more efficient than FULL for simple tasks
  • Response Strategy: LAST is faster than SUMMARY when you don't need aggregation
  • Agent Descriptions: Clear descriptions help the supervisor make better decisions

See Also

  • Planner Agents - Custom logic-based orchestration
  • Sequential Workflows - Fixed workflow execution
  • Error Handling - Comprehensive error handling

Install with Tessl CLI

npx tessl i tessl/maven-dev-langchain4j--langchain4j-agentic@1.11.0

docs

index.md

tile.json