DEV Community

NEXMIND AI
NEXMIND AI

Posted on

LLM Evals in 2026: How to Test AI Agents Before They Break in Production

LLM Evals in 2026: How to Test AI Agents Before They Break in Production

Your agent nails the demo. It impresses the stakeholders. Then you ship it — and it starts hallucinating product IDs, calling tools with garbage arguments, and silently "succeeding" at tasks it never actually completed.

This isn't bad luck. It's the fundamental difference between LLM applications and every other piece of software you've ever written: the output is non-deterministic. Your unit tests can't catch a regression that doesn't exist in code — it exists in the model's behavior, the prompt's drift, or the context window's contents.

In 2026, the teams that ship reliable AI agents don't rely on vibes or manual "let me try it a few times" checks. They treat evals as a first-class CI gate, right next to unit tests and linting. This article shows you exactly how to build that — with real code you can adapt today.

Why evals are non-negotiable in 2026

Three things changed in the last 12 months that made eval pipelines mandatory:

  1. Model updates are silent breaking changes. You wake up one day, your provider bumped the model version, and your agent's tool-calling format changed subtly. No code changed. Nothing in your test suite failed. But your production accuracy dropped 20%.
  2. Agents have longer trajectories. A single agent run now involves 5-20 tool calls, reasoning steps, and context rewrites. A failure anywhere in that chain produces a confidently wrong final answer. You can't debug that with a print statement.
  3. The cost of silent failure is compounding. AI agents are no longer a chatbot in the corner — they're creating invoices, sending emails, and modifying databases. A wrong-but-confident action has real consequences.

Industry analysis in 2026 consistently shows that when agentic systems fail, the failure is retrieval and tool-calling, not generation — and those are exactly the layers your unit tests never touch.

The eval taxonomy: four levels you actually need

Don't build "an eval suite." Build four layers, each catching a different failure class:

Level What it catches Cost per run Speed Typical failure it prevents
Unit evals Single-step outputs (classification, extraction, summarization) $0.001 ms Wrong JSON, wrong label, hallucinated entity
Tool-call evals Tool name, arguments, and ordering $0.001-0.005 ms Agent calls delete_user instead of get_user; passes user_id="abc" to an int field
Task evals End-to-end outcome of a complete run $0.01-0.10 seconds Agent "completes" the task but never actually did it
Trajectory evals The path the agent took (reasoning, efficiency, safety) $0.01-0.10 seconds Agent takes 15 tool calls when 3 would do; touches a forbidden tool

Most teams start at level 3 and skip levels 1-2 — backwards. Levels 1 and 2 are where 80% of production failures live, and they're 100x cheaper to test. Build bottom-up.

Free content: the working eval harness

Here's the exact pattern we use in production. It's built on pytest — no framework lock-in, no vendor, works with any model provider.

Step 1: The golden dataset

Evals are only as good as your test cases. Store them as versioned JSONL — one line per case, with an id so you can trace failures back to the exact prompt, model, and dataset version:

{"id": "tool-001", "type": "tool_call", "input": "What's the balance for account 4472?", "expected_tool": "get_account_balance", "expected_args": {"account_id": 4472}}
{"id": "tool-002", "type": "tool_call", "input": "Delete user with email john@example.com", "expected_tool": "delete_user", "expected_args": {"email": "john@example.com"}, "forbidden": ["delete_everything"]}
{"id": "task-001", "type": "task", "input": "Summarize the Q2 revenue report and email it to the finance team", "success_condition": "email sent to finance@company.com containing a Q2 summary with total revenue"}
Enter fullscreen mode Exit fullscreen mode

Rules for a golden dataset:

  • Real inputs from production logs, not hand-crafted happy paths. Your demo cases are exactly the ones that pass.
  • Include the hard cases: ambiguous queries, missing context, malicious inputs, edge formats.
  • Add regression cases every time a bug is found in production. A bug you fixed is an eval you're missing.
  • Target 50-200 cases per critical flow to start. 20 cases will make you feel good and catch nothing.

Step 2: The pytest harness

# tests/evals/test_tool_calls.py
import json
import pytest
from pathlib import Path

from my_agent import run_agent  # your agent entry point

GOLDEN = Path(__file__).parent / "golden" / "tool_calls.jsonl"

def load_cases():
    return [json.loads(line) for line in GOLDEN.open() if line.strip()]

@pytest.mark.parametrize("case", load_cases(), ids=lambda c: c["id"])
def test_tool_call(case):
    result = run_agent(case["input"])

    assert result.tool_name == case["expected_tool"], (
        f"Wrong tool: got {result.tool_name}, "
        f"expected {case['expected_tool']}"
    )
    assert result.tool_args == case["expected_args"], (
        f"Wrong args: got {result.tool_args}, "
        f"expected {case['expected_args']}"
    )

    for forbidden in case.get("forbidden", []):
        assert result.tool_name != forbidden, f"Called forbidden tool {forbidden}"
Enter fullscreen mode Exit fullscreen mode

That's it — the same test runner you already use, pointed at LLM behavior instead of pure functions. When this suite goes red, you know exactly which prompt change, model bump, or context change broke what.

Step 3: LLM-as-judge for subjective outputs

Some outputs can't be asserted with == — summaries, tone, completeness. Use a judge LLM with a rubric (a different model than the one being tested, to avoid self-grading bias):

def llm_judge(output, rubric, model="judge-model-v2"):
    """Score an LLM output against a rubric. Returns 0.0-1.0."""
    prompt = f"""
You are an evaluation judge. Score the output on the rubric.
Be strict. Partial credit only when criteria are explicitly met.

RUBRIC:
{rubric}

OUTPUT:
{output}

Respond with a single number between 0.0 and 1.0, nothing else.
"""
    score = float(call_llm(prompt, model=model).strip())
    return score

def test_summary_quality(case):
    output = run_agent(case["input"])
    score = llm_judge(
        output,
        rubric="Must mention: total revenue, YoY growth, top segment. "
                "Must NOT invent numbers not present in the source.",
    )
    assert score >= 0.8, f"Quality score {score} below threshold"
Enter fullscreen mode Exit fullscreen mode

Judge rubric design is a skill, not a checkbox. The best rubrics are behavioral: "must contain X", "must not claim Y" — not vibes like "well-structured". And always keep a human-reviewed set of ~20 judge outputs per week to make sure your judge isn't drifting.

Step 4: The CI gate

Evals belong in CI, on every PR, and on a schedule (to catch model drift). GitHub Actions:

name: agent-evals
on:
  pull_request:
  schedule:
    - cron: "0 6 * * *"   # nightly drift check

jobs:
  evals:
    runs-on: ubuntu-latest
    env:
      LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: "3.12" }
      - run: pip install -e ".[dev]"
      - name: Run eval suite
        run: pytest tests/evals/ -q --junitxml=evals.xml
      - name: Fail on accuracy drop
        run: python scripts/check_threshold.py evals.xml --min-accuracy 0.9
Enter fullscreen mode Exit fullscreen mode

The nightly schedule is the part everyone forgets. Your model provider can change behavior at any time — a nightly eval run is your early warning system for silent regressions. Pin your model versions (model="claude-3-7-sonnet-20260601", not model="claude-3-7-sonnet") so a provider default bump never silently reaches production.

Anti-patterns that will sink your eval suite

Anti-pattern Why it fails The fix
Judging on vibes "Looks good" isn't a test Behavioral rubrics, assertion-based checks
Same model grades itself Self-grading bias inflates scores Different judge model + human review set
Golden set = your demo script Tests exactly what already passes Production logs, failure cases, regressions
Single sample per case LLM variance makes results noise Run 3-5 samples, compare distributions not points
No thresholds Scores drift silently Hard accuracy/quality thresholds + trend tracking
Eval-only-at-release Model drift hits between releases Nightly CI schedule + PR gate

Pro tips from production

  1. Eval-driven development: write the eval before the fix. Reproduce the bug, add it to the golden set, watch it fail, then fix. The eval is your definition of done.
  2. Trace capture is free eval data: log every production run (tool calls, timestamps, outcomes). When accuracy dips, the worst 5% of traces become your next golden-set additions.
  3. Test the safety rails, not just the happy path: forbidden-tool assertions and input-guard checks are the highest-ROI evals you can write. One catastrophic action prevented pays for the whole suite.
  4. Track evals over time: a single passing run means nothing; a trend line does. Store scores with model version + prompt version + dataset version so you can bisect regressions.
  5. Keep unit evals under 30 seconds: if your fast layer is slow, developers will stop running it locally and evals become a release-day ritual — the exact failure mode you're trying to escape.

What's inside the full collection

This article covers the eval layer — but evals are one pillar of shipping production AI agents. The AI Agents & Automation Playbook takes you through the whole lifecycle:

Section What you get
Agent architecture patterns Supervisor-worker, tool design, context management
MCP integration Building and wiring MCP servers for real tools
Production hardening Evals, observability, failure handling, rate limiting
Monetization Turning agent systems into products and services

Why the playbook over free resources: it's the complete system, not scattered fragments — 100+ pages of battle-tested patterns from real agent deployments, with code you can copy, plus checklists that turn "I read about agents" into "my agent shipped."

Ready to ship agents that don't break?

You've seen the harness. The question isn't whether your agent works — it's whether you know it works. Every demo that passed "by hand" is a bug you haven't found yet.

The AI Agents & Automation Playbook gives you the complete production toolkit:

  • ✅ The 4-layer eval system with golden datasets and CI gates (fully worked)
  • ✅ MCP server patterns for connecting real tools safely
  • ✅ Production architecture: supervisor-worker, retries, observability
  • ✅ Failure-handling playbooks for the top 10 agent failure modes
  • ✅ Monetization blueprints for packaging agents into products
  • ✅ Instant download — start today, ship this week

👉 Get the AI Agents & Automation Playbook →

PS: Building agents means talking to them well. The 500 ChatGPT Prompts Library has production-grade prompts for every stage of the agent lifecycle — worth grabbing while you're here.

Top comments (0)