Every published comparison of these four optimizers ranks them by how much accuracy they buy, and that ranking is unavailable to you — because each one consumes a different shape of feedback, and the shape you can supply was fixed the day you wrote your eval function. Before you read another benchmark table, answer one question about your metric: does it return a number, or a number and a sentence? That answer eliminates half this field.
At a glance
Three of these live in DSPy and optimize a compiled program; one is a standalone framework that treats any text in your system as a variable. What separates them is not the search algorithm but what they can learn from.
| Optimizer | What it changes | What it learns from | Home |
|---|---|---|---|
| BootstrapFewShot | Demonstrations only | Whether a trace passed | DSPy |
| MIPROv2 | Instructions and demonstrations, jointly | A scalar score over many rollouts | DSPy |
| GEPA | Instruction text, by reflection | The trajectory, plus any diagnostic text | DSPy; standalone library |
| TextGrad | Any text variable in the graph | A written critique from a second model | Standalone |
The metric is the interface, and almost nobody designs it that way
In a DSPy program the metric is a function you write that scores a prediction against an example. Most people write it once, return True or a float, and never think about it again — it is plumbing. It is not plumbing. It is the only channel through which any of these optimizers learns anything, and its return type decides which of them can do useful work.
A bare float is enough for the search-based optimizers
BootstrapFewShot runs your program over training examples, keeps the traces where the metric said yes, and installs them as few-shot demonstrations. It needs a pass/fail verdict and nothing else, it terminates fast, and on a program whose failures are mostly formatting or missing pattern, it is a startling amount of the available gain for an hour of work.
MIPROv2 does something more ambitious with the same signal: it proposes candidate instructions, pairs them with candidate demonstration sets, and searches that joint space against your scalar over a budget of rollouts. It is the sensible default when you have a few hundred labelled examples and an automatic checker. What it cannot do is know why a candidate lost — the score is a scalar, so the search is guided by the shape of the surface rather than by any understanding of the failure.
The reflective optimizers want words, and get sharply worse without them
GEPA, introduced at ICLR 2026 as a gradient-free reflective optimizer, inverts that. Rather than sampling the space and following the score, it reads the program's own trajectory — the inputs, the intermediate outputs, what the metric said — and writes an improved instruction the way a person would after reading a failed run. It then evolves a population of these along a Pareto frontier so that a candidate strong on one slice of the data is not discarded for being weak on another.
This is why its reported numbers are what they are. Across six tasks on Qwen3 8B the paper reports GEPA beating GRPO — a serious reinforcement-learning baseline — by up to 20%, and MIPROv2 by 13% aggregate. On MATH, GEPA-optimized programs are reported at 93% against 67% for a plain chain-of-thought module. On AIME 2025 with GPT-4.1 Mini it lands about 10% over the unoptimized baseline and about 12% over MIPROv2.
Now notice what every one of those tasks has in common: a free, automatic, unambiguous checker. A maths answer is right or wrong, and — this is the load-bearing part — a failed maths trace can be described. The metric can say the model dropped the constraint from line two. That sentence is GEPA's fuel. Hand it a metric that returns 0.0 and you have not disabled it, but you have taken away the thing it beats MIPROv2 with.
TextGrad takes the same idea further and makes it the whole system. It treats a compound LLM application as a computation graph in which the "gradient" is a natural-language critique written by an LLM, propagated backwards through the graph by the chain rule with text in place of derivatives. There is no scalar loss at all in the usual sense; there is a critic that says what was wrong and which way to push. The honesty of the design is that its authors are clear about the limits — the gradients are approximate and stochastic, they can contradict each other across a batch, and there is no learning rate and no convergence guarantee.
Three things the benchmark tables will not tell you
1. Your task probably has no free checker
The published margins come from maths, code and retrieval — domains chosen precisely because ground truth is cheap. If your task's ground truth is a support lead's judgement collected weekly, you cannot run any of these at their published rollout budgets, and your binding constraint is the labelled set rather than the algorithm. The correct first move is not to pick an optimizer; it is to buy a checker, which usually means a rubric-driven judge, calibrated against human labels, of the kind argued for in judge calibration & meta-evaluation. Optimizing against an uncalibrated judge is the fastest way to fit your prompt to that judge's biases.
2. An optimized prompt is a fitted artefact, not an asset
What comes out of these is a set of instructions and demonstrations tuned to one model at one version. Swap the model — because the provider deprecated it, because a cheaper one appeared, because you moved to a smaller one for cost — and the search has to run again. That is a genuine and under-budgeted operational cost, and it belongs in the same migration plan as everything else in model deprecation & migration. It also means the optimizer's own run cost is recurring, not one-off.
3. The gain frequently lands where you didn't want it
An optimizer maximises the metric. If the metric rewards final-answer correctness, it will happily discover instructions that get there through reasoning you would not endorse, or that overfit to a quirk of your training slice. This is ordinary reward hacking with a text-shaped action space, and the defences are the same: a held-out set the optimizer never sees, a look at the prompts it produced rather than only the score, and the process-versus-outcome distinction from reward design & hacking. Read the optimized instruction before you ship it. It is short, it is in English, and it will occasionally say something alarming.
When to pick which
| Your situation | Start with | Why |
|---|---|---|
| Metric returns pass/fail, you have a few dozen examples | BootstrapFewShot | Cheapest possible experiment; often most of the available gain |
| Scalar metric, hundreds of examples, budget for rollouts | MIPROv2 | The mature default for joint instruction and demo search |
| Your metric can explain a failure in a sentence | GEPA | The diagnostic text is exactly what its reflection step consumes |
| Few examples, but a strong model available as a critic | TextGrad | Needs a critique rather than a labelled set |
| Multi-module program where you don't know which stage is failing | GEPA or TextGrad | Both attribute credit through the trace; scalar search cannot |
| No reliable metric at all | None of them, yet | Build the eval first — every one of these amplifies whatever it measures |
One move dominates all of the above and costs an afternoon: change your metric to return a score and a short reason string. Search-based optimizers ignore the string harmlessly; reflective ones get their main input. You do not have to choose an optimizer to make that change, and you cannot use half this field without it.
FAQ
Is prompt optimization just a worse version of fine-tuning?
They answer different questions. Fine-tuning changes the weights and needs a training set, a serving story and a repeat of the whole exercise per model. Prompt optimization changes text, runs in minutes to hours, and transfers across providers about as well as any prompt does — which is to say, badly, but recoverably. The decision framework is in prompt, fine-tune or RL; in practice most teams have not exhausted prompt optimization before reaching for weights.
Does GEPA replace MIPROv2 in DSPy?
Not automatically. It reports better results on the paper's tasks under the paper's conditions, which include a rich feedback signal. On a program whose metric is a bare boolean and whose failures are demonstration-shaped, MIPROv2 or even BootstrapFewShot can match it for less money. Run the cheap one first — it takes an hour, and it tells you how much headroom there is before you spend on reflection calls.
How many examples do I actually need?
Fewer than people expect for the demonstration-based optimizers — tens is a real starting point — and the harder constraint is a held-out set large enough that the improvement you measure is not noise. This is the same statistical-power question as any other eval, treated properly in eval variance & statistical power. A 3% gain on 50 held-out examples is not a gain.
Can I optimize a multi-agent system this way?
Partially, and the credit-assignment problem is the reason it is hard: when a five-step pipeline produces a wrong answer, which module's instruction was at fault? Reflective optimizers have a real advantage here because the trajectory names the intermediate outputs, but the failure attribution is still the bottleneck — the same one described in multi-agent failure modes.
What about COPRO, and the other optimizers in DSPy?
COPRO does instruction-only coordinate ascent and is a reasonable middle option when your demonstrations are already good and only the instruction is weak. It sits on the same scalar-signal side of the split as MIPROv2, so nothing in this post's central argument changes for it. The DSPy optimizer set moves quickly; the question to carry forward is always what shape of feedback a new one consumes.
Further reading
On this wiki:
- DSPy 3 & GEPA for agent optimization — the long-form treatment of this stack.
- Prompt optimization — the concept-level introduction.
- Judge calibration & meta-evaluation — how to build the checker these need.
- Eval-driven development & CI — where the optimized program has to keep proving itself.