- Prompts aren’t static config recordsdata. Each instruction you add adjustments the behaviour of each question kind the immediate already handles.
- Most groups catch immediate failures via person experiences, not exams. This text builds the take a look at suite.
- The suite runs 40 golden queries throughout 4 immediate variations, validates outputs with 4 deterministic checks, and detects the False Enchancment sample, the place total accuracy rises whereas a crucial class collapses.
- v4, the “greatest” immediate at 67.5% total accuracy, triggered FALSE IMPROVEMENT DETECTED resulting from a 66.7% collapse in negation classification.
- Zero exterior dependencies. Pure Python. Runs in beneath two seconds.
My RAG question layer was working nice. Then I added doc routing for PDFs and insurance policies, and the immediate ballooned from six directions to 14. I spot-tested a couple of instances, every little thing appeared proper, and I shipped it.
Three weeks later, I used to be monitoring down a help concern the place negation queries (stuff like “Which merchandise aren’t lined beneath guarantee?”) had been being misclassified as commonplace coverage lookups as a substitute of negation checks. The bizarre half was that I hadn’t touched the classification logic or the routing code. The one factor that modified was the system immediate.
That’s after I understood the issue. I used to be treating my immediate like a static config file. It isn’t. A immediate is a stochastic API, and each time you add directions to it, you might be altering the API contract for each question kind it handles, not simply those you had been fascinated about.
The software program engineering world has a reputation for what I didn’t have: a regression take a look at suite. The concept is straightforward. Earlier than any change ships, you run the exams. If one thing that was passing is now failing, you don’t ship. I had nothing like that for prompts. Most groups don’t.
This mirrors the core concept behind Check-Pushed Growth (Beck [5]): outline anticipated conduct earlier than making adjustments. The self-discipline forces you to outline right conduct earlier than you contact the code. Utilized to prompts, this implies defining legitimate classification logic for every class earlier than including a brand new instruction. With out these definitions, you don’t have any solution to detect when a change breaks one thing you weren’t even fascinated about.
The hidden value downside exists in ML methods as nicely. Sculley et al. [4] documented how undeclared dependencies and unstable knowledge interfaces accumulate as technical debt in manufacturing ML pipelines. A immediate that silently alters conduct throughout classes with out detection is that this precise class of downside. The interface seems steady from the skin, however the conduct has drifted beneath.
All numbers beneath are from actual runs of this technique on Python 3.12, Home windows 11, CPU solely.
The code is at: https://github.com/Emmimal/prompt-regression-suite
The Setup
The regression suite exams 4 immediate variations towards 40 golden queries throughout six intent classes, constructed on high of a RAG intent classification system [1]. The 4 variations mirror an actual iteration sequence from the RAG intent classification system I constructed for this text. Each single change was made for a official purpose, and each single one launched a hidden downside.
v1 is the baseline. It handles clear intent classification with minimal directions and nil reasoning steps. There is only one rule about preserving issues concise and one other in regards to the JSON output format.
v2 provides chain-of-thought reasoning. I introduced this in as a result of multi-hop queries like checking a response time for an enterprise plan with a P1 ticket after hours had been getting misclassified. Chain-of-thought has been proven to considerably enhance efficiency on advanced reasoning duties [2], and it did repair that particular downside. The error was making use of it globally. The v2 immediate now tells the mannequin to “be concise” in a single rule, whereas demanding it “clarify your reasoning step-by-step” in one other. These two guidelines contradict one another on each easy question the system touches.
v3 provides doc routing. The brand new directions inform the mannequin to test for tabular, coverage, and PDF alerts earlier than it classifies intent. One line specifically fully broke negation dealing with: “Prioritize doc routing earlier than intent classification.” Negation queries like “Which areas are excluded from the specific transport coverage?” include coverage key phrases, so beneath v3, the mannequin resolves the doc kind earlier than it ever touches intent. The negation test by no means even fires.
v4 combines each adjustments, and that is what grew to become the manufacturing immediate. The entire instruction floor space roughly tripled, and the latent conflicts from v2 and v3 are actually compounding.
The Golden Set
The 40 queries are distributed throughout six classes.
| Class | N | Failure Mode Focused |
|---|---|---|
| simple_intent | 10 | overreasoning_noise |
| comparability | 8 | missing_comparative_anchor |
| aggregation | 6 | numeric_scope_collapse |
| negation | 6 | instruction_conflict |
| multi_hop | 6 | benefits_from_cot |
| edge_ambiguous | 4 | false_confidence |
| TOTAL | 40 |
Every question was chosen to show a selected failure mode, to not be a common illustration. Take the comparability class, as an illustration. It’s a recognized failure on this system as a result of comparability queries require a comparative anchor that the present immediate structure merely doesn’t resolve. I’m not hiding that on this benchmark, and you will note the [KNOWN FAILURE] annotation in each single diff report.
As a substitute of checking towards a hardcoded reference reply, every question carries a validation signature: a set of deterministic constraints.
{
"id": "NQ_01",
"question": "Which merchandise aren't lined beneath the guarantee coverage?",
"class": "negation",
"expected_intent": "negation_check",
"expected_schema_keys": ["intent", "confidence", "query_type", "rewritten_query"],
"expected_patterns": ["not covered", "warranty"],
"must_not_contain": ["I cannot", "As an AI"],
"failure_mode": "instruction_conflict"
}
The failure_mode area isn’t there for documentation. It’s a testable declare. If the immediate has an instruction battle that intercepts negation decision, this question will fail, and that failure mode label tells you precisely the place to look.
The Validator
The QueryValidator class runs 4 deterministic checks on each single output. No LLM-as-a-judge, and completely no subjective high quality scoring.
class QueryValidator:
def validate(self, output: dict, question: dict) -> ValidationResult:
# 1. Schema test: required keys current in output dict
schema_failures = [k for k in expected_keys if k not in output]
schema_pass = len(schema_failures) == 0
# 2. Sample test: anticipated patterns current in output textual content
output_text = " ".be a part of(str(v) for v in output.values()).decrease()
pattern_failures = [
p for p in expected_patterns
if not re.search(re.escape(p.lower()), output_text)
]
pattern_pass = len(pattern_failures) == 0
# 3. Intent test: labeled intent matches anticipated label
detected_intent = output.get("intent", "")
intent_pass = detected_intent == expected_intent
# 4. Guard test: must_not_contain strings are absent
guard_violations = [g for g in must_not_contain if g.lower() in output_text]
guard_pass = len(guard_violations) == 0
A question both passes all 4 checks or it fails. There’s no partial credit score or advanced weighting, and undoubtedly no choose mannequin introducing variance between runs. The class rating is simply passed_count / total_count. You feed it the identical enter, you get the very same output each single time.
I fully skipped the LLM-as-a-judge route. Truthfully, I noticed one thing necessary right here: regression testing isn’t actually a high quality downside — it’s a contract downside. Checking if the output intent matches the anticipated intent is binary, so a choose mannequin simply provides noise. Plus, working an LLM choose throughout 40 queries for each minor immediate tweak will get costly quick. This script finishes in beneath two seconds and prices completely nothing.
The Scorer and False Enchancment Detection
The Scorer class computes per-category accuracy after which does another factor that’s the precise level of this technique.
REGRESSION_THRESHOLD = 0.10
CRITICAL_CATEGORIES = {"simple_intent", "negation"}
# False Enchancment Detection
overall_improved = candidate.overall_score > baseline.overall_score
if overall_improved and critical_regressions:
candidate.false_improvement_detected = True
candidate.false_improvement_reason = (
f"Total rating improved by "
f"{(candidate.overall_score - baseline.overall_score) * 100:.1f}% "
f"however crucial classes regressed: [{cats}]"
)
The false enchancment sample is that this: a immediate change improves the combination accuracy rating whereas collapsing efficiency on a selected crucial class. The general metric seems good, so that you ship it as a result of the quantity went up. The immediate is damaged.
CRITICAL_CATEGORIES is a system-specific design choice. For my intent classifier, simple_intent and negation are crucial as a result of they symbolize the vast majority of actual site visitors. Multi-hop queries matter, however they’re uncommon. A 100% enchancment on uncommon queries doesn’t justify a 66.7% collapse on widespread ones. That is why you write integration exams earlier than unit exams on a cost move: defend the factor that breaks customers first.
The Deterministic Simulator
The suite makes use of a deterministic mock simulator as a substitute of reside LLM calls. That is a very powerful architectural choice within the codebase and it wants a direct rationalization.
The simulator doesn’t produce random outputs. Every failure operate displays a selected actual failure sample brought on by a selected instruction battle within the corresponding immediate model.
def simulate_output(prompt_version: str, question: dict) -> dict:
# v2 + simple_intent → CoT bleeds into rewritten_query, guard test fires
if model == "v2" and class == "simple_intent":
return _overreasoning_noise(question)
# v3 + negation → doc routing intercepts earlier than intent resolves
if model == "v3" and class == "negation":
if query_number in (1, 3, 5):
return _instruction_conflict_moderate(question)
# v4 + negation → each conflicts compound, intent misclassified as ambiguous
if model == "v4" and class == "negation":
if query_number in (1, 2, 4, 5):
return _instruction_conflict_severe(question)
The _instruction_conflict_severe operate produces "intent": "ambiguous" the place the right reply needs to be "negation_check". Confidence drops to 0.39. The rewritten question accommodates CoT noise: "Step 1: Scan for doc kind alerts... Step 2: Negation key phrase detected: however doc routing takes precedence... Step 3: Due to this fact classifying as ambiguous pending doc context decision."
That output fails the intent test (unsuitable intent), the sample test (negation patterns absent), and the guard test (CoT step tokens current). That’s three of 4 checks failing on the identical output, which is what the benchmarked 66.7% negation collapse displays: 4 of 6 negation queries failing beneath v4.
The selection between deterministic simulation and reside LLM calls relies upon solely on what you are attempting to measure. Regression testing shouldn’t be high quality analysis. High quality analysis asks if an output is sweet; regression testing asks if a change broke one thing that was already working. They’re distinct issues requiring totally different instruments.
LLM-as-a-judge works nicely for high quality analysis as a result of it might probably course of open-ended outputs [3] the place deterministic metrics fall brief. Regression testing, nevertheless, calls for absolute determinism. In case your take a look at outcomes fluctuate between runs, you lose the flexibility to separate a real immediate regression from background noise. The truth that a deterministic simulator yields the very same output each run is a characteristic, not a limitation.
The 2 strategies complement one another. Run this regression suite earlier than each immediate decide to intercept structural breaks, and run your LLM-as-a-judge evaluations periodically to audit the open-ended nuances that code-based checks can’t catch.
By avoiding reside API calls, working python run_regression.py produces equivalent numbers each time, no matter who clones the repository. You get rid of mannequin variance, provider-side updates, and pointless API payments. For a regression framework, reproducibility is the one metric that issues.
Benchmark Outcomes
CATEGORY SCORES BY PROMPT VERSION
| Class | v1 | v2 | v3 | v4 |
|---|---|---|---|---|
| simple_intent | 100.0% | 40.0% | 80.0% | 90.0% |
| negation | 100.0% | 66.7% | 50.0% | 33.3% |
| aggregation | 100.0% | 100.0% | 100.0% | 100.0% |
| multi_hop | 0.0% | 100.0% | 100.0% | 100.0% |
| comparability | 0.0% | 0.0% | 0.0% | 0.0% |
| edge_ambiguous | 25.0% | 100.0% | 100.0% | 100.0% |
| OVERALL | 57.5% | 60.0% | 67.5% | 67.5% |
The general row is the one which will get prompts shipped to manufacturing. v4 ties v3 at 67.5%, each above the v1 baseline of 57.5%. By that metric, v4 is your greatest immediate. By the regression suite’s metric, v4 is a damaged immediate.
VERDICT: v1 → v4
⚠ FALSE IMPROVEMENT DETECTED
Total rating improved by 10.0% however crucial classes
regressed: [negation]
Crucial regressions:
• negation 100.0% → 33.3% ▼ 66.7%
Failure mode: instruction_conflict
STATUS: ✗ DO NOT PROMOTE TO PRODUCTION
The identical verdict fires for v2 and v3. All three candidates set off FALSE IMPROVEMENT DETECTED. All three present total enchancment over baseline. All three have damaged crucial classes.
What Every Model Really Did
This Picture breakdown reveals the regression cascade throughout all three candidates.

The multi-hop accuracy reveals precisely what occurred. The v1 baseline scores 0.0% right here. With out chain-of-thought, advanced conditional queries (the place three or extra situations should be resolved in sequence) get misclassified as fact_retrieval. The mannequin can’t deal with these situations in parallel with out express reasoning scaffolding. CoT fastened that fully, bringing v2, v3, and v4 as much as 100.0%.
Chain-of-thought was the fitting repair for the precise downside it was meant to unravel. The error was making use of it globally. The precise instruction that fastened conditional reasoning chains induced the mannequin to over-explain easy queries, corrupting the rewritten_query area with step-by-step noise. Implementing conditional CoT (making use of reasoning solely when query_type == "advanced") would have fastened multi-hop with out breaking easy intent. With out a regression suite, you don’t have any solution to see that occur till customers begin reporting it.
The False Enchancment Sample, Visualised

This isn’t a constructed worst case. It’s the usual end result of iterative immediate enchancment with out category-level monitoring. Each change solves an actual downside. Each change hides an actual value inside the combination metric.
The Structure

Sincere Design Selections
The YAML parser in loader.py is a minimal, hand-written parser that handles string fields and multiline block scalars. I didn’t add PyYAML as a result of including a dependency to a framework designed to be auditable and simply cloned is the unsuitable trade-off. In the event you want YAML anchors or aliases in your immediate recordsdata, swapping in PyYAML is only a one-line change.
The deterministic simulator produces managed degradation, not random noise. The precise queries that fail beneath every immediate model mirror actual failure patterns from my manufacturing system. A unique system with totally different instruction conflicts could have solely totally different failure factors. The framework is transportable, however the degradation mannequin shouldn’t be. You’ll want to write your personal simulator based mostly on the precise conflicts in your personal immediate historical past.
The ten% regression threshold is bigoted. I set it as a result of it’s the smallest change that’s clearly not measurement noise in a deterministic system. For a medical triage system the place urgent_symptom classification issues, I might set it at 5%. For a low-stakes advice system, 15% may be acceptable. The edge is a parameter, not a precept.
The comparability class scores 0.0% throughout all 4 immediate variations. It is a recognized failure within the present immediate structure, not a regression launched by any of the 4 variations. The intent classifier doesn’t have a comparative anchor decision step, so queries that require evaluating two entities throughout a shared attribute fail constantly. I’ve not hidden it or excluded it from the benchmark. It seems in each diff report with a [KNOWN FAILURE] annotation. A manufacturing regression suite ought to distinguish between anticipated failures which are tracked and regressions which are newly launched. This benchmark makes that distinction express.
CRITICAL_CATEGORIES presently covers simple_intent and negation. Including a brand new crucial class requires one line of code and a corresponding set of golden queries. The framework doesn’t assume these two classes are universally necessary: they’re necessary for my particular system.
Apply This in Your System
The validator and scorer are system-agnostic. Right here is the minimal viable model—simply sufficient to catch the “False Enchancment” sample earlier than it hits manufacturing.
Begin with 20 golden queries break up throughout two classes. Decide the 2 sorts that deal with your heaviest site visitors, writing ten queries for every. For each single question, outline the validation signature earlier than writing the enter itself. Being compelled to articulate what right conduct seems like is strictly what helps you choose the fitting take a look at instances. In the event you can’t write the signature, you don’t but perceive what the immediate is definitely purported to do for that question kind.
Outline two CRITICAL_CATEGORIES. These are the segments the place a regression triggers an automated ship block. For a buyer help bot, that may be refund_eligibility and escalation_trigger; for a medical triage system, it’s urgent_symptom classification. The definition of “crucial” is solely system-specific, and this framework doesn’t make assumptions about your necessities.
Run these exams earlier than each immediate change, not after. Following the self-discipline Beck described [5], the suite runs earlier than the code ships—by no means after the person experiences a failure. The complete suite takes beneath two seconds to execute; there isn’t a operational justification for delaying it.
Develop your golden set every time a manufacturing bug surfaces. Each time a person experiences a misclassification, add that question to the set together with its corresponding validation signature. Over time, the golden set turns into a complete archive of your immediate’s whole historic failure floor.
Regulate the brink for CRITICAL_CATEGORIES based mostly on the affect of failure. The default 10% drop is simply a place to begin. For prime-stakes classes, tighten the brink to five%. For low-stakes areas, 15% could also be acceptable. Keep in mind that the brink is a parameter ruled by the price of failure, not a common fixed.
For the simulator, audit your immediate changelog. Each instruction launched after the preliminary baseline represents a possible battle. For each, write a failure operate that forces an output reflecting that particular battle. In the event you added a routing precedence rule, create a operate that forces the misclassification of the question kind that rule intercepts. The act of constructing this simulator forces you to map the immediate’s failure floor in a method handbook testing by no means will.
Closing
Immediate engineering shouldn’t be a one-time process. It’s ongoing upkeep on a stochastic API. Each time you add an instruction to deal with a brand new edge case, you might be altering the behaviour of each question kind the immediate already handles. A few of these adjustments are innocent. A few of them are silent collapses in classes you weren’t fascinated about.
The regression suite doesn’t stop you from altering prompts. It tells you precisely what broke while you did.
Full code: https://github.com/Emmimal/prompt-regression-suite
Disclosure
All code on this article was written by me and is authentic work, developed and examined on Python 3.12, Home windows 11, CPU solely. The benchmark outputs are from actual runs of run_regression.py and are absolutely reproducible by cloning the repository and working the entry level. The simulator produces deterministic outputs: the identical run produces the identical numbers each time. No LLM was referred to as throughout benchmarking. The comparability question failure (0.0% throughout all 4 immediate variations) is a recognized architectural limitation of the present immediate design and is included on this benchmark unchanged. I’ve no monetary relationship with any device, library, or firm talked about on this article.
References
[1] Lewis, P., Perez, E., Piktus, A., Petroni, F., Karpukhin, V., Goyal, N., Küttler, H., Lewis, M., Yih, W.-t., Rocktäschel, T., Riedel, S., & Kiela, D. (2020). Retrieval-augmented technology for knowledge-intensive NLP duties. Advances in Neural Data Processing Methods, 33, 9459–9474. https://doi.org/10.48550/arXiv.2005.11401
[2] Wei, J., Wang, X., Schuurmans, D., Bosma, M., Ichter, B., Xia, F., Chi, E., Le, Q., & Zhou, D. (2022). Chain-of-thought prompting elicits reasoning in giant language fashions. Advances in Neural Data Processing Methods, 35. https://doi.org/10.48550/arXiv.2201.11903
[3] Zheng, L., Chiang, W.-L., Sheng, Y., Zhuang, S., Wu, Z., Zhuang, Y., Lin, Z., Li, Z., Li, D., Xing, E. P., Zhang, H., Gonzalez, J. E., & Stoica, I. (2023). Judging LLM-as-a-Choose with MT-Bench and Chatbot Enviornment. Advances in Neural Data Processing Methods, 36, 46595–46623. https://doi.org/10.48550/arXiv.2306.05685
[4] Sculley, D., Holt, G., Golovin, D., Davydov, E., Phillips, T., Ebner, D., Chaudhary, V., Younger, M., Crespo, J.-F., & Dennison, D. (2015). Hidden technical debt in machine studying methods. Advances in Neural Data Processing Methods, 28, 2503–2511. https://dl.acm.org/doi/10.5555/2969442.2969519
[5] Beck, Okay. (2002). Check-Pushed Growth: By Instance. Addison-Wesley Skilled.
In the event you discovered this convenient, be at liberty to attach with me on LinkedIn and discover extra of my work on my web site.
I often share insights on LLM methods, immediate analysis, and constructing dependable AI in manufacturing.
LinkedIn: Emmimal P Alexander
Web site: EmiTechLogic

