Most AI agent demos share a structure: a curated task, a clean input, and a confident narrator explaining what the agent "decided" to do. That's a reasonable way to show off a capability. It's a poor way to judge whether an agent is ready for production, because production doesn't hand you curated inputs.
The demo-to-production gap
An agent in a demo runs once, on an example chosen because it works. An agent in production runs continuously, on inputs nobody hand-picked, some of which are malformed, ambiguous, or actively adversarial. The failure modes that matter in production — the agent calling a tool with the wrong arguments, getting stuck in a loop, or confidently taking an irreversible action based on a misunderstanding — rarely show up in a demo, because demos are, almost by definition, the cases where nothing goes wrong.
Design for the failure, not just the happy path
The single highest-leverage design decision for a production agent is deciding, explicitly, what happens when it's uncertain. Not "the agent tries its best" — an actual decision: does it ask a clarifying question, hand off to a human, retry with a narrower scope, or refuse the action outright? Agents that don't have an explicit uncertain-state behavior default to guessing confidently, which is the worst option in almost every domain that matters.
This means building in:
- Bounded tool access. An agent should only be able to call the tools it actually needs for its task, with permission scopes that match the blast radius of a mistake. An agent that can read a database and one that can delete records from it need very different levels of trust.
- Reversibility where possible. Prefer actions that can be undone. If an agent is about to do something irreversible — sending an email, charging a card, deleting data — that's exactly where a human checkpoint belongs, at least until the agent has a long track record.
- Structured, validated outputs. Don't parse free text and hope. Define a schema for what the agent should return, validate against it, and treat a validation failure as a signal to retry or escalate, not something to silently coerce into shape.
Observability is not optional
You cannot debug an agent you can't see inside of. Every production agent we build logs its reasoning trace, tool calls, and outcomes in a way a human can review after the fact — not just the final output. When an agent does something wrong, the question is never just "what did it output," it's "what sequence of tool calls and intermediate reasoning led here," and if you didn't log that, you're reconstructing it from memory or guessing.
Start narrower than you think you need to
The instinct is to build a general-purpose agent that can handle a wide range of requests. In practice, a narrowly scoped agent with well-defined tools and clear boundaries is more reliable, easier to evaluate, and faster to actually ship — and you can always expand scope once the narrow version has proven itself against real usage. Broad scope is something you earn by demonstrating reliability, not something you start with.
None of this is exotic engineering. It's the same discipline that applies to any system making decisions with real consequences: bound the blast radius, make failure explicit rather than silent, and instrument it well enough that when something goes wrong, you can find out why.