Skip to main content
Evaluation is how you tell an optimizer what “good” means. The evaluate module provides a metric trait, a result type, a concurrent evaluation loop, and helper functions that build rich textual feedback. A metric sees fully typed data on both sides: the trainset row with all its gold data and the prediction as the module actually produced it.

Writing and running a metric

A minimal exact-match metric for a QA task, over a row struct trainset:
evaluate_trainset runs the module on every example, scores each rollout with the metric, and average_score reduces the results to one number:

TypedMetric

TypedMetric<E, M> is the metric trait. It is generic over E (the trainset row — any struct you like, see Data) and M: Module, so the metric sees fully typed data: the row with all its fields, and the prediction as the module actually produced it (for example WithReasoning<QAOutput> from ChainOfThought). Because the metric receives the row rather than a signature-shaped pair, gold data need not fit the module’s output type — a row can carry metric-only fields the module never sees, such as HotpotQA supporting facts.
Return Eval::score(f64) for a numerical score, Eval::with_feedback(f64, text) to also explain why. Scores are 0.0 to 1.0 by convention.

Per-span credit

evaluate assigns one score to the whole rollout. For a multi-step module that single score over-credits: a good final answer marks every intermediate Predict call as good, including a step a later call had to recover from. evaluate_spans is the optional hook for per-span credit. The evaluation loop calls it once per traced rollout, after evaluate, and stamps each returned Eval onto its span (Span::eval); pairs whose id is not in the trace are ignored.
Demo harvesting (BootstrapFewShot, MIPROv2, SIMBA) prefers a span’s own eval over the rollout score when gating and ranking demo candidates, so a scored-down span stays out of the demo pool even when its rollout won, and a scored-up span qualifies even when its rollout lost. Spans you leave out keep whole-rollout credit, and a metric that implements only evaluate behaves exactly as before. See Optimizers for the harvesting semantics.

Eval and Rollout

Eval is defined in the trace module and re-exported by evaluate. The public evaluation entry points return Vec<Eval>; the traced Rollout path is what optimizers consume internally.

Evaluation functions

Each example runs inside a trace capture scope and the metric receives that rollout’s Trace. Metric evaluation itself happens outside the scope, so LM-as-judge metrics do not pollute the execution trace.

Metrics and optimizers

Optimizers call the evaluation loop internally; the metric you hand them determines what they can do with the results. The feedback helpers above exist mainly to serve GEPA: a metric that explains why a rollout scored low gives the reflection model something concrete to fix. See Optimizers for the optimizer-side contract.

See also