The iteration loop: from feedback to prompt changes
Turn production feedback into measured improvements by finding failure patterns, changing prompts or design, verifying with evals and shipping safely.
On this page
Why this matters
Launch is where learning starts. Real users find failure modes no eval anticipated, ask for things the spec didn’t cover, and use the feature in ways that change what “good” means. An AI feature that isn’t iterated on doesn’t stay the same: as users and inputs drift, it slowly gets worse.
The teams that keep AI features improving don’t rely on bursts of heroic prompt tweaking. They run a steady loop: find the most common failure, fix it at the right layer, prove the fix with evals, ship it gradually, record what happened. This article puts together everything from this stage into that loop.
The loop
Show text descriptionHide text description
A sequence of 5 steps that loops back to the start.
- Find a pattern : From traces, edits, retries, thumbs and tickets
- Add eval cases : Capture the failure before fixing it
- Choose the fix : Prompt, context, model, UX or scope
- Verify : The new cases pass and nothing else broke
- Ship and record : Behind a flag; log the change and its result
After the last step, the process starts again at step 1.
A cycle can take a day or two. Running one per week, consistently, compounds into large improvements over a quarter.
Finding patterns in failures
Start from the signals you already collect:
- Feedback: heavy edits, quick retries and thumbs-down with reasons, from capturing feedback.
- Traces: errors, refusals, truncations and surprising inputs, from tracing.
- Support tickets and user comments about the feature.
Read a sample, tag each failure with a cause, and count. Pick the most common pattern that matters to users, not the most interesting one. “Drafts include an apology even when the customer didn’t report a problem” in 12% of heavy edits beats a fascinating edge case seen twice.
Add eval cases first
Before changing anything, turn the pattern into eval cases: real examples of the failure, with criteria describing what the user wanted. Then run the current version against them and confirm they fail.
This order matters for three reasons:
- It proves you understand the failure. If you can’t write a case that reproduces it, you don’t understand it yet.
- It makes the fix measurable. “Fixed 9 of 10 apology cases” is a result; “the prompt feels better” isn’t.
- It prevents the failure from returning. The cases stay in the golden dataset and the CI suite.
Choosing the fix
Prompt changes are the obvious lever, but not always the right one. Match the fix to the cause:
| Cause | Typical fix | Example |
|---|---|---|
| Unclear or missing instruction | Prompt change | Add “Apologize only if the customer reports a problem” |
| Missing information | Context change | Include the order status the model kept guessing |
| Task too hard at this setting | Model or effort change | Raise effort for the “complex billing” category |
| Users misunderstand what it does | UX change | Clearer entry point label; show sources |
| The request shouldn’t be handled | Scope change | Route legal questions to a human |
Prefer general fixes over special cases. A prompt that grows a new “if the customer mentions X, do Y” rule for every failure becomes brittle and contradictory. If you find yourself writing special cases, step back and ask what general principle they share.
Verifying before shipping
A change is ready when two things are true: the new cases pass, and nothing that used to pass now fails. Overall pass rates can hide the second. A change that fixes five cases and breaks five others has the same score as no change at all.
Compare runs case by case:
/** One eval run: which cases passed. Produced by your suite runner for each prompt version. */
type Run = Record<string, boolean>;
/** Case-by-case comparison of two runs: what got fixed, what broke, and the net change. */
export function compareRuns(before: Run, after: Run) {
const ids = [...new Set([...Object.keys(before), ...Object.keys(after)])].sort();
const fixed = ids.filter((id) => before[id] === false && after[id] === true);
const broken = ids.filter((id) => before[id] === true && after[id] === false);
const added = ids.filter((id) => !(id in before));
const passRate = (run: Run) => Object.values(run).filter(Boolean).length / Object.values(run).length;
return { fixed, broken, added, before: passRate(before), after: passRate(after) };
}
const v4: Run = { 'apology-1': false, 'apology-2': false, 'refund-1': true, 'export-1': true, 'tone-1': true };
const v5: Run = { 'apology-1': true, 'apology-2': true, 'refund-1': true, 'export-1': false, 'tone-1': true, 'apology-3': true };
const diff = compareRuns(v4, v5);
console.log(`Pass rate ${(diff.before * 100).toFixed(0)}% → ${(diff.after * 100).toFixed(0)}%`);
console.log(`Fixed: ${diff.fixed.join(', ') || 'none'}`);
console.log(`Broken: ${diff.broken.join(', ') || 'none'}`); // export-1: investigate before shipping
console.log(`New cases: ${diff.added.join(', ') || 'none'}`); The overall pass rate went up, but export-1 broke. Read that output before shipping: the fix for apologies might have shortened replies enough to drop the export instructions. Either refine the change until nothing breaks, or decide explicitly that the trade-off is worth it and record why.
Then ship the change behind a flag, roll it out gradually, and check that the production signal that started the cycle improves: fewer heavy edits mentioning apologies, in this example.
Keeping a change log
Record every change in one place, next to the prompts themselves. Each entry:
## reply-v5 (2026-10-17)
- Pattern: unnecessary apologies in 12% of heavily edited drafts (week of 6 Oct).
- Change: "Apologize only if the customer reports a problem or a delay."
- Evals: apology cases 0/3 → 3/3; export-1 broke and was fixed in v5.1; overall 82% → 88%.
- Rollout: 10% from 14 Oct, 100% from 17 Oct.
- Result: heavy edits mentioning apologies fell from 12% to 3% of heavy edits. A change log turns iteration from tribal knowledge into a record. It answers “why does the prompt say this?” months later, prevents someone from reverting a deliberate change, and becomes the raw material for your case studies.
Common mistakes
- Fixing without eval cases. Capture the failure as cases first, so the fix is measurable and the failure can’t quietly return.
- Chasing interesting edge cases. Fix the most common pattern that matters to users first.
- Trusting the overall pass rate. Compare runs case by case; fixes often break something else.
- Special-case prompt rules. Look for the general principle behind repeated failures.
- No change log. Without a record, nobody knows why the prompt says what it says.
Try it
Exercise
About half a day
Run one full iteration loop on a feature
- Pick the most common failure pattern from your feedback or traces.
- Write at least three eval cases that reproduce it, and confirm they fail on the current version.
- Choose the fix at the right layer and implement it.
- Run the full suite, compare case by case, resolve anything that broke, and write a change log entry.
Show a hint
If your fix works on the new cases but breaks old ones, try a narrower wording first. Most breakage comes from instructions that are broader than the problem they solve.
Show a worked solution
A complete cycle produces:
- A tagged sample of failures and the chosen pattern, with its share of failures.
- Three or more new eval cases that failed before the change and pass after.
- A case-by-case comparison showing nothing else broke, or an explicit, recorded trade-off.
- A change log entry with pattern, change, eval results, rollout dates and, after a week, the production result.
Check your understanding
Key takeaways
- Run a steady loop: find a pattern, add eval cases, choose the fix, verify, ship and record.
- Fix the most common failure that matters, at the right layer: prompt, context, model, UX or scope.
- Compare runs case by case so a fix can’t quietly break something else.
- Keep a change log next to the prompts.
Progress is saved in this browser and lights up the roadmap.
Related articles
- Capturing feedback: thumbs, edits and retries Collect useful feedback on AI output, from explicit ratings to implicit signals in edits and retries, and turn both into improvements. Level: Advanced
- Regression eval suites in CI Run evals in CI so prompt and model changes can't silently make an AI feature worse, with thresholds, flakiness handling, cost control and reporting. Level: Advanced
- Feature flags and staged rollouts for AI Ship AI features gradually with feature flags, covering staged exposure, kill switches, flagging prompts and models, and rollback plans that work in minutes. Level: Advanced