Trail content
7 minEnglish narration, Portuguese subtitlesPodcast (RSS)
Chapters
  1. 0:00Opening
  2. 1:00The diagnosis
  3. 1:55Why it happens
  4. 2:41What it costs
  5. 3:43A challenge
  6. 4:37The treatment
  7. 5:47Close relatives
  8. 6:32When to ignore
  9. 6:54Wrap-up
Transcript

Opening

The pull request that changed the invoice extractor had one line. Extract the invoice total became: extract the invoice total, with two decimal places.

The description said: format tweak, tested on three invoices. The reviewer approved it. The change looked harmless.

A week later, accuracy on the total field for discounted invoices had dropped. And nobody knew since when, or by how much. Because there was no number from before to compare against.

Here's what happened. The three test invoices were the ones that motivated the change. Round totals, no discount.

To force two decimal places, the model started combining the goods value and the discount.

And the total came out wrong, on exactly the invoices the team never looked at. In this lesson, you'll learn to recognize this smell, and the order of work that removes it.

The diagnosis

The cycle looks like this. Someone changes the prompt to fix one case.

They test with the few examples they have on hand.

The change ships, with no comparison against the previous version.

The effect shows up on cases nobody tested.

And users discover the regression. Late, and with no data.

How do you spot it? Prompt changes go through code review as if they were text, with no results attached.

The test for a change is: I ran a few examples, and it looked fine.

There's no set of cases with expected answers stored in the repository.

Nobody can state the system's current accuracy. Only that it works. And switching models keeps getting postponed, because nobody knows what will break.

And production bugs get fixed in the prompt, and never become test cases.

Why it happens

A prompt looks like text, not code. Changing a sentence doesn't feel like changing logic. But with a model, a sentence is logic. With two decimal places changed the total field.

Building a dataset is work. Collecting and labeling fifty cases seems expensive next to a one line change. The cost shows up later, in the silent regression.

Output varies. Not knowing how to test something that isn't deterministic, the team gives up on testing. But a grading rule, like comparing fields, covers most of it.

And the bug's cases become the only test. Whoever fixes a bug tests the case that broke. And nothing else.

What it costs

The first cost is the silent regression. Quality drops on part of the cases, and nobody notices until the cost shows up somewhere else. A wrong payment slip. Tax computed on the wrong total. A seller with a rejected invoice.

Then fear. With no safety net, the team avoids improving the prompt, or switching models, even when it would be cheaper.

Then endless debates. It got better, versus it got worse, with no number to settle it.

And bugs that come back. The error fixed in March returns in June, because nothing stops it.

And here's how the hole hides, with illustrative numbers. Two hundred invoices in the eval, six of them with a discount. The overall pass rate drops from ninety-seven to ninety-four percent. It looks like noise. But in the discount category, six out of six now fail. The average hid exactly the hole that finance is going to find.

A challenge

Here's one for you. You have no eval at all, and you need to fix an extractor that gets totals wrong, by tomorrow. What's the first step you still have time to do?

Label the fifteen invoices you already know break. Measure the current prompt on them. Then change it. Fifteen cases with expected answers already are an eval. Measuring first gives you the floor. And those fifteen go into the repository, and run on the pull request.

Shipping now and filing a card to add an eval next sprint doesn't work. The card sits behind the next fix. And asking a model to generate two hundred synthetic invoices as ground truth misses the crooked discount of a real one. Start with what already failed in production.

The treatment

The treatment is a refactoring called add eval before changing the prompt. And the order matters. It's the part teams invert most often.

First, store cases with expected answers. Start with production bugs, and a couple of dozen happy examples. Split them by category. With discount, missing line item, a rare tax code.

Measure the current version. That number is the floor. Without it, every it got better is just talk.

Change the prompt, or the model, on a branch.

Measure again. Look at the overall rate and the rate per category. A small category at zero is a regression, even if the average held still.

And the case that broke goes into the set. Otherwise it comes back.

And in your pipeline, the eval runs on every pull request that touches a prompt, a template, or a model. That last part matters. A team with a forty case eval that hasn't run in four months, with half the cases in an old format, still has this smell. An eval that doesn't run protects nothing.

Close relatives

Some close relatives. Before each deploy, someone asks the bot the same eight questions and eyeballs the answers. That's a ritual, not a measurement. It has its own name: vibe check eval.

A team runs two hundred cases on every change, but only looks at the overall rate. That's not this smell. The eval exists. It just needs results per category, and an alert when any of them drops.

And a production bug, total ignores discount, fixed in the prompt. The pull request passed a two hundred case eval that had no discounted invoice at all. It passed because it couldn't see the bug. Add the invoice that broke, and others like it.

When to ignore

When can you live without it? A prototype, in its first week. Before you know what the system should do, testing by hand is reasonable. Start the dataset when the first real user shows up.

And a personal script that summarizes your meetings can live without an eval. Once someone else depends on it, it can't.

Wrap-up

So here's the idea to take with you. With a model, a sentence is logic. Treat every prompt change like a code change. With stored cases, a number from before, a number from after, and the broken case added to the set. Then switching models becomes a measured decision, made in an afternoon.

In the next lesson, we'll do that refactoring step by step: add eval before changing the prompt. See you there.

SmellChange preventers

Untested Prompt

Prompt Sem Eval

Untested Prompt is an AI code smell, a sign of trouble in LLM systems, in the Change preventers group. The prompt changes in production with no test set to prove it did not get worse.

Element
13/37
Level
Beginner
Read
4 min
Updated
On this page 7
  1. 01Signs and symptoms
  2. 02Reasons
  3. 03Cost of ignoring
  4. 04Treatment
  5. 05Payoff
  6. 06When to ignore
  7. 07Is it this smell?
  8. ··Quick answers

Signs and symptoms

The pull request that changed the NF-e extractor (Brazilian electronic invoices) had one line:

-Extract the invoice total.
+Extract the invoice total, with two decimal places.

The description said “format tweak, tested on 3 invoices”. The reviewer approved it: the change looked harmless. A week later, accuracy on the total field for discounted invoices had dropped, and nobody knew since when or by how much, because there was no number from before to compare against.

The three test invoices were the three that motivated the change: round totals, no discount. The model started concatenating “goods value” and “discount” to force two decimal places, and total came out wrong on the invoices the team never looked at.

Signs of an Untested Prompt:

  • Prompt changes go through code review as if they were text, with no results attached.
  • The test for a change is “I ran a few examples and it looked fine”.
  • There is no set of cases with expected answers stored in the repository.
  • Nobody can state the system’s current accuracy, only that “it works”.
  • Switching models keeps getting postponed because nobody knows what will break.
  • Production bugs get fixed in the prompt and never become test cases.
flowchart LR
  C["1. Prompt change"]:::tool --> V(["2. Eyeball test with 3 examples"]):::llm
  V --> D["3. Deploy"]:::tool
  D --> P[("4. Production")]:::store
  P --> B(["5. Complaint weeks later"]):::io
  1. Someone changes the prompt to fix one case.
  2. They test with the few examples they have on hand.
  3. The change ships with no comparison against the previous version.
  4. The effect shows up on cases nobody tested.
  5. Users discover the regression, late and with no data.

An eval (a test for model output) does not need to be born large. It needs to exist before the change, with the expected answer written down, and to run again after.

Check +20 XP on first tryThe PR changes one sentence in the NF-e extractor. The author tested the 3 invoices that were failing, all passed, and asks for review. What should the reviewer require?

Reasons

  • A prompt looks like text, not code. Changing a sentence does not feel like changing logic. Code review treats the diff as style.
  • Building a dataset is work. Collecting and labeling 50 cases seems expensive next to a one-line change. The cost shows up later, in the silent regression.
  • Output varies. Not knowing how to test something nondeterministic, the team gives up on testing. Temperature 0 and a grading rule (field equality, or a judge with a rubric) cover most of it.
  • It worked last time. Earlier changes without an eval caused no visible problem, which does not mean they caused none.
  • The bug’s cases become the only test. Whoever fixes it tests the case that broke. That bias is the sibling of Vibe-Check Eval.

Cost of ignoring

  • Silent regressions. Quality drops on part of the cases and nobody notices until the cost shows up somewhere else: a wrong boleto (Brazilian payment slip), tax computed on the wrong total, a marketplace seller with a rejected NF-e.
  • Fear of change. With no safety net, the team avoids improving the prompt or switching models, even when it would be cheaper.
  • Endless debates. “It got better” versus “it got worse”, with no number to settle it.
  • Bugs that come back. The error fixed in March returns in June, because nothing stops it.

A count that shows the hole

The numbers below are illustrative. Suppose 200 invoices in the eval, 6 of them with a discount. Overall pass rate drops from 97% to 94%. It looks like noise. In the “with discount” category, 6 of 6 now fail. The average hid the hole finance will find.

Treatment

Refactoring Choose it when
Add Eval Before Changing the Prompt Always, before the next change. Build the dataset, measure the current version, and only then change it. Targets: Eval Harness and Golden Dataset.

Also read What an eval is if the concept is new to the team.

Order matters, and it is the part teams invert most often:

  1. Store cases with expected answers. Start with production bugs and a couple of dozen happy examples. Split by category: with discount, missing line item, rare CFOP code.
  2. Measure the current version. That number is the floor. Without it, every “it got better” is talk.
  3. Change the prompt (or the model) on a branch.
  4. Measure again. Look at the overall rate and the rate per category. A small category at zero is a regression, even if the average held still.
  5. The case that broke goes into the set. Otherwise it comes back.

In CI, the eval runs on every PR that touches a prompt, template, or model. A set that has not run in four months is the same as having no set.

Check +20 XP on first tryYou have no eval at all and must fix an extractor that gets totals wrong by tomorrow. What is the first step you still have time to do?

Payoff

  • Every prompt change comes with a before and after number.
  • Regressions show up in CI, not in production.
  • Switching models becomes a measured decision made in an afternoon.
  • Every fixed bug becomes a case that keeps it from coming back.

When to ignore

  • A prototype in its first week. Before you know what the system should do, testing by hand is reasonable. Start the dataset when the first real user shows up.
  • Low-risk internal use. A personal script that summarizes meetings can live without an eval. Once someone else depends on it, it cannot.

Is it this smell?

Check +20 XP on first tryThe team has a 40-case eval, but it has not run in four months and half the cases use an old output format. Prompt changes ship without running anything. Is this an Untested Prompt?

Check +20 XP on first tryBefore each deploy, someone on the team asks the bot the same 8 questions and eyeballs the answers. Is this an Untested Prompt?

Check +20 XP on first tryThe team runs an automatic 200-case eval on every change, but only looks at the overall pass rate. A rare category with 6 cases went from 100% to 0% and the overall rate barely moved. What is the problem?

Check +20 XP on first tryA production bug ('total ignores discount') was fixed in the prompt. The PR passed the 200-case eval, which had no discounted invoice. What is missing?

Quick answers

What is Untested Prompt?

Untested Prompt is an AI code smell, a sign of trouble in LLM systems, in the Change preventers group. The prompt changes in production with no test set to prove it did not get worse.

How do you fix Untested Prompt?

With Add Eval Before Changing the Prompt. Each refactoring has safe step-by-step mechanics with an eval before and after.

Where does Untested Prompt show up in practice?

In the real-world scenarios Invoice and contract extraction and Natural language to SQL.

Go further

Relations

Refactorings that treat it 1
Part of the tracks 1
Search