Prompt Evolution Instead of RL Under the Hood of the GEPA Framework
Tuning system instructions and agents usually turns into endless manual text tweaking. Fix one formulation — improve the logic, but break the output formatting. Using reinforcement learning like GRPO for such tweaking is too expensive: algorithms require tens of thousands of runs, and all feedback boils down to a single score.
Recently I explored the GEPA (Genetic-Pareto) repository. The project is developed by researchers from Berkeley and Stanford, offering a fundamentally different approach to optimizing any text parameters.
The Core Idea Behind the Project
Classical optimizers treat the system as a black box: they get a numeric score at the output and try to guess where to move next. GEPA works differently. The framework feeds the neural network the entire execution log — errors, profiler output, stack traces, and intermediate reasoning.
The model analyzes this data the same way a developer does during debugging. It sees the specific cause of a failure and suggests targeted fixes. Then a genetic algorithm kicks in with Pareto front considerations: the system preserves text variants that perform best across different subsets of tasks.
What the Framework Can Do
This approach enables automatic tuning of various elements:
- Prompts for individual models or chains in DSPy and LangChain
- Agent architecture and their skill sets
- Task planning rules and configuration files
- Tool descriptions for the MCP protocol
In the authors' tests, the GPT-4.1 Mini model improved accuracy on the AIME math benchmark from 46.6% to 56.6% after a hundred iterations. Databricks engineers used GEPA to reduce their agent operation costs by 90x without losing quality.
How the Optimization Process Works
The framework operates in a loop of five sequential steps:
- Candidate selection from the Pareto front. The system picks a variant that showed the maximum result on a specific test group.
- Running on a small dataset. During this, all execution logs and errors are collected.
- Reflection. The reflector model reads textual failure logs and formulates diagnostics.
- Mutation. A new version of the prompt or code is created, accounting for past errors from all ancestors.
- Decision making. The new candidate is added to the shared pool if it demonstrated real improvement.
All diagnostics are called Actionable Side Information in the authors' terminology. In text optimization, it serves as the gradient equivalent from traditional machine learning.

How to Write Code
You can install the library from PyPI:
pip install gepa
The project has a simple API called optimize_anything. It lets you tune not only prompts but any text artifact:
import gepa.optimize_anything as oa
from gepa.optimize_anything import GEPAConfig, EngineConfig, optimize_anything
def evaluate(candidate: str) -> float:
result = run_my_system(candidate)
oa.log(f"Output: {result.output}")
oa.log(f"Error: {result.error}")
return result.score
result = optimize_anything(
seed_candidate="Начальный текст инструкции или кода",
evaluator=evaluate,
objective="Уменьшить количество ошибок форматирования вывода",
config=GEPAConfig(engine=EngineConfig(max_metric_calls=100)),
)
Logs sent through oa.log() are exactly what go to the reflector model for error detection. If you already use DSPy, the tool is available out of the box as dspy.GEPA.
When Tuning via GEPA Is Actually Worth It
The method performs best in the following scenarios:
- Running agents with many external tools
- Small training datasets with only 5–10 examples
- Closed models without weight access via API
- Expensive or slow calls, including code compilation and simulations
Where RL requires 5,000–25,000 runs to converge, this algorithm usually needs only 100–500 evaluations.
The Bottom Line
The framework addresses the painful topic of manual text instruction tuning. It's nice that the tool has already been integrated into MLflow, Pydantic AI, and Google ADK, so you won't need to drag a bunch of extra code into your project. Start with the short tutorial in the documentation or run optimize_anything on a couple of your most problematic prompts.
Related projects