Instruction optimization¶
Instead of choosing demonstrations, these optimizers rewrite the instructions in a program's signatures, searching for wording that scores better on your metric.
COPRO¶
COPRO proposes candidate instructions and refines them over several rounds
(breadth and depth), keeping the best:
def copro(metric: Metric, student: DynamicPredict, trainset: Vector[Example])(using
RuntimeContext
): Either[DspyError, DynamicPredict] =
new COPRO[DynamicPredict](COPROConfig(metric = metric)).compile(student, trainset).map(_.bestProgram)
MIPROv2¶
MIPROv2 optimizes instructions and demonstrations together, guided by the
metric. It takes a validation set alongside the training set:
def miprov2(metric: Metric, student: DynamicPredict, trainset: Vector[Example], devset: Vector[Example])(
using RuntimeContext
): Either[DspyError, DynamicPredict] =
new MIPROv2[DynamicPredict](MIPROv2Config(metric = metric))
.compile(student, trainset, valset = Some(devset)).map(_.bestProgram)
GEPA¶
GEPA is a reflective, genetic-Pareto optimizer. Rather than sampling
instructions blindly, it reflects on where the program failed and evolves a
Pareto front of candidates, trading off competing objectives. It is a
self-contained implementation plus a dspy4s adapter, and it follows the same
compile(student, trainset) shape as the optimizers above.
A reflection model writes each new instruction. Gepa takes that model, and
an optional instructionProposer. The default is DefaultInstructionProposer().
Its options add requirements for each new instruction
(additionalInstructions), replace the instructions of the proposal call
(baseInstructions), and set a length limit (maxChars). To control the
proposal fully, implement the InstructionProposer trait.
A metric can also give scores for named objectives
(ScoreWithFeedback.objectiveScores), for example accuracy and cost.
GepaConfig.frontierType then selects how GEPA keeps candidates that are good
on one objective: Objective, Hybrid, or Cartesian. The default is
Instance, which uses the score of each validation example only.
An iteration makes one proposal by default. GepaConfig.proposalSampling
gives it more: for example SameParent(4) proposes four children of one
parent, each from its own minibatch, and evaluates them in parallel.
The budget of a run (GepaConfig.budget) is a number of metric calls, a
number of full evaluations, or a level of effort: GepaBudget.Auto(Light),
Medium, or Heavy. With no validation set, GEPA uses the trainset for the
Pareto scores. GepaResult.stopReason tells why a run stopped, and
GepaConfig.runDir lets a stopped run continue.
Choosing one¶
| Optimizer | Strategy | Use when |
|---|---|---|
COPRO |
Iterative instruction proposals | You want better wording, cheaply. |
MIPROv2 |
Joint instructions + demos | You want the strongest single optimizer. |
GEPA |
Reflective genetic-Pareto search | You can describe failures and want it to learn from them. |
Next: Runtime context.