Engineering

DSPy Optimizers Explained in 2026: BootstrapFewShot, MIPROv2, COPRO, and GEPA

DSPy optimizers compared: how BootstrapFewShot, MIPROv2, COPRO, and GEPA tune prompts, what DSPy 3.4.1 changed in GEPA, and which optimizer to run first.

· Updated
· 9 min read
dspy dspy-optimizers prompt-optimization gepa miprov2 2026
Editorial cover comparing DSPy optimizers BootstrapFewShot, MIPROv2, COPRO, and GEPA in 2026
Table of Contents

Originally published May 29, 2026.

You wrapped your task in a dspy.Module, wrote a metric, and got to the line everyone gets stuck on: optimizer = ???. The docs list BootstrapFewShot, BootstrapFewShotWithRandomSearch, MIPROv2, COPRO, and GEPA, each with its own knobs, and none of them says which one is for your problem. So you pick the one from the tutorial you read last, run it for an hour, and hope.

This post settles that choice. DSPy optimizers tune your program’s prompts or weights against a metric; we will walk through what each one does, where each one wins, and a ladder for picking the cheapest one that clears your eval. If you want the method-level theory behind these (textual gradients, genetic search, meta-prompting), read our companion piece on automatic prompt optimization; this one is about DSPy’s specific implementations.

What Are DSPy Optimizers?

DSPy optimizers, formerly called teleprompters, are the algorithms behind DSPy prompt optimization: they tune the prompts and few-shot examples in a DSPy program, and in a few cases the LM weights, against a metric. You define a metric and a trainset, pick an optimizer, and it searches for instructions and demos that score higher. DSPy ships about a dozen; the four here differ in what they tune and cost.

The naming changed, which trips people up. DSPy renamed teleprompters to optimizers, so older tutorials and newer docs describe the same classes with different words. The role never changed: compile a program by searching for better prompts and demos against your metric. If you are new to the framework itself, start with what DSPy is and come back for the optimizer choice.

How Does BootstrapFewShot Work?

BootstrapFewShot is the fast baseline. It runs your program over the trainset, keeps the traces where the output passed your metric, and uses those successful runs as bootstrapped few-shot demonstrations in the prompt. No new instructions are written; the lift comes entirely from showing the model good examples of the task being done right.

It is the right first move because it is cheap and it works on small data. If a handful of bootstrapped demos clears your eval, you are done in minutes. The ceiling is also where it stops: when the instruction itself is the problem, better examples will not fix it, and you climb the ladder.

How Does MIPROv2 Work?

MIPROv2 (Multiprompt Instruction PRoposal Optimizer, version 2) optimizes two things at once: the instructions and the few-shot demos. It proposes candidate instructions, generates candidate demonstration sets, and then runs a Bayesian search over which combination of instruction and demos scores best across your trainset.

The design point is the joint search. MIPROv2 writes instructions that complement the examples it selects, instead of treating them as independent, which produces a more cohesive prompt than tuning either alone. It rewards data: with a couple hundred examples it has enough signal for the Bayesian search to find a strong combination. With twenty examples, the search is mostly noise, and BootstrapFewShot is the better spend.

A minimal MIPROv2 example, with trainset as a list of dspy.Example objects marked with .with_inputs("question"):

# MIPROv2 needs the optional Optuna extra: pip install -U "dspy[optuna]"
import dspy

dspy.configure(lm=dspy.LM("openai/gpt-6-luna"))

trainset = [
    dspy.Example(question="What is the capital of France?", answer="Paris").with_inputs("question"),
    # ...the rest of your labeled examples
]

def exact_match(example, pred, trace=None):
    return example.answer.lower() == pred.answer.lower()

program = dspy.ChainOfThought("question -> answer")
optimizer = dspy.MIPROv2(metric=exact_match, auto="light")  # or "medium", "heavy"
optimized = optimizer.compile(program, trainset=trainset)
optimized.save("optimized.json")

The auto setting sizes the run: in DSPy’s source, light, medium, and heavy cap the validation sample at 100, 300, and 1,000 examples. To tune instructions only, pass max_bootstrapped_demos=0 and max_labeled_demos=0, which turns MIPROv2 into a zero-shot instruction optimizer, the setup DSPy’s docs suggest for keeping a prompt 0-shot.

How Does COPRO Work?

COPRO optimizes instructions only, and it does so by coordinate ascent. Each round it scores a set of candidate instructions (10 per predictor by default), then hands the top-scoring attempts back to the prompt model to propose the next set. It stops after a fixed number of rounds set by depth, 3 by default, rather than when the score plateaus.

COPRO sits beside MIPROv2 rather than above it. Reach for COPRO when the demonstrations are fixed or irrelevant and the instruction is the lever, for example a task where you cannot show examples for privacy reasons but you can describe the rules. When demos matter, MIPROv2’s joint search usually wins because COPRO never touches them.

How Does GEPA Work?

GEPA (Genetic-Pareto) is the reflective evolutionary optimizer, accepted as an ICLR 2026 oral. Instead of bootstrapping demos or searching instruction combinations, it reads the program’s execution trajectory, reflects in natural language on what worked and what failed, and proposes prompts that address the gaps. It keeps a Pareto frontier of candidates that each score best on at least one example, and it can use textual feedback as signal.

Two properties make GEPA worth the setup. First, the Pareto front keeps prompts that are each best at something, so multi-objective and multi-module pipelines do not get averaged into a bland compromise. Second, the reflection is sample-efficient: the GEPA paper reports beating MIPROv2 on every tested benchmark and model (+12 percent on AIME-2025 with Qwen3 8B) and GRPO by 6 percent on average with up to 35 times fewer rollouts.

What Changed for GEPA in DSPy 3.4.1

DSPy 3.4.1, released on October 12, 2026, made GEPA’s structured InstructionProposer the default. The DSPy GEPA optimizer now calls the reflection LM through dspy.Predict with a JSON adapter, so tool trajectories, dspy.History inputs, and images reach it as structured content instead of flattened text. GEPA’s reflection instructions themselves did not change.

Three notes in the release affect GEPA upgrades. The reflection LM must be a dspy.LM that can return JSON, and results can differ from 3.4.0 even with the same seed, so re-run your baseline before you compare scores across versions. On Python 3.15, dspy.GEPA raises an ImportError, because the gepa package it depends on supports only earlier Python versions.

Which DSPy Optimizer Should You Use?

OptimizerTunesSearch methodBest forData and compute
BootstrapFewShotFew-shot demosBootstrapped successful tracesFast baseline, small dataLow, minutes
MIPROv2Instructions + demosBayesian joint searchDemo-heavy single-metric tasks200+ examples, medium
COPROInstructions onlyCoordinate ascentInstruction-led, no demosSmall to medium
GEPAInstructions, every predictorReflective Pareto evolutionMulti-objective, pipelinesModerate, rollout-efficient

GEPA vs MIPROv2

Pick between them by what your metric returns. MIPROv2 treats the metric as a black-box scalar and runs Bayesian search over instruction and demo combinations. GEPA reads text feedback from each metric call, returned as dspy.Prediction(score=..., feedback=...), and threads it into the next instruction, so it gains the most when your metric can explain why an output failed.

In the GEPA paper’s GPT-4.1 Mini results, GEPA gained 12.2 points of aggregate score over the unoptimized baseline, against 5.6 points for MIPROv2. DSPy’s own selection guide adds the flip side: without a feedback-rich metric, COPRO or MIPROv2 may give better mileage than GEPA on the same budget.

The DSPy Optimizer Ladder

The mistake is picking the fanciest optimizer first. The rule is to run the cheapest rung that clears your eval and climb only when it does not. We call this the DSPy Optimizer Ladder, and most single-prompt tasks never leave its first two rungs.

The DSPy Optimizer Ladder as a decision tree: start on BootstrapFewShot, ship if it clears your eval, otherwise climb to COPRO or zero-shot MIPROv2, MIPROv2, or GEPA by what you have

  1. Start on BootstrapFewShot. Minutes to run, works on small data. If the baseline passes, ship it.
  2. Climb to MIPROv2 when you have a couple hundred examples and want instructions and demos tuned together, or step sideways to COPRO or zero-shot MIPROv2 when only the instruction is in play.
  3. Climb to GEPA when you have multiple objectives, a multi-module pipeline, or MIPROv2 has plateaued and you can spend the rollouts.

Other DSPy Optimizers Worth Knowing

Two more DSPy optimizers help once the ladder above stops fitting. Both appear in DSPy’s own selection guide, which sorts every optimizer two ways: by whether it tunes instructions, demos, or model weights, and by what a run costs.

  • BootstrapFewShotWithRandomSearch (alias dspy.BootstrapRS): runs BootstrapFewShot with several random seeds, scores each candidate on a valset, and keeps the best. DSPy’s docs suggest it once you have 50 or more examples.
  • SIMBA (Stochastic Introspective Mini-Batch Ascent): the SIMBA optimizer in DSPy samples a mini-batch each step, picks out the challenging examples in it, and proposes a natural-language rule or a new demo for them.

How Do You Run Optimization Without Wiring DSPy Yourself?

DSPy is a framework: you author modules and signatures, define a metric, and run the optimizer in-process. That control is the point, and it is also the cost. If you want GEPA and other prompt optimizers without managing the plumbing, a platform is the other path.

Future AGI’s agent-learning-kit ships six open-source prompt optimizers (Random Search, Bayesian Search, ProTeGi, Meta-Prompt, PromptWizard, and GEPA) behind one interface, scored by the same evaluators it uses for LLM evaluation. Instead of compiling a module in your code, you point an optimizer at a dataset and an evaluator, and the score that picks the winner is the same score you monitor in production.

Install it with pip install agent-learning-kit; the optimizers import from fi.opt. Its GEPAOptimizer calls the open-source gepa package, the same engine dspy.GEPA uses. The GEPA reference lists GEPA’s parameters and defaults, including max_metric_calls, the evaluation budget that the example below sets to 150.

from fi.opt.optimizers import GEPAOptimizer
from fi.opt.base.evaluator import Evaluator
from fi.opt.datamappers.basic_mapper import BasicDataMapper

evaluator = Evaluator(metric=your_metric)              # a Future AGI metric object
data_mapper = BasicDataMapper(key_map={"output": "generated_output", "expected": "expected"})

optimizer = GEPAOptimizer(
    reflection_model="gpt-6-astra",     # reflects on failures, proposes prompts
    generator_model="gpt-6-luna",       # runs the candidate prompts
)

result = optimizer.optimize(
    evaluator=evaluator,
    data_mapper=data_mapper,
    dataset=test_cases,                            # list of {input, expected} dicts
    initial_prompts=["You are a helpful assistant.\n\n{input}"],
    max_metric_calls=150,                          # the rollout budget
)

print(result.best_generator.get_prompt_template())   # the winning prompt
print(result.final_score)

Before You Run Any Optimizer

  • DSPy needs a metric and a trainset. Every optimizer maximizes the metric, so a weak metric yields a program that games it. Calibrate the metric first, and if you are scoring a multi-step program, our guide to evaluating DSPy pipelines covers signature-level metrics.
  • GEPA and MIPROv2 cost rollouts. They are more compute than BootstrapFewShot. Budget them like a CI job and use the ladder so you only pay for the rung you need. Trace each compile with the open-source traceAI DSPyInstrumentor, which traces DSPy compilation and inference, so you can see where the rollouts went.

From an Empty Optimizer Line to a Compiled Program

That optimizer = ??? line now has a test behind it. Run the cheapest optimizer your data supports, score it on a held-out set, and spend more rollouts only when that score misses your bar. Then save the compiled program and reload it in production, since DSPy’s docs note that compile cost pays off when you compile once per version and serve the saved artifact many times.

If you are weighing DSPy against other frameworks entirely, see our DSPy alternatives breakdown. If you want GEPA scored by the same evals you run on production traffic, Future AGI’s open-source optimizers in agent-learning-kit give you that loop outside your DSPy code.

Want to optimize a prompt against your eval without compiling a DSPy module? Start with Future AGI’s optimization docs and run a GEPA or ProTeGi pass on the dataset you already have.

Sources

Frequently Asked Questions

What are DSPy optimizers?

DSPy optimizers, formerly called teleprompters, are algorithms that tune the instructions and few-shot demos in a DSPy program, and sometimes the LM weights, against a metric you define. You pass a program, a metric, and a trainset, and the optimizer returns a compiled copy. DSPy ships about a dozen, including BootstrapFewShot, MIPROv2, COPRO, GEPA, and SIMBA.

How does DSPy prompt optimization work?

DSPy prompt optimization works by running your program on training examples, scoring each output with your metric, and keeping the instructions and demos that score highest. Some optimizers bootstrap demos from passing traces, MIPROv2 runs Bayesian search, and GEPA has a reflection LM rewrite instructions from text feedback.

What is the difference between MIPROv2 and GEPA in DSPy?

MIPROv2 runs Bayesian search over instruction and demo combinations and treats your metric as a scalar, while GEPA reflects on text feedback from each metric call to rewrite instructions. The GEPA paper reports GEPA beating MIPROv2 on every benchmark and model it tested, including a +12 percent accuracy gain on AIME-2025 with Qwen3 8B.

What paper introduced MIPROv2?

MIPROv2 comes from the paper Optimizing Instructions and Demonstrations for Multi-Stage Language Model Programs by Opsahl-Ong and colleagues, published at EMNLP 2024 as arXiv 2406.11695. It introduced MIPRO, which outperformed baseline optimizers on five of seven multi-stage programs with Llama-3-8B, by as much as 13 percent accuracy.

What replaced teleprompters in DSPy?

Nothing replaced teleprompters in DSPy, because the same classes were renamed optimizers and still tune a program's prompts or weights against a metric. The code still lives in the dspy.teleprompt module, so older tutorials that say teleprompter and newer docs that say optimizer describe the same BootstrapFewShot, MIPROv2, and COPRO classes.

Can you use GEPA without DSPy?

Yes, GEPA also ships as the standalone open-source gepa package, whose optimize_anything API tunes any text artifact you can score with an evaluator, from prompts to code and configurations. Future AGI's agent-learning-kit wraps that package in GEPAOptimizer and scores each candidate prompt with Future AGI evals or your own metric.
Related Articles
View all