Menu

Prompt Iteration: How to Test and Improve a Prompt

Improving a prompt works best as a small experiment: decide what a good answer looks like, keep a few fixed test inputs, change one thing at a time and compare the outputs side by side.

Every prompt below is editable: change it, then open it in ChatGPT, Claude or another AI app.

The first version of a prompt is a draft. It often gets you something close to what you want, and the gap between close and right is closed by iterating: changing the prompt on purpose, running it again on the same input, and checking whether the change helped. Done carelessly, iterating turns into rewording at random until one lucky output looks fine. Done as a small experiment, it gives you a prompt that works on the next hundred inputs, not just the one you tested.

The method has five steps: define what good looks like, keep fixed test inputs, change one thing at a time, compare outputs, and know when to stop.

Define what a good answer looks like

Before you edit anything, write down what the output must do, as checks you can answer yes or no. "A good commit message" cannot be checked. These can:

  1. The subject line is under 50 characters.
  2. It follows the Conventional Commits format (fix:, feat: and so on).
  3. The body says why the change was needed, not what the diff already shows.
  4. It mentions the issue number when there is one.

Criteria do two jobs. They tell you what to add to the prompt, since each one is often a missing instruction. And they stop you from judging outputs by how pleasant they sound, which is the easiest way to accept a confident but wrong answer.

Keep a small set of test inputs

Pick three to ten inputs and keep them fixed while you work. Include typical cases, a couple of awkward ones (an empty field, a very long input, a language the prompt did not expect), and every input that has failed before. A prompt tuned on a single example tends to fit that example and fail on the next one.

Write the prompt as a template with a slot for the input, so every version runs on exactly the same material.

Change one thing at a time

When you change the role, the format and the examples together and the output improves, you do not know which change did it, and you may be keeping two useless edits. Change one thing, run it, compare. The tabs below are three versions of one prompt, each a single change from the last.

Write a commit message for this diff.- if len(password) > 8: + if len(password) >= 8: return True
Try it
Example replyReplies vary between models and runs.

Update password length validation

This commit updates the password validation logic by changing the comparison operator from > to >=. As a result, passwords that are exactly 8 characters long will now be considered valid. This change improves the accuracy of the validation and provides a better experience for users creating accounts.

Version 1 fails criteria 2 and 3: the subject has no type prefix, and the body retells the diff in more words. Version 2 adds the format requirements and passes criteria 1 and 2, but its body still describes the diff. The obvious next edit is another instruction ("explain why"), but the model cannot explain a reason it was never given. Version 3 adds the missing context instead, and the body and the issue reference follow without being asked. That is the most common lesson of iterating: when an instruction does not fix an output, the prompt is usually missing information, not emphasis.

Compare outputs side by side

Run every version on every test input, and run each more than once, because chat models sample their words and two runs of the same prompt differ. Put the outputs next to each other and check them against your criteria, not against your memory of the last run.

For criteria that are precise, a second model call can do the first pass of grading. Paste the outputs into a grading prompt with the criteria spelled out:

Grade outputs against fixed criteria
Fill in
Check each output below against the criteria. For every criterion, answer pass or fail with a short reason that quotes the output. Judge only the listed criteria. Do not reward length or style. Criteria: 1. Subject line under 50 characters. 2. Follows Conventional Commits. 3. Body says why the change was needed, not what the diff shows. 4. Mentions the issue number. Output A: """ fix: accept passwords of exactly 8 characters Change the length check from > to >= so that passwords with exactly 8 characters pass validation. """ Output B: """ fix: accept passwords of exactly 8 characters The signup page asks for at least 8 characters, but the check rejected passwords of exactly that length, so users who followed the instructions could not sign up. Fixes #412 """ Answer as a table with one row per criterion.
Try it
Example replyReplies vary between models and runs.
CriterionOutput AOutput B
1. Subject under 50 charactersPass: the subject is 45 charactersPass: same subject, 45 characters
2. Conventional CommitsPass: starts with "fix:"Pass: starts with "fix:"
3. Body explains whyFail: "Change the length check from > to >=" restates the diffPass: "users who followed the instructions could not sign up"
4. Mentions the issueFail: no issue numberPass: "Fixes #412"

Treat a model grader as an assistant, not a referee. Zheng et al. 2023, "Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena", documented biases in model judges, including a preference for longer answers and for the answer in a particular position. Keep criteria checkable, ask for quoted evidence, swap the order of A and B when you compare two, and read a sample of the outputs yourself. Checks such as character counts are more reliable as a line of code than as a model's judgement.

Fix the prompt, not the conversation

In a chat it is tempting to correct the answer with follow-ups: "shorter", "no, mention the issue", "use the other format". That gets you one good output and leaves the prompt as bad as it was. When a correction works, move it into the prompt and run the prompt fresh. The next time you need the result, you paste one message instead of repeating five.

Keep old versions with a one-line note of what changed and what it fixed. A plain text file is enough. When a later edit makes things worse, you can go back instead of trying to remember what the prompt used to say.

Running a comparison in code

Once a prompt runs through an API, a short script can produce the side-by-side view for every version and every test input. This one uses the OpenAI Python SDK and writes a markdown file you can read top to bottom.

from openai import OpenAI

client = OpenAI()
MODEL = "your-model-id"  # e.g. from your provider's model list

# each prompt file contains {input} where the test diff goes
PROMPTS = {
    "v2": open("prompts/commit_v2.txt").read(),
    "v3": open("prompts/commit_v3.txt").read(),
}
TESTS = [open(f"tests/diff_{i}.txt").read() for i in range(1, 6)]

with open("results.md", "w") as out:
    for i, test in enumerate(TESTS, 1):
        out.write(f"## Test {i}\n\n")
        for name, template in PROMPTS.items():
            for run in (1, 2):
                response = client.chat.completions.create(
                    model=MODEL,
                    messages=[{"role": "user", "content": template.replace("{input}", test)}],
                )
                out.write(f"### {name}, run {run}\n\n{response.choices[0].message.content}\n\n")

When to stop

Stop when every criterion passes on every test input across a couple of runs. Adding more after that mostly adds length, and every extra instruction is one more thing that can conflict with the others.

Also stop when changes start trading failures: one edit fixes test 2 and breaks test 4, the next reverses it. That pattern means the prompt is being asked to do something a single instruction cannot pin down. The usual ways out are to show the format with a couple of examples (few-shot prompting), to split the job into steps with prompt chaining, or to move the deterministic parts, such as counting characters or checking a format, into code that checks the output. If you are stuck for ideas, meta prompting can help: give a model the prompt, the input and the bad output, and ask which part of the prompt most likely caused it.

Frequently Asked Questions

How do I improve a prompt that gives bad answers?

Look at the bad answer and name what is wrong with it: wrong format, missing fact, wrong audience, too long. Then find what the prompt failed to say that would have prevented it, add that one thing, and run the new version on the same input. Bad answers more often come from missing context or a missing format instruction than from wording.

How many test inputs do I need to test a prompt?

For a prompt you will reuse, three to ten is usually enough: a few typical cases, one or two edge cases (very short, very long, unusual) and one input that previously went wrong. Keep them fixed while you iterate, so a change in the output comes from the prompt and not from a different input.

Why do I get a different answer when I run the same prompt again?

Chat models sample each word from a probability distribution, so outputs vary between runs. When you compare two prompt versions, run each more than once on the same inputs. A difference that shows up in every run is probably real; one that appears in a single run may be chance. Through an API you can also lower the temperature to reduce the variation.

Can I use AI to grade my prompt's outputs?

Yes, for criteria you can state precisely, such as "the body says why the change was needed" or "mentions the issue number". Give the grader your exact criteria and ask for pass or fail per criterion with a quote as evidence. Model graders have known biases, including favouring longer answers and favouring one position over the other, so read some outputs yourself and swap the order when you compare two.

When should I stop improving a prompt?

Stop when every criterion passes on every test input across a couple of runs, or when each new change fixes one case and breaks another. At that point the prompt is usually not the problem: the task may need examples, to be split into steps, or a check in code.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED