Skip to main content
An optimizer proposes candidates (instruction or demo overlays), evaluates them with your metric on your trainset, and keeps the best. compile is the entry point: it takes a module, a training set, and a metric, then searches for better instructions, and in some cases demos, for each Predict leaf. The module is mutated in place: after compile returns, calling the module produces better results with no code changes.
All five optimizers are thin strategies over the shared evaluation engine. Candidates are overlays evaluated through a cached, budget-metered, bounded-concurrency fan-out, and winners are installed through the apply_candidate seam. The engine types (EvalEngine, Candidate, Budget, Spend, ParetoView) are documented in Optimizer engine. Step-by-step how-to pages: COPRO, MIPROv2, and GEPA.

The Optimizer trait

compile takes exclusive &mut access to the module: no concurrent call() during optimization. The trainset is Vec<E> for any row type that projects into the module’s input via ToInput — a #[derive(Example)] struct, an (Input, Output) tuple, or a hand-written impl; the Serialize bound feeds rollout-cache uids, which content-hash the whole row. All type parameters are inferred from the arguments, so no turbofish is needed: optimizer.compile(&mut module, trainset, &metric). The Facet bound is what lets the optimizer discover Predict leaves by reflection and address them by dotted path. compile returns an error when no optimizable predictors are found, when a metric evaluation fails, or when an LM call fails during candidate evaluation. Each optimizer declares its own Report:

Choosing an optimizer

GEPA is the only optimizer that requires textual feedback from the metric. The others use numerical scores alone.

COPRO

Breadth-first instruction search: generates breadth candidate instructions per predictor, evaluates each on the trainset, installs the best, and repeats for depth rounds. The base instruction always competes in every round. How-to: COPRO. Cost: approximately breadth × depth × num_predictors × trainset_size LM calls, minus rollout-cache hits. Runs with an unlimited engine budget.

MIPROv2

Trace-guided instruction and demo optimizer. Four phases: one traced teacher pass over the trainset; demo bootstrapping from successful spans via the trace name-join; generation of num_candidates instruction variants per predictor seeded by prompting tips; evaluation of up to num_trials candidates per predictor on one sampled minibatch, keeping the best. Demos are installed before instruction search so candidates are scored against the module as it will actually run. How-to: MIPROv2. Public helper types: PromptCandidate (an instruction with its evaluated score: f64) and PromptingTips (the rotation of prompting best practices appended to candidates, default_tips() and format_for_prompt()). Public methods on MIPROv2: select_best_traces, create_prompt_candidates, format_schema_fields. The report is ().

GEPA

Genetic-Pareto instruction evolution driven by per-example feedback. Each generation samples a parent proportional to Pareto coverage, re-evaluates it on a trainset minibatch, has a reflection LM (prompt_model) rewrite the instruction from the feedback and the mutated component’s execution trace, then scores the child on the validation columns. Without a prompt_model, mutation degrades to deterministic feedback concatenation. Only instruction space is searched: no demo mutation, no crossover. How-to: GEPA.
GEPA errors if any Eval from the metric has feedback: None. Build metrics with Eval::with_feedback.
GEPA additionally exposes compile_with_valset(module, trainset, valset, metric). With Some(valset), initial evaluation and child scoring use the validation set while parent re-evaluation uses trainset minibatches; with None, the trainset serves both roles (this is what compile does).

GEPAResult

GEPACandidate carries id, instruction, module_name, example_scores: Vec<f32>, parent_id: Option<usize>, and generation, plus average_score() and mutate(new_instruction, generation).

SIMBA

Stochastic Introspective Mini-Batch Ascent, the cheap agentic default. SIMBA keeps one current program as a candidate overlay and hill-climbs. Each step: sample a seeded trainset minibatch; pick the best and worst rollout of the current program on it (served from engine bookkeeping, no extra rollouts); propose exactly one move; accept it through the engine’s minibatch gate. A child is promoted to a full-trainset evaluation only when its minibatch mean strictly beats the current program’s, so rejected moves never pay for a full pass. The winner is installed when compile returns. The two moves, in order of preference: Cost: trainset_size for the baseline pass, then minibatch_size rollouts per step, plus the remaining trainset_size - minibatch_size only on promotion and one reflection call per rule move. The run stops cleanly when the budget no longer fits a step.

SimbaStep and SimbaReport

Each SimbaStep records one step: The SimbaReport summarizes the run:

BootstrapFewShot

The simplest complete optimizer: one teacher pass, one candidate, one comparison. It runs the module over the trainset under trace capture, harvests few-shot demos from successful spans of rollouts scoring at least min_demo_score, evaluates the demo candidate on the same engine (teacher rollouts already sit in the rollout cache, so the baseline never re-runs), and installs the demos only when the candidate’s mean beats the baseline.

BootstrapReport

adopted: false with a populated demos_per_predictor means demos were harvested but did not beat the baseline; the module is left unchanged.

Demo harvesting

Demo harvesting is a pure name join over captured traces. A rollout trace records one span per Predict invocation under the same dotted-path component name the mutation seam addresses, so successful spans (parsed output present) from rollouts scoring at least the optimizer’s min_demo_score become flat demo rows for exactly the predictor that produced them: no pointer identity, identical behavior for fx and struct harnesses. Rows are ranked by whole-rollout score, deduplicated on input fields so repeated inputs do not crowd the demo set, and capped per predictor. BootstrapFewShot, MIPROv2, and SIMBA share this machinery; it is internal to the crate and not part of the public API.

See also