Column

Best Practices for LLM Testing Before Deployment

June 12, 2026
6
min read

Testing an LLM before deployment is not like testing traditional software. Conventional code is deterministic: the same input returns the same output, and a test either passes or fails. LLMs are probabilistic. The same prompt can produce different responses, correctness is often a matter of degree, and failures show up as hallucinations, unsafe outputs, broken formats, or subtle regressions rather than clean exceptions. Teams that treat LLM testing like a quick demo check ship systems that work in the lab and fail in production.

The teams that ship reliable LLM applications treat testing as a structured, repeatable process. They define what good looks like before they test, build a representative evaluation dataset, run layered evals, red-team for safety, gate every change behind regression tests, and keep evaluating after launch. This post walks through the best practices for LLM testing before deployment, and how each one moves you from "it works in the demo" to measurable, defensible reliability.

Define success criteria before you test

The most common pre-deployment failure is subjective evaluation. If you cannot describe what a passing result looks like, you are vibe-testing, and vibe-testing does not survive contact with real users.

Before writing a single test, define measurable criteria for your use case:

  • Accuracy and task success: what counts as a correct or acceptable answer.
  • Safety and policy compliance: what the system must never do (leak PII, produce toxic content, give disallowed advice).
  • Format and structure: valid JSON, required fields, schema adherence, tool-call correctness.
  • Performance: latency and cost ceilings per request.

Turn each into an explicit pass/fail threshold (for example, "hallucination rate below 2%," "tool-call schema valid 99% of the time," "P95 latency under 3 seconds"). These thresholds become your deployment gates. Without them, every release decision is a judgment call.

Build a golden dataset

A golden dataset, sometimes called an evaluation set or behavior dataset, is the single highest-value asset in LLM testing. It is a curated set of inputs that represent how the system will actually be used, paired with expected behavior or grading criteria.

A strong dataset includes:

  • Common, high-frequency requests that cover your core use cases.
  • Edge cases: ambiguous, incomplete, malformed, or multi-turn inputs.
  • Adversarial cases: prompt injection attempts, jailbreaks, and out-of-scope requests.
  • Known failures: every production bug becomes a permanent test case.

Treat the dataset like code. Version it, review changes, and grow it continuously as you discover new failure modes. Most teams start with 50 to 200 high-quality examples and expand from there. The instinct to test only clean, happy-path inputs is the most common mistake. Real users are messier than developers expect, and the messy cases are where systems break.

Use layered evaluation

No single evaluation method catches everything, and running an expensive LLM judge on every output is wasteful. Strong setups layer evaluation from cheap and deterministic to nuanced and expensive:

  • Layer 1, deterministic checks: JSON and schema validation, regex, required fields, length limits, refusal correctness. Fast, free, and catches obvious failures.
  • Layer 2, semantic checks: embedding similarity to reference answers, retrieval grounding for RAG.
  • Layer 3, LLM-as-a-judge: a capable model scores outputs for helpfulness, tone, completeness, and groundedness using a clear rubric.
  • Layer 4, human review: reserved for high-risk workflows, edge cases, and final release sign-off.

For the eval layers, follow a few principles that make results reliable. Make evals binary (pass/fail) rather than scored on a range, since ranges push the judgment burden onto a human and LLMs are inconsistent scorers. Make each eval specific to one concrete failure mode rather than a vague "is this good?" And include examples of passing and failing outputs in the eval prompt to anchor the judgment, especially for edge cases. Require an explanation alongside each pass/fail decision so you can spot patterns across failures quickly.

Test for hallucinations and groundedness

Hallucination is one of the highest-risk failure modes, especially in regulated or high-stakes domains. Test for it explicitly rather than assuming "looks correct" means correct.

Useful approaches include verifying factual claims against trusted sources, checking that numbers, dates, and entities are accurate, and including unanswerable questions where the correct behavior is to abstain rather than invent an answer.

For retrieval-augmented generation, evaluate retrieval separately from generation. Bad retrieval is one of the most common root causes of agent failures, and it is invisible at the output level because the model confidently generates an answer from whatever context it received. Test whether the retriever returns the right documents for known queries before you judge whether the model used them correctly.

Run experiments and regression tests

Improving an LLM system is iterative, not a one-shot fix. You have many knobs to tune: prompts, retrieval configurations, model selection, tool definitions. Changing one can fix a failure and silently break something else. Experiments and regression tests are how you catch that.

An experiment combines a fixed dataset, a scoring method, and a single variable you are changing (a new prompt version, a model swap, a retrieval change). Run experiments at the right level of isolation:

  • Prompt experiments run a prompt against a dataset of known inputs and outputs. The fastest iteration loop.
  • RAG experiments test whether retrieval returns the right context for known queries.
  • Agent experiments run the full agent end-to-end and evaluate both the final output and the intermediate traces.

Start narrow with prompt and RAG experiments, then validate end-to-end before promoting. Critically, wire these into CI/CD so evals run on every change (prompt edit, model upgrade, retrieval update) and block deployment if metrics regress beyond a threshold. Replaying real production traffic against a candidate version often surfaces regressions that handwritten test sets miss. The dataset that drove an improvement then becomes a permanent regression suite.

Red-team for safety and security

Adversarial testing is mandatory for any system touching sensitive data, tools, or external-facing responses. Assume users will try to break it, and try first.

Test for:

  • Prompt injection and jailbreaks that try to override system instructions.
  • Data leakage: PII, credentials, system prompts, or proprietary data appearing in outputs.
  • Unsafe content: toxicity, harmful instructions, policy violations.
  • Tool and action misuse for agentic systems.

Red-teaming should be systematic and repeatable, not ad-hoc prompting. Convert every discovered exploit into a permanent test case. Beyond pre-deployment testing, guardrails provide a runtime safety layer: pre-LLM guardrails strip PII and catch prompt injection before input reaches the model, and post-LLM guardrails check outputs for hallucinations, toxicity, and format compliance before they reach the user. The most powerful pattern uses a post-LLM guardrail failure as a self-correction signal, feeding the flagged issue back to the model for a revised response rather than surfacing an error.

Test agent-specific behavior

If you are deploying an agent rather than a single-turn LLM call, test the execution path, not just the final answer. Many production failures come from tool interactions, not language generation.

Validate tool selection (did the agent call the right tool?), tool arguments (were they correct?), multi-step reasoning, recovery from tool failures, loop prevention, and permission boundaries. Logging tool traces is often as important as evaluating the output, because that is where agents actually go wrong.

Validate performance: latency and cost

A correct answer that arrives too slowly or costs too much can still fail in production. Before launch, measure latency (time-to-first-token and total generation time), throughput under realistic and peak concurrency, and cost per request in tokens and dollars. Set explicit budgets and treat a breach as a failing test, the same way you would treat an incorrect answer.

Shadow test and roll out gradually

Even a green test suite cannot fully predict real-world behavior. Reduce blast radius with staged rollouts:

  • Shadow testing: run the new version against live production traffic in parallel without exposing its output to users, then compare against the current system.
  • Canary or A/B releases: route a small percentage of traffic to the new version and monitor quality, latency, cost, and user signals before expanding.

These catch distribution-shift issues, the cases where real users behave differently than your test set assumed.

Don't stop at deployment: continuous evaluation

Pre-deployment testing is necessary but not sufficient. LLM behavior can change over time as model providers update their systems, user behavior shifts, and your retrieval corpus changes. Treat evaluation as a continuous loop, not a one-time certification.

After launch, monitor hallucination rates, safety incidents, tool failures, latency, cost, and user feedback. Set alerts for drift and degradation. And feed every production failure back into your golden dataset so the same problem can never silently reappear. The strongest teams treat deployment as the start of evaluation, not the end.

How Arthur supports pre-deployment LLM testing

Arthur's Agent Development Toolkit, built on the open-source Arthur Engine, covers the reliability half of the LLM lifecycle, the testing, evaluation, and safeguarding work that turns a functional prototype into a production-ready system.

  • Continuous evaluations run unsupervised, binary, explanation-backed evals (hallucination, answer completeness, topic adherence, goal accuracy) against live traffic, so you catch failures before users report them.
  • Experiments and supervised evals let you test prompt, RAG, and full-agent changes against curated datasets, with regression suites that block regressions before deployment.
  • Prompt management keeps prompts versioned and testable outside your codebase, so you can replay datasets against new versions before promoting them.
  • Guardrails provide pre- and post-LLM checks (PII, prompt injection, hallucination, toxicity) with a self-correction loop at runtime.
  • Observability and tracing built on OpenTelemetry give you the trace data that feeds evals, experiments, and debugging.

A concrete example: when Arthur's team hardened an internal Jira bot for production, they wrote evals before changing any code, mapping each eval to a specific failure mode (incorrect formatting, over-prioritization, incomplete tickets). Those evals then caught two regressions the refactor introduced before they shipped. That is the core pattern of good pre-deployment testing: define what good looks like, test against it automatically, and let evals catch what you would otherwise miss.

TLDR

  • LLM testing is probabilistic, not deterministic. Define measurable pass/fail criteria before you test, and avoid vibe-testing.
  • Build a version-controlled golden dataset of common, edge, and adversarial cases, and grow it from real production failures.
  • Use layered evaluation: deterministic checks, semantic similarity, LLM-as-a-judge, and human review. Keep evals binary, specific, and example-anchored.
  • Test hallucinations explicitly, and evaluate RAG retrieval separately from generation.
  • Run prompt, RAG, and agent experiments in CI/CD; gate deployments on regression; replay production traffic.
  • Red-team for prompt injection, data leakage, and unsafe outputs, and back it with runtime guardrails.
  • Validate latency and cost, roll out with shadow and canary testing, and keep evaluating after launch.

Want to put these practices into production? Book a demo with an AI expert or explore the Agent Development Toolkit.