cn|
WorkWritingAboutConnect

cn

building things that matter

  • Work
  • Writing
  • About
  • Connect

© 2026 Cristian Najera

  1. Home
  2. /Writing
  3. /Evals Are the Product
AITesting

Evals Are the Product

Why treating evaluations as a first-class product concern is the difference between shipping reliable LLM applications and guessing.

April 28, 2026·4 min read

The Eval Mindset

Most teams building with large language models start the same way: they write a prompt, try a few examples by hand, and ship it when the outputs look "good enough." This works for prototypes. It falls apart the moment you need to change anything — the model, the prompt, the temperature, the retrieval strategy — because you have no way to know if the change made things better or worse.

Evals fix this. An eval is a structured test that measures how well your LLM system performs a specific task. Not a vibe check. Not a spot-check. A repeatable measurement that runs the same way every time, on the same inputs, with the same scoring criteria.

The teams that ship reliable LLM products are the ones that treat evals as a first-class product concern, not an afterthought.

The shift is subtle but important: instead of asking "does this output look right?" you ask "does this output score higher than yesterday's?" That reframing turns prompt engineering from guesswork into science.

What Makes a Good Eval

A good eval has three properties: it is deterministic in setup, measurable in output, and representative of real usage.

Deterministic Setup

Every eval run should use a fixed dataset. If you're testing a RAG pipeline, pin the documents in the index. If you're testing a chat agent, use recorded conversation transcripts. Randomness in the setup makes results incomparable across runs.

Measurable Output

You need a scoring function — something that takes the model's output and returns a number. This can be as simple as exact-match accuracy or as nuanced as an LLM-as-judge rubric. The key is consistency: the same output should always get the same score.

Representative Data

Your eval dataset should reflect production traffic, not just the examples you thought of during development. Pull samples from logs, ask your support team for tricky cases, and include adversarial inputs that expose failure modes.

Building Your Pipeline

The simplest eval pipeline has four stages: load the dataset, run each example through your system, score the outputs, and report the results.

import json
from pathlib import Path
 
def run_eval(dataset_path: str, system_fn):
    """Run an eval suite and return scored results."""
    dataset = json.loads(Path(dataset_path).read_text())
    results = []
 
    for example in dataset["examples"]:
        output = system_fn(example["input"])
        score = score_output(output, example["expected"])
        results.append({
            "input": example["input"],
            "output": output,
            "expected": example["expected"],
            "score": score,
        })
 
    return {
        "mean_score": sum(r["score"] for r in results) / len(results),
        "results": results,
    }

This isn't production code — it's the skeleton. In practice you'll want parallel execution, retry logic for rate limits, and structured logging. But the four-stage pattern stays the same regardless of complexity.

Scoring and Iteration

The scoring function is where most of the nuance lives. For factual QA, exact match or F1 over tokens works well. For open-ended generation, you'll likely need an LLM-as-judge approach where a second model grades the output against a rubric.

Here's the iteration loop that actually moves the needle:

  1. Run your eval suite against the current system.
  2. Identify the lowest-scoring examples — these are your failure modes.
  3. Categorize failures: is it a retrieval problem, a prompt problem, or a model limitation?
  4. Make one change at a time and re-run the suite.
  5. If the mean score improves without regressions, ship it.

Make one change at a time. If you change the prompt and the model simultaneously, you won't know which one helped.

Evals in Production

Running evals in CI is table stakes. The more interesting challenge is running them against production traffic. Sample a percentage of real requests, run them through your eval pipeline offline, and track scores over time.

This gives you two things you can't get any other way:

  • Drift detection — if scores trend downward, something changed (your data, your users' expectations, or the model's behavior after a provider update).
  • Coverage gaps — production traffic will surface input patterns your hand-crafted dataset missed.

The goal isn't perfection — it's awareness. When you know your system's baseline performance, you can make informed decisions about tradeoffs. Without evals, every change is a leap of faith.

0%
← PreviousBuilding a Design System from ScratchNext →Why I Still Reach for Boring Python First

Related posts

Testing LLM ApplicationsStrategies for deterministic testing when your outputs are non-deterministic.1 min read
TestingAI
Why I Still Reach for Boring Python FirstI default to stdlib and dataclasses until complexity is earned. Here is the heuristic I use to decide when a framework is worth the overhead.3 min read
PythonOpinionEngineering
Building a Design System from ScratchLessons learned creating a token-based design system with Tailwind v4.1 min read
Design SystemsTailwind

Stay in the loop

New posts on engineering, architecture, and what I'm building.