← All writingIssue 08 · May 2026
AI EngineeringEvalsProductionPhilosophy

Building Agents Is Easy. Reliability Is the Real Work.

Rushikesh Gandhmal12 min reada slow read

There's a comforting misconception going around right now: that AI engineering is mostly about building agents. Pick an SDK, wire up a few tools, write three prompts, and you have something that looks intelligent in a demo. The hard part, the part the demos quietly skip, is what happens on the second day — when the inputs get weird, the model has a bad afternoon, and a real user asks the question you didn't think to test.

I want to write this one as a senior engineer talking to a junior version of myself — because I was that junior version not long ago, and the mental model I had then was wrong in ways that took shipping a few systems to correct. The short version is: building the agent is the smallest part of the job. The real work starts after the first successful demo.

§Why building an agent feels like the whole job (and isn't)

Modern tooling is genuinely good. An afternoon with the right SDK, a model endpoint, a vector store, and a few tools, and you can put together something that holds a conversation, plans, calls APIs, and produces an output that looks startlingly correct. The first time you watch your own agent do something useful, it feels like you've crossed a threshold. You have, but it's the wrong threshold. You've crossed the line from 'nothing' to 'demo'. The line that matters is from 'demo' to 'dependable', and most of the distance between those two is invisible from where you're standing.

I've watched teams (mine included) celebrate the moment the agent works end-to-end, then assume the remaining work is polish — a nicer UI, faster latency, maybe a few more tools. That's the trap. Polish is what you do to a finished product. The agent isn't finished; the real work has barely begun. What it lacks is the property that turns a clever toy into a product: it does not yet behave consistently.

The demo asks: summarize this clean support ticket. Production asks: summarize a half-written complaint, infer the product, ignore the copied email thread, avoid leaking private notes, and still give a useful answer. That is where the real system shows itself.

§What 'reliable' actually means when you say it

Reliability is one of those words that sounds obvious until you have to operationalize it. In conventional software, we can often define it with crisp service indicators: availability, latency, error rate, throughput, and deterministic behavior for well-scoped code paths. AI systems make that definition messier in two places at once. The same input can produce different outputs, especially when sampling is enabled or the underlying model changes. And 'correct' isn't always a binary check — it's often a judgment about quality, faithfulness, helpfulness, safety, tone, and a dozen other axes that depend on context.

So when I say an AI system is reliable, I mean something more textured. It produces outputs that fall inside an acceptable distribution. It fails in ways that are bounded and visible rather than silent and confident. It degrades gracefully when the input is noisy or ambiguous. It is designed to surface uncertainty when uncertainty matters. And — most importantly — those properties hold not just on the sample of inputs you happened to test, but across the long, weird tail of what real users will eventually throw at it.

  • Consistency: similar inputs should land in similar regions of output space, not jump around between answers.
  • Calibration: when the system is uncertain, it should say so — not pick a confident-sounding wrong answer.
  • Boundedness: failures should be recognizable and recoverable, not silent hallucinations dressed up as facts.
  • Coverage: the system should perform across the distribution of real inputs, not just the demo set.
  • Auditability: every output should be traceable to the prompts, context, and tools that produced it.

§The shift: from 'building' to 'improving'

Once you accept that the demo isn't the destination, the shape of the work changes. You stop thinking like a builder and start thinking like a scientist with a deadline. The codebase is no longer the artifact you're optimizing — the behavior of the system is. And behavior is something you understand best by measuring it.

This is the part of AI engineering that doesn't make for a great screen recording. There's no satisfying moment of 'and now it works'. Instead there's a slow, disciplined cycle: define what 'good' means for this slice of the product, build the smallest thing that might be good, and measure how often it actually is.

Then comes the useful part: look hard at where it fails, change one thing, and measure again. Repeat until the curve is where it needs to be, then move to the next slice.

ts
// Pseudocode for the loop that matters most.
let metrics = evaluate(system, evalSet); // versioned, reproducible

while (notGoodEnough(metrics)) {
  const hypothesis = inspectFailures(failureSet);
  const change = smallestChangeThatTests(hypothesis);

  apply(change);                       // prompt, context, tool, workflow, model
  metrics = evaluate(system, evalSet);
  log({ hypothesis, change, metrics });

  if (regressed(metrics)) revert(change);
}

Notice what's not in that loop. There's no 'rewrite the agent'. No 'try a bigger model and see'. No 'add another tool because it feels like it should help'. Those moves can be right, but they should be backed by evidence. The discipline is in the boringness: one change, one measurement, one decision.

§Evals are the regression tests of the AI era

If there's a skill that separates engineers who ship AI products from engineers who ship AI prototypes, it's the willingness to write evals. Not 'we'll add evals when we have time'. Not 'the PM will eyeball it'. Evals as a first-class artifact, versioned alongside the code, run automatically where practical, and treated with the same seriousness a backend engineer treats their test suite.

And like regression tests, evals are not glamorous. They are a pile of input/expected-behavior pairs, a scoring function, and a discipline. The scoring function is the interesting bit, because for many AI tasks you cannot just compare strings. You need a rubric — sometimes a human-written one, sometimes a model-graded one, sometimes a regex-and-heuristic stack — that turns 'is this output good?' into a number you can plot over time.

  1. 01Start with a golden set. Twenty to fifty real-looking inputs with hand-curated expected behavior. This is your floor — if you regress here, you do not ship.
  2. 02Add an adversarial set. Inputs designed to break the system: empty, noisy, off-topic, prompt-injection attempts, contradictory instructions. The adversarial set is where you find what your system actually believes.
  3. 03Add a production replay set. Sampled real traffic, anonymized, graded after the fact. This is the most grounded set for learning what your users are actually doing.
  4. 04Score with a mix. Deterministic checks where you can (schema, format, citations present). Model-graded rubrics where you can't (helpfulness, faithfulness, tone). Human spot-checks for new rubrics, high-risk changes, and the slices where automated graders are weakest.
  5. 05Track metrics over time. A single number is a smell; a dashboard of three to five metrics by eval set is a signal.

§Failure patterns are the actual product feedback

Once evals exist, something quietly important happens: the failures stop being embarrassments and start being data. A failed eval case is not a bug to hide — it's a sample of the distribution where your system is currently weakest, and therefore the most valuable place to spend the next hour of engineering. The teams that get good at this build a habit of staring at failures the way an engineer stares at stack traces.

What you're looking for is patterns. Not 'this one output was wrong' but 'every time the user asks a comparison question, we cite the wrong document'. Not 'the agent hallucinated' but 'when the retrieved context is empty, the model fills the gap with plausible-sounding fiction rather than saying it doesn't know'. The individual failures are noise. The clusters are the product roadmap.

When I cluster failures, three categories show up over and over again. The first is context failures — the right information wasn't in the prompt because retrieval missed it or chunking mangled it. The second is instruction failures — the prompt was ambiguous, contradictory, or didn't anticipate the case. The third is reasoning failures — the model had what it needed and still drew the wrong conclusion. Each category points at a different fix, and confusing them is how you burn weeks tuning prompts when the actual problem is the retriever.

§Iterating on the right surface

Here's a habit I've had to build: before changing anything, name the surface I'm changing. AI systems have at least four of them — the prompt, the context (retrieval, tools, memory), the workflow (how steps are wired together), and the model itself. Each surface has different costs, different feedback loops, and different failure signatures. Changing the wrong surface is the most expensive mistake you can make, because it can take days before the metrics confirm you've been pulling on a string that wasn't connected to anything.

  • Prompt: fastest feedback, cheapest to change, easiest to over-fit to your eval set. Reach for it first, but distrust gains that don't generalize.
  • Context: the highest-leverage surface for many RAG-shaped systems. If retrieval is wrong, prompt cleverness usually won't save you.
  • Workflow: where reliability actually lives. Retries, guards, human-in-the-loop, fallbacks. Most production wins are workflow wins, not prompt wins.
  • Model: expensive lever, not a reflex. If the task is beyond the model's capability, change the model; otherwise, a smaller model with a better workflow can often win on both cost and quality.

The senior move is to know which knob to turn. The junior move is to turn all of them at once and lose track of what helped.

§What it looks like when this is going well

When a team has internalized this loop, the rhythm of the work changes in a way you can feel from the outside. Standups stop being 'I added a tool' and start being 'I moved the faithfulness score from 0.71 to 0.78 by tightening the retrieval filter on doc_type'. Reviews stop being 'does this prompt look good?' and start being 'what does the eval delta look like?'. Outages stop being mysteries and start being traceable, because every output is grounded in a versioned prompt, a logged context, and a recorded decision.

And the product feels different. Users notice that the system says 'I don't know' sometimes — and trust it more, not less, because its answers are right often enough to be useful. Edge cases that used to embarrass you start getting caught by guardrails before they reach a screen. The CEO stops forwarding bad outputs to engineering chat, not because the system is perfect but because the failure rate has dropped below the threshold where any one example feels like an emergency.

§The mental shift, in one line

If you take one thing from this: the value of AI engineering is not in creating a system that works once. It's in creating a system that works consistently enough that people and businesses can depend on it. Everything else — the framework you chose, the model you picked, the agent architecture you fell in love with last week — is implementation detail. The discipline is the loop. Build, evaluate, improve, evaluate again. Repeat for as long as the system matters.

— rushikeshend · 2026-05-20