logo
Kurashizu Blogwhere ideas flow
  • Home
  • News
  • Blog
  • About
  • Home
  • News
  • Blog
  • About

© 2026 Kurashizu. All rights reserved.

Admin·New Post·Service Status
Powered by Cloudflare·01.11.26
← Back to news

Infrastructure Patterns for Agentic Applications

Original article
render.com|23 points|2 comments|by jacobprall|Jul 29, 2026

Architecting Production-Ready AI Agents: Infrastructure Patterns

Many developers initially approach AI agent development as they would any standard web feature: they wrap a Large Language Model (LLM) in a route handler, process the incoming request, and wait for the model to return a response.

This works for simple chatbots. However, for complex agents, this leads to disaster. When agents begin calling tools, interacting with external APIs, branching into sub-tasks, or hitting rate limits, they often crash mid-sequence.

The Core Risk: If your agent's lifecycle is bound to a single HTTP request, your system's reliability is tethered to the wall-clock time of a non-deterministic loop.

This guide explores three essential patterns to transition from fragile scripts to resilient, scalable production systems.


The Fundamental Nature of Agents

At its heart, an agent is a continuous loop. We can represent the logic of this loop as: Goal→Decision→Action→Observation→State Update→Repeat\text{Goal} \rightarrow \text{Decision} \rightarrow \text{Action} \rightarrow \text{Observation} \rightarrow \text{State Update} \rightarrow \text{Repeat}Goal→Decision→Action→Observation→State Update→Repeat

This loop introduces several properties that are inherently hostile to traditional web architectures:

  1. Extended Lifespans: Agents aren't always fast; some may take hours or days to reach a conclusion.
  2. Complex State: The "state" isn't just a user ID; it's a combination of the goal, the current plan, tool outputs, error logs, and intermediate decisions.
  3. Persistence Requirements: If a process crashes, the system must know exactly where it left off to avoid starting from scratch.
  4. Dynamic Execution: Unlike traditional code, the model decides the next step at runtime.
  5. Unpredictable Resource Use: Agents may fan out into parallel tasks, wait for human intervention, or generate massive artifacts.

Agent Logic vs. Traditional Logic

FeatureTraditional WorkflowAgentic Workflow
PathingPre-defined (If/Else)Dynamic (Model-driven)
RecoverySimple retry of the functionComplex state replay/recovery
ExecutionLinear or predictable DAGNon-deterministic loop

Pattern 1: The Web-Queue-Worker Architecture

To solve the "timeout" problem, production systems decouple the request from the execution. Instead of running the agent inside the web request, the API should:

  1. Create a durable record of the "run."
  2. Enqueue the task.
  3. Return an immediate response to the user.

The user then monitors progress via status polling, WebSockets, or a callback webhook.

The Role of the Queue: It acts as a durable buffer, providing worker scaling, burst absorption, and basic retry logic.

The Limitation: While a queue knows a job exists, it is "blind" to the logical flow. It cannot natively manage a sequence of twenty dependent steps, complex branching, or pauses for human approval.


Ensuring Reliability: Idempotency and Compensation

Moving to a queue introduces a new problem: at-least-once delivery. This means a job might be executed more than once. To prevent this from causing chaos (e.g., charging a customer twice), you need two strategies:

1. Idempotency (Handling Duplicate Steps)

Idempotency ensures that performing an operation multiple times has the same effect as performing it once.

Bad Code: Assumes the worker never crashes between steps. Good Code: Implements an idempotency boundary.

For every tool call, the agent should follow this logic:

def execute_tool_step(step_id, tool_func, args):
    # 1. Check if this specific step was already completed
    if db.check_completed(step_id):
        return db.get_result(step_id)
    
    # 2. Mark as 'running' to prevent concurrent duplicates
    db.upsert_status(step_id, "RUNNING")
    
    # 3. Execute the actual side-effect
    result = tool_func(args)
    
    # 4. Mark as complete and store result
    db.mark_complete(step_id, result)
    return result

2. Compensation (Handling Partial Failures)

What happens when an agent completes 3 out of 5 steps and then fails permanently? If the agent charged a credit card and provisioned a server, you cannot simply "roll back" a database transaction.

This is solved via the Saga Pattern: for every action, define a corresponding compensating action to reverse the effect.

Compensation Requirements:

  • Must be idempotent.
  • Must have a bounded retry limit.
  • Must have a "dead-letter" path for failures.
  • Must provide a manual escape hatch for human intervention.

Note: Compensation is not always the answer. If an agent is processing five parallel orders and one fails, it is often better to accept the four successes rather than undoing everything.


Pattern 2: Workflow Engines

Once you have solved the "where does this run" problem with queues, you face the "how do I track this" problem. This is where Workflow Engines replace simple workers.

A workflow engine does not just execute a job; it manages the entire lifecycle of the run. It tracks:

  • Which steps started, finished, or failed.
  • Which steps are currently timing out.
  • Where the process is waiting for external events (e.g., a human clicking "Approve").
  • The exact state required to replay a failed run from the point of failure.

Infrastructure Diagram Placeholder

By moving to a workflow-based architecture, you shift the burden of state management and reliability from your application code to the infrastructure layer.