Conductor is a Java-based framework for building sophisticated AI applications using a subagent architecture. It provides a robust and flexible platform for orchestrating multiple specialized AI agents to accomplish complex tasks. This project is inspired by the concepts outlined in "The Rise of Subagents" by Phil Schmid at https://www.philschmid.de/the-rise-of-subagents and it aims to provide a practical implementation of this powerful architectural pattern.
The Conductor framework is built around the idea of a central Orchestrator that manages a fleet of Subagents. Each subagent is a specialized AI agent designed to perform a specific task. This architecture allows for better modularity, reusability, and scalability of AI applications.
The Orchestrator is the heart of the framework. It is responsible for:
- Task Decomposition: Using an
LLMPlanner, the orchestrator can break down a high-level user request into a series of smaller, manageable tasks. - Agent Management: The orchestrator manages the lifecycle of subagents, including their creation, execution, and persistence.
- Workflow Coordination: The orchestrator coordinates the execution of subagents, chaining them together to create complex workflows.
Subagents are the workhorses of the framework. They are specialized AI agents that can be either:
- Explicit: Pre-defined, long-lived agents that are registered with the orchestrator and can be called by name.
- Implicit: Temporary, on-the-fly agents that are created dynamically to handle a specific task.
The framework provides a SubAgent interface which is implemented by ConversationalAgent which is a subagent that uses a Large Language Model (LLM) to perform its task with conversational capabilities.
Understanding when to use explicit versus implicit agents is crucial for effective framework usage:
Explicit Agents are formal, persistent agents with stable identities:
- Created via: Manual registration in the
SubAgentRegistry - Lifecycle: Long-lived, persisted across sessions
- Identity: Stable, predefined names that can be referenced
- Use cases: Reusable components, service-oriented agents, centralized management
- Example: A
technical-writeragent registered once and used across multiple documentation tasks
// Create and register an explicit agent
ConversationalAgent writer = new ConversationalAgent(
"technical-writer",
"Expert technical writer for documentation",
llmProvider,
"Write clear, concise technical documentation for: {{input}}",
memoryStore
);
registry.register(writer);
// Use the explicit agent by name
ExecutionResult result = orchestrator.callExplicit("technical-writer", input);Implicit Agents are temporary, lightweight agents created on-demand:
- Created via:
orchestrator.createImplicitAgent() - Lifecycle: Exists only during current JVM session, not persisted
- Identity: Dynamic names with UUID suffix for uniqueness
- Use cases: One-off tasks, dynamic workflows, YAML-based workflows
- Example: Temporary agents created for each stage of a book creation workflow
// Create an implicit agent for a specific task
SubAgent dataAnalyst = orchestrator.createImplicitAgent(
"data-analyst",
"Specialized agent for analyzing CSV data",
llmProvider,
"Analyze the following data: {{input}}"
);
// Use immediately (agent will be garbage collected after use)
ExecutionResult result = dataAnalyst.execute(input);When to Use Each:
| Scenario | Agent Type | Reason |
|---|---|---|
| Multi-step workflows (YAML/code-based) | Implicit | Memory consistency, automatic cleanup |
| Reusable documentation generator | Explicit | Stable identity, cross-session persistence |
| Dynamic task decomposition | Implicit | Flexible creation based on runtime needs |
| Service-oriented architecture | Explicit | Named services, lifecycle management |
| One-off data processing | Implicit | Temporary use, automatic resource cleanup |
Memory Consistency: Both agent types share the orchestrator's MemoryStore, ensuring consistent context across workflow steps while providing different lifecycle management approaches.
- Subagent Architecture: A clean and powerful implementation of the subagent architecture.
- LLM-based Planning: An
LLMPlannerthat can dynamically decompose user requests into a sequence of tasks. - Explicit and Implicit Agents: Support for both pre-defined and on-the-fly agents.
- Memory Persistence: A
MemoryStorethat allows agents to maintain state across sessions. - Tool Use: A flexible system for both programmatic and LLM-assisted tool use.
- Retry System: Robust retry mechanisms with configurable policies (NoRetry, FixedDelay, ExponentialBackoff).
- Metrics Collection: Comprehensive metrics and monitoring system with timer contexts and aggregated summaries.
- Security: Secure tool execution with command injection prevention and configurable whitelists.
- Comprehensive Testing: Extensive unit test coverage with 220+ tests using JUnit 5 and Mockito.
- YAML Workflows: YAML-based workflow definition system enabling configuration-driven AI applications without code changes.
- Unified Architecture: Both code-based and YAML-configured workflows use identical underlying execution primitives, ensuring consistent behavior.
- Human Approval System: Built-in approval workflows with interactive console interface and timeout support.
- Extensible: The framework is designed to be extensible, allowing you to create your own custom agents, tools, and providers.
- Java-based: Built on Java 21 and
langchain4j, providing a modern and robust foundation.
Prerequisites: Java 21+ and Maven 3.6+
# Clone and run demo in one command
git clone https://github.com/skanga/conductor && cd Conductor
mvn clean install && mvn exec:java@book-demo -Dexec.args="Quick Demo"Expected Output: β
Book creation completed! Check output/ folder for generated content.
For comprehensive development environment setup including IDE configuration, testing setup, and troubleshooting guides, see DEVELOPMENT.md.
| Requirement | Minimum | Recommended | Purpose |
|---|---|---|---|
| Java | 21.0.0 | 21.0.8+ LTS | Core runtime |
| Maven | 3.6.0 | 3.9.0+ | Build management |
| Memory | 2 GB RAM | 8 GB RAM | LLM operations |
| Storage | 500 MB | 2 GB | Models and outputs |
java --version # Should show 21.x.x
mvn --version # Should show 3.6+
echo $JAVA_HOME # Should point to Java 21mvn clean installmvn clean compile -DskipTests # Skip tests for faster iteration
mvn test -Dtest=ClassName # Run specific testsmvn clean install -Pdev # Development profile
mvn clean install -Pproduction # Production optimizationsShowcases comprehensive multi-agent book writing workflow:
# Basic usage
mvn exec:java@book-demo -Dexec.args="AI-Powered Content Creation"
# With custom output directory
mvn exec:java@book-demo -Dexec.args="Your Topic" -Dconductor.output.dir="./my-books"
# Debug mode with verbose logging
mvn exec:java@book-demo -Dexec.args="Debug Topic" -Dconductor.debug=trueOutput Location: output/book_[topic]_[timestamp]/
Configuration-driven workflows without code changes:
# Run iterative book creation workflow
mvn exec:java -Dexec.mainClass="com.skanga.conductor.workflow.runners.WorkflowRunner" \
-Dexec.args="src/main/resources/yaml/workflows/iterative-book-creation.yaml"
# Tool demonstration workflow
mvn exec:java -Dexec.mainClass="com.skanga.conductor.workflow.runners.WorkflowRunner" \
-Dexec.args="src/main/resources/yaml/workflows/tool-demo.yaml"See DEMOS.md for comprehensive information about all available demo applications.
# 1. Make changes to source code
# 2. Quick compile check
mvn compile
# 3. Run specific tests
mvn test -Dtest="*YourFeature*"
# 4. Test with demo
mvn exec:java@book-demo -Dexec.args="Test Topic"
# 5. Full verification before commit
mvn clean install- IntelliJ IDEA: Import as Maven project
- VS Code: Install Java Extension Pack, configure workspace settings
- Eclipse: Import as Existing Maven Project
See DEVELOPMENT.md#ide-configuration for detailed IDE configuration guides.
mvn test # All unit tests (~220 tests)
mvn verify # Include integration testsmvn test -Dtest=WorkflowTest # Specific test class
mvn test -Dtest="*Agent*" # Pattern matching
mvn test -Dtest=WorkflowTest#testMethod # Specific test methodmvn test -Dgroups="unit" # Unit tests only
mvn test -Dgroups="integration" # Integration tests only
mvn test -Dgroups="security" # Security tests only# Standard build (fast) - comprehensive tests skipped
mvn test # ~1:23 minute build time
# Enable comprehensive tests - includes expensive concurrent and stress tests
mvn test -Dtest.comprehensive=true # ~4+ minute build time
mvn test -Dtest.comprehensive=true -Dtest.performance.enabled=true # Full validation
# Enable specific test categories
mvn test -Dtest.performance.enabled=true # Performance benchmarks only
mvn test -Dtest.comprehensive=true -Dtest="*ThreadSafety*" # Comprehensive + specific patternπ Comprehensive Test Categories:
| Test Type | Default | Comprehensive (-Dtest.comprehensive=true) |
|---|---|---|
| Thread Safety | β Skipped | β All concurrent operations tested |
| Stress Tests | β Skipped | β High-load scenario validation |
| CLOB Efficiency | β Skipped | β Large data handling tests |
| Performance Benchmarks | β Skipped | β
With -Dtest.performance.enabled=true |
| WAV File Analysis | β Skipped | β Audio processing validation |
β‘ Performance Optimization: Comprehensive tests are conditionally executed to maintain fast development cycles while ensuring full validation when needed.
β‘ Fast Builds: Performance tests are disabled by default to maintain ~1 minute build times.
# Standard build (fast) - performance tests skipped
mvn test # ~1 minute, 41 tests skipped
# Enable basic performance validation - minimal iterations (quick smoke test)
mvn test -Dtest.performance.enabled=true # ~30 seconds additional time
# Full performance benchmarking - extensive iterations (deep validation)
mvn test -Dtest.performance.enabled=true -Dtest.performance.intensive=true
# ~3-5 minutes additional time
# Specific performance test classes
mvn test -Dtest=ThreadSafetyTest -Dtest.comprehensive=true
mvn test -Dtest=PromptTemplateEnginePerformanceTest -Dtest.performance.enabled=trueπ Performance Test Modes:
| Test Type | Default | Basic Mode | Intensive Mode |
|---|---|---|---|
| Execution | β Skipped | -Dtest.performance.enabled=true |
Add -Dtest.performance.intensive=true |
| Template Rendering | β Skipped | 10 iterations | 10,000 iterations |
| Caching Performance | β Skipped | 5 iterations | 5,000 iterations |
| Concurrent Processing | β Skipped | 2 threads Γ 3 ops | 10 threads Γ 1,000 ops |
| Memory Usage | β Skipped | 10 templates | 1,000 templates |
| Cache Eviction | β Skipped | 10 templates | 1,000 templates |
| Build Time Impact | - | +30 seconds | +3-5 minutes |
π― When to Use Each Mode:
- Default: Daily development, quick feedback loops
- Basic Mode (
-Dtest.performance.enabled=true): Pre-commit validation, smoke testing performance - Intensive Mode (add
-Dtest.performance.intensive=true): Pre-release validation, performance regression analysis, benchmarking
π§ Build Time Optimization Strategy:
- Problem: Enabling all performance tests increased build time from 1 min β 7 min
- Solution: Two-tier approach with
@EnabledIfSystemPropertyannotationstest.performance.enabled=trueβ Enables performance test classestest.performance.intensive=trueβ Switches from 10 to 10,000 iterations
- Result: Default builds ~1 minute, quick validation +30s, deep benchmarking on-demand
| Issue | Solution | Reference |
|---|---|---|
UnsupportedClassVersionError |
Verify Java 21+ with java --version |
Setup Guide |
OutOfMemoryError |
Increase Maven memory: export MAVEN_OPTS="-Xmx4g" |
Troubleshooting |
| Tests fail with DB locks | Clean test databases: find target -name "*.db" -delete |
Testing Guide |
| Build hangs during tests | Skip tests: mvn install -DskipTests or disable performance tests (default) |
Performance Testing |
For comprehensive troubleshooting including IDE issues, environment problems, and debugging techniques, see DEVELOPMENT.md#troubleshooting-guide.
The project is organized into the following key packages:
com.skanga.conductor.agent: Contains theSubAgentinterface and its implementations.com.skanga.conductor.orchestration: Contains theOrchestratorandLLMPlanner.com.skanga.conductor.tools: Contains theToolinterface and related classes for tool use.com.skanga.conductor.memory: Contains theMemoryStorefor agent state persistence.com.skanga.conductor.provider: Contains theLLMProviderinterface for integrating with different LLM providers.com.skanga.conductor.retry: Contains retry policies and execution logic for resilient operations.com.skanga.conductor.metrics: Contains metrics collection and monitoring infrastructure.com.skanga.conductor.config: Contains configuration management and validation.com.skanga.conductor.engine: Contains the unified workflow execution engine and builder patterns.com.skanga.conductor.demo: Contains the demo applications.com.skanga.conductor.workflow: Contains the YAML-based workflow system including configuration models, execution engine, and demo applications.src/test/java: Contains comprehensive unit tests for all framework components.
SubAgentRegistry registry = new SubAgentRegistry();
MemoryStore memoryStore = new H2MemoryStore("jdbc:h2:./data/subagentsdb");
Orchestrator orchestrator = new Orchestrator(registry, memoryStore);ConversationalAgent explicitAgent = new ConversationalAgent(
"my-explicit-agent",
"An agent that can answer questions.",
new MockLLMProvider(),
"Answer the following question: {{prompt}}",
memoryStore
);
registry.register(explicitAgent);
TaskResult result = orchestrator.callExplicit("my-explicit-agent", new TaskInput("What is the capital of France?"));
System.out.println(result.output());SubAgent implicitAgent = orchestrator.createImplicitAgent(
"my-implicit-agent",
"A temporary agent for a specific task.",
new MockLLMProvider(),
"Summarize the following text: {{prompt}}"
);
TaskResult result = implicitAgent.execute(new TaskInput("This is a long text..."));
System.out.println(result.output());Both code-based and YAML workflows use the same underlying execution primitives:
// Code-based approach using WorkflowBuilder
List<StageDefinition> stages = WorkflowBuilder.create()
.addStage("title-generation", "title-generator", "Expert title generator",
llmProvider, systemPrompt, promptTemplate, maxRetries, validator, metadata)
.build();
DefaultWorkflowEngine engine = new DefaultWorkflowEngine(orchestrator);
WorkflowResult result = engine.executeWorkflow(stages);
// No-code approach using YAML adapter
YamlWorkflowEngine adapter = new YamlWorkflowEngine(orchestrator, llmProvider);
adapter.loadConfiguration("workflow.yaml", "agents.yaml", "context.yaml");
WorkflowResult yamlResult = adapter.executeWorkflow(context);
// Both produce identical WorkflowResult objects with same behaviorSee CONFIGURATION.md for comprehensive configuration documentation.
See ARCHITECTURE.md for detailed information about the framework architecture, unified workflow system, advanced technical features including thread safety, security, memory management, templating system, and text-to-speech integration.
Contributions are welcome! Please feel free to open an issue or submit a pull request.
This project is licensed under the MIT License. See the LICENSE file for details.