Skip to main content

What You’ll Build

An evaluation pipeline that verifies an AI agent’s modifications to a Maven project. By the end you’ll have three judges — file existence, build success, and content validation — combined into a jury with majority voting.

Prerequisites

  • Java 21+
  • A Maven project directory to evaluate (any Spring Boot starter project works)
  • agent-judge-core and agent-judge-exec (setup)
  • Optional: agent-judge-llm for Step 6
  • Optional: agent-judge-koog for the bridge example

Step 1: Create the Evaluation Context

Every evaluation starts with a JudgmentContext — it describes what the agent was asked to do and where it worked.
The context is immutable and shared across all judges. It carries the agent’s goal, workspace path, execution status, and timing — everything a judge needs to evaluate the result without knowing which agent produced it.

Step 2: Evaluate with a Single Judge

Start with the simplest possible check — does a file exist?
Output when the file exists:
Every Judgment contains:
  • score — BooleanScore, NumericalScore, or CategoricalScore
  • status — PASS, FAIL, ABSTAIN, or ERROR
  • reasoning — human-readable explanation
  • checks — granular sub-assertions (useful for complex judges)

Step 3: Add a Build Judge

File existence is necessary but not sufficient — the code also needs to compile. Add a command judge that runs the Maven build:
BuildSuccessJudge.maven() auto-detects the ./mvnw wrapper in the workspace directory. It runs the specified goals and checks the exit code — zero means pass.
Build judges execute real processes. The default timeout is 10 minutes. Make sure the workspace has a valid Maven project before running.

Step 4: Compose with Judges.and()

Before reaching for a jury, you can compose judges with simple boolean logic:
Judges.and() short-circuits — if the file doesn’t exist, the build never runs. This is useful when one check is a precondition for another. Other composition operators:

Step 5: Build a Jury

When you need more than boolean composition — weighted scoring, named results, parallel execution — use a SimpleJury:
Now inspect the verdict:
Example output:
Judges.named() wraps any judge with a name and description. Without it, judges get auto-generated names, making the verdict harder to read.

Step 6: Add an LLM Judge (Optional)

Deterministic judges handle objective criteria — did it compile, does the file exist? For subjective evaluation — is the code well-structured, does it follow conventions? — add an LLM judge.
The CorrectnessJudge sends the goal and agent output to an LLM and asks whether the agent accomplished its task. It costs tokens — but combined with free deterministic judges, you get both speed and depth.
LLM judges require the agent-judge-llm module, Spring AI on the classpath, and a valid API key. They are significantly slower and more expensive than deterministic judges. Use them for criteria that can’t be checked structurally.
CorrectnessJudge extends LLMJudge, which uses Spring AI directly. For a framework-neutral alternative, ModelBackedJudge from agent-judge-ai-core composes a prompt template, model backend, and classifier without subclassing. See Writing Custom Judges — ModelBackedJudge for details.

What You Built

You started with a single file-existence check and built up to a weighted jury with four judges spanning three cost tiers: This is the core pattern: use cheap judges to catch obvious failures, and reserve expensive judges for semantic confirmation. In production, formalize this with a CascadedJury that runs cheap tiers first and stops early when they already have a verdict.
The tutorial uses SimpleJury with parallel execution for readability. Production pipelines often use CascadedJury to avoid running LLM judges when deterministic checks already fail.

Bonus: Evaluate a Framework Agent

The tutorial above builds JudgmentContext manually. When you’re evaluating output from a specific framework, the bridge modules do this for you. Here’s the same evaluation pipeline, but with the context built automatically from a Koog agent:
Bridge evaluators either adapt an existing framework response or wrap a framework call/supplier that produces one. The judges and jury don’t change — swap KoogEvaluator for SpringAiEvaluator, LangChain4jEvaluator, or AgentClientEvaluator.

Runnable Code

Every step in this tutorial has a corresponding runnable module in the agent-judge-tutorial repository. Clone it and run any module with ./mvnw exec:java -pl module-NN-name.

What’s Next

Writing Custom Judges

Lambda judges, DeterministicJudge subclasses, and LLMJudge template method

Jury System

CascadedJury, voting strategies, and jury composition