plugins/testing-llm-features/skills/testing-llm-features/SKILL.md
Builds an offline eval suite for LLM-powered features: golden reference cases per prompt template, deterministic scoring where possible, a regression gate on prompt, model and retrieval changes, and CI wiring with promptfoo, Vitest or deepeval. Use when a product ships prompts, agents or RAG, when a model or prompt upgrade needs a regression check, when LLM output is currently verified by someone eyeballing it, or when asked how to test a feature whose output is non-deterministic.
npx skillsauth add jaktestowac/awesome-copilot-for-testers testing-llm-featuresInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill when a product's behaviour depends on a model, and the current verification method is a person looking at output and deciding it seems fine.
The problem is not that LLM output is hard to assert on. It is that the same input produces different output, and a prompt or model change can degrade quality without breaking anything. No test in a normal suite fails. Coverage stays green. The feature just gets worse, and you find out from users.
An eval suite is the unit-test layer for this: a fixed set of cases, run on every change that could affect model behaviour, scored consistently enough that a regression is visible.
Find everything that can change model behaviour, because each is a trigger for the suite:
| Element | Where to look |
| --- | --- |
| Prompt templates | prompts/, *.prompt.*, template literals passed to the SDK |
| System prompts | client construction, agent definitions |
| Model config | model id, temperature, top_p, max tokens, stop sequences, thinking budget |
| Tool definitions | tool/function schemas, MCP servers, tool grants |
| Retrieval | chunking, embedding model, index, topK, reranking, filters |
| Output contract | Zod/schema on the response, structured-output config, parsing code |
| Orchestration | chain and agent-loop structure, retries, fallbacks between models |
Write down what the feature promises - the user-visible contract. "Summarise the ticket in ≤3 sentences, never invent a customer name, always cite the ticket id." That sentence is where the cases come from.
./resources/eval-case-design.md has the taxonomy. The minimum viable set per prompt template:
| Class | Purpose | Count to start |
| --- | --- | --- |
| Golden | canonical inputs with known-good outputs | 5–10 |
| Edge | empty, huge, multilingual, malformed, contradictory input | 5 |
| Negative | must refuse, must not answer, must not leak | 3–5 |
| Regression | one case per bug ever found in production | grows forever |
| Adversarial | injection and jailbreak attempts | see testing-llm-guardrails |
Cases carry the metadata that makes a failure diagnosable: which prompt template, which capability, why the expectation is what it is. A case whose expectation nobody can justify is a case nobody will maintain.
The regression class is the one that compounds. Every production incident becomes a permanent case. After six months this set is the most valuable test asset the feature has, and it costs one case per incident to build.
./resources/scoring-strategies.md covers each in detail. Pick the cheapest one that can actually fail:
| Strategy | Use when | Cost | | --- | --- | --- | | Exact / regex match | classification, extraction, IDs, enum outputs | free, exact | | Schema validation | any structured output | free, exact | | Required / forbidden substrings | must cite the ticket id, must never say "as an AI" | free | | Deterministic property | length limits, valid JSON, no PII pattern, citation resolves to a real source | free | | Embedding similarity | paraphrase-tolerant equivalence | cheap, fuzzy | | Rubric-based LLM judge | tone, helpfulness, faithfulness | expensive, needs validation | | Human review | the final arbiter on a sample | expensive, definitive |
The ordering is the advice. Teams reach for an LLM judge first because it feels closest to "quality", and end up with a noisy score they cannot debug. Most real regressions trip a free check.
Two viable shapes, both in ./resources/promptfoo-setup.md:
Non-negotiables whichever you pick:
claude-sonnet-4-5-20250929, not latest) - a floating alias makes every run unreproducibleThe gate is comparative:
| Condition | Verdict | | --- | --- | | A case that passed on the baseline now fails | BLOCK - this is the whole point | | Aggregate score drops beyond the noise band | WARN - investigate before merging | | New cases fail | INFO - they were added because they fail | | Cost or latency regresses beyond budget | WARN | | Flaky case (passes and fails across N runs) | fix the case or the determinism, do not average it away |
Establish the noise band empirically: run the suite three times on an unchanged system and see how much the score moves. Anything inside that band is not a signal, and gating on it produces the flakiest CI job in the repo.
Store the baseline as a committed artifact so the comparison is reviewable in the diff. See ./resources/promptfoo-setup.md for the CI job, the trigger paths, and the API-key-free path for forks.
latest silently changes the system under test between runs../resources/eval-case-design.md - case taxonomy, how to write a golden expectation, case metadata, growing the set from incidents./resources/scoring-strategies.md - each scoring method, when to use it, LLM-judge rubrics and how to validate a judge./resources/promptfoo-setup.md - promptfoo and Vitest implementations, determinism settings, CI job, baseline comparison, cost controltesting-llm-guardrails - runtime output validation and the adversarial suite: injection, jailbreaks, tool abusereviewing-ai-output-groundedness - the human review protocol for factuality, and the attestation an eval suite cannot replacedesigning-test-data - building the input corpora these cases consumeanalyzing-quality-metrics - defining and trending eval pass rate, variance, and cost as real metricsunslop-tests - the same discipline applied to test code: an eval that cannot fail is worse than no evalscoping-change-relevance - which changes should trigger the suite (modified-prompt, model config, tool grants, retrieval)This skill is complete when:
testing
Tests the customization assets themselves - skills, prompts, custom agents, instructions - the way a product is tested: activation cases that check an asset fires when it should and stays quiet when it should not, output-contract cases, safety cases, collision cases between assets competing for the same trigger, a weighted rubric scored blind, and a baseline-versus-candidate gate before an edit ships. Use when a skill is edited and nobody knows whether behaviour changed, when two skills fight over the same request, when a description is being tuned for discoverability, when a collection has grown past manual spot-checking, or when the request mentions skill evals, prompt regression, or "does this skill actually work".
development
Shapes QA output for the person who has to act on it: result and blocker in the first two lines, one decision per report, findings ordered by what they cost, the long artifact in a file and the decisions in the message, and magnitude stated in units the reader can count. Use when a report is accurate but nobody acts on it, when a finding set is too long to read under time pressure, when the same findings must be retold for a developer, a release manager, and an on-call engineer, or when the request mentions "too long", "make this readable", "just tell me what to do", "so what", or "summarize this for stakeholders". Pairs with unslop-answers, which makes the same report honest.
testing
Verifies that the lines and branches a change actually touched are executed by tests, using LCOV or Cobertura diff coverage instead of whole-repo percentages, and escalates uncovered high-risk changes into a blocking finding. Use when a pull request needs a coverage gate that unrelated tests cannot satisfy, when total coverage looks healthy but the diff is untested, when wiring diff coverage into CI, or when someone claims a change is covered because the suite is green.
development
Cuts AI tells from test code: tests that pass without proving anything, tautological assertions, mock-only tests, hardcoded waits, coverage theater, vague names, swallowed errors, retries used as fixes. Use whenever test code is written, changed, or reviewed, including tests produced as a side effect of a feature task, and when the request mentions "review these tests", "are these tests any good", "this test always passes", "this suite is flaky", or "clean up these tests". Must always apply to test code.