compile_module method: it takes a module, a training set, and a metric, then searches for better instructions, and in some cases demos, for each Predict leaf. After it returns, the winner is installed and calling the module produces better results with no code changes.
Predictors (one predictors! line). All six optimizers are thin strategies over the shared evaluation engine. Candidates are data, never mutation: each candidate is a name-keyed Candidate injected ambiently per rollout (fx::with_params) — nothing touches the module during evaluation, so different candidates evaluate concurrently — and the winner is installed exactly once at the end (OptimizeTarget::install). The engine types (Engine, Candidate, Budget, Spend, ParetoView) are documented in Optimizer engine.
Five strategies tune parameter values through overlays; the sixth, Structural, proposes graph edits over the edit calculus and runs on the program lane only.
Step-by-step how-to pages: COPRO, MIPROv2, GEPA, and Structural.
The Optimizer trait
Box<dyn Optimizer> pipelines can share one Engine — one budget, one rollout cache, one score matrix — across stages). The target carries the thing under optimization and its example set by reference; the engine carries the spend.
OptimizeTarget is the lane-erased pair of (thing under optimization, evaluation harness), one of two lanes:
OptimizeTarget::module(&mut module, &trainset, &metric)— a typedModule(+Predictorsdiscovery), a trainset slice, and aTypedMetric. The trainset is&[E]for any row type that projects into the module’s input viaToInput; theSerializebound feeds rollout-cache uids, which content-hash the whole row.OptimizeTarget::module_with_valset(...)adds an optional validation set (the layout GEPA’s Pareto bookkeeping uses). Construction runs the naming pass: every declared leaf is stamped with its declared name, so trace spans, candidate entries, and persistence all address the same names.OptimizeTarget::program(&interp, &examples, &metric)— an interpreter-loaded IRProgram, labeledDemoRowexamples, and a JSON-nativeProgramMetric. The winner is retrievable as anir::Overlay(OptimizeTarget::winner_overlay) forProgram::bake.
compile_module(&mut module, &trainset, &metric) inherent method constructs a module target and a default engine, runs compile, and installs the winner. compile returns an error when the target has no optimizable leaves, when a metric evaluation fails, or when an LM call fails during candidate evaluation.
compile returns the Report enum (Report::None, Report::Gepa(GEPAResult), Report::Simba(SimbaReport), Report::Bootstrap(BootstrapReport), and Report::Custom(serde_json::Value) as the third-party extension point), with into_gepa()/into_simba()/into_bootstrap() accessors. The typed compile_module sugar unwraps it:
Structural is the exception to this table and to the trait: it edits program structure, so its input is an interpreter-loaded program rather than a lane-erased target, and its entry point is compile_program instead of compile_module/compile.
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 type:
PromptingTips (the rotation of prompting best practices appended to candidates, default_tips() and format_for_prompt()). compile_module returns (); through the trait, the report is Report::None.
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_module_with_valset(module, trainset, valset, metric) — sugar over OptimizeTarget::module_with_valset plus the Optimizer trait. 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_module 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.Structural
LM-guided hill-climbing over the edit calculus, program lane only. Each generation gathers thelegal_edits menu for every leaf, has a reflection LM (prompt_model) choose one edit from the serialized menu plus the incumbent’s evaluation feedback, applies it with Program::edited, carries the incumbent overlay across the change with migrate_overlay, loads the child through a caller-supplied RuntimeEnv factory, and accepts it through the engine’s minibatch gate: only a strict win on the shared minibatch promotes the child to a full-set evaluation and makes it the new incumbent. Edits that fail to apply, children that fail to load, and reflection replies that do not parse are recorded and skipped. How-to: Structural.
Entry points: compile_program(&interp, &examples, &metric, env) and compile_program_with_overlay(&interp, Some(overlay), &examples, &metric, env), where env: Fn() -> RuntimeEnv supplies fresh bindings for each child load. The winner is returned in the report (program plus migrated overlay), never installed; bake it with Program::bake.
StructuralStep and StructuralReport
EachStructuralStep records one generation:
The
StructuralReport summarizes the run:
Demo harvesting
Demo harvesting is a pure name join over captured traces. A rollout trace records one span perPredict invocation under the leaf name the module declares via Predictors (stamped by the target’s naming pass), so successful spans (parsed output present) 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 gated and ranked by their effective 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.
A span’s effective score is the whole-rollout metric score unless the metric attached a span-level eval through TypedMetric::evaluate_spans (see Evaluation), which then takes precedence in both directions: a span scored down stays out of the demo pool even when its rollout won, and a span scored up qualifies even when its rollout lost. Without span evals the behavior is exactly the whole-rollout join described above.
See also
- Optimizer engine:
Engine,OptimizeTarget,Candidate,Budget,Spend, andParetoView - Evaluation:
TypedMetric,Eval, andEval::with_feedback - Traces: the span capture that feeds demo harvesting and reflection
- The edit calculus: the structural moves
Structuralproposes - How-to pages: COPRO, MIPROv2, GEPA, Structural
- 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
