Reference: “GEPA: Reflective Prompt Evolution Can Outperform Reinforcement Learning” (Agrawal et al., 2025, arxiv:2507.19457)
Overview
GEPA adaptively evolves the textual components of your module (its instructions). In addition to the scalar score, your metric returns text feedback explaining why the score is what it is. That feedback gives GEPA visibility into the failure, and a reflection LM uses it to propose a better instruction. Because each rollout carries an explanation rather than just a number, GEPA can find high-performing prompts in comparatively few rollouts.What GEPA adds
Compared to COPRO and MIPROv2, GEPA changes four things:Rich textual feedback
Instead of just scalar scores (0.8, 0.9), GEPA uses detailed explanations:Pareto-based selection
GEPA maintains a diverse set of candidates that excel on different examples, preventing premature convergence:- Candidate A: Best on examples 1, 3, 5
- Candidate B: Best on examples 2, 4, 6
- Both stay in the population (complementary strengths)
LLM-driven reflection
A reflection LM (prompt_model) reads the current instruction, the per-example feedback, and the mutated component’s execution trace, then proposes a targeted rewrite:
prompt_model, mutation degrades to deterministic feedback concatenation, so setting one is strongly recommended.
Inference-time search
GEPA can optimize at test time, not just training time (see Inference-time search).Quick start
1. Implement a typed metric with feedback
Trace; metrics that inspect intermediate steps can slice it with trace.for_component("predictor").
2. Configure and run GEPA
Configuration options
num_trials and temperature also exist on the builder but are currently unused (reserved for multi-child evolution and mutation diversity control). The full field table is in the optimizers reference.
Pass validation data at compile time:
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).
Understanding GEPA results
Architecture
Core components
Eval The metric result type: one score, optional textual feedback. GEPA errors if anyEval has feedback: None.
Predict invocation. GEPA feeds the mutated component’s spans (trace.for_component(name)) to the reflection LM alongside the feedback. See Traces.
Pareto bookkeeping
GEPA uses the engine’s score matrix directly: ParetoView (see Optimizer engine) tracks which validation columns each candidate wins on, parent sampling is proportional to that coverage, and candidates with zero wins are dominated.
GEPACandidate
Evolutionary algorithm
- Initialize the candidate pool with the unoptimized program
- Iterate:
- Sample a candidate from the Pareto frontier (proportional to coverage)
- Sample a minibatch from the training set
- Collect execution traces with feedback
- Select a module component for targeted improvement
- LLM Reflection: Propose a new instruction using reflective meta-prompting
- Roll out the new candidate; if improved, evaluate on the validation columns
- Update the Pareto frontier
- Continue until budget is exhausted
- Return best candidate by average score
Implementing feedback metrics
A well-designed metric is central to GEPA’s sample efficiency. The DSRs implementation expects the metric to return anEval; for GEPA that means Eval::with_feedback(score, feedback) on every example.
Practical recipe for GEPA-friendly feedback
- Leverage existing artifacts: Use logs, unit tests, evaluation scripts, profiler outputs
- Decompose outcomes: Break scores into per-objective components
- Expose trajectories: Label pipeline stages with pass/fail and errors
- Ground in checks: Use validators or an LLM judge for subjective tasks
- Prioritize clarity: Focus on error coverage and decision points
Feedback examples by domain
Document retrieval: List correctly retrieved, incorrect, or missed documents Multi-objective tasks: Decompose aggregate scores to reveal contributions from each objective Stacked pipelines: Expose stage-specific failures (parse, compile, run, test)Best practices
Design feedback for actionability
Leverage domain knowledge
- Code generation: Show stage-specific failures
- Retrieval: List specific documents missed
- QA: Explain reasoning errors
Balance feedback detail
- Too brief: Not actionable
- Too verbose: Drowns out signal
- Aim for 2 to 5 lines per issue
Set realistic budgets
Using an LLM judge for feedback
For tasks where feedback rules are hard to codify, a second LLM can generate the feedback: it reads the task output and writes the evaluation text that becomes the metric’s feedback string.- Subjective quality assessment (writing style, helpfulness, clarity)
- Complex reasoning evaluation (soundness of the logic)
- Tasks where rules are hard to codify
- Analyzing reasoning quality beyond answer correctness
- Unit tests or schema validation cover the failure modes
- Correctness is verifiable (code compilation, exact matches)
- Evaluation must be fast and cheap
- The outcome is a simple binary pass/fail
Task signature with reasoning
Judge signature
Optimized module
TypedMetric with judge
GEPA itself does not own a special feedback_metric hook.
The feedback function lives in your TypedMetric implementation, and GEPA enforces that every evaluation returns Eval::with_feedback(...).
That keeps the optimizer generic while preserving full judge-driven behavior.
What a judge catches
- Lucky guesses: a correct answer reached through unsound reasoning is penalized instead of scoring 1.0.
- Partial progress: a wrong answer with a correct approach (an arithmetic slip in the final step) earns partial credit instead of 0.
- Systematic issues: the judge surfaces recurring patterns such as skipped intermediate steps, confused concepts (area versus perimeter), or missing unit checks, and GEPA’s reflection turns them into explicit instructions.
Cost considerations
Budget accordingly:- Use a cheaper model for judging (gpt-4o-mini vs gpt-4)
- Judge only failed examples (not ones that passed)
- Cache judge evaluations for identical outputs
- Use parallel evaluation to reduce wall-clock time
Hybrid metrics
Combining explicit checks with LLM judging often gives the best results:Running the judge example
Full Working Example
See the complete implementation with step-by-step comments
Examples
Sentiment Analysis
Basic GEPA usage with explicit feedback for sentiment classification
LLM-as-Judge
Using an LLM judge to generate feedback
Comparison with other optimizers
GEPA is the only optimizer that requires textual feedback from the metric (
Eval::with_feedback). The others use numerical scores alone. Full configuration tables for all six live in the optimizers reference.
When to use GEPA
- Complex tasks with subtle failure modes
- When you can provide rich feedback
- Multi-objective optimization
- Need for diverse solutions
- Inference-time search
When to use alternatives
- COPRO: Simple tasks, quick iteration
- MIPROv2: Best prompting practices, single objective
Troubleshooting
Issue: GEPA errors because an Eval has no feedback
GEPA requires feedback for every evaluated example.
Issue: Slow convergence
Issue: Running out of budget
Inference-time search
GEPA can act as a test-time/inference search mechanism. By setting yourvalset to your evaluation batch and enabling track_best_outputs(true), GEPA produces for each batch element the highest-scoring outputs found during the evolutionary search.
