September 15, 2026
The Agent Is Not the Architecture: Designing Reliable Systems Around LLM Agents
An LLM agent can decide correctly and still leave the system in the wrong state. Reliable architecture controls side effects and safely recovers from retries, restarts, delayed approvals, and uncertainty.
The problem begins after the decision
An agent can make the right decision and still leave the system in the wrong state. I first encountered that gap while building an agent that managed consultation cancellations and rescheduling. A request would time out, and suddenly the agent had a small mystery on its hands. Had the operation failed, or had the result simply been lost? Retrying a cancellation could produce “appointment not found” because the appointment was already gone. A reschedule was more awkward. The requested slot might now be occupied by the same user because the first attempt had worked after all.
Nothing was obviously wrong with the agent's decision. The failure occurred after that decision, when the system could no longer establish what the action had changed. I introduced request-context middleware to support idempotent handling across retries. That contained the immediate problem and changed how I thought about the agent's role. Once an agent can alter an external system, its decision is only one stage in a longer execution path.
Runtime discretion is the feature that separates an agent from a fixed workflow. Given a goal and the current state, it can choose a tool, revise its plan, ask for missing information, or hand the problem to a person. This is useful for work whose path cannot be fully specified in advance. It also means the rest of the system has to be designed around decisions that will vary from one run to another.
The agent chooses what should happen next. The surrounding system decides whether that choice is allowed, executes it safely, and preserves enough state to recover when reality interrupts the plan. Better reasoning may improve the choice. It cannot make a network call atomic or keep an approval alive after a process exits. If an operation times out, reasoning alone cannot prove that it never happened.
A convincing demonstration
Now consider an agent that handles service-credit requests for a software company. A customer reports that an outage disrupted their business and asks for compensation. The agent reads the support case and incident report, checks the customer's plan and service-level agreement, then inspects the latest invoice. The outage qualifies. It calculates a $1,200 credit, notices that the amount exceeds the automatic approval limit, and asks a support manager to approve it. Once approved, the agent issues the credit through the billing system, updates the case, and drafts a response to the customer.
It is an effective demonstration. Information that normally lives across several systems becomes one coherent decision, and work that crosses multiple teams finishes in minutes. It is also a generous environment. The process stays alive, every dependency answers, and the manager approves the request on cue. Real managers, inconveniently, have calendars. Every tool runs once, and every response accurately describes what happened.
The demonstration is accurate as far as it goes. It says little about what happens when the same work stretches across hours, processes restart, or an API returns no answer.
Then time enters the system
The agent decides that the customer qualifies for a credit. Before that decision is persisted, its worker restarts. On the next attempt, where should the case resume?
Starting over is tempting because it avoids deciding where to resume. It may also repeat expensive work and produce a different conclusion. A stored transcript tells us what the model said, but not necessarily which workflow state was committed. Assuming that every preceding step completed is worse. The system would then be acting on facts that existed only in the memory of a process that has disappeared.
A conventional service faces the same question after a crash. It must locate the last durable state and determine which transition can safely run next. An agentic workload needs an answer just as precise.
For this case, an authoritative workflow record outside the model's context could show that the evidence was collected under the applicable policy, a $1,200 credit was proposed, and approval is pending. Each transition is committed deliberately. The model can help choose the next transition, while the workflow record establishes which ones actually occurred.
Meanwhile, the support manager has gone to lunch. Approval arrives four hours later, which is perfectly ordinary for a person and an eternity for an open request. The process that asked for approval may be long gone. Holding a worker or model session for that interval wastes resources and makes recovery harder. The workflow should persist its position, release its compute, and resume when an authenticated approval event arrives. If nobody responds by the deadline, it can reassign or escalate the case.
Workflow systems already have a practical model for this situation. They persist the pending approval, release the worker, and resume after either an external event or a durable timer fires. Microsoft's human-interaction pattern for durable tasks shows one implementation, though the same design can be built with other orchestration systems.
Nor is a Boolean approval flag much of an approval record. The system needs to know who approved the request, which amount they saw, and which policy governed the decision. It must bind that approval to the action being authorized. If the invoice changes while the manager is away, the old approval may need to be rejected or revalidated.
The model can decide to request approval, but the surrounding services define the approval record and enforce its scope.
The timeout that already succeeded
The manager approves the $1,200 credit, and the system calls the billing API. Billing creates the credit. Before its response reaches the caller, the connection times out.
Now the workflow knows that it sent a request and little else. The operation may have failed before reaching the server, it may still be running, or it may have finished with its response lost on the return journey. An automatic retry could recover from the first case and create a duplicate credit in the last one.
There is no comfortable default here. Refusing to retry could leave the customer with nothing, while retrying could issue the credit twice. Asking the model what probably happened only adds an opinion to the ambiguity. The missing fact has to come from the billing system.
The credit operation needs a stable identity created before execution and reused across attempts. The billing boundary records that identity with the target account and the $1,200 amount. When the same request returns, it provides the original result instead of creating another credit. If the identifier arrives with different parameters, the request is rejected because its meaning has changed.
With that contract in place, several delivery attempts can refer to one logical credit operation. Stripe's guidance on idempotent requests describes a similar approach for API clients. The client supplies a unique key, and a retry after a connection error receives the result associated with the original request instead of creating the side effect again.
Idempotency may still leave work for the workflow. After an ambiguous response, it can query billing by operation ID, verify that exactly one $1,200 credit exists, and only then mark the step complete. Completion is based on the recorded billing state rather than a tool call retained in the agent's conversation.
This is where a harmless-looking retry can turn into a production incident. A transient network error may justify another attempt after backoff, while invalid arguments will not improve with persistence. Repeated calls against an overloaded dependency can deepen the outage. The agent may help classify a failure, but the execution layer should enforce retry limits and decide which failures are safe to retry.
If the operation has no stable identity, billing has no reliable way to recognize the retry as another delivery of the earlier request.
The execution envelope
At this point, the apparently simple service-credit agent has accumulated quite a supporting cast. It needs workflow state, an approval protocol, a stable operation identity, a retry policy, and a way to reconcile external state. These components do not improve its reasoning. They allow the business to rely on what happens after the reasoning.
The agent sits in the middle of this diagram by design. It receives a constructed view of the case and returns a proposed next action. It has no unrestricted route into the billing database. It cannot choose which user identity to borrow or decide that its own arguments are valid. A proposed $1,200 credit still passes through policy and approval checks before it reaches an executor.
A production tool interface needs structured input, validation for the account and amount, an explicit execution identity, and a result that reports whether the outcome is known. Its capability should be as narrow as the task allows. A tool limited to issuing service credits is easier to constrain and audit than one that accepts arbitrary billing commands.
The boundary becomes especially important when policy is involved. We can instruct the model never to issue credits above $1,000 without approval, but the executor must verify that approval before calling billing. A simple test helps here. If the model ignored the instruction, would the rule still hold? If the answer is no, the system is treating a mandatory policy as expected model behavior.
Where responsibility sits
The boundary is easier to see if we follow one decision through the system. The agent interprets the evidence and proposes what to do next. It might request another document, select a tool, or escalate because the case falls outside the policy it understands. The application supplies the current context and checks whether the proposed transition is valid.
Once an action has been proposed, system-owned services take over the guarantees. They verify identity, permissions, policy, and approval before anything reaches billing. They assign the operation its identity, execute it under a retry policy, and reconcile an uncertain response with the external system.
The separation continues after execution. Workflow services preserve progress across interruptions and prevent duplicate delivery from creating duplicate effects. Traces and audit records retain the inputs, decisions, approvals, attempts, and final state. The agent can provide its rationale, but the application preserves the evidence required to verify it.
This still leaves substantial work for the agent. Interpreting incomplete evidence, choosing among permitted actions, and recognizing an exceptional case are the reasons to use an agent instead of encoding the entire process as a fixed workflow.
Rules such as “one approved credit per case” must survive variation in model output, including variation introduced by a model upgrade. Enforcing them in the tool layer limits the damage an ambiguous instruction, stale context, or duplicate call can cause. Building tools for agents explores how these execution contracts shape the safety and reliability of the larger system.
State that outlives the worker
The durable record also expresses the lifecycle of the work. It shows when the evidence has been collected, when a credit has been proposed, and when the case is waiting for approval. After execution, it distinguishes a confirmed credit from one whose outcome is still uncertain. Each state restricts the next valid transitions and records the facts a later worker will need.
Versioning can sound overly cautious until an approval outlives the data behind it. While the manager is away, a finance administrator corrects the invoice, making the proposed credit stale. When approval finally arrives, the workflow compares the version the manager saw with the current one. Without that check, it could issue a credit based on an invoice that no longer exists in the form the manager approved. The amount may need to be recomputed and sent back for approval.
Time also exposes the difference between retry and compensation. Suppose the credit succeeds but the support case update fails. Reversing the credit would probably be worse than retrying the case update. A credit issued to the wrong account is different. Recovery may require an explicit compensating action and human review because external side effects rarely come with a universal rollback button.
Distributed systems have handled this tension for years through patterns such as sagas. They distinguish forward recovery, where a failed step is retried, from backward recovery through a compensating operation. AWS's overview of saga patterns offers a useful introduction. Agentic workflows inherit the same constraints whenever their actions cross service and transaction boundaries. An agent can help choose among approved recovery plans, but it should not invent what “undo” means while an incident is unfolding.
The process does not have to stay alive for the duration of the case. Any healthy worker can continue it if the necessary events and transitions have been persisted. Designing long-running AI jobs requires careful decisions about what to record, when to checkpoint, and how to resume without repeating completed work.
Observe the outcome, not the transcript
Suppose the customer still receives two credits. The agent transcript is an obvious place to look because it is readable and gives the incident a neat narrative. It contains a coherent explanation for issuing one credit. The duplicate, however, was created somewhere outside that narrative.
The investigation has to follow the causal path through the entire system. Which workflow version was running? What evidence did the model see? Which approval authorized the credit, and what reached billing on each attempt? The final account state matters as much as any of those records. Model input and output occupy one span in that sequence, even if they are the easiest span to read.
The system therefore needs correlated traces across orchestration, model calls, policy checks, tool execution, and external services. Metrics should make rising retry rates or approval delays visible. Audit events should preserve business facts in terms an operator can use. OpenTelemetry's observability primer explains the value of traces in distributed systems. They preserve the path of a request across components, while isolated logs often lose the relationship between events.
Operators use that evidence to reconstruct an individual run. The same data can support evaluations across a larger set of cases, including failures that are hard to reproduce manually.
Checking whether the model selected the correct billing tool is too narrow. An evaluation should verify that the amount matched the evidence, the correct approval was obtained, one credit appeared in billing, and the support case reached a consistent state. It should inject timeouts and restarts as well. If an ambiguous response leads to reconciliation rather than another credit, the architecture has passed a test that a happy-path model score cannot express.
The final billing state and approval record can be checked deterministically. Assessing the quality of the agent's explanation may need expert review or a carefully validated model grader. Together, these checks evaluate both the decision and the effects it caused. The same instrumentation will expose performance problems that transcripts miss, including repeated context construction, slow approval queries, serial tool calls, and retries hidden inside several layers. Those problems are explored further in understanding where agent time went.
Stronger models do not make the network reliable
When a stronger model demonstrably improves decisions for a particular workload, we can give it harder judgments. Perhaps it interprets policy more accurately, notices missing evidence more often, or knows when to escalate. That can widen the range of cases handled autonomously. It may also reduce how often the surrounding system rejects a poor proposal.
The execution environment does not improve along with the model. Processes still terminate, networks still lose responses, and external systems may accept the same instruction twice. An approval can become stale before anyone uses it. Permissions can also drift beyond what a task requires. Model quality has little bearing on any of these conditions.
Success creates its own pressure. Once the agent handles routine cases well, the natural next step is to give it more consequential tools and longer-running work. That is exactly when failures in authorization, state management, or side-effect handling become more expensive.
Removing every runtime choice would turn the agent back into a fixed workflow. A production design instead gives it a defined set of choices and places validation, authorization, execution, and recovery around them. Sensitive capabilities may also need isolation, especially when an agent executes code or handles untrusted input. Secure agent execution examines that problem in detail.
This can feel disproportionate when the model call is the most sophisticated part of the product. Yet the mundane questions decide whether the product can be trusted. Did the state survive a restart? Did the approval authorize this exact action? Could a retry issue the credit twice? When the agent's record disagrees with billing, operators need a way to reconcile the difference and enough evidence to explain how it arose.
The agent is free to choose what should happen next. The architecture must ensure that this freedom does not compromise correctness, safety, or recoverability.