Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Build a held-out eval set, run it on every prompt/model change, and block regressions in CI. An LM change is a code change — gate it with a test suite (eval set + metric + threshold). Cross-framework SOP not surfaced by any single base skill.
.claude/skills/agentsope-agentsop-regression-gate/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 140% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 234% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 235% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 343% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 312% | 0% |
> "Every subsequent change must be gated on these numbers." > — Synthesized from llamaindex]] Stage 2 (eval loop before optimizing) llamaindex-sop-skill/SKILL.md:114-126]
> "Compiled program beats baseline on a held-out test set (not the val set used in optimization)." > — dspy]] Stage 3 exit criterion dspy-sop-skill/SKILL.md:101]
This is an enhancement overlay. The regression-gate SOP exists only as fragments scattered across base skills — llamaindex]] OP-10 EvalLoop ("gate every change"), dspy]] train/dev/test split + metric — and is never assembled as a standalone cross-framework discipline. It is the discipline that turns a one-off eval into a gate: a test suite that runs in CI on every prompt/model/retriever change and fails the build on regression. It consumes a metric from [[agentsop-metric-design]] and, for domain-specific held-out sets, hands off to [[agentsop-domain-eval-set]].
Activate when any of these is true:
OP-10: "Quantitative regression test for every chunking / embedding / retriever / prompt change" llamaindex-sop-skill/SKILL.md:235].Do NOT activate for:
[[agentsop-metric-design]] first; if the user refuses, this skill cannot help.You already gate code with unit tests in CI: a change that breaks a test fails the build. A prompt edit, a model swap, a chunk-size tweak are also changes to the system's behavior — but they slip through review because their effect is statistical, not a stack trace. The regression gate is the missing unit test for LM behavior.
The gate is exactly three artifacts plus a wiring step:
eval set metric threshold CI wiring
(held-out QA) (ex,pred)->score (fail if <X / drop>Y) (block merge)
│ │ │ │
└──────────────┴──────────────────┴────────────────────┘
REGRESSION GATEThree load-bearing principles:
train / dev / test; the gate runs on test only. If the eval set leaks into the prompt (few-shot demos, instructions), the gate measures memorization, not quality.[[agentsop-metric-design]], not invented here. This skill does not design metrics — it consumes one. A bad metric makes the gate theatre: it will pass changes that hurt users and block changes that help them. The metric must be human-calibrated before it gates anything (agentsop-metric-design]] OP-M05).llamaindex]] Stage 2 is named "Build the eval loop before optimizing anything" llamaindex-sop-skill/SKILL.md:114]. The anti-pattern it names is A3: "No eval loop; debug by anecdote" llamaindex-sop-skill/SKILL.md:348]. The gate is the institutional form of that loop — once it exists, every change is debugged by number, not by vibe.
0. Confirm activation (§1); confirm a metric exists or invoke [[agentsop-metric-design]]
1. BUILD eval set: generate candidates -> curate to a golden set -> freeze + version
2. SPLIT: train / dev / test; the GATE runs on TEST only
3. PICK metric: consume from [[agentsop-metric-design]] (do not invent here)
4. SET threshold: absolute floor AND/OR relative no-regression delta
5. WIRE into CI: run eval on every prompt/model/retriever PR; fail on regression
6. HANDLE flakiness: pin seeds/temp, average N runs, separate flaky from real dropsTwo stages, never one. Generation gives coverage cheaply; curation gives trust.
DatasetGenerator.from_documents(docs).generate_dataset_from_nodes(num=50) produces labelled QA pairs from the documents themselves llamaindex-sop-skill/SKILL.md:121]. promptfoo and synthetic-data generators do the same for non-RAG tasks.eval/golden_v1.jsonl), tagged with the date and the generator model. Changing it is a versioned event, not an edit.Size: dspy]] documents the sweet spot — "30 examples = minimum useful, 300 = recommended" dspy-sop-skill/SKILL.md:87]. For a held-out gate, 50–200 curated domain examples is the working range; descend to [[agentsop-domain-eval-set]] for domain-specific construction.
The gate runs on test only. Keep test sealed from anything that touches the prompt:
train — feeds optimizers / few-shot demo selection.dev — tuning and threshold-setting.test — the gate. Never used to author prompts, pick demos, or tune. (dspy]] held-out exit criterion dspy-sop-skill/SKILL.md:101].)[[agentsop-metric-design]])Do not invent a metric here. Consume one from [[agentsop-metric-design]]:
OP-10 llamaindex-sop-skill/SKILL.md:234]).OP-M01/OP-M02/OP-M03).A metric that has not been human-calibrated must not gate (agentsop-metric-design]] OP-M05). An uncalibrated gate is worse than no gate — it gives false confidence.
| Threshold shape | Rule | Use when | |---|---|---| | Absolute floor | fail if score(test) < X | "never ship below this quality bar" | | Relative no-regression | fail if baseline − score > Δ | "this PR must not make it worse" (the gate proper) | | Per-slice floor | fail if any slice (e.g. lexical-query subset) drops > Δ | aggregate hides a regressed minority |
Set Δ above measured run-to-run noise (Stage 6), else the gate flaps. Commit the current test score as baseline.json next to the eval set; the gate compares against it.
eval CI job that runs on every PR touching prompts, model config, retriever/chunking config, or the program graph.baseline.json → exit non-zero on threshold breach → post the before/after table as a PR comment.baseline.json in the same PR (reviewed, not silent).LLM outputs are nondeterministic; a naive gate flaps and gets disabled. Mitigations:
temperature=0 and seeds where the provider supports them; disable response caching in CI (dspy]] AP-10: "Forgetting cache=False in stateless deploys" dspy-sop-skill/SKILL.md:255]).[[agentsop-metric-design]], not papered over by widening Δ.DatasetGenerator.generate_dataset_from_nodes(num=50), promptfoo synthetic generation, or task-specific synthesis. Tag with generator model + date.OP-10 llamaindex-sop-skill/SKILL.md:234]; external "eval set generation".golden_vN.jsonl).OP-M05; Dilemma 1.test from all prompt-authoring. The gate reads only test. (Note dspy]]'s reversed 20/80 train/val split for prompt optimizers dspy-sop-skill/SKILL.md:96] — that is an optimizer concern; the gate still needs an untouched test slice.)test score; need a pass/fail policy.test score as baseline.json. Define absolute floor X and/or relative no-regression Δ (Δ > measured noise). Optionally per-slice floors.OP-10 regression-test framing llamaindex-sop-skill/SKILL.md:233-235]; external "llm regression testing CI", "promptfoo".baseline.json to the new test score. Never let CI auto-bump silently.program.gpt4o.json and program.llama8b.json; A/B" dspy-sop-skill/SKILL.md:191] (versioned-artifact discipline).[[agentsop-metric-design]]) or widen Δ — never disable the gate.cache=False AP-10 dspy-sop-skill/SKILL.md:255]; agentsop-metric-design]] judge-bias hardening; dspy]] Stage 2 exit "stable across two runs" dspy-sop-skill/SKILL.md:91].困境: Team needs an eval set fast. DatasetGenerator produces 200 QA pairs in minutes (llamaindex]] Stage 2 llamaindex-sop-skill/SKILL.md:121]). Hand-curating 200 examples costs days of human time. Ship the generated set as the gate, or pay for curation?
约束: The generator is the same model family that powers the pipeline → its questions are answerable by exactly the kind of reasoning the pipeline already does (self-preference leakage). Generated sets skew easy and miss the long-tail failures users actually hit. But zero eval set means shipping blind (anti-pattern).
决策步骤:
OP-02): a human keeps the good items, fixes labels, drops the trivially-easy and the ambiguous, and injects known production failures and adversarial/edge cases the generator never proposes.OP-M04).结果: The golden set is the gate; the generated pool is scaffolding. Teams that gate on raw generated sets ship regressions that the easy set never exercised — the gate was green while users churned.
可提取的操作: OP-01 GenerateEvalCandidates, OP-02 CurateGoldenSet. Lesson: generation buys coverage, curation buys trust. A gate needs trust — never gate on an uncurated generated set.
困境: A no-regression gate is set at Δ = 0 (any drop fails). A genuinely good refactor — simpler prompt, 40% cheaper model — scores 0.81 vs the 0.83 baseline: a 2-point drop within run-to-run noise. The gate blocks a change that is net-positive (equal quality, far cheaper). The team starts overriding the gate, and soon ignores it entirely.
约束: Run-to-run noise on this judge-based metric is ±1.5 points (measured across 3 reruns). The 2-point "drop" is statistically indistinguishable from noise. A gate that flags noise as regression trains the team to bypass it — a bypassed gate is worse than none.
决策步骤:
OP-07): rerun the baseline config N times; compute the standard deviation. Here σ ≈ 1.5pp.[[agentsop-cost-tiered-models]]). Don't let a quality gate block a cost win that doesn't hurt quality.[[agentsop-metric-design]] (decompose, length penalty, cross-family judge), don't widen Δ to infinity.结果: Δ tuned to ~2σ passes the cheaper-equal-quality change, still catches real regressions (a 6pp drop), and the team keeps trusting the gate. A gate calibrated to noise survives; a Δ=0 gate gets disabled.
可提取的操作: OP-04 SetRegressionThreshold, OP-07 StabilizeFlakyEval. Lesson: the threshold must clear measured noise. A gate that flags noise as failure gets bypassed, and a bypassed gate protects nothing.
| # | Anti-pattern | Why it's wrong | Fix | |---|---|---|---| | AP-1 | No eval set; ship blind | Every prompt/model change is an uncontrolled experiment on users; "it got worse" is discovered in production | Build a held-out gate (llamaindex]] A3 llamaindex-sop-skill/SKILL.md:348]) | | AP-2 | Eval set leaks into the prompt (few-shot demos / instructions drawn from test) | The gate measures memorization, not generalization; green build, real regression | Seal test; demos come from train only (OP-03; dspy]] AP-9 dspy-sop-skill/SKILL.md:254]) | | AP-3 | Gate on a raw generated set | Inherits generator blind spots; too easy; misses real failures | Curate a golden set (OP-02; Dilemma 1) | | AP-4 | Gate on an uncalibrated metric | A wrong metric passes harmful changes and blocks good ones — gate is theatre | Calibrate via [[agentsop-metric-design]] OP-M05 before gating | | AP-5 | Δ = 0 / threshold below noise | Gate flaps on noise, team bypasses it | Set Δ > 2σ measured noise (OP-04, OP-07; Dilemma 2) | | AP-6 | Run the gate on the val/dev set used for tuning | Optimistic, leaks tuning into evaluation | Gate on held-out test only (dspy]] dspy-sop-skill/SKILL.md:101]) | | AP-7 | Caching on in CI | Stale cached outputs mask the change under test | cache=False (dspy]] AP-10 dspy-sop-skill/SKILL.md:255]) | | AP-8 | Aggregate-only gate | A win on the majority hides a regressed minority slice | Per-slice gating (OP-08) | | AP-9 | Silent baseline auto-bump | Quality can ratchet down unnoticed if CI rewrites baseline | Bump baseline only in a reviewed PR (OP-06) | | AP-10 | Disabling the gate when it flakes | Removes the only protection; flakiness is a metric/Δ bug, not a gate bug | Stabilize (OP-07), never disable |
[[agentsop-metric-design]] first.lm-evaluation-harness. For a domain-specific held-out set, descend to [[agentsop-domain-eval-set]].| Concept | LlamaIndex | DSPy | promptfoo | LangSmith | This skill | |---|---|---|---|---|---| | Eval set generation | DatasetGenerator.generate_dataset_from_nodes(num=N) llamaindex-sop-skill/SKILL.md:121] | bring labelled examples; BootstrapFewShot self-generates demos (not the test set) | tests: synthesis / generate from prompts | Datasets created from traces / uploads | OP-01 GenerateEvalCandidates | | Golden / curated set | manual review of generated QA | hand-labelled trainset/devset | curated tests YAML with assert | curated Dataset + reference outputs | OP-02 CurateGoldenSet | | Train/dev/test split | manual | explicit; reversed 20/80 for prompt optimizers, held-out test for gate dspy-sop-skill/SKILL.md:96,101] | n/a (test set is the suite) | dataset splits | OP-03 SplitTrainDevTest | | Metric | Faithfulness/Relevancy/RetrieverEvaluator(mrr,hit_rate) llamaindex-sop-skill/SKILL.md:234] | def metric(ex,pred,trace=None)->bool\|float dspy-sop-skill/SKILL.md:88] | assert (equals/contains/llm-rubric/javascript) | evaluator fns / LLM-as-judge | consumed from [[agentsop-metric-design]] | | Threshold / gate | manual (gate every change llamaindex-sop-skill/SKILL.md:124]) | held-out beats baseline "by ≥ delta" dspy-sop-skill/SKILL.md:101] | assert pass + --fail-on thresholds | rules + alerts on eval scores | OP-04 SetRegressionThreshold | | CI wiring | not built-in (DIY job around Evaluate) | not built-in (DIY around dspy.Evaluate) | first-class: promptfoo eval in CI, non-zero exit | CI integration + regression alerts | OP-05 WireCIGate | | Flaky handling | run multiple times | cache=False; "stable across two runs" dspy-sop-skill/SKILL.md:91,255] | repeat + threshold | run aggregation | OP-07 StabilizeFlakyEval |
Combination patterns:
DatasetGenerator for OP-01, the Faithfulness/Relevancy/Retriever triad as the metric, wired into a DIY CI job. The base skill names the loop ("gate every change"); this skill makes it a CI gate.promptfoo eval exits non-zero on failed asserts; it is the closest off-the-shelf realization of OP-05. Use it as the runner; still bring a curated set (OP-02) and a calibrated metric.Opinionated default: build the eval set with the base framework's generator (OP-01), curate by hand (OP-02), keep the metric in [[agentsop-metric-design]], and run the gate with promptfoo (CI-native) or a thin script around dspy.Evaluate / LlamaIndex evaluators. The gate, the metric, and the eval set are three separable, version-controlled artifacts — never one tangled blob.
references/R1-source-evidence.md — every cited claim resolved to a source lineintermediate/operation_candidates.json — machine-readable operation registryCitations: llamaindex]] OP-10 EvalLoop / Stage 2 llamaindex-sop-skill/SKILL.md:114-126,232-236,348]; dspy]] Stage 2-3 split+metric+held-out dspy-sop-skill/SKILL.md:85-105,137,191,254-255]; agentsop-metric-design]]; agentsop-domain-eval-set]]; external "llm regression testing CI", "promptfoo", "eval set generation".
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-02 | pass→pass | 22,499 | 21,516 | -4% | 1 | 1 | 0% | 3,551 | 10,515 | +196% | 0 | 0 | — |
case-03 | pass→pass | 17,530 | 14,712 | -16% | 1 | 1 | 0% | 3,113 | 9,231 | +197% | 0 | 0 | — |
case-01 | pass→pass | 25,348 | 18,717 | -26% | 1 | 1 | 0% | 3,892 | 9,801 | +152% | 0 | 0 | — |
case-15 | pass→pass | 12,312 | 14,010 | +14% | 1 | 1 | 0% | 1,893 | 8,933 | +372% | 0 | 0 | — |
case-04 | fail→pass | 24,895 | 20,582 | -17% | 1 | 1 | 0% | 4,346 | 10,443 | +140% | 0 | 0 | — |
case-05 | fail→pass | 19,602 | 18,362 | -6% | 1 | 1 | 0% | 2,926 | 9,771 | +234% | 0 | 0 | — |
case-06 | pass→pass | 16,865 | 14,573 | -14% | 1 | 1 | 0% | 2,702 | 9,289 | +244% | 0 | 0 | — |
case-07 | pass→pass | 14,934 | 16,459 | +10% | 1 | 1 | 0% | 2,315 | 9,364 | +304% | 0 | 0 | — |
case-08 | fail→pass | 17,586 | 13,390 | -24% | 1 | 1 | 0% | 2,654 | 8,896 | +235% | 0 | 0 | — |
case-09 | fail→pass | 11,370 | 7,677 | -32% | 1 | 1 | 0% | 1,828 | 8,101 | +343% | 0 | 0 | — |
case-10 | pass→pass | 18,731 | 14,404 | -23% | 1 | 1 | 0% | 2,866 | 9,348 | +226% | 0 | 0 | — |
case-11 | fail→pass | 13,076 | 10,695 | -18% | 1 | 1 | 0% | 2,065 | 8,514 | +312% | 0 | 0 | — |
case-12 | pass→pass | 16,828 | 16,402 | -3% | 1 | 1 | 0% | 2,606 | 9,535 | +266% | 0 | 0 | — |
case-13 | fail→pass | 15,237 | 14,174 | -7% | 1 | 1 | 0% | 2,431 | 9,083 | +274% | 0 | 0 | — |
case-14 | pass→pass | 16,263 | 13,454 | -17% | 1 | 1 | 0% | 2,062 | 8,884 | +331% | 0 | 0 | — |
case-16 | pass→pass | 16,835 | 18,114 | +8% | 1 | 1 | 0% | 2,727 | 9,785 | +259% | 0 | 0 | — |
case-17 | pass→pass | 15,833 | 15,304 | -3% | 1 | 1 | 0% | 2,539 | 9,251 | +264% | 0 | 0 | — |
case-18 | pass→pass | 13,515 | 10,130 | -25% | 1 | 1 | 0% | 1,903 | 8,318 | +337% | 0 | 0 | — |
case-19 | pass→pass | 10,721 | 6,944 | -35% | 1 | 1 | 0% | 1,650 | 7,959 | +382% | 0 | 0 | — |
case-20 | pass→pass | 9,542 | 8,692 | -9% | 1 | 1 | 0% | 1,525 | 8,398 | +451% | 0 | 0 | — |
case-21 | pass→pass | 11,963 | 12,571 | +5% | 1 | 1 | 0% | 2,013 | 8,966 | +345% | 0 | 0 | — |
case-22 | pass→pass | 12,858 | 13,196 | +3% | 1 | 1 | 0% | 2,079 | 9,091 | +337% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +27 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.