GEPA (Genetic-Pareto) a fost propus în lucrarea „GEPA: Reflective Prompt Evolution Can Outperform Reinforcement Learning” (Agrawal et al., 2025, arXiv:2507.19457). În DSPy este un optimizator de instrucțiuni: rescrie docstring-ul semnăturii fiecărui predictor și lasă neschimbate demonstrațiile, numele și descrierile câmpurilor. Ghidul de început al DSPy îl folosește ca prim optimizator.
GEPA ține o populație de programe candidate. La fiecare pas alege un predictor (implicit pe rând, component_selector="round_robin"), rulează un mini-lot de exemple, iar reflection_lm citește intrările, ieșirile și feedback-ul exemplelor slabe și propune o instrucțiune nouă. Candidatul următor este ales din frontiera Pareto pe exemple (programele care au cel mai bun scor pe cel puțin un exemplu); la final se întoarce programul cu cel mai bun scor agregat pe valset. Fără valset, GEPA folosește trainset și pentru selecție, ceea ce permite potrivirea excesivă pe acele exemple.
Metrica poate întoarce un număr, dar GEPA folosește pe deplin doar forma dspy.Prediction(score=..., feedback="..."): textul din feedback ajunge direct în promptul de reflecție. Bugetul se dă prin exact unul dintre auto ("light" / "medium" / "heavy", adică 6 / 12 / 18 candidați), max_full_evals sau max_metric_calls. În dspy 3.4.1, reflection_lm (sau un instruction_proposer propriu) este obligatoriu. Pachetul gepa se instalează automat doar pe Python sub 3.15.
Concepte cheie și caracteristici
| Concept / Parametru | Descriere practică |
|---|---|
metric |
metric(gold, pred, trace=None, pred_name=None, pred_trace=None), de preferință cu dspy.Prediction(score, feedback). |
auto / max_full_evals / max_metric_calls |
Bugetul; exact unul trebuie setat, altfel constructorul dă eroare. |
reflection_lm |
Modelul care propune instrucțiuni; documentația recomandă unul mai puternic decât cel al programului. |
reflection_minibatch_size |
Exemple arătate modelului de reflecție la o propunere; implicit 3. |
candidate_selection_strategy |
"pareto" (implicit) sau "current_best". |
skip_perfect_score / perfect_score |
Implicit True / 1.0: exemplele cu scor maxim nu intră în mini-lotul de reflecție. |
use_merge / max_merge_invocations |
Implicit True / 5: combină instrucțiunile a doi candidați buni. |
num_threads |
Paralelizează evaluările; reflecția rămâne serială. |
track_stats / log_dir |
Implicit False; cu True, programul întors are detailed_results (toți candidații, scorurile, descendența). |
compile(student, trainset, valset=None) |
Întoarce o copie a programului cu instrucțiunile celui mai bun candidat. |
Exemple practice și scenarii reale
Exemplul 1: Optimizarea unui clasificator de tichete
from typing import Literal
import dspy
dspy.configure(lm=dspy.LM("openai/gpt-6-luna"))
class ClasificaTichet(dspy.Signature):
"""Clasifică tichetul de suport."""
tichet: str = dspy.InputField()
categorie: Literal["facturare", "tehnic", "cont", "altele"] = dspy.OutputField()
program = dspy.ChainOfThought(ClasificaTichet)
# train, val: liste de dspy.Example(tichet=..., categorie=...).with_inputs("tichet")
def metrica(gold, pred, trace=None, pred_name=None, pred_trace=None):
if gold.categorie == pred.categorie:
return dspy.Prediction(score=1.0, feedback="Categoria este corectă.")
return dspy.Prediction(
score=0.0,
feedback=f"Ai ales {pred.categorie}, dar tichetul este de tip {gold.categorie}.",
)
optimizator = dspy.GEPA(
metric=metrica,
auto="light",
reflection_lm=dspy.LM("openai/gpt-6-astra"),
num_threads=8,
track_stats=True,
)
optimizat = optimizator.compile(program, trainset=train, valset=val)
optimizat.save("clasificator_gepa.json")
Exemplul 2: Instrucțiunea găsită și istoricul căutării
print(optimizat.predict.signature.instructions) # ChainOfThought ține predictorul în .predict
rezultate = optimizat.detailed_results # doar cu track_stats=True
print(rezultate.best_idx, rezultate.val_aggregate_scores[rezultate.best_idx])
Exemplul 3: Buget fix în apeluri de metrică
optimizator = dspy.GEPA(
metric=metrica,
max_metric_calls=500,
reflection_lm=dspy.LM("anthropic/claude-sonnet-5-5"),
)
Greșeli frecvente și capcane
- Construiești
dspy.GEPA(metric=..., auto="light")fărăreflection_lm. În 3.4.1 constructorul se oprește cu eroare de aserțiune. - Setezi și
auto, șimax_metric_calls. GEPA acceptă exact un tip de buget. - Întorci doar un număr din metrică. Merge, dar modelul de reflecție vede doar scorul, nu și motivul eșecului; scrie un
feedbackconcret. - Omiți
valsetși raportezi scorul pe aceleași date. Ține un set de test separat, nefolosit nici la reflecție, nici la selecție. - Pornești cu
auto="heavy". Documentația avertizează că o rulare GEPA sau MIPROv2 poate costa sute de dolari în apeluri; începe cu"light".