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-coreandagent-judge-exec(setup)- Optional:
agent-judge-llmfor Step 6 - Optional:
agent-judge-koogfor the bridge example
Step 1: Create the Evaluation Context
Every evaluation starts with aJudgmentContext — it describes what the agent was asked to do and where it worked.
Step 2: Evaluate with a Single Judge
Start with the simplest possible check — does a file exist?Judgment contains:
- score —
BooleanScore,NumericalScore, orCategoricalScore - status —
PASS,FAIL,ABSTAIN, orERROR - 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 aSimpleJury:
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.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.
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 buildsJudgmentContext 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:
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