Skip to content

Agent Architecture Mental Model

An agentic application is not "an LLM with some tools". It is a software system in which a probabilistic decision-making component participates inside a deterministic runtime that owns state, policy, execution, persistence and observability.

The most useful starting model is:

User / API / Event
        ↓
Application Use Case
        ↓
Agent Runtime / Orchestrator
        ↓
Context Builder → Model Gateway
        ↓                ↓
   state projection   decision proposal
                         ↓
              Policy / Validation Layer
                         ↓
             Skill / Tool / Workflow
                         ↓
                 External World
                         ↓
                    Observation
                         ↓
                  Runtime State

The LLM is therefore one component in the decision path, not the owner of the application.

Model vs agent vs runtime

These concepts should stay separate:

Model
  probabilistic inference component

Agent
  goal-directed execution capability built around a model

Agent Runtime
  software that owns lifecycle, state, tools, policies, budgets and loop control

Application
  business/domain system that decides why the agent exists and what it is allowed to accomplish

A model can generate text without being an agent. An agent can exist only because a runtime gives the model state, capabilities and an execution loop. The application remains responsible for the actual business contract.

Probabilistic core, deterministic shell

The central engineering pattern is:

        deterministic shell
┌────────────────────────────────────┐
│ auth / policy / state / budgets    │
│ validation / retries / audit       │
│                                    │
│       probabilistic core           │
│      ┌──────────────────┐          │
│      │      LLM         │          │
│      │ plan / classify  │          │
│      │ decide / draft   │          │
│      └──────────────────┘          │
│                                    │
│ tool execution / persistence       │
└────────────────────────────────────┘

Use the model for tasks where semantic reasoning adds value:

  • interpreting ambiguous requests,
  • planning under incomplete information,
  • selecting a useful next action,
  • summarizing or transforming information,
  • extracting meaning from unstructured data,
  • choosing among several valid strategies.

Keep deterministic software responsible for hard guarantees:

  • authorization,
  • data integrity,
  • money movement,
  • permission checks,
  • schema validation,
  • state transitions,
  • idempotency,
  • resource budgets,
  • approval gates,
  • audit logging,
  • cancellation and timeout enforcement.

A model can recommend SEND_REFUND; application code decides whether the caller is authorized, whether the order is refundable, whether an approval is required, and whether the operation has already happened.

Control plane vs execution plane

It is useful to distinguish two conceptual planes.

Control plane

The control plane decides what should happen next and under which constraints.

Typical responsibilities:

  • run creation,
  • goal and policy resolution,
  • context construction,
  • planning,
  • next-action selection,
  • routing to skills/tools,
  • budget accounting,
  • stop-condition evaluation,
  • checkpointing.

Execution plane

The execution plane performs actual operations against systems.

Examples:

  • reading a GitHub repository,
  • executing SQL through a restricted data service,
  • sending an email,
  • writing a file,
  • invoking a deployment API,
  • querying a search index.

This does not require separate microservices. The distinction can exist inside one modular monolith. It is a responsibility boundary first, deployment boundary second.

Canonical state must live outside the model

A production runtime should never rely on the model's conversation context as the canonical state store.

Bad mental model:

LLM conversation
      =
current truth about the run

Better:

State Store
   ↓
selected projection
   ↓
Model Context

The runtime state can contain:

run_id
status
goal
success_conditions
current_plan
completed_steps
pending_steps
observations
artifacts
budgets
approvals
tool_results
failure_history
state_version

The model receives only the relevant projection for the current decision.

This separation enables:

  • resumability,
  • concurrency control,
  • auditing,
  • replay/debugging,
  • context compaction,
  • model/provider replacement,
  • deterministic state transitions.

Main architectural boundaries

A robust agentic system usually has several explicit boundaries.

Application boundary

Defines business use cases and domain rules.

The agent should not become an alternative path around application services.

Model boundary

All provider-specific behavior should enter through a model gateway or port.

The application should not scatter calls such as:

client.responses.create(...)

through business modules.

Capability boundary

Tools and skills should expose narrow, typed capabilities rather than raw infrastructure access.

Prefer:

create_support_ticket(input)

over:

execute_arbitrary_http_request(url, method, body)

State boundary

The runtime owns durable execution state. Model context is not the database.

Policy boundary

Authorization and safety rules must be enforceable independently of model compliance.

External-system boundary

Every side effect should cross an adapter where timeout, retry, idempotency, credentials and observability can be controlled.

Failure boundaries matter more with AI

A traditional function can fail because of code or infrastructure. An AI component adds another class: it can produce a syntactically valid but semantically poor decision.

Useful failure categories include:

Model failure
  invalid / low-quality decision

Contract failure
  schema or business validation fails

Policy failure
  action not authorized

Tool failure
  dependency unavailable / timeout

State conflict
  stale observation / optimistic lock conflict

Execution failure
  side effect partially or ambiguously completed

These should not collapse into one generic "agent failed" exception.

Single application before distributed system

Nothing about AI automatically implies microservices.

A strong initial structure is often:

Modular Monolith
├── domain modules
├── application/use cases
├── agent_runtime
├── skills
├── retrieval
├── policy
└── infrastructure adapters

This provides module boundaries without introducing network, deployment and distributed-state complexity too early.

Service extraction should happen because of a concrete requirement:

  • independent scaling,
  • separate ownership,
  • stronger isolation,
  • different availability requirements,
  • specialized infrastructure,
  • independent deployment lifecycle,
  • security/tenant boundary.

Example: support agent

A support application may look like:

HTTP API
  ↓
ResolveCustomerIssue Use Case
  ↓
Agent Runtime
  ├── Model Port
  ├── CustomerLookup Skill
  ├── OrderRead Skill
  ├── RefundProposal Skill
  └── TicketCreation Skill
          ↓
      Policy Layer
          ↓
Application Services
          ↓
CRM / Orders / Payments

The agent can reason that a refund appears appropriate. It does not bypass the refund application service. The existing deterministic refund policy still runs.

Anti-patterns

The LLM is the application

request → giant prompt → tool access → hope

There is no explicit state, policy or use-case boundary.

Provider SDK everywhere

Business code imports one model provider directly in many modules. Provider replacement and testing become expensive.

Raw infrastructure as tools

The model receives generic shell/database/network capabilities when domain-specific capabilities would be safer.

Hidden state in prompts

Important execution state exists only in messages, summaries or model-created notes.

Agent bypasses the domain

The normal application path validates rules, but the agent calls infrastructure directly and skips those rules.

Practical design rule

Ask of every architectural responsibility:

Does this need semantic judgement, or does it need a guarantee?

If it needs semantic judgement, an LLM may participate.

If it needs a guarantee, deterministic software must own it.

Takeaways

  • The model is not the agent runtime.
  • The agent runtime is not the whole application.
  • Put probabilistic reasoning inside deterministic boundaries.
  • Keep canonical state outside model context.
  • Make application, model, capability, policy and state boundaries explicit.
  • Do not introduce microservices merely because the system uses AI.
  • Architecture becomes more important, not less, when part of the system is probabilistic.