---
title: "Evolve your agent's prompt with GEPA"
hook: "Make a cheap edge model match a larger one on a specialized task by optimizing the prompt."
lesson_id: "ex01"
---

# Evolve your agent's prompt with GEPA

- **Lesson ID:** ex01
- **Goal:** Make a cheap edge model match a larger one on a specialized task by optimizing the prompt. GEPA is Genetic-Pareto prompt optimisation.
- **Human lesson:** [exercise-evolve-agent-prompt-gepa.html](exercise-evolve-agent-prompt-gepa.html)
- **Source:** [Grok conversation, 14 Oct 2026](https://grok.com/share/c2hhcmQtMg_5f9c32be-a967-4a5c-bfd9-70cf60c75c88), [GEPA repo](https://github.com/gepa-ai/gepa), [quickstart](https://gepa-ai.github.io/gepa/guides/quickstart/), [paper](https://arxiv.org/abs/2507.19457).

## Prerequisites

- Python 3.11 or newer.
- `uv`, as in lesson 03.
- An API key in the provider env var (for example `OPENAI_API_KEY`), or a local model with an OpenAI-compatible chat API (still set `OPENAI_API_KEY` to any value). With no key, the run fails with a confusing `AttributeError ... 'choices'`.
- A small labeled train, validation, and test set. JSONL rows use `input`, `answer`, and optional `additional_context`.
- Lessons 04 and 05: a golden row and a written bar before a prompt change.

## Inputs, outputs, and artifacts

- **Inputs:** Labeled alerts (or the reader's own specialized task) split into `train.jsonl`, `val.jsonl`, and `test.jsonl`. A seed system prompt. A cheap task model and a stronger reflection model.
- **Outputs:** `prompts/edge_alert.gepa.txt`, a held-out table (accuracy, page recall, mean characters, cost or latency), and one explained prompt edit.
- **Artifacts:** `gepa_runs/edge_alert` from `run_dir`.

## Agent build steps

1. Install with `uv venv --python 3.11` (3.11 or newer), then `uv pip install "gepa[full]"`. Plain `gepa` installs no dependencies and fails later on missing `tqdm` and `litellm`. Check with `python -c "import gepa, litellm, tqdm"`.
2. Build three JSONL files. Example answer labels are `### page` and `### hold`. Never pass the test file to the optimizer. Print label counts.
3. Write a seed prompt that demands one final line: `### page` or `### hold`.
4. Write `edge_alert_metric(data, response)` returning `EvaluationResult(score=..., feedback=...)` from `gepa.adapters.default_adapter.default_adapter`. Feedback must say what failed. Score 0 when the label is missing, wrong, or both labels appear.
5. Run `gepa.optimize(seed_candidate, trainset, valset, task_lm, reflection_lm, evaluator, max_metric_calls)` with `max_metric_calls` from 100 to 200 (the sample uses 150). `task_lm` is the edge model. `reflection_lm` is the larger model. Set `run_dir`. Reusing a `run_dir` silently resumes the old run, so delete it or use a new dir for a fresh run. Write `result.best_candidate["system_prompt"]` to disk.
6. Score the held-out test set only after search: edge model plus seed, edge model plus GEPA prompt, larger model plus seed. Record accuracy, page recall, tokens, and cost or latency. `LM.batch_complete` returns strings. Read usage from `lm.total_tokens_in`, `lm.total_tokens_out`, and `lm.total_cost`. Use characters divided by 4 only as a fallback when the endpoint reports no usage.
7. For a multi-step agent, use `dspy.GEPA` with a metric that returns `dspy.Prediction(score=..., feedback=...)`, then `compile`. Install DSPy only for that path.
8. Local server: set `OPENAI_API_BASE=<url>/v1` and use `task_lm="openai/<model>"`. Passing your own adapter requires `task_lm=None` and `evaluator=None` on `gepa.optimize`. After a run, `run_dir` holds `candidates.json`, `run_log.txt`, `run_log.json`, `gepa_state.bin`, `candidate_tree.html`, and `generated_best_outputs_valset/`.

## Constraints

Keep the language simple and literal. No quizzes, no em dashes. Platform-neutral: no vendor device stack. The task model is the one that runs at the edge. The reflection model is not shipped. A reported 17x cost cut is not the target.

## Key concepts

- GEPA edits the prompt. It does not edit weights.
- `gepa.optimize` needs a seed candidate, train set, validation set, task model, reflection model, and `max_metric_calls`.
- The metric returns a score plus textual feedback.
- The test set is only for the final table.
- GEPA and fine-tuning work together. Ship the prompt when it closes the gap. Fine-tune the remaining slice with that prompt as the system prompt.

## Takeaways

- A cheap edge model can be pushed toward a larger model's score on one specialized task by searching the prompt.
- Page recall catches an always-hold prompt on a skewed set.
- One concrete GEPA edit should be explainable from the feedback.

## Acceptance checks

- Goal, prerequisites, steps, expected result, self-check, and solution notes are on the human page.
- Install lines are `uv venv --python 3.11` and `uv pip install "gepa[full]"`. The optimize call uses the documented arguments.
- Self-check covers held-out data, written feedback, class balance, and one GEPA change.
- Local server routing (`OPENAI_API_BASE` + `openai/<model>`) and the `run_dir` file names are stated. No unverified notes remain.
- Token usage comes from `lm.total_tokens_in` / `lm.total_tokens_out` / `lm.total_cost`, with chars/4 only as a fallback.
- The course index and lesson 05 nav link here.
- [ ] Return to [course SKILL.md](SKILL.md).
