Call
AI Backend

Backend for AI Agents: Durable Runs, Tool Execution, Memory, Safety, and Observability

A production backend blueprint for AI agents covering durable run state, tool execution, MCP, idempotency, approvals, memory, cancellation, sandboxing, budgets, recovery, observability, and agent evaluations.

Published: April 8, 2026
Updated: September 10, 2026
13 min read
Backend for AI Agents: Durable Runs, Tool Execution, Memory, Safety, and Observability

Backend for AI Agents: Durable Runs, Tool Execution, Memory, Safety, and Observability

An AI agent backend is not just an API endpoint that repeatedly calls an LLM.

Once an agent can use tools, wait for approvals, survive long tasks, resume after failures, manipulate external systems, or maintain memory across sessions, it becomes a distributed workflow runtime.

The backend has to answer questions such as:

  • What exactly is the current run state?
  • Which tools is this user allowed to invoke?
  • What if a tool succeeds but the network times out before the result is recorded?
  • What happens if the server restarts halfway through a 30-minute task?
  • How does the user cancel or steer an active run?
  • How many iterations can the model take before it stops?
  • How are approvals represented durably?
  • Which model/tool event caused a bad action?

That is the real backend architecture problem for AI agents.


The Agent Loop Belongs Inside a Controlled Runtime

At its simplest, an agent loop is:

user goal
   ↓
model decides next step
   ↓
tool call or answer
   ↓
tool result returns to model
   ↓
repeat until finished

The dangerous implementation is an unbounded loop:

while model_wants_tool:
    execute_tool()
    ask_model_again()

A production runtime needs policy around every transition.

Run Controller
  ├── model call
  ├── tool validation
  ├── authorization
  ├── approval policy
  ├── execution
  ├── state persistence
  ├── budgets / stop rules
  ├── cancellation
  └── observability

The model proposes what should happen next. The runtime decides what is actually allowed to happen.


1. Give Every Agent Run a Durable Identity

Every task should have a stable run ID.

A useful run record might include:

run_id
user_id / tenant_id
conversation_id
agent_id
status
model configuration
started_at
updated_at
current_step
iteration_count
cost/token counters
cancellation state

Possible states:

queued
running
waiting_for_tool
waiting_for_approval
waiting_for_external_event
completed
failed
cancelled

Do not infer run state only from the latest chat message.

Explicit state makes recovery, UI status, debugging, cancellation, and concurrency controls much easier.


2. Persist Important Transitions, Not Just Chat Messages

A transcript alone cannot tell you everything that happened.

Store structured events such as:

run.started
model.requested
tool.proposed
tool.authorized
tool.started
tool.completed
approval.requested
approval.granted
state.compacted
run.completed

Each event should preserve safe identifiers and relevant metadata.

This creates an execution history that can answer:

> Did the model request the action twice, or did the executor run it twice?

That distinction is impossible to debug from a flattened chat transcript.


3. Separate Conversation State From Execution State

These are related but different.

Conversation state

Contains what the model needs to reason:

  • user messages
  • assistant messages
  • tool calls/results
  • summaries/compaction
  • retrieved context

Execution state

Contains what the runtime needs to remain correct:

  • active tool call IDs
  • approval status
  • retry counts
  • idempotency keys
  • deadlines
  • external job handles
  • run ownership
  • cancellation flags

Do not hide critical execution state inside natural-language conversation summaries.

A model may forget or reinterpret text. Your backend should not.


4. Tool Calls Need Stable IDs and Lifecycle States

Every tool invocation should have a unique call ID.

Conceptually:

proposed
   ↓
validated
   ↓
authorized
   ↓
approved if required
   ↓
executing
   ↓
succeeded / failed / cancelled

Persist enough state that a retry can answer:

Has this exact tool action already run?

This becomes essential for side effects.


5. Idempotency Protects Against Duplicate Actions

Imagine an agent calls:

create_refund(order_123)

The refund succeeds, but your worker crashes before recording the response.

After restart, the runtime sees an incomplete step and executes it again.

Without idempotency, one infrastructure failure becomes a duplicate business action.

Use a stable idempotency key derived from the logical action where supported:

run_id + tool_call_id

For systems that do not natively support idempotency, maintain your own durable action ledger where possible.

Retries should repeat safe execution, not blindly replay side effects.


6. Tool Definitions Are Capabilities, Not Permissions

The model may know that a tool exists without being allowed to use it in the current context.

Separate:

available tools

from:

allowed tools for this user/run/step

Authorization should consider:

  • authenticated user
  • tenant/workspace
  • role
  • resource
  • tool
  • action
  • current run policy

The system prompt is not an authorization layer.

OWASP's Excessive Agency guidance specifically warns about giving agents unnecessary functionality, excessive permissions, or too much autonomy.


7. Prefer Narrow Tools Over Open-Ended Power

Compare:

run_shell(command: string)

with:

restart_service(service_id)
read_log(service_id, range)
deploy_release(release_id)

The generic shell tool is flexible but gives the model a much larger action surface.

Narrow tools:

  • constrain inputs
  • make authorization easier
  • improve audit logs
  • reduce accidental actions
  • allow resource-level policy

Open-ended tools can still be justified for coding or infrastructure agents, but they need stronger sandboxing, path/network restrictions, approvals, and validation.


8. Validate Tool Arguments Deterministically

A model-generated argument object is untrusted input.

Validate:

  • schema
  • types
  • ranges
  • allowed enum values
  • path boundaries
  • resource ownership
  • tenant scope
  • maximum payload size

Do not rely on a tool description saying:

"Only use safe paths."

If the tool accepts a filesystem path, trusted code should enforce the allowed root.

If it accepts an order ID, trusted code should verify that order belongs to the current tenant.


9. Approval Is a Durable Workflow State

Human approval should not be implemented as:

agent asks in chat
server hopes the next message means yes

Create an explicit approval object:

approval_id
run_id
tool_call_id
action summary
risk level
requested_at
expires_at
decision
decided_by

The agent run transitions to:

waiting_for_approval

When approval arrives, the runtime resumes from the exact suspended action.

This remains correct even if the server restarts or the user returns hours later.


10. Long-Running Work Needs Durable Execution

Some agent work lasts longer than one HTTP request:

  • repository-wide coding changes
  • browser research
  • large data imports
  • infrastructure migrations
  • deployment workflows
  • approval-dependent business processes

Do not keep one web request open as the source of truth.

Use a durable execution mechanism:

API request
   ↓
create run
   ↓
queue/workflow system
   ↓
worker executes steps
   ↓
persist checkpoints/events
   ↓
stream progress separately

Systems such as Temporal are built around durable workflows that resume after process, network, or infrastructure failures. You do not need Temporal specifically, but you do need the same fundamental property for important long-running agent work: execution must survive the worker that happens to be running it.


11. MCP Is a Tool Protocol, Not Your Agent Runtime

Model Context Protocol (MCP) is useful for standardizing how agents/clients discover and call external tools and data services.

But MCP does not replace your application-level run state, policy, memory, approval model, or business workflow.

The latest MCP specification released on July 28, 2026 moved the protocol core toward stateless HTTP requests and placed long-running Tasks in an extension.

That reinforces an important separation:

MCP
→ tool/context transport contract

Your backend
→ durable agent execution + policy + state

A scalable MCP server can remain stateless while the agent application using it maintains durable state elsewhere.


12. Tool Catalogs Should Be Discoverable Without Flooding Context

Large platforms can have hundreds of tools.

Sending every schema to the model on every request increases:

  • token usage
  • prompt size
  • model confusion
  • tool-selection errors

Use grouping, discovery, or tool-search patterns so only relevant tools enter the active context.

The runtime can maintain a large registry while exposing a much smaller active subset to the model.

Think:

all platform tools
       ↓
policy + task relevance
       ↓
small allowed tool set
       ↓
model

This improves both safety and context efficiency.


13. Memory Is Not One Table

Agent systems often mix several kinds of memory.

Working/conversation memory

The active context needed for the current task.

Compacted session state

A condensed representation of long conversations/runs.

User memory

Durable preferences or facts intentionally retained across sessions.

Project/domain memory

Knowledge tied to a repository, customer, workspace, or long-running project.

Episodic execution history

What the agent actually did in previous runs.

Do not retrieve every memory type for every model request.

Use scoped retrieval and explicit ownership boundaries.


14. Compaction Must Preserve Operational Facts

Long agent runs can exceed useful context size.

When compacting, preserve facts such as:

  • completed actions
  • failed attempts
  • IDs created during the run
  • user constraints
  • tool outputs that affect future steps
  • unresolved blockers
  • current plan
  • next action

Do not preserve every token equally.

Conversation compaction is lossy by design, so durable execution facts should exist outside the summary as structured state.


15. Budgets and Stop Rules Prevent Runaway Agents

Every run should have bounded resources.

Useful limits include:

maximum model turns
maximum tool calls
maximum wall-clock duration
maximum token usage
maximum spend
maximum repeated failures
maximum consecutive no-progress steps

The runtime should stop or escalate when limits are exceeded.

This protects against:

  • accidental loops
  • repeated failing tools
  • adversarial prompts
  • unexpected provider behavior
  • runaway cost

“Continue until done” is a behavioral instruction, not a resource policy.


16. Detect Lack of Progress

A model can repeat variations of the same failing action.

Track signals such as:

same tool + equivalent arguments repeatedly failing
same error repeated N times
no new state produced across several iterations
same file/query repeatedly inspected

The runtime can then:

  • stop
  • ask the user
  • switch strategy
  • escalate to another model/workflow

Do not rely entirely on the model to notice its own loop.


17. Cancellation Must Propagate Downstream

When the user presses Stop, setting:

run.status = cancelled

is not enough.

Cancellation should propagate to:

  • active model stream/request
  • tool execution
  • subprocess
  • browser job
  • remote workflow where supported
  • queued future steps

Every executor should periodically observe cancellation or receive an explicit cancellation signal.

A cancelled agent that keeps modifying external systems is not actually cancelled.


18. Steering and New User Input Need Ordering Rules

Modern agents may receive new instructions while already working.

Define semantics for:

  • steer — modify the active run
  • follow-up — execute after the current run finishes
  • cancel-and-replace — stop current work and start a new run

Do not silently map every new message to cancellation.

Store user input with ordering/causality so the runtime knows which run or checkpoint it applies to.


19. Concurrency Needs Ownership

Two workers should not execute the same run step simultaneously.

Use one of:

  • durable workflow ownership
  • leases
  • row/version locks
  • optimistic concurrency
  • compare-and-swap state transitions

A state transition might require:

UPDATE run
SET status='running', version=version+1
WHERE run_id=? AND version=?

The exact mechanism varies, but there must be one logical owner for side-effecting work.


20. Retries Belong at the Correct Layer

Different failures deserve different retries.

Model request retry

Appropriate for some transient provider failures.

Tool transport retry

Appropriate when the operation is idempotent or its state can be checked safely.

Business action retry

Requires stronger idempotency/transaction semantics.

Whole agent-step retry

Dangerous if previous side effects may already have succeeded.

Do not put a generic retry wrapper around the entire agent loop.


21. Sandboxing Is Essential for High-Power Tools

Coding, shell, browser, and infrastructure tools can execute attacker-controlled or model-generated instructions.

Use defense in depth:

  • isolated processes/containers/VMs where appropriate
  • filesystem allowlists
  • network policy
  • CPU/memory/time limits
  • secret isolation
  • dropped privileges
  • command/tool allowlists where feasible
  • cleanup after runs

The more generic the tool, the stronger the execution boundary should be.


22. Treat Tool Output as Untrusted Too

External tools can return malicious or misleading content.

Examples:

  • webpage with prompt injection
  • repository file containing instructions to the agent
  • compromised MCP tool response
  • user-controlled database field

Label external results as data and prevent them from changing authorization policy.

A tool result should influence reasoning, not redefine what the runtime allows.


23. Observability Must Follow the Entire Run

A useful trace hierarchy is:

agent.run
  ├── model.call
  ├── tool.call
  │    └── external dependency
  ├── model.call
  ├── approval.wait
  └── model.call

Record metrics such as:

  • run completion rate
  • run duration
  • model calls per run
  • tool calls per run
  • tool failure rate
  • approval frequency
  • tokens/cost per successful run
  • cancellation rate
  • loop/limit termination rate

A model latency dashboard alone cannot explain agent behavior.


24. Build Evals From Real Agent Trajectories

Evaluate more than the final answer.

Useful agent metrics include:

  • task success
  • correct tool selection
  • unnecessary tool calls
  • policy violations
  • side-effect correctness
  • recovery after tool failure
  • number of iterations
  • cost per successful task
  • whether the run stopped when it should

Store sanitized failed trajectories and convert recurring failures into regression tests.

Agent engineering is empirical. Prompts, models, tool schemas, and runtime policies should be changed against measured outcomes.


25. A Practical Production Architecture

Client / UI
    ↓
Agent API
    ↓
Run Controller ───────────────→ Durable Run Store
    │                              │
    ├── Model Gateway              ├── events/checkpoints
    │                              ├── approvals
    ├── Policy / Authorization     └── budgets/status
    │
    ├── Tool Registry / MCP Clients
    │          ↓
    │      Tool Executors
    │          ↓
    │   sandbox / external APIs
    │
    ├── Memory / Retrieval
    │
    └── Queue / Durable Workflow Engine
               ↓
            Workers

Start with fewer services if the workload is small, but preserve these logical boundaries so the system can evolve without mixing model reasoning with trusted execution policy.


Production Checklist

Run state

  • Every run has a stable ID and explicit status
  • Critical transitions are stored as structured events
  • Execution state is separate from chat text
  • Worker ownership prevents duplicate execution
  • Runs can recover after process/server failure

Tools

  • Every tool call has a stable call ID
  • Arguments are validated in trusted code
  • Authorization is enforced outside prompts
  • Side-effecting actions are idempotent or reconciled
  • High-power tools run inside appropriate isolation
  • External tool output is treated as untrusted data

Control

  • Approval states are durable
  • Cancellation reaches active downstream work
  • Steer/follow-up/cancel semantics are explicit
  • Iteration, time, token, and cost budgets exist
  • Repeated no-progress behavior can be detected

Memory

  • Working memory and durable memory are separate concepts
  • Memory is tenant/user/project scoped
  • Compaction preserves critical operational facts
  • Structured state is not replaced by summaries

Operations

  • Run-level traces connect model and tool calls
  • Cost per successful task is measurable
  • Failed trajectories feed regression evals
  • Provider/tool retries are error-aware and bounded

Final Takeaway

A production AI agent backend is a durable, policy-controlled execution runtime.

The model should be responsible for reasoning and proposing actions. Trusted backend code should remain responsible for identity, authorization, validation, approvals, idempotency, resource limits, persistence, and recovery.

That separation lets you change models, tool protocols, or orchestration libraries without rebuilding the security and correctness boundary of the system.

Start with one controlled run loop. Make every side effect traceable and recoverable. Add memory, MCP, long-running Tasks, multi-agent coordination, and advanced orchestration only when the product genuinely needs them.

References

Tags:AI AgentsAgent RuntimeTool CallingMCPDurable ExecutionAI SafetyObservability
AI & AGENT ENGINEERING

BUILDING AN AI PRODUCT?

Talk to Lofingo about custom autonomous AI agents, enterprise workflow automation, and scalable software systems.

EXPLORE AI SERVICES →