Packages
| Package | Contains |
|---|
io.github.markpollack.judge | Core judge interfaces and utilities |
io.github.markpollack.judge.context | JudgmentContext, ExecutionStatus |
io.github.markpollack.judge.result | Judgment, JudgmentStatus, Check |
io.github.markpollack.judge.score | Score, BooleanScore, NumericalScore, CategoricalScore |
io.github.markpollack.judge.jury | Jury, Verdict, voting strategies |
io.github.markpollack.judge.springai | Spring AI bridge |
io.github.markpollack.judge.langchain4j | LangChain4j bridge |
io.github.markpollack.judge.koog | Koog bridge |
io.github.markpollack.judge.agentclient | AgentClient bridge |
io.github.markpollack.judge.ai | AI-backed judge infrastructure |
io.github.markpollack.judge.rag | RAG judges and RagContext |
Core Types
The fundamental evaluation interface. A functional interface for lambda and method reference support.
Use directly as a lambda, or extend DeterministicJudge / LLMJudge for metadata support.
AsyncJudge
Asynchronous variant for non-blocking evaluation:
ReactiveJudge
Reactive variant for Spring WebFlux / Project Reactor:
DeterministicJudge
Abstract base class for rule-based judges. Provides JudgeWithMetadata support:
JudgeWithMetadata extends Judge, so DeterministicJudge is also a Judge.
NamedJudge
Composition wrapper that attaches metadata to any judge (including lambdas):
Marker interface for judges that expose identity:
Infrastructure code can use instanceof JudgeWithMetadata for discovery:
Identity record:
JudgeType
Context
JudgmentContext
All evaluation inputs in one immutable record:
Builder methods:
| Method | Type | Required |
|---|
goal(String) | The agent’s task description | Yes |
workspace(Path) | Directory the agent modified | Yes |
status(ExecutionStatus) | Agent execution outcome | Yes |
startedAt(Instant) | When execution began | Yes |
executionTime(Duration) | How long execution took | Yes |
agentOutput(String) | Text output from the agent | No |
error(Throwable) | Exception if execution failed | No |
metadata(String, Object) | Arbitrary key-value pairs | No |
metadata(Map<String, Object>) | Bulk metadata | No |
ExecutionStatus
| Value | Meaning |
|---|
SUCCESS | Agent completed normally |
FAILED | Agent threw an exception or returned an error |
TIMEOUT | Execution exceeded time limit |
CANCELLED | Execution was cancelled |
REFUSED | Model declined the request (content filter) |
UNKNOWN | Status could not be determined |
Results
Judgment
Immutable evaluation result:
Static factory methods:
Builder:
Utility methods:
| Method | Returns | Description |
|---|
pass() | boolean | true if status == PASS |
elapsed() | Duration | Elapsed time from metadata |
error() | Throwable | Error from metadata |
JudgmentStatus
Granular sub-assertion within a judgment:
Factory methods:
Score Types
Score is a sealed interface with three permitted implementations:
BooleanScore
Simple pass/fail:
NumericalScore
Continuous scoring with bounds:
CategoricalScore
Discrete categories from a fixed set:
Scores Utility
Convert between score types for heterogeneous aggregation:
Composition
Judges Utility
Static methods for creating and composing judges:
| Method | Description |
|---|
named(Judge, String) | Wrap with a name |
named(Judge, String, String) | Wrap with name and description |
named(Judge, String, String, JudgeType) | Wrap with full metadata |
alwaysPass(String) | Test judge that always passes |
alwaysFail(String) | Test judge that always fails |
tryMetadata(Judge) | Extract metadata if available (Optional<JudgeMetadata>) |
and(Judge, Judge) | Short-circuit AND |
or(Judge, Judge) | Short-circuit OR |
allOf(Judge...) | All must pass (variadic AND) |
anyOf(Judge...) | Any can pass (variadic OR) |
AI-Core Types
Framework-neutral infrastructure for AI-backed judges. Located in the agent-judge-ai-core module (zero external dependencies).
ModelBackedJudge
Composed AI-backed judge built via builder pattern. Pipeline: render prompt → invoke model → classify response → produce Judgment. No subclassing needed.
| Builder Method | Required | Description |
|---|
model(JudgeModel) | Yes | AI backend to invoke |
template(JudgePromptTemplate) | Yes | Prompt template with {{variable}} placeholders |
classifier(JudgmentClassifier) | Yes | Maps model response to Judgment |
JudgeModel
Functional interface for AI model invocation. Framework-specific implementations live in bridge modules.
| Implementation | Module | Backend |
|---|
SpringAiJudgeModel | agent-judge-llm | Spring AI ChatClient |
AgentClientJudgeModel | agent-judge-agent-client | CLI agent via AgentClient |
JudgePromptTemplate
Loads, validates, and renders prompt templates with {{variable}} placeholders extracted from JudgmentContext.
| Builder Method | Default | Description |
|---|
source(TextSource) | Required | Template text source (classpath, file, or string) |
renderer(JudgeTemplateRenderer) | SimpleJudgeTemplateRenderer | Pluggable template engine |
missingVariablePolicy(MissingVariablePolicy) | STRICT | STRICT, EMPTY_STRING, or LEAVE_PLACEHOLDER |
Available variables from JudgmentContext: {{goal}}, {{output}}, {{workspace}}, {{status}}, {{metadata.*}}.
JudgeTemplateRenderer
Pluggable template engine interface:
Default implementation SimpleJudgeTemplateRenderer performs {{variable}} substitution.
JudgmentClassifier
Functional interface that maps a model response to a Judgment:
LabelJudgmentClassifier
Exact normalized label matching with builder pattern:
Supporting Records
Jury System
Jury Interface
SimpleJury
Flat multi-judge aggregation. See Jury System for full usage.
Builder:
| Method | Description |
|---|
.judge(Judge) | Add with weight 1.0 |
.judge(Judge, double) | Add with custom weight |
.votingStrategy(VotingStrategy) | Required |
.parallel(boolean) | Default true |
.executor(Executor) | Custom thread pool |
CascadedJury
Sequential tiered evaluation. See Jury System for full usage.
Builder:
| Method | Description |
|---|
.tier(String, Jury, TierPolicy) | Add a named tier |
.build() | Validates last tier is FINAL_TIER |
Verdict
| Field | Description |
|---|
aggregated | The voting strategy’s aggregated result |
individual | All individual judge results (ordered) |
individualByName | Results keyed by judge name |
weights | Weight assigned to each judge |
subVerdicts | Per-tier verdicts (CascadedJury only) |
VotingStrategy
Implementations:
| Class | Constructor |
|---|
MajorityVotingStrategy | () or (TiePolicy, ErrorPolicy) |
ConsensusStrategy | () |
AverageVotingStrategy | () |
WeightedAverageStrategy | () |
MedianVotingStrategy | () |
TierPolicy
TiePolicy
ErrorPolicy
Juries Utility
Framework Bridge Evaluators
Each framework bridge provides an Evaluator (one-liner convenience) and a JudgmentContextBuilder (full control).
All evaluators follow the same 4-method pattern: Judge/Jury x with/without extra metadata.
| Runtime | Input type | Evaluator | Context builder |
|---|
| Spring AI | ChatResponse | SpringAiEvaluator | SpringAiJudgmentContextBuilder |
| LangChain4j | Result<T> | LangChain4jEvaluator | LangChain4jJudgmentContextBuilder |
| Koog | AIAgent | KoogEvaluator | KoogJudgmentContextBuilder |
| AgentClient | AgentClientResponse | AgentClientEvaluator | AgentClientJudgmentContextBuilder |
Bridge modules declare framework dependencies with provided scope. Your application must already include the corresponding framework/runtime dependency.
SpringAiEvaluator
Bridges Spring AI ChatResponse output to agent-judge evaluation.
Uses Supplier<ChatResponse> because Spring AI ChatClient calls don’t take the goal as an argument at call time.
Metadata extracted (constants in SpringAiMetadataKeys):
| Key | Source |
|---|
springai.responseId | ChatResponse.getMetadata().getId() |
springai.model | ChatResponse.getMetadata().getModel() |
springai.finishReason | Generation finish reason |
springai.usage.promptTokens | Prompt token count |
springai.usage.completionTokens | Completion token count |
springai.usage.totalTokens | Total token count |
springai.hasToolCalls | Whether tool calls were made |
springai.toolCalls | Best-effort tool-call requests (not a full execution trace) |
Finish reason mapping: stop → SUCCESS, tool_calls → SUCCESS, length → SUCCESS (indicates truncation; judges may choose to abstain), content_filter → REFUSED, null → UNKNOWN
LangChain4jEvaluator
Bridges LangChain4j Result<T> to agent-judge evaluation.
Uses Function<String, Result<T>> because LangChain4j AiServices are dynamic proxies — there’s no common agent interface.
Metadata extracted:
| Key | Source |
|---|
langchain4j.tokenUsage | Result.tokenUsage() |
langchain4j.toolExecutions | Result.toolExecutions() |
langchain4j.sources | Result.sources() (also used as RAG context fallback) |
langchain4j.finishReason | Result.finishReason().name() |
Finish reason mapping: STOP/TOOL_EXECUTION → SUCCESS, LENGTH → SUCCESS (indicates truncation; judges may choose to abstain), CONTENT_FILTER → REFUSED, OTHER → UNKNOWN
KoogEvaluator
Bridges JetBrains Koog AIAgent to agent-judge evaluation.
Calls agent.run(input) directly — Koog’s native Java API is synchronous from the caller’s perspective.
Metadata extracted:
| Key | Source |
|---|
koog.agentId | agent.getId() |
AgentClientEvaluator
Bridges CLI-delegated agents (Claude Code, Codex, Gemini CLI, Amazon Q, etc.) via AgentClient.
Uses Supplier<AgentClientResponse> to keep process execution inside AgentClient.
Metadata extracted (constants in AgentClientMetadataKeys):
| Key | Source |
|---|
agentclient.model | response.getMetadata().getModel() |
agentclient.sessionId | response.getMetadata().getSessionId() |
agentclient.finishReason | response.getMetadata().getFinishReason() |
AgentClientJudgmentContextBuilder also maps result text to agentOutput, success/failure to ExecutionStatus, workspace to JudgmentContext.workspace, and metadata duration to executionTime.
JudgmentContextBuilder (All Bridges)
For full control, use the JudgmentContextBuilder directly:
Each bridge’s builder follows the same two-entry-point pattern: from() for pre-existing responses, execute() for wrapping the call.
Both have overloads accepting Map<String, Object> extraMetadata for attaching run IDs, experiment tags, etc.
RAG Evaluation
RagContext
Static helper for extracting RAG metadata from a JudgmentContext:
Metadata key constants:
| Constant | Value | Fallback |
|---|
RagContext.QUESTION_KEY | rag.question | context.goal() |
RagContext.CONTEXT_KEY | rag.context | langchain4j.sources |
RagContext.ANSWER_KEY | rag.answer | context.agentOutput() |
The context() method handles both String and List<?> values — lists are joined with newlines.
RAG Judges
All three RAG judges extend LLMJudge and return ABSTAIN when required metadata is missing:
| Judge | Evaluates | Requires |
|---|
FaithfulnessJudge | Is the answer grounded in the context? | context + answer |
ContextualRelevanceJudge | Is the context relevant to the question? | context |
HallucinationJudge | Does the answer contain unsupported claims? | context + answer |
See Built-in Judges for usage examples.
Module Coordinates
Judge families:
| Module | Artifact | Key Dependencies |
|---|
| Core | io.github.markpollack:agent-judge-core | None (zero deps) |
| AI Core | io.github.markpollack:agent-judge-ai-core | None (zero deps) |
| Exec | io.github.markpollack:agent-judge-exec | agent-sandbox |
| File | io.github.markpollack:agent-judge-file | JavaParser, Maven Model |
| LLM | io.github.markpollack:agent-judge-llm | Spring AI ChatClient, SpringAiJudgeModel |
| RAG | io.github.markpollack:agent-judge-rag | agent-judge-llm |
Framework bridges:
| Module | Artifact | Key Dependencies (provided) |
|---|
| Spring AI | io.github.markpollack:agent-judge-spring-ai | Spring AI Model |
| LangChain4j | io.github.markpollack:agent-judge-langchain4j | LangChain4j |
| Koog | io.github.markpollack:agent-judge-koog | Koog Agents |
| AgentClient | io.github.markpollack:agent-judge-agent-client | AgentClient, AgentClientJudgeModel |
Add modules with explicit versions: