Agentic demos are easy. A chain of five steps, each of which works about 90% of the time, looks impressive on a good run.
Run it a thousand times and roughly 41% of executions fail somewhere. In a demo that is a retry. In production it is a customer email that never went out, a record left half-written, or the same action taken twice.
Design for the failure, not the happy path
Three things separate a production agent from a demo:
Every side effect is idempotent. If a step sends, writes or charges, it carries a key derived from the input so running it twice does nothing the second time. Agents retry. Without this, retries are duplicates.
Every step is resumable. State lives outside the run, not in the model's context. A crashed run picks up at the last completed step rather than starting over — and starting over is not a neutral act if step two already sent something.
There is a defined stop. A budget on steps, on wall-clock time, and on cost. Agents that can call themselves will, and the failure mode is not a crash, it is a bill.
Tools should refuse, not comply
The instinct is to give an agent powerful, general tools. The safer design gives it narrow tools that validate their own inputs and refuse work that looks wrong.
A send_email(to, body) tool that will send anywhere is a liability. A send_reply(ticket_id, body) tool that can only reply to an existing open ticket, in that ticket's thread, cannot be talked into emailing a customer list. The constraint lives in the tool, where a prompt cannot argue with it.
Read-only until it earns write access
Run the workflow in shadow first: it does everything except the side effects, and logs what it would have done. Compare that log against what humans actually did for a week or two.
This is dull and it is the single most useful thing you can do. It surfaces the cases nobody described in the spec, at no risk, and it produces the evidence needed to decide whether to hand over write access at all.
What to log
Not just the final output. The inputs, the tool calls, the arguments, the intermediate results, and the reason a run stopped. When something goes wrong in a month, "the model got it wrong" is not a diagnosis — you need to see which step, on which input, with what retrieved context.
Agents are not magic and they are not a threat. They are distributed systems with a fuzzier component in the middle, and the same engineering applies.