Skip to main content
EvaluationLoop implements the “Ralph Loop” pattern: run an agent, judge the output, provide feedback, and repeat until the quality threshold is met.

How It Works

Quick Start

Modes

Optimize Mode

Stops as soon as the threshold is met. Best for production use.

Review Mode

Runs all iterations regardless of score. Best for analysis.

Configuration

agent
Agent
required
The Agent instance to evaluate
criteria
string
required
Evaluation criteria for the Judge (e.g., “Response is thorough and accurate”)
threshold
float
default:"8.0"
Score threshold for success (1-10 scale)
max_iterations
int
default:"5"
Maximum number of iterations before stopping
mode
string
default:"optimize"
"optimize" (stop on success) or "review" (run all iterations)
on_iteration
Callable
Optional callback called after each iteration with IterationResult
verbose
bool
default:"false"
Enable verbose logging
metric
Callable[[str], float]
Numeric metric on (output). When set, the loop scores with this callable instead of the LLM Judge. Non-finite results (NaN / inf) are floored to 0.0.

Keep the Best Iteration

The result exposes the highest-scoring iteration, not just the last one.
success is now best.score >= threshold, not iterations[-1].score >= threshold. A run that improves and then regresses reports the improvement instead of the regression.
best
IterationResult
The highest-scoring iteration
best_iteration
IterationResult
The highest-scoring iteration (falls back to max() over iterations if best is unset)
best_score
float
Score of the best iteration
best_output
string
Output of the best iteration

Score with a Numeric Metric

Pass a metric to score iterations with an empirical function instead of the LLM Judge.
The Judge remains the default — the metric only takes over when set. This works with any empirical score (rouge_l, accuracy, latency, or a custom function).
Non-finite metric results (NaN / inf) are floored to 0.0 so they never win selection.

Results

EvaluationLoopResult

success
bool
Whether the loop achieved the threshold
final_score
float
Score from the last iteration (1-10)
score_history
list[float]
All scores across iterations
final_output
string
Output from the last iteration
accumulated_findings
list[string]
All findings/suggestions collected
num_iterations
int
Number of iterations completed
total_duration_seconds
float
Total time taken

IterationResult

Each iteration produces an IterationResult:

Async Support

Best Practices

Be specific in your criteria to get consistent results:
  • 8.0 (default): Good for most use cases
  • 9.0+: High quality, may require more iterations
  • 7.0: Acceptable quality, faster completion
Each iteration makes LLM calls. Set max_iterations based on your budget:
Track progress in real-time:

Judge

LLM-as-judge for evaluating outputs

Evaluator-Optimizer

Multi-agent evaluator-optimizer pattern

Goal Loop

Gate a tool-using loop on an independent acceptance-criteria judge

Prompt Optimizer

Optimise an agent’s instructions against an eval set
EvaluationLoop uses lazy loading - the Judge is only imported when you actually run an evaluation, ensuring zero performance impact when not in use.