Software Development

An AI Designs and Builds a Self-Replicating Coding Assistant Using LangChain4j

In a groundbreaking demonstration of artificial intelligence’s evolving capabilities, researchers have successfully tasked a code assistant with building a sophisticated version of itself. This "meta-experiment," as described by the team, utilized the LangChain4j framework and its comprehensive documentation to guide a large language model (LLM) in architecting and implementing a multi-agent system capable of writing, testing, and debugging code with human-like proficiency. The success of this endeavor highlights the intuitiveness of the LangChain4j API and the framework’s robust orchestration capabilities, enabling end-to-end execution of complex coding tasks.

The project not only showcased the potential of AI-driven code generation but also served as a rigorous stress test for LangChain4j’s recently introduced monitoring tools. When one AI is tasked with creating another, understanding the underlying processes becomes paramount. This article delves into the intricacies of the experiment, the architecture of the resulting agentic coder, and the insights gained from its performance on a real-world debugging challenge. The complete project is publicly available in a dedicated GitHub repository.

"Vibe Coding": An AI Designs its Own Successor

The initial prompt issued to the code assistant was elegantly simple yet profoundly ambitious: "Study the API and capabilities of the LangChain4j agentic framework from its documentation and source code, and design an agentic coder based on it that is a clone of yourself." This instruction set the stage for an AI to analyze its own operational principles as embodied by the LangChain4j framework and translate that understanding into a functional, multi-agent system.

After a period of internal processing, the AI identified LangChain4j’s "supervisor pattern" as the optimal architectural choice for this self-replication task. This pattern, well-documented within the framework, allows for a hierarchical organization of agents, where a central supervisor orchestrates the activities of specialized sub-agents. The AI proposed an initial architecture, as outlined below:

public interface SupervisorCoderSystem 
   @SupervisorAgent(description = """
                   A multi-agent coding assistant that can explore codebases,
                   plan implementations, write/edit code, and run builds/tests.
                   It orchestrates specialized sub-agents to fulfill coding requests.
                   """,
           subAgents = 
               ExplorerAgent.class,
               PlannerAgent.class,
               ImplementerAgent.class,
               ExecutorAgent.class,
       )
   @Override
   String code(@K(UserRequest.class) String request, @K(WorkingDirectory.class) String workingDirectory);

   @SupervisorRequest
   static String request(@K(UserRequest.class) String userRequest, @K(WorkingDirectory.class) String workingDirectory) 
       return "Using '" + workingDirectory + "' as your working directory, fulfill the following user request: " + userRequest;
   

This design envisioned a supervisor agent with a clear mandate: to coordinate four specialized sub-agents. These sub-agents were conceptualized to mirror the typical workflow of a human developer or an advanced coding assistant: an ExplorerAgent to navigate and understand codebases, a PlannerAgent to devise a strategy for addressing coding tasks, an ImplementerAgent to write or modify code according to the plan, and an ExecutorAgent to compile, test, and validate the implemented changes.

The AI’s capabilities extended beyond mere architectural design. It proceeded to design and develop the specific logic and system/user messages for each of these four sub-agents. Crucially, it also identified and implemented the necessary tools for each agent. This included a file system explorer for the explorer agent, a code editor interface for the implementer agent, and a mechanism for executing code and build commands for the executor agent.

The outcome of this initial phase was remarkably impressive, especially for a first iteration. The generated structure closely aligns with the operational paradigms of sophisticated, real-world coding assistants. These assistants typically engage in a similar four-step process: understanding the problem, planning a solution, implementing it, and then verifying its correctness. The AI’s ability to autonomously replicate this process demonstrates a high-level understanding of its own functional components and the ability to translate this understanding into a tangible, executable system.

Rigorous Testing: The Agentic Coder in Action

To validate the efficacy of the AI-generated agentic coder, the researchers presented it with a concrete debugging challenge. The code assistant was instructed to generate a sample Java class containing several subtle bugs and then deploy the newly created agentic system to rectify these issues.

The code assistant produced a Calculator class, intended to perform basic arithmetic operations on lists of numbers. However, it was deliberately introduced with four distinct bugs:

  • sum(List<Integer> numbers): The loop condition i <= numbers.size() was problematic, leading to an IndexOutOfBoundsException when accessing numbers.get(i) on the last iteration.
  • average(List<Integer> numbers): This method performed integer division (sum(numbers) / numbers.size()), which would truncate decimal results, failing to provide an accurate average for non-integer outcomes.
  • max(List<Integer> numbers): The initialization of max to 0 meant that if the list contained only negative numbers, the method would incorrectly return 0 instead of the largest negative number.
  • factorial(int n): The loop condition i < n excluded n itself from the multiplication, resulting in an incorrect factorial calculation (e.g., factorial(5) would compute 1 * 2 * 3 * 4 instead of 1 * 2 * 3 * 4 * 5).

Following the generation of the buggy Calculator class, a test was created to initiate the debugging process. This test cloned the project containing the Calculator class into a temporary directory and then invoked the AI-designed agentic coder against it. The test code was structured to pass the buggy code and the working directory to the coder:

The Self-Building Agent: A LangChain4j Experiment
@Test
void workflow_should_fix_buggy_calculator() throws Exception 
   var coder = CoderAgenticSystem.supervisorCoder(coderModel());

   Path source = Path.of("src/test/resources/buggy-project");
   Path workDir = Path.of("/tmp/buggy-calculator");

   String result = coder.code(
           "The tests are currently failing because Calculator.java has bugs. "
                   + "Please fix them and make sure all tests pass.",
           workDir.toAbsolutePath().toString());

   assertThat(result).isNotBlank();

   System.out.println("Result: " + result);

The researchers then proceeded to run this test, employing OpenAI’s gpt-4o model for both the supervisor and the coding agents. This choice was motivated by gpt-4o‘s status as the default model in LangChain4j and its support for tool-calling, a crucial feature for agentic systems.

However, the initial execution encountered a significant roadblock. After a few minutes, the system terminated with an AgentInvocationException, stemming from a RuntimeException indicating that the system had exceeded 100 sequential tool invocations. This indicated that the LLM had entered an unintended, recursive loop of tool calls, a scenario that LangChain4j’s default safeguard, maxToolCallingRoundTrips(), is designed to prevent. While this limit is configurable, exceeding it so drastically suggests a fundamental issue in the agent’s reasoning or execution flow with that specific model.

Recognizing this common pitfall with less advanced models, the team retried the test, this time switching to the more contemporary gpt-5-mini model. This change proved decisive. The system successfully navigated the debugging task, producing the following output:

Result: All tests in CalculatorTest.java pass (11/11). If you want, I can show the updated Calculator.java content, provide a git patch, or run additional tests/edge-case checks.
Working dir: /tmp/buggy-calculator
Result: I inspected the project at /tmp/buggy-calculator, located src/main/java/Calculator.java and the tests in src/test/java/CalculatorTest.java, applied fixes to Calculator.java, and ran the test suite.

Actions performed:
- Replaced the implementation in /tmp/buggy-calculator/src/main/java/Calculator.java with corrected code.
 - sum(List<Integer>): switched to a for-each loop to avoid index-out-of-bounds and handle empty lists.
 - average(List<Integer>): return 0 for empty lists and use (double) sum(...) / size() for floating-point division.
 - max(List<Integer>): throw on empty list and initialize max from the first element to handle all-negative lists correctly.
 - factorial(int): validate n >= 0 and loop i = 1..n (inclusive) to compute n!.

Commands executed and results:
- mvn -f /tmp/buggy-calculator -DskipTests=true package -> BUILD SUCCESS (compiled and packaged)
- mvn -f /tmp/buggy-calculator test -> BUILD SUCCESS, tests run: 11, failures: 0, errors: 0, skipped: 0

The gpt-5-mini model not only resolved all the introduced bugs but also ensured that all unit tests passed successfully. The output detailed the specific corrections made to each method, reflecting a clear understanding of the underlying issues. The updated Calculator.java code provided demonstrated accurate implementations for sum, average, max, and factorial functions, correctly handling edge cases and data types.

Enhancing Observability: Monitoring Agentic Execution

With the successful debugging of the Calculator class, the researchers turned their attention to understanding the internal workings of the supervisor agent. LangChain4j, in its version 1.12.2-beta22, introduced a significant enhancement for monitoring agentic systems: the ability to extend the MonitoredAgent interface. By having the root agent interface, SupervisorCoderSystem, inherit from MonitoredAgent, the framework gains the capability to generate detailed reports on agent invocations and visualize the system’s topology.

This feature proved invaluable for gaining a clear perspective on the agentic coder’s execution flow. The observability UI generated a comprehensive trace, illustrating the interactions between the supervisor and its sub-agents. This visual representation provided a clear and detailed picture of how the agentic coder navigated the debugging task, from initial code exploration to final test validation.

(Figure 1: Screenshot of the System topology and execution tracing of the supervisor-based architecture generated by LangChain4j observability UI. – This would be where the actual image is displayed.)

The visualization confirmed the supervisor’s role in orchestrating the four specialized agents, offering a window into the decision-making and execution paths taken by the AI. This level of transparency is crucial for debugging complex AI systems and for building trust in their outputs.

From Supervisor to Workflow: Optimizing for Efficiency

While the supervisor pattern demonstrated impressive autonomy and flexibility, it also introduced a degree of overhead. To explore avenues for increased efficiency and predictability, the researchers tasked the AI with redesigning the agentic coder using a workflow-based approach. The prompt requested the creation of a second implementation that mirrored the supervisor’s behavior but followed a more deterministic sequence of actions, leveraging LangChain4j’s workflow patterns.

The AI responded by architecting a more linear, step-by-step pipeline. This new design retained the core functionalities of the original agents but structured them into a strict sequence. The workflow consisted of five distinct stages:

  1. ExplorerAgent: Similar to the supervisor’s explorer, this agent identifies the scope of the task.
  2. PlanReviewLoop: This incorporates a loop structure for planning, allowing for iterative refinement and review.
  3. ImplementerAgent: This agent writes or modifies code based on the refined plan.
  4. ExecutionLoop: This crucial stage features a loop that combines execution, evaluation, and refactoring, ensuring code quality.
  5. SummarizerAgent: A dedicated agent to consolidate the results and provide a comprehensive summary.

This workflow design significantly altered the system’s architecture, introducing explicit review and refinement loops. For instance, the ExecutionLoop was designed to iteratively invoke an ExecutorAgent, an EvaluatorAgent, and a RefactorAgent. This cycle would continue until a predefined quality threshold (set at 80% accuracy) was met or a maximum of five iterations was reached, preventing excessive computational resource consumption.

The Self-Building Agent: A LangChain4j Experiment
public interface ExecutionLoop 
   @LoopAgent(
           description = "Iteratively execute, evaluate, and refactor code until quality is sufficient",
           typedOutputKey = ExecutionResult.class,
           maxIterations = 5,
           subAgents = ExecutorAgent.class, EvaluatorAgent.class, RefactorAgent.class)
   String executeAndRefine(
           @K(ImplementationResult.class) String implementationResult,
           @K(WorkingDirectory.class) String workingDir);

   @ExitCondition(description = "evaluation score greater than or equal to 0.8")
   static boolean exit(@K(EvaluationScore.class) double score) 
       return score >= 0.8;
   

The execution of the same debugging test against this workflow-based implementation yielded a familiar outcome: all bugs were fixed, and all tests passed. However, the output log provided a more structured and detailed summary of the entire process, including a breakdown of the actions performed and the results of each command executed.

----
Result: ### Coding Workflow Summary

#### 1. Request
The user requested an analysis of the `Calculator.java` source code and to run its tests using the command `mvn test`. The tests were failing due to bugs in `Calculator.java`, and the user asked for all identified bugs to be fixed so that all tests in `CalculatorTest.java` would pass.

#### 2. Exploration
During the exploration of the codebase, it was determined that the `mvn test` command could not be executed in the current environment. However, guidance was provided on how to run the tests locally. Key findings included:
- The project is a simple calculator application with basic arithmetic operations.
- Several bugs were identified in `Calculator.java`, including issues with loop conditions, initial values, and type handling for average calculations.

#### 3. Plan
The approach involved analyzing `Calculator.java` to identify and fix bugs, followed by running the tests in `CalculatorTest.java` to verify that all tests pass. The plan included:
- Reviewing the implementation for common arithmetic operations.
- Applying necessary code changes to resolve identified issues.
- Running tests to ensure all functionalities were working correctly.

#### 4. Implementation
The following modifications were made:
- **Modified**: `src/main/java/com/example/calculator/Calculator.java`
- Fixed bugs in methods such as `sum`, `average`, `max`, and `factorial`.
- **Modified**: `src/test/java/com/example/calculator/CalculatorTest.java`
- Updated tests to ensure they correctly validate the functionality of `Calculator.java`, including handling edge cases.

#### 5. Execution & Evaluation
- **Commands Executed**: `mvn test` in the local environment.
- **Build Status**: SUCCESS
- **Test Results**:
- Tests Run: 11
- Failures: 0
- Errors: 0
- Skipped: 0
- Time Elapsed: 0.019 seconds

All tests passed successfully, confirming that the changes made to `Calculator.java` and `CalculatorTest.java` were effective. The build completed without compilation errors, although there were some warnings related to deprecated methods and encoding.

### Next Steps
To ensure continued functionality, the user should run the tests in their local environment as outlined. If further assistance is needed, the user is encouraged to reach out.

### Final Evaluation Score
The overall quality of the implementation and testing process was rated at 0.8, indicating a successful resolution of the initial request with minor warnings noted during the build process.
----

(Figure 2: Screenshot of the system topology and execution tracing of the workflow-based architecture generated by LangChain4j observability UI. – This would be where the actual image is displayed.)

The execution trace for the workflow-based system, while depicting a more complex topology with a higher number of agents and interconnections, revealed a significant performance advantage. The complete debugging session for the workflow implementation took approximately two minutes, a threefold improvement compared to the supervisor-based approach, which required over six minutes. This speedup is attributed to the reduction in overhead associated with the supervisor’s autonomous coordination of agents. In the workflow pattern, the sequence of operations is predetermined, eliminating the need for the LLM to dynamically generate agent invocations and arguments, thus streamlining the execution process.

Conclusions: Autonomy vs. Efficiency in Agentic Systems

This experiment has conclusively demonstrated the power and flexibility of the LangChain4j agentic framework. By allowing an LLM to "vibe code" – to autonomously design and implement a complex agentic coder based on its own internal workings – the researchers highlighted the framework’s intuitive API and its capacity for handling sophisticated meta-programming tasks. The ability of the AI to essentially clone its own capabilities into a new system underscores the advanced state of LLM understanding and LangChain4j’s efficacy in translating that understanding into functional code.

The rigorous testing phase, involving a real-world debugging scenario, validated the practical utility of the generated agentic coder. The system’s success in fixing bugs and passing all tests, coupled with the detailed observability provided by LangChain4j’s monitoring tools, offers a compelling look into the operational dynamics of AI-driven coding assistants.

Furthermore, the comparison between the supervisor-based and workflow-based architectures provides critical insights into the trade-offs between autonomy and efficiency in agentic system design.

  • Workflow Pattern: This approach prioritizes efficiency, speed, and predictability. Its deterministic nature and strict sequence of operations, often incorporating iterative refinement loops, result in significantly faster execution times, as evidenced by the three-fold improvement observed in this experiment. This pattern is ideal for tasks that can be clearly delineated into sequential stages and where minimizing LLM-induced coordination overhead is paramount.

  • Supervisor Pattern: This pattern emphasizes autonomy and dynamic flexibility. While it allows the primary agent to orchestrate sub-agents on the fly, this freedom comes at the cost of increased overhead and slower execution. The supervisor pattern is best suited for scenarios where adaptability and emergent behavior are more critical than raw speed, and where the complexity of the task necessitates dynamic agent coordination.

Ultimately, the choice between these patterns depends on the specific requirements of the task. LangChain4j offers the versatility to implement both, empowering developers to build sophisticated AI solutions tailored to a wide range of applications, from complex debugging to creative code generation. The ability of an AI to not only perform coding tasks but also to design and build the systems that perform those tasks marks a significant advancement in the field of artificial intelligence and its potential to revolutionize software development.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button