Engineering

Build Your Own Prompt Optimizer: A Step-by-Step Framework

A framework-agnostic build guide for a prompt optimizer: candidate generation, golden-set scoring, selection, and the failure modes nobody documents.

· 12 min read
prompt-optimization prompt-engineering llm-evaluation automated-prompt-optimization 2026
Editorial cover image showing a four-stage prompt optimizer build loop on a dark blueprint grid.
Table of Contents

Most teams start optimizing prompts by hand: change a line, rerun the prompt, eyeball the output, repeat. It works until you have more than a handful of test cases, and then it stops scaling entirely. A prompt optimizer replaces that manual loop with a scored search you can run on demand.

You do not need a vendor SDK to build one. The core loop is four repeatable steps: generate candidate prompts, score them against a fixed test set, select and mutate the winners, and check for convergence. This guide walks through building that loop yourself, with any model provider and any stack, plus the failure modes that quietly wreck it in production.

What a Prompt Optimizer Actually Does

A prompt optimizer is a search algorithm wrapped around your existing prompt. It takes a starting prompt, a set of representative inputs with expected outcomes, and a scoring function. From there it proposes variations, measures each one, and keeps whatever scores higher. Nothing about this requires a specific framework.

The reason this beats manual editing isn’t cleverness, it’s memory. A human editing prompts by hand can eyeball five outputs but not five hundred, and has no record of which past edit caused which regression. An optimizer keeps every candidate and its score, so it never reintroduces a change it already disproved. That’s the entire advantage: a search with perfect recall.

Three things make this loop possible, and all three need to exist before you write a line of optimizer code. A golden set of labeled or reference examples. A scoring function that turns an output into a number. A way to generate new prompt candidates from the current best one. Skip any of these and you’re not building an optimizer, you’re building a random prompt shuffler.

This is also where the algorithm-versus-process distinction matters. A research paper describing textual gradients or genetic search is describing the candidate-generation step alone. The golden set, the scorer, and the stopping rule are engineering decisions that determine whether that algorithm actually produces something usable, and most build guides skip straight past them.

None of the four steps below assume a particular model provider, orchestration framework, or vendor SDK. They assume an API you can call in a loop, a way to store scored results, and a test set that reflects how your prompt gets used. That’s a deliberately low bar, because the value is in the discipline of the loop, not the sophistication of any single step.

Step 1: Build the Golden Set Before Anything Else

The golden set is the test suite your optimizer runs against every round. It needs real inputs your prompt will actually see, not synthetic edge cases invented in isolation. Pull them from production logs, support tickets, or manually written cases that mirror your actual traffic distribution.

Thirty to eighty examples is a reasonable starting size for most tasks. Fewer than that and the optimizer has too little signal to distinguish a genuinely better prompt from noise. More than a few hundred and each round gets expensive without adding much signal, since most of the value comes from covering distinct failure patterns, not raw volume.

Split the set before you start optimizing: roughly 70% for the optimization loop itself, 30% held out for validation. The optimizer never sees the held-out split during search. You only check it after a round finishes, to confirm the score gain generalizes instead of just fitting the examples the optimizer was staring at.

Label each example with what a correct output looks like, whether that’s an exact answer, a required set of facts, or a rubric a judge can apply. Vague labels like “sounds good” produce a scoring function that can’t discriminate between candidates, which stalls the whole loop before it starts.

Coverage matters more than volume once you clear the thirty-example floor. A golden set built from a single, easy failure pattern teaches the optimizer to fix that one pattern and nothing else. Deliberately include the messy inputs, short queries, ambiguous phrasing, edge-case formatting, because those are where prompts actually break in production.

Refresh the golden set periodically instead of treating it as fixed forever. New failure patterns show up as your product changes, and a golden set built six months ago won’t reflect what users are asking today. Add newly discovered failures back into the set the same week you find them, before you forget the exact conditions that caused them.

How Do You Score a Candidate Prompt?

Scoring is the piece that makes automated optimization possible instead of manual guesswork. You need a function that takes a prompt’s output and returns a number, consistently, across hundreds of runs. Two approaches cover most tasks.

Deterministic scoring works when your task has a checkable answer: exact match, JSON schema validity, a regex pattern, or a computed metric like ROUGE against a reference string. It’s fast, cheap, and produces the same score every time you run it, which makes debugging the optimizer itself much easier.

LLM-as-judge scoring covers everything deterministic scoring can’t reach: open-ended writing, summarization quality, tone, or faithfulness to a source document. You write a rubric, hand it to a judge model alongside the candidate output, and the judge returns a score with reasoning. Run the judge at a low temperature and give it explicit criteria, or its scores will drift between runs.

Scoring approachBest forCost per runConsistency
Exact match / regexStructured extraction, classificationNear zeroPerfect
Schema validationJSON or function-call outputsNear zeroPerfect
Reference metric (ROUGE, embedding similarity)Summarization with a gold referenceLowHigh
LLM-as-judge with rubricOpen-ended writing, tone, faithfulnessModerate to highDepends on rubric clarity

Whichever scorer you pick, test it against a handful of outputs you’ve already judged by hand first. If the scorer disagrees with your own judgment on obvious cases, fix the scorer before you touch the optimizer, because every downstream decision depends on that number being trustworthy.

Step 2: Generate Candidate Prompts

With a golden set and a scorer in place, the next piece is candidate generation: producing new prompt variants worth testing. Three approaches cover most real builds, and you can mix them inside the same loop.

The simplest is instruction rewriting: feed a stronger model your current prompt plus a sample of its failing outputs, and ask it to propose a revised instruction that would have avoided those specific failures. This is the meta-prompt approach behind methods like ProTeGi, which frames the failing examples as a “textual gradient” the rewriting model edits against, and it works because the rewriting model gets concrete evidence instead of guessing blind.

A second approach is few-shot selection: instead of rewriting the instruction, you search over which examples to include as few-shot demonstrations inside the prompt. This is the mechanism behind DSPy’s MIPRO optimizer, and it matters more than people expect, since swapping which three examples you show a model can shift accuracy as much as rewording the instruction itself.

A third approach is mutation-based search: take the current best prompt, apply small structural edits (reorder sections, adjust constraint phrasing, vary output format instructions), and test each mutation independently. This is closer to genetic search, in the spirit of GEPA’s Pareto-based evolutionary optimization, and works well once you already have a reasonably strong starting prompt and want incremental gains.

Generate three to eight candidates per round rather than one. A single new prompt gives you one data point; a small batch lets your selection step actually compare and lets you separate real improvement from lucky variance on a handful of examples.

Keep a record of why each candidate was generated, not just its score. A candidate that came from rewriting around three specific failures tells you something different than one that came from a random structural mutation, and that context matters later when you’re deciding which generation strategy to lean on for the next round.

Step 3: Selection, Mutation, and the Loop Itself

Once a round produces scored candidates, selection decides what happens next. Keep the top one or two performers, discard the rest, and feed the survivors back into candidate generation for another round. This is the part that turns a single test into an actual search.

A basic loop looks like this: score the seed prompt on the golden set, generate a batch of candidates, score every candidate on the same golden set, keep the best scorer if it beats the current champion, then repeat with the new champion as the seed. Stop when the score plateaus across two consecutive rounds.

For tasks with a single, well-defined metric, keeping only the top scorer each round is fine. For tasks balancing multiple objectives at once (faithfulness and brevity, for example), keep several candidates that each lead on a different dimension instead of collapsing everything into one averaged number too early. That’s the same logic behind Pareto-style evolutionary search: a prompt that’s best on faithfulness and one that’s best on conciseness can both survive a round.

Loop elementPurposeTypical setting
Candidates per roundGive selection something to compare3–8
Rounds before convergence checkLet the score trend stabilize2 consecutive plateaued rounds
Champion carryoverPrevent losing prior gainsAlways keep best-so-far as fallback
Validation check frequencyCatch overfitting earlyEvery round, on held-out split

Log every candidate, its score, and the round it came from. When a later round underperforms an earlier champion, that log is the only way to tell whether the regression came from the golden set, the scorer, or a genuinely worse prompt.

Stripped to its mechanics, the loop is a few dozen lines. This is the skeleton, not a production implementation, but every piece above maps directly onto a function call here:

def optimize(seed_prompt, golden_set, score_fn, generate_candidates_fn, rounds=8):
    champion = {"prompt": seed_prompt, "score": score_fn(seed_prompt, golden_set)}
    history = [champion]
    plateau_count = 0

    for round_num in range(rounds):
        candidates = generate_candidates_fn(champion["prompt"], golden_set, n=5)
        scored = [{"prompt": c, "score": score_fn(c, golden_set)} for c in candidates]
        best = max(scored, key=lambda c: c["score"])

        if best["score"] > champion["score"]:
            champion = best
            plateau_count = 0
        else:
            plateau_count += 1

        history.append(champion)
        if plateau_count >= 2:
            break  # converged: two consecutive rounds with no gain

    return champion, history

score_fn is whichever scorer you chose in the section above; generate_candidates_fn is one of the three approaches from Step 2 (or a mix). Everything else in the loop, champion carryover, plateau detection, per-round logging, is exactly what’s in the table above, translated into code.

A short worked example makes this concrete. Say your seed prompt scores 0.61 on a summarization golden set using an embedding-similarity metric. Round one produces five candidates, three from instruction rewriting and two from few-shot selection, and the best scores 0.68. That candidate becomes the new seed, round two mutates it into four variants, and the best of those scores 0.70. Round three produces nothing above 0.70, so you’ve converged.

Score progression across three optimization rounds, plateauing at 0.70

Step 4: Convergence Checks and Knowing When to Stop

Convergence isn’t a fixed round count, it’s a signal from the data. Track the champion’s score across rounds and stop once it plateaus: two or three consecutive rounds without a meaningful gain is a reasonable default threshold for most tasks.

Running past convergence doesn’t help. Once the golden-set score stops moving, additional rounds mostly search around noise, and the risk of drifting toward a prompt that games the specific examples in your golden set goes up, not down. Treat a plateau as a stop signal, not a reason to try harder.

Before you promote a converged prompt to production, run it against the held-out validation split you set aside in step one. If the validation score tracks the training score closely, the gain is real. If validation lags well behind training, the optimizer overfit the golden set and you need to either grow the set or tighten the scorer before trusting the result.

Failure Modes Nobody Talks About

Most optimizer writeups stop at “it converged, ship it.” Three failure modes show up consistently once you run this in production, and catching them early saves you from a prompt that looks great on paper and breaks on real traffic.

Three prompt optimizer failure modes: overfitting, reward hacking, and model drift

Overfitting to a small golden set is the most common one. A thirty-example set with narrow coverage lets the optimizer find a prompt tuned to those exact phrasings rather than the underlying task. The fix is the held-out split from step one, checked every round, not just at the end. If validation and training scores diverge by more than a few points, stop and grow the set before trusting the champion.

Reward hacking the metric is the sneakier failure. If your scorer rewards length, the optimizer finds a prompt that pads every answer with filler. If it rewards keyword presence, the optimizer learns to stuff keywords regardless of whether they’re relevant. Watch for candidates that spike the score without an obvious quality improvement in the actual output, and spot-check the top scorer by hand every round rather than trusting the number alone.

Prompt drift across model versions is the one that breaks things weeks after you’ve stopped looking. A prompt optimized against one model checkpoint can quietly underperform after a silent model update, since the phrasing that worked for the old version’s quirks doesn’t transfer cleanly. Re-run your golden set against the live prompt on a schedule, not just at optimization time, so a silent regression shows up before a customer finds it. Treat that scheduled re-run the same way you’d treat a regression test suite in ordinary software.

Future AGI

Everything above is buildable with a spreadsheet, a scoring script, and any LLM API, and it’s worth building yourself once to understand the mechanics. Once that loop needs to run continuously against production traffic instead of a one-off test, the parts you’d have to build yourself, tracing, custom evals, and a search algorithm library, start to add real engineering weight.

Future AGI’s Prompt Optimize module, built on the open-source agent-opt SDK, runs the exact loop this guide describes: candidate generation, scoring against your dataset with a custom eval or an LLM judge, and iterative selection, across six search algorithms including Bayesian search, GEPA, and ProTeGi. You score candidates with a custom eval built from your own rubric or a template from the platform, and every optimization run gets traced the same way production requests do, so a converged prompt’s behavior stays visible after deployment instead of disappearing into a one-off script.

The practical split holds either way: you frame the task and define what a good answer looks like, and the search does the rewriting. Whether that search runs in your own script or inside a platform that also traces and gates the result before it ships is a build-versus-buy call, not a different loop.

That distinction is worth sitting with before you decide. A hand-rolled loop is the right call while you’re still learning what your task’s failure modes actually look like. A platform earns its keep once the loop needs to run on a schedule, survive model version changes, and stay auditable for a team that isn’t the one who wrote it.

Conclusion

A prompt optimizer is four repeatable steps: a golden set that reflects real inputs, a scoring function you trust, a way to generate new candidates, and a selection process with a real stopping point. None of that requires a specific vendor or framework, and building it once will teach you more about your prompt’s actual failure modes than another week of manual editing.

The parts that separate a working optimizer from a fragile one aren’t the search algorithm, they’re the discipline around it: a held-out validation split you actually check, a scorer you’ve sanity-tested against your own judgment, and a habit of re-running the golden set after model updates. Get those three right and the rest of the loop is mechanical.

Frequently Asked Questions

What is a prompt optimizer?

A prompt optimizer is a search loop that generates candidate prompt rewrites, scores each one against a test set with a metric or judge, and keeps the best performers across several rounds instead of editing prompts by hand.

Do I need a large dataset to build a prompt optimizer?

No. A golden set of 30 to 80 representative, labeled examples is enough to start. Quality and coverage of edge cases matter more than raw example count for early rounds.

What causes a prompt optimizer to overfit?

A golden set that's too small or too narrow lets the optimizer find a prompt that scores well on those exact examples but fails on new inputs. A held-out validation split catches this before deployment.

Can I build a prompt optimizer without an LLM-as-judge?

Yes, if your task has a deterministic answer like exact match or schema validity. Open-ended tasks like summarization usually need an LLM judge with a written rubric, since no fixed string comparison captures quality.

How many rounds does a prompt optimization loop usually need?

Most tasks converge within 3 to 8 rounds once the score plateaus across two consecutive rounds. Running past that point risks overfitting the golden set rather than improving real performance.
Related Articles
View all