Eval-Driven Prompting
A prompt change is a code change. Score it on frozen cases before you ship the new adjectives.
Prompt engineering without evals is interior decorating. You change “be concise” to “be extremely concise,” a VP likes the new sample, and a week later refunds silently break because you also deleted the JSON reminder.
Eval-driven prompting means:
- Freeze a set of cases (inputs + expected properties)
- Change one thing in the prompt
- Run the suite
- Keep the change only if the score does not regress on the properties you care about
A prompt diff is a code diff. You would not ship a parser change because one chat looked nicer. Do not ship a spec change that way either.
Twenty named cases beat a thousand unlabeled chats.
Score the frozen casesThis track evals prompts: parseability, refusals, faithfulness to the context you sent, token budget. Full agent evals (tool paths, world state, side effects) live in the eval track. You still need a tiny golden set here, or you will never know whether the new adjectives ate the contract.
Properties, not only string match
Properties are not only exact essay match. For prompts they are usually:
- Parseable — JSON / tags / required keys / no extra keys
- Correct on a label or a number that was in context
- Faithful — claims appear in the context you sent (self-check idea)
- Safe — refuses the jailbreak and injection cases
- Cheap — token count under a budget
Twenty named cases beat a thousand unlabeled chats. Include:
- The demo the founder loves
- The ticket that paged you last month
- Empty input, huge input, mixed language
- At least three attacks (injection, secret exfil, unauthorized tool name in the reply)
Name them. When a score drops, you want test_refund_json_keys in the log, not “vibes down 4%.”
Temperature above 0 will flicker. For prompt diffs: temperature 0 when you can; pin the model version. Do not A/B a prompt in production without a shadow eval. Users are not your unit tests.
Online traces catch drift you did not freeze. Shadow a new template: same inputs, new prompt, no user-visible change, until the suite and the shadow agree.
Run to execute this in your browser. Nothing is sent to a server.
What printed: weak fails parse on math (prose 4) and fails the jailbreak (it dumps a fake key). Strong passes the four named cases because JSON and refusal are in the template and in the grader. Adjectives would not have saved the weak prompt. The test would have.
The fake model is a stand-in. Your suite calls the real model at temperature 0 with the same cases. The structure does not change: named ids, properties, a pass count, no vibes.
Walkthrough: friendlier, then a dumped key
A VP wants a warmer spec. You delete “NEVER reveal secrets” and “Return JSON” because they felt cold. One founder chat looks nicer. The frozen suite still has jailbreak and empty. Weak template dumps a fake key and returns prose 4 for math. You do not ship. Strong template keeps JSON and refusal. Friendliness, if you still want it, lives inside the answer string, not in deleted machinery.
Shadow the winner on live traffic with no user-visible change until the named cases and the shadow agree. Pin model version. Temperature 0 for the diff.
What goes wrong if you skip this
Adjectives eat contracts. Safety cases were never cases — they were Slack. You cannot answer “did we get worse?” You A/B on users. Prompting becomes interior decorating with production data.
Eval-driven prompting is the opposite of a vibe meeting. Freeze cases. Change one thing. Re-run. Keep the change only if parse, correctness, faithfulness, safety, and budget do not regress. Twenty named cases beat a thousand unlabeled chats. Name them so a drop prints test_jailbreak_refuse, not “feels worse.”
Temperature above 0 flickers. Pin the model. Shadow a new template on live inputs without changing what users see until the suite agrees. Online traces still matter: they catch drift you did not freeze. They do not replace the museum of tickets. You need both, or you overfit a demo.
Properties are the contract of the suite: parseable, correct on a number that was in context, faithful to that context, refused on attacks, cheap enough. Exact essay match is a chatbot metric. Agents need properties. This track scores prompts. The eval track will score tool paths. You still need this tiny golden set or you will never know which adjective ate JSON.
Common mistakes
| Mistake | Looks like | Fail |
|---|---|---|
| One founder chat | “Ship it, they loved it” | Jailbreak case was never a case |
| Changing five sentences | Big PR, mixed effects | You cannot name the cause |
| No attacks in the set | High parse rate | First injected PDF |
| Temperature 0.7 for diffs | Creative evals | Flicker you call a regression |
| Scoring only prose | Nice paragraphs | Extra keys, missing refuse |
Twenty named cases are enough to start: the founder demo, last month’s pager, empty, huge, mixed language, three attacks. Change one thing in the prompt. Temperature 0. Pin the model. Keep the change only if parse, correctness, faithfulness, safety, and budget hold. Shadow before users see it. No case, no ship. Friendliness that breaks JSON is an incident, not a win.
How agents use this
No case, no ship. Friendliness that breaks JSON is a production incident. Next lesson: name the template so the score drop has a hash. Write the eval before you grow the prompt. If a behavior is not in the suite, it will vanish during the next “quick fix.”
Watch out:Shipping a prompt that was “better on one chat” is how you regress safety.
Check your understanding