Designing Smart AI Agents: Architecture Patterns That Survive Production
A practical field guide to agent topologies, state design, and the failure modes that separate a demo from a system that survives 90 days in production.
Six months ago, a logistics company in Dubai flew me in to look at their "autonomous customer operations" pilot. The vendor demo was stunning. An agent quoted delivery timelines, resolved address discrepancies, and flagged high-risk shipments for human review. In the controlled demo, it resolved 94% of test cases without a human in the loop.
I asked for the production numbers. A pause. Then the CTO pulled up a dashboard. On real traffic — about 4,000 tickets a day, messy addresses, late tracking feeds, angry customers — the same agent resolved 11% of cases, and it hallucinated a delivery promise onto at least a dozen of the rest. Some of those promises cost the company real money in refunds and re-shipping.
The demo was not fake. The model was fine. The problem was that nobody had designed the system's architecture. They had pointed a capable model at a prompt, wrapped it in a loop, and called it an agent.
This article is the pattern language I wish that vendor had used: the topologies, the state design, the tool contracts, and the failure modes that decide whether an agent survives production. By the end you will be able to look at any agent project, name the pattern it is using, and — more importantly — say whether it is the right one.
First, Kill the Word "Agent" — Talk About Topology
"Agent" is a marketing word. "Topology" is an engineering word. A topology is the shape of your system: how many reasoning loops exist, how they talk to each other, who owns the state, and who decides what happens next. When a production agent collapses, it is almost never the model's fault. It is a topology that did not match the task.
Every agent architecture, no matter how clever the slideware, is one of six topologies. Learn to spot them, because each has a cost profile, a failure mode, and a narrow range of tasks it is genuinely good at.
1. The Single Loop
One model, one context window, a set of tools, a while loop. This is the default and the workhorse. The system prompt holds the goal, the context window holds working state, tools give it hands, and budget counters stop it from running forever.
Cost: lowest. Latency: lowest. Good for: narrow, well-scoped tasks — balance lookups, form extraction, single-domain Q&A with tools.
2. The Router
A small, fast model classifies the request and dispatches it to one of several specialized handlers. A ticket-triaging router sends payment disputes to a refund workflow, delivery questions to a tracking tool, and everything else to a general agent.
Cost: low. Latency: adds one cheap call. Good for: high-volume traffic where most requests are one of a few known shapes. This is the most underrated pattern in production, and the one I reach for first.
3. Orchestrator–Worker
One orchestrator decomposes a task into subtasks and hands each to a worker agent (or a plain function, or a search job). Workers return results; the orchestrator synthesizes. This is what people actually mean when they say "multi-agent," and most of the time it is one orchestrator with several specialized workers.
Cost: medium. Latency: medium. Good for: report generation, research, code review — tasks with a natural breakdown.
4. Hierarchical
Agents manage agents. A lead orchestrator spawns sub-orchestrators, each managing its own workers. This is how you scale orchestrator–worker to genuinely huge tasks, and it is also where complexity and cost start to compound.
Cost: high. Latency: high. Good for: enterprise research pipelines with thousands of documents. Usually a mistake for anything pattern 3 handles.
5. Peer Team
Multiple agents with equal standing converse or work in parallel toward a shared goal — the classic CrewAI and AutoGen picture: a researcher, a writer, and a critic arguing over a document until they agree.
Cost: high — every peer turn is a full model call and coordination overhead is real. Latency: high. Good for: creative drafting and debate-style tasks. Bad for: anything with a deadline and a strict budget.
6. The State Machine (Workflow)
No loop at all. A directed graph of steps — query, validate, charge, confirm — where each step is deterministic or model-assisted. LangGraph's graph model and n8n's node model are this pattern wearing graph paper.
Cost: lowest per step. Latency: predictable. Good for: anything that is 80% a known process with a few fuzzy decision points. Most "agent" use cases are secretly this, and it is the most honest pattern in the list.
Here is the quick reference I put in front of clients:
| Pattern | Loop? | Cost | Failure mode | Best for |
|---|---|---|---|---|
| Single loop | yes | low | context creep | narrow, scoped tasks |
| Router | no | low | bad classifier | high-volume triage |
| Orchestrator–worker | yes | medium | handoff context loss | research, reports |
| Hierarchical | yes | high | exponential cost | huge decompositions |
| Peer team | yes | high | coordination chatter | drafting, debate |
| State machine | no | low | rigid on exceptions | known processes |
The most useful question I ask before writing any code: is this task a process with a few judgment calls, or an open-ended goal with unknown steps? Process → state machine. Open-ended → single loop or orchestrator–worker. Almost never a peer team on day one.
State: The Part Everyone Forgets
Now the part that kills more production agents than any topology choice: state.
An agent's state is everything it carries between steps — the task definition, what it has already tried, what it has ruled out, the results of tool calls, and the budget it has left. If state lives only in the model's context window, you have a memory problem: context windows are bounded, noisy, and easy to poison. If state lives in your database, you have an engineering problem: every step needs a save, a load, and a version.
Here is the rule I now enforce with clients. Working state (what is on the model's desk right now) goes in the context window, trimmed ruthlessly. Durable state (what this task has accomplished, across retries and restarts) goes in a store — Postgres for structured task state, a vector store for retrieved knowledge, Redis for ephemeral job state. Every step is a pure function of durable state plus the model's decision. That one discipline — "state in the store, not in the prompt" — fixed more agent projects than any model upgrade I have ever shipped.
Concretely, a task row in Postgres looks like this:
CREATE TABLE agent_tasks (
id uuid PRIMARY KEY,
pattern text NOT NULL, -- which topology
goal text NOT NULL,
status text NOT NULL DEFAULT 'queued',
step_count int NOT NULL DEFAULT 0,
tool_calls jsonb NOT NULL DEFAULT '[]',
result jsonb,
created_at timestamptz NOT NULL DEFAULT now()
);
Every tool call is appended to tool_calls. If the process crashes, a worker picks up the row and replays from step_count. That is the entire secret of "reliable" agents: they are just jobs that can resume.
Tool Design: Descriptions Are Contracts
I keep saying tools are the agent's hands, but the part people get wrong is the description. The model reads your tool description and decides whether to use the tool. Write a lazy description and the model will misuse it in production, every single time.
Treat the description as a contract with three clauses:
- What it does. "Fetches the current available balance for a verified account."
- When to use it. "Call this when the customer asks about money they have or owe. Do not call it for transaction history — that is
get_transactions." - What it returns. "Returns
{balance: number}. Returns an error object if the account is not verified."
One more rule: validate inputs server-side before execution. The model's arguments are model output — they can be wrong, and in adversarial inputs they can be malicious. A SQL injection string smuggled through a tool argument is not a joke; it is a Tuesday.
A Working Orchestrator–Worker, Minimal
Here is the smallest orchestrator–worker I would ship, with the state discipline above. No framework — just Postgres, a queue, and two model calls per task.
import json
from typing import Any
def orchestrator(task: dict) -> str:
plan = llm_call(
"You are a research lead. Split this task into 3-5 subtasks "
"that can be executed independently. Return JSON.",
task["goal"],
)
subtasks = json.loads(plan)["subtasks"]
results = []
for sub in subtasks:
results.append(worker(sub)) # worker may call tools
save_task_state(task["id"], results) # durable state every step
return llm_call(
"You are a synthesis editor. Combine these subtask results "
"into one coherent answer for the original task.",
json.dumps({"goal": task["goal"], "results": results}),
)
def worker(subtask: dict) -> Any:
# deterministic routing: one tool call, one model pass
return run_tool(subtask["tool"], subtask["args"])
def save_task_state(task_id: str, results: list) -> None:
# UPDATE agent_tasks SET tool_calls = $1 WHERE id = $2
pass
Run this against real traffic and you will find the handoffs — the exact spots where context gets lost and tasks stall. That is the point: you want your failures in the handoff layer, because handoffs are cheap to instrument and cheap to fix. A hallucinated subtask decomposition, by contrast, is expensive to catch and expensive to repair.
Production Reality: The Failure Modes That Actually Hurt
After a year of shipping these systems across fintech, logistics, and support clients, here is my honest list of what breaks, ranked by how much it hurts:
- Silent overreach. The agent does something you never authorized, confidently. It sends the email, applies the discount, closes the ticket. Fix: a permission layer — read-only tools are free; mutating tools require approval or a hard policy.
- Context creep. Every step appends to the prompt, so by step 9 the model is reading a wall of its own noise. Fix: trim aggressively, summarize old steps, or move state to the store.
- Handoff loss. In orchestrator–worker, the orchestrator re-sums what workers already spent tokens producing. Fix: have workers return structured JSON, not prose, and let the orchestrator only assemble.
- Cost explosion. Peer teams and hierarchical patterns burn tokens at 5–10x a single loop. I costed a research task last month: single loop $0.18, orchestrator–worker $0.61, peer team $2.90 — for roughly the same output quality. Measure cost per resolved task, not per run.
- Silent degradation. The model slowly stops calling tools and starts guessing from training data. Fix: monitor tool-call rate per pattern and alert when it drops below a threshold.
And the biggest one, which is not technical at all: the demo/test gap. Your evaluation set was curated by the same person who built the system. Measure success on held-out production traffic from week one, or you will discover your own 11% version in a client call, like the logistics company did.
When NOT to Use a Pattern
- Single loop, but your task is a known process? Use a state machine. You are paying for open-ended reasoning you do not need.
- Orchestrator–worker, but your subtasks cannot run independently? You have invented a slower single loop. Each worker waits on the previous one and the orchestrator just adds a hop.
- Peer team, but there is no genuine disagreement or complementarity between the roles? You are paying for theater.
- Any pattern, but a deterministic script would do? It would. This year I told a client their "agent" for parsing an invoice format that never changes was really a 40-line parser. The parser cost a fraction of a cent per run. The agent cost four cents and failed 3% of the time. I saved them a recurring bill by not building the architecture.
The Checklist I Use Before Shipping Any Agent
- The topology is named and justified against the task, not assumed ("multi-agent" is not an answer)
- Process-like tasks use a state machine; only open-ended tasks get a loop
- Durable state lives in a store; the context window holds only what the current step needs
- Tasks can resume from a crash (step_count plus a tool-call log)
- Tool descriptions specify what, when, and what they return
- Tool inputs are validated server-side before execution
- Mutating tools have a permission layer
- Cost per resolved task is measured and budgeted
- Tool-call rate is monitored as a health signal
- Evaluation runs on held-out production traffic from day one
What Survives Production
Back to the logistics company in Dubai. We rebuilt the pilot as a router plus a state machine: a cheap classifier sent tickets to one of five deterministic workflows, and only the genuinely fuzzy cases reached a single-loop agent with strict budgets and a permission layer. Resolution climbed from 11% to 78% in the first month — not because the model got better, but because the shape of the system finally matched the shape of the work.
The model was never the problem. The topology was.
Start by naming the pattern you are actually building. If you cannot name it, you do not have an architecture — you have a prompt with a cost. Draw the graph, put the state in the store, write the tool contracts, and treat the checklist above as your last step before production.
*Gulshan Yad
Architectural Patterns Overview
Modern AI agents thrive when built atop proven distributed systems foundations. A microservice‑centric approach slices the agent into discrete services—intent parsing, policy evaluation, action execution, and state persistence—each with its own deployment pipeline and scaling constraints. Layering these services ensures that a failure in the natural‑language understanding module does not cascade into the policy engine or the external API layer.
Event‑driven communication, typically via a message bus or event stream, decouples services and provides inherent replayability. Agents can process intents asynchronously, queueing them for later resolution, which is essential for handling bursty traffic without overloading expensive inference engines. Coupling this with a service mesh gives fine‑grained traffic control, mutual TLS, and observability hooks that surface latency and error rates at the per‑service level.
Trade‑offs are inevitable. A heavily modular design introduces network hops, which can inflate latency, but the benefit of independent versioning and fault isolation far outweighs that cost in production. The key is to evaluate the criticality of each service: if an intent parser can be swapped out without affecting end‑to‑end flow, keep it separate; otherwise, co‑locate tightly coupled components.
Intent‑Driven Design
At the heart of every resilient agent is a clear separation between what the system should do (intent) and how it does it (execution). Declarative intents—expressed as policy rules, constraint sets, or natural‑language goals—allow non‑technical stakeholders to influence behavior without touching code. Execution services, often powered by large language models or rule engines, consume these intents and materialize them into concrete API calls or internal actions.
A typical intent‑execution pipeline starts with a policy engine that validates and enriches raw user intent. The enriched intent is then routed to an execution orchestrator that selects the appropriate model or rule set. This orchestrator can also manage fallback paths: if the primary model fails or returns low confidence, the orchestrator may invoke a simpler heuristic or a human‑in‑the‑loop queue.
Best practices include keeping intent definitions versioned in a central repository, enforcing schema validation, and exposing a policy‑as‑code interface where developers can write tests against intent scenarios. This discipline ensures that intent evolution does not silently break downstream logic.
State Management and Persistence
Agents often need to remember context across sessions—user preferences, conversation history, or task progress. Stateless services scale effortlessly, but the agent’s value lies in its stateful awareness. A hybrid approach balances performance with durability.
Event sourcing is a powerful pattern: every state change is recorded as an immutable event. By replaying the event stream, the system can reconstruct any snapshot of the agent’s state, providing auditability and facilitating debugging. Periodic snapshots compress the event log, reducing replay time while still preserving the ability to reconstruct older states.
Consistency models must align with the agent’s tolerance for staleness. Strong consistency guarantees—such as two‑phase commit or distributed locking—are suitable for transactional intents, while eventual consistency suffices for conversational context that can tolerate brief lag. Caching with time‑to‑live (TTL) semantics ensures that hot state stays in memory, while stale data is refreshed from the event store.
Observability and Telemetry
Without visibility, even the best‑designed agents become black boxes. Embed instrumentation at every layer: metrics for latency, throughput, and error rates; logs that capture intent payloads and policy decisions; and distributed traces that follow a request across services.
Model‑specific telemetry—confidence scores, token counts, and drift indicators—provides early warning that a model’s performance is degrading. Combine these signals with anomaly detection algorithms that flag deviations from established baselines. Alerting should be granular: a spike in policy violations triggers a separate alert from a sudden increase in inference latency.
Dashboards that surface intent success rates, user satisfaction scores, and resource utilization empower operators to spot trends before they hit SLA thresholds. A well‑instrumented system also supports post‑mortem analysis, turning incidents into learning opportunities.
Deployment Strategies and Rollouts
Rolling out new agent code or model updates can be risky; progressive deployment mitigates that risk. Blue/green deployments swap entire environments, while canary releases expose the new version to a small percentage of traffic. Feature flags give fine‑grained control over which intents or user segments see the change.
CI/CD pipelines should treat models as first‑class artifacts: build the model, run unit tests against a small validation set, and push the artifact to a registry. Continuous integration should also run integration tests that simulate real‑world intent flows. Once a model passes, a canary deployment can start, monitoring metrics for any regression before full rollout.
Rollback mechanisms rely on keeping the previous model version alive behind the feature flag. If drift detection or error thresholds are breached, the system automatically toggles the flag back, ensuring uninterrupted service.
Governance, Compliance, and Ethics
Production agents must operate within legal and ethical boundaries. Embed a policy engine that enforces access controls, data residency constraints, and content filters. Every policy decision should be logged, timestamped, and stored for audit purposes.
Data privacy is paramount: anonymize personal data before it reaches the execution layer, and store only essential context. Implement encryption at rest and in transit, and enforce strict key‑management practices.
Bias mitigation requires continuous monitoring of model outputs. Use explainability tools to surface the rationale behind decisions, and maintain a feedback loop where human reviewers flag problematic responses. Regulatory compliance—such as GDPR or CCPA—demands that agents provide user rights to access, correct, or delete their data; design interfaces and workflows that satisfy these requirements.
Incident response plans should include rollback strategies, stakeholder notification procedures, and post‑incident reviews that feed back into policy refinement and model retraining. By treating governance as an integral part of architecture, agents can scale responsibly while maintaining trust.
Key Takeaways
- Modular microservice architecture keeps agents lightweight and independently deployable, reducing cross‑service failure risk.
- Separating intent from execution allows policy changes without retraining models, enabling rapid iteration and safer rollouts.
- Persisting state with snapshotting and event sourcing guarantees recoverability and auditability across restarts and scaling events.
- Embedding comprehensive observability—metrics, logs, and distributed traces—turns hidden agent behavior into actionable data.
- Deploying agents through progressive rollouts and canary releases mitigates impact of model drift or misbehavior.
- Planning graceful degradation and fallback paths ensures user experience remains intact even when external services or models fail.
Frequently Asked Questions
What distinguishes the intent layer from the execution layer in an agent architecture?
The intent layer captures declarative goals—what the agent should achieve—often expressed as natural‑language policies or constraints. The execution layer contains the procedural logic and models that transform those goals into concrete actions. Keeping them separate lets you tweak the intent without retraining the heavy execution models.
How can I maintain consistent state across distributed agents?
Use a combination of local in‑memory caches for high‑speed access and a distributed event‑store or snapshot service for durable persistence. Adopt idempotent operations and version stamps to detect and resolve conflicts, and consider eventual consistency when strict real‑time sync is unnecessary.
Which observability metrics are essential for monitoring AI agents in production?
Track latency per intent, throughput of action requests, error rates per policy, and resource utilization per model. Include model‑specific metrics such as confidence scores, token usage, and drift indicators to surface degradation early.
Is container orchestration or serverless the better fit for agent workloads?
Container orchestration (e.g., Kubernetes) offers fine‑grained control, persistent storage, and robust networking, making it suitable for stateful agents. Serverless is ideal for stateless, short‑lived tasks with bursty traffic. Many teams adopt a hybrid approach: orchestrated containers for core services, serverless for auxiliary, event‑driven functions.
How do I enforce policy and compliance constraints in production agents?
Embed a policy engine that evaluates every intent against a rule set before execution. Store policy definitions in a versioned repository, audit every policy decision, and expose a governance dashboard to track compliance violations in real time.
What is the best practice for versioning and rolling back agent models?
Treat each model as a first‑class artifact: tag it with a semantic version, store the training data snapshot, and maintain a model registry. Deploy new versions behind feature flags or canaries, and keep the previous version alive for rollback until confidence thresholds are met.
How can external knowledge bases be integrated without compromising performance?
Expose knowledge sources through lightweight APIs or local caches, and decouple the knowledge lookup from the core execution loop. Use asynchronous pre‑fetching and fallback strategies to avoid blocking critical paths.
What common failure modes should I monitor for early detection?
Watch for model drift (confidence drops), policy violations, resource exhaustion, network partitions, and data quality issues. Combine threshold alerts with anomaly detection on telemetry to surface subtle, evolving problems before they surface as user‑visible errors.
1 followers
AI systems builder · 7 years in production. RAG, self-hosted infra, agent architecture. 📬 Deep-dives → mrgulshanyadav.substack.com




Comments
Sign in to join the conversation
No comments yet. Be the first to share your thoughts!