Skip to content
AI Product Engineer Wiki

    ↑ ↓ to move between results, Enter to open, Esc to close

    Menu

    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.

    Level: Advanced 8 min read Updated
    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

    The iteration loop. One pattern per cycle, measured before and after.
    Show text descriptionHide text description

    A sequence of 5 steps that loops back to the start.

    1. Find a pattern : From traces, edits, retries, thumbs and tickets
    2. Add eval cases : Capture the failure before fixing it
    3. Choose the fix : Prompt, context, model, UX or scope
    4. Verify : The new cases pass and nothing else broke
    5. 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:

    evals/compare-runs.ts
    /** 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:

    prompts/CHANGELOG.md
    ## 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

    1. Pick the most common failure pattern from your feedback or traces.
    2. Write at least three eval cases that reproduce it, and confirm they fail on the current version.
    3. Choose the fix at the right layer and implement it.
    4. 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

    Question 1 of 4: Why add eval cases before changing the prompt?

    Show answer

    B. To prove you understand the failure, make the fix measurable and stop it returning

    Cases that fail before and pass after are the evidence that the fix worked.

    Question 2 of 4: Users ignore the feature because they think it only works for English. What kind of fix fits?

    Show answer

    C. A UX change that clarifies what it supports

    The problem is understanding, not output quality; fix it in the experience.

    Question 3 of 4: Version B has the same overall pass rate as version A. What could still be wrong?

    Show answer

    B. B might fix some cases and break others; compare case by case

    Equal scores can hide a swap of fixed and broken cases.

    Question 4 of 4: What belongs in a prompt change log entry?

    Show answer

    B. The pattern, the change, eval results, rollout dates and the production result

    The entry should explain why the change was made, how it was verified and what it achieved.

    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.