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.
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: generatesbreadth 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 ofnum_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 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 whencompile 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
EachSimbaStep 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 leastmin_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 perPredict 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
- Optimizer engine:
EvalEngine,Candidate,Budget,Spend,ParetoView, and checkpointing - Evaluation:
TypedMetric,Eval, andEval::with_feedback - Traces: the span capture that feeds demo harvesting and reflection
- How-to pages: COPRO, MIPROv2, GEPA
- Runnable examples:
- COPRO: https://github.com/krypticmouse/DSRs/blob/main/crates/dspy-rs/examples/04-optimize-hotpotqa.rs and https://github.com/krypticmouse/DSRs/blob/main/crates/dspy-rs/examples/02-module-iteration-and-updation.rs
- MIPROv2: https://github.com/krypticmouse/DSRs/blob/main/crates/dspy-rs/examples/08-optimize-mipro.rs
- GEPA: https://github.com/krypticmouse/DSRs/blob/main/crates/dspy-rs/examples/09-gepa-sentiment.rs and https://github.com/krypticmouse/DSRs/blob/main/crates/dspy-rs/examples/10-gepa-llm-judge.rs
- Optimizer interface smoke test: https://github.com/krypticmouse/DSRs/blob/main/crates/dspy-rs/examples/94-smoke-slice5-optimizer-interface.rs
