AI Briefing/Blog
prompt evals·October 1, 2026·7 min read

Prompt evals: how Rechat's Lucy stalled, and how to know a prompt change helped

Part 3: golden sets, LLM-as-judge, pairwise comparison and regression on real traffic. The Lucy case, plus a promptfoo config to paste.

  1. 01Every user complaint becomes a test case before anyone touches the prompt
  2. 02Code assertions first, LLM-as-judge only for what code can't check
  3. 03Run the old prompt against the new one on the same set, with --repeat 3

89% of organizations have observability on their agents. 52% run offline evals on a test set. Only 37% run evals on real traffic. The numbers come from LangChain’s State of Agent Engineering survey, published in June 2026. Put in standup terms: almost everyone can see what the model is doing, and fewer than half can say whether today’s prompt is better than yesterday’s.

In the previous part we built a system prompt in four blocks. This time we look at what happens after you change one line of it. The best-documented case I know on the subject is Lucy.

Lucy ran on prompts, and it worked

Rechat is a SaaS for real estate agents: contracts, property search, meetings, marketing materials. Lucy is their assistant, a chat interface that replaces all the clicks and forms. Hamel Husain, who led CodeSearchNet at GitHub (one of the precursors of Copilot), worked with them and published the case on March 29, 2024, in the post Your AI Product Needs Evals.

At first everything moved fast. Prompt engineering alone delivered improvement after improvement. New feature? Another paragraph in the prompt, a few questions in the chat, looks good, deploy. Every team that built an assistant two years ago knows this rhythm.

When the curve went flat

As Lucy gained more capabilities, performance stalled. Hamel describes three symptoms, and I think most of you will recognize at least two:

From the outside this doesn’t look like an incident. No outage, no 500s in the logs, no alert. Just a different complaint every week, and every week someone fixes it. That’s the most dangerous kind of regression, because it has no timestamp.

How the mechanism works
How the mechanism works
Four versions, four fixes, the same 4 out of 5. Without a fixed set you only see the cell you fixed (Hamel Husain on Lucy)
Four versions, four fixes, the same 4 out of 5. Without a fixed set you only see the cell you fixed (Hamel Husain on Lucy)

The first fix: one more line in the prompt

This is the intuitive fix, and it’s the wrong one. Lucy showed the user an internal ID from the DB? Add “never display IDs”. Property search returns junk on a vague question? Add an example. Each line like that gets tested on the case that caused it, and only on that case.

Wait, why is that a problem? Because a prompt has no scope. A line you wrote for property search also changes how the model phrases a contract summary. Without a fixed set that runs on every change, you see exactly one cell in the table: the one you looked at. Everything else shifts quietly.

The real cause: nothing to run

Hamel opens the post with a sentence I come back to in every conversation on this:

I’ve found that unsuccessful products almost always share a common root cause: a failure to create robust evaluation systems.

— Hamel Husain, Your AI Product Needs Evals

The prompt’s wording wasn’t the problem. Measurement was missing. Every decision about the prompt rested on five questions someone typed that morning. And that’s exactly the situation LangChain’s survey describes two years later: teams see traces, but they don’t judge them.

Rechat isn't an outlier: almost everyone sees traces, and only about a third judge what happens in production (LangChain, State of Agent Engineering)
Rechat isn’t an outlier: almost everyone sees traces, and only about a third judge what happens in production (LangChain, State of Agent Engineering)

What Rechat built, in three levels

Roughly, three layers, from cheap to expensive.

Level 1, unit tests. Assertions in code, no model. No UUID in the response. Search never runs with an empty query. The number of properties in the answer matches what the tool returned. They run on every change, and results are kept over time so you see a trend, not just pass/fail. Some of the test cases they generated with an LLM, per feature.

Level 2, traces and LLM-as-judge. Log every conversation, read them yourself, and write a judge for the things code can’t check. Hamel insists on one point: measure how often the judge agrees with a human, and don’t trust it before that.

Level 3, A/B. Only once the first two levels are stable do you test on real users.

My take: I don’t trust a judge that hasn’t been checked against at least 50 human-graded answers. An uncalibrated judge tends to like long, polite answers, which is the opposite of what a real estate agent needs in the middle of the day.

The grader was also written by a person, and it can be wrong. In January 2026 Anthropic described how Opus 4.5 “failed” a τ2-bench task because it found a loophole in the airline’s policy and gave the customer a better solution than the eval expected. When the eval says fail, read the transcript before you touch the prompt.

The order is the point: cheap assertions first, the judge next, A/B last. Start with A/B and you're measuring noise (credit: hamel.dev)
The order is the point: cheap assertions first, the judge next, A/B last. Start with A/B and you’re measuring noise (credit: hamel.dev)

What to check this week

Okay, enough story. This is the minimum to avoid becoming Lucy, using promptfoo (open source, runs locally, has a GitHub Action for CI):

  1. A golden set of 30–50 cases. From the logs, not from your head. Every user complaint goes into the set before you fix it.
  2. Code first. Whatever a regex or a JSON schema can check doesn’t go to the judge. Cheap, deterministic, doesn’t argue.
  3. A judge with a narrow rubric. One sentence that checks one thing. Not “is the answer good”.
  4. Pairwise comparison. The current prompt against the candidate, on the same inputs. A 7 versus a 7.5 doesn’t say much. “Which of the two is better” does.
  5. Regression on real traffic. Once a week, pull 20 traces from production (Braintrust, LangSmith, or just a log) and add whatever looks odd to the set.
promptfooconfig.yaml
description: prompt regression, current vs candidate
prompts:
- file://prompts/current.txt
- file://prompts/candidate.txt
providers:
- id: anthropic:messages:claude-sonnet-5-5 # replace with the model ID you run in production
config:
temperature: 0
defaultTest:
options:
provider: anthropic:messages:claude-opus-5-5 # the judge: a stronger model than the one under test
assert:
- type: not-regex
value: '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
- type: javascript
value: 'output.length < 1500'
- type: llm-rubric
value: Does not mention a property, price or address that did not appear in the context
- type: select-best
value: Which answer moves the agent to the next task in fewer messages
tests: file://golden.csv

Both prompt files use {{question}}, and the CSV holds a single column with that name:

golden.csv
question
Find me a 4-room apartment in Ramat Gan under 3 million
Schedule a meeting with yesterday's buyer
How much commission do I get on the Bialik Street deal
run.sh
npx promptfoo@latest eval -c promptfooconfig.yaml --repeat 3 --no-cache -o results.json
npx promptfoo@latest view

The --repeat 3 isn’t decoration. The same input doesn’t return the same answer, and a test that passes 2 out of 3 times is flaky, not green. select-best is the pairwise comparison: the judge sees both versions side by side and picks one. If the candidate doesn’t win or at least tie in most cases, it doesn’t ship.

And if you only have time for one item, do the first. Lucy didn’t stall because the prompt was bad. It stalled because every fix was tested on one case, and a complaint that never became a test comes back in the next version.

Sources

  1. Intro | Promptfoo
  2. Get started with Braintrust - Braintrust
  3. Your AI Product Needs Evals
  4. Evaluating AI Agents at the Run, Trace, and Thread Level
  5. Demystifying evals for AI agents \ Anthropic

How this was made: drafted by our agent from 5 sources, edited and approved by Koby Almog.

More terms

All terms →

89 tasks gone: what happened to SWE-Bench Pro, and what to check in your eval

Scale AI pulled 89 tasks from SWE-Bench Pro after agents were caught reading answers from git history. What happened, and what to check in your eval.

Same engineering: same tasks, a different score, and no model changed

DeepSWE v1.1 changed only execution and grading, and tasks moved 36 points. How to measure this yourself without mistaking noise for progress.

Small coding: a code agent with a local model, a one-file task, and a loop that checks itself

How to build a small coding agent on Ollama: a task with a verify command, a 50-line harness, trimmed context, and when to hand off to a big model.