Skip to main content

Evaluator-Optimizer Agent

To use this agent, add the Maven dependency to your project, replacing ${agentic-patterns-version} with the latest version.

Latest version: Maven Central Version

<dependency>
<groupId>com.javaaidev.agenticpatterns</groupId>
<artifactId>evaluator-optimizer</artifactId>
<version>${agentic-patterns-version}</version>
</dependency>

Usage

EvaluatorOptimizerAgent

To create a Evaluator-Optimizer agent, you can create a subclass of EvaluatorOptimizerAgent. When constructing a EvaluatorOptimizerAgent, parameters in the table below can be provided.

You can use the same ChatClient for generation and evaluation.

ParameterRequired?TypeDescription
generationChatClientyesChatClientSpring AI ChatClient for generating results
evaluationChatClientyesChatClientSpring AI ChatClient for evaluating results
responseTypenoTypeType of response, only required when auto-detection fails
observationRegistrynoObservationRegistryMicrometer ObservationRegistry for tracing

EvaluatorOptimizerAgent uses three other TaskExecutionAgents for execute a task. These agents must be created by subclasses.

AgentRequestResponseMethodDescription
initialResultAgentRequestResponsebuildInitialResultAgentAgent to generate the initial result
evaluationAgentRequestEvaluationbuildEvaluationAgentAgent to evaluate a result
optimizationAgentOptimizationInput<Response>ResponsebuildOptimizationAgentAgent to optimize a result based on feedback

The subclass can override getMaxIterations method to update the maximum number of evaluation iterations. The default value is 3.

PromptBasedEvaluatorOptimizerAgent

Most of agents used by an EvaluatorOptimizerAgent use an LLM to generate results. In this case, you can extend from PromptBasedEvaluatorOptimizerAgent instead. When extending from PromptBasedEvaluatorOptimizerAgent, you only need to provide prompt templates and the logic to prepare values for template variables.

MethodDescription
getInitialResultPromptTemplatePrompt template for the agent to generate initial result
buildInitialResultPromptContextPrepare for the values of variables in the prompt template to generate initial result
getEvaluationPromptTemplatePrompt template for the agent to evaluate a result
buildEvaluationPromptContextPrepare for the values of variables in the prompt template to evaluate a result
getOptimizationPromptTemplatePrompt template for the agent to optimize a result
buildOptimizationPromptContextPrepare for the values of variables in the prompt template to optimize a result

Example

The example is an agent to generate code with evaluation feedbacks.

In the implementation of CodeGenerationAgent, we only need to implement methods to get the prompt templates and prepare the context for templates.

CodeGenerationAgent
package com.javaaidev.agenticpatterns.examples.evaluatoroptimizer;

import com.javaaidev.agenticpatterns.core.AgentUtils;
import com.javaaidev.agenticpatterns.evaluatoroptimizer.PromptBasedEvaluatorOptimizerAgent;
import com.javaaidev.agenticpatterns.examples.evaluatoroptimizer.CodeGenerationAgent.CodeGenerationRequest;
import com.javaaidev.agenticpatterns.examples.evaluatoroptimizer.CodeGenerationAgent.CodeGenerationResponse;
import io.micrometer.observation.ObservationRegistry;
import java.util.Map;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.springframework.ai.chat.client.ChatClient;

/**
* An agent to generate code with evaluation feedbacks
*/
public class CodeGenerationAgent extends
PromptBasedEvaluatorOptimizerAgent<CodeGenerationRequest, CodeGenerationResponse> {

public CodeGenerationAgent(ChatClient chatClient,
@Nullable ObservationRegistry observationRegistry) {
super(chatClient, chatClient, CodeGenerationResponse.class, observationRegistry);
}

@Override
protected String getInitialResultPromptTemplate() {
return AgentUtils.loadPromptTemplateFromClasspath(
"prompt_template/code-generator/initial-result.st");
}

@Override
protected @Nullable Map<String, Object> buildInitialResultPromptContext(
@Nullable CodeGenerationRequest request) {
return AgentUtils.objectToMap(request);
}

@Override
protected String getEvaluationPromptTemplate() {
return AgentUtils.loadPromptTemplateFromClasspath(
"prompt_template/code-generator/evaluation.st");
}

@Override
protected @Nullable Map<String, Object> buildEvaluationPromptContext(
@Nullable CodeGenerationResponse codeGenerationResponse) {
return AgentUtils.objectToMap(codeGenerationResponse);
}

@Override
protected String getOptimizationPromptTemplate() {
return AgentUtils.loadPromptTemplateFromClasspath(
"prompt_template/code-generator/optimization.st");
}

@Override
protected @Nullable Map<String, Object> buildOptimizationPromptContext(
@Nullable OptimizationInput<CodeGenerationResponse> optimizationInput) {
var optionalInput = Optional.ofNullable(optimizationInput);
return Map.of(
"code", optionalInput.map(input -> input.response().code()),
"feedback", optionalInput.map(input -> input.evaluation().feedback())
);
}

public record CodeGenerationRequest(String input) {

}

public record CodeGenerationResponse(String code) {

}
}

We can also use a REST API to access the agent.

REST controller of agent
package com.javaaidev.agenticpatterns.examples.evaluatoroptimizer;

import com.javaaidev.agenticpatterns.examples.evaluatoroptimizer.CodeGenerationAgent.CodeGenerationRequest;
import com.javaaidev.agenticpatterns.examples.evaluatoroptimizer.CodeGenerationAgent.CodeGenerationResponse;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/code_generation")
public class CodeGenerationController {

private final CodeGenerationAgent codeGenerationAgent;

public CodeGenerationController(CodeGenerationAgent codeGenerationAgent) {
this.codeGenerationAgent = codeGenerationAgent;
}

@PostMapping
public CodeGenerationResponse generateCode(@RequestBody CodeGenerationRequest request) {
return codeGenerationAgent.call(request);
}
}