AI
Agents
Architecture
LLM
Automation

How AI Agents Actually Work: Architecture, Memory, Tools, and the Agent Loop

Mouhssine Lakhili profile
Mouhssine Lakhili
February 9, 202613 min read

A technical walkthrough of AI agent architecture: the agent loop, tool use, memory (RAG/vector DBs), evaluation, and common production failure modes.

How AI Agents Actually Work: Architecture, Memory, Tools, and the Agent Loop
Article cover: A practical guide to agent architecture, memory, tool use, and orchestration by Mouhssine Lakhili.

Introduction

Most people explain AI agents as "an LLM with tools". That is directionally true, but incomplete.

To understand how AI agents work, you need a systems view: an agent is a control loop that repeatedly (1) reads state, (2) decides, (3) acts, and (4) measures what happened. The LLM is usually the decision module, but the agent is the whole runtime around it.

This is a technical, implementation-minded guide to AI agent architecture: the components, the data flows, and the patterns that make LLM agents reliable in production.

Why AI agents are important now

AI agents matter right now because three things became practical at the same time:

  1. Models are good enough at planning and tool selection for many narrow tasks.
  2. Tool calling became a first-class interface (structured function calls, JSON schemas, constrained outputs).
  3. The cost/latency curve dropped enough to run multi-step loops instead of one-shot prompts.

Where they are used today

AI agents are already deployed in production for:

  • Developer tooling: code search, refactors, test generation, CI triage, PR reviews.
  • Support and operations: ticket triage, runbook execution, incident summarization, on-call assistants.
  • Data work: SQL generation with validation, dashboard explanations, anomaly follow-ups.
  • Security and IT: access request workflows, alert enrichment, remediation suggestions (often with approvals).
  • Research: source collection, summarization, and synthesis (usually with human checkpoints).

What is an AI agent?

Definition (simple and useful): An AI agent is a software system that uses an LLM (or other policy) inside a loop to choose actions that change the state of an environment in order to achieve a goal.

That definition has three non-negotiables:

  1. Loop: the agent runs multiple steps, not one prompt.
  2. Actions: it can trigger side effects (API calls, DB writes, file edits, transactions).
  3. State: it reads and updates a representation of the world (observations + memory).

LLM vs chatbot vs AI agent

Here is the mental model most teams converge on:

ThingWhat it isWhat it outputsTypical failure
LLMA probabilistic text-to-text functionTokens (text / JSON)Confident nonsense ("hallucination")
ChatbotAn LLM wrapped in a conversation UIMessagesHelpful but passive (no action)
AI agentA loop + state + tools + policies with an LLM as a plannerActions and outcomesUnsafe actions, bad tool calls, loops

Callout: An LLM is stateless. An agent is stateful. That difference explains most architecture decisions.

Core architecture of an AI agent

You can implement agents many ways, but most production designs contain the same core components.

(inputs) User/Env
      |
      v
  +---------------------------+
  | Perception / I-O          |
  +-------------+-------------+
                |
                v
  +---------------------------+      +---------------------------+
  | Context Builder           | <--> | Memory                    |
  | (rules + RAG + schemas)   |      | (state + vector DB)       |
  +-------------+-------------+      +---------------------------+
                |
                v
  +---------------------------+
  | LLM Reasoner              |
  | (plan + choose next step) |
  +-------------+-------------+
                |
                v
  +---------------------------+
  | Tool Router + Guardrails  |
  | (validate + approve +     |
  |  retry + limits)          |
  +-------------+-------------+
                |
                v
  +---------------------------+      +---------------------------+
  | Tool Execution            | ---->| External systems / tools  |
  | (APIs, DBs, code, web)    |<---- | (APIs, DBs, services...)  |
  +-------------+-------------+      +---------------------------+
                |
                v
  +---------------------------+
  | Observations              |
  | (results + errors + state)|
  +-------------+-------------+
                |
                v
  +---------------------------+
  | Eval + Telemetry          |
  | (score + trace + alerts)  |
  +-------------+-------------+
                |
                +----> loop to Context Builder

(outputs) response / tool calls / state updates

Let us map the diagram to the mandatory components.

Inputs

Inputs are not only "the user's message". An agent typically ingests:

  • A goal: what success means (often explicit in the prompt or task payload).
  • User constraints: "do not email customers", "only suggest", "ask before spending money".
  • Environment state: current ticket status, repo state, database rows, system metrics.
  • Tool observations: the results of previous tool calls (including failures).
  • Policies: security rules, compliance requirements, tenant boundaries.

Reasoning

The "reasoning" module is usually an LLM call, but the important design choice is this:

  • Treat the LLM as an untrusted planner.
  • Keep the orchestrator code deterministic and strict.

Implementation concept: do not let "reasoning" directly run tools. Put a tool router between the LLM and side effects (for example ReAct or plan-and-execute styles).

Memory

Agents need memory because LLM calls are (effectively) stateless.

Two different problems get called "memory": short-term state during a run, and long-term knowledge across runs (facts, preferences, prior decisions).

Tools

Tools are how an agent affects the world. A tool is a function with a contract:

  • Name + description (what it does)
  • Schema (what inputs it accepts)
  • Deterministic implementation (what it actually executes)
  • Risk classification (read-only vs write, reversible vs irreversible)

Actions

Actions are the side effects created by tool calls:

  • Reading: fetch a record, list files, query metrics.
  • Writing: update a ticket, open a PR, send an email, execute a transaction.
  • Communicating: ask the user for missing information, request approval.

Production concept: actions should be idempotent and auditable. Treat every tool call like an API endpoint.

Feedback loop

Without feedback, agents become "demo loops": they keep doing things without knowing if it helped.

Feedback in real systems typically includes:

  • Outcome metrics: task success, user corrections, time-to-resolution.
  • Safety signals: policy violations, blocked tool calls, high-risk approvals.
  • Quality evaluation: rubric scoring, regression suites, golden datasets.
  • Tracing: step logs and tool call traces for debugging. If you cannot answer "what did the agent do, and why?", you do not have an agent. You have an incident waiting to happen.

The agent loop explained (Perceive, Think, Act, Evaluate, Repeat)

Most LLM agents can be understood as a loop with five phases:

  1. Perceive: collect observations (messages, environment state, tool results).
  2. Think: decide the next best step (plan, select tool, ask a question).
  3. Act: execute an action (tool call or user-facing response).
  4. Evaluate: check if the action helped (success criteria, safety, errors).
  5. Repeat: update state and continue until a stop condition.

Minimal pseudo-code

This is the simplest agent runtime you can ship (conceptually):

type Observation = { kind: "user" | "tool"; payload: unknown };
type ToolCall = { tool: string; args: unknown };

type StepDecision =
  | { kind: "tool_call"; call: ToolCall }
  | { kind: "final"; output: string };

const MAX_STEPS = 12;

export async function runAgent(goal: string, userMessage: string) {
  const state = { goal, history: [] as Observation[] };

  for (let step = 0; step < MAX_STEPS; step++) {
    // 1) Perceive
    const observation: Observation = step === 0
      ? { kind: "user", payload: userMessage }
      : state.history[state.history.length - 1];

    // 2) Think (LLM call produces either a tool call or a final answer)
    const context = buildContext({ state, observation });
    const decision: StepDecision = await llmDecide({ context, toolSchemas });

    // 3) Act
    if (decision.kind === "final") return decision.output;

    const validated = validateToolCall(decision.call); // schema + policy checks
    const result = await executeTool(validated);

    // 4) Evaluate + 5) Repeat
    recordTrace({ step, validated, result });
    state.history.push({ kind: "tool", payload: result });

    if (isGoalSatisfied({ goal, result })) break;
  }

  return "Stopped: max steps reached (needs human review).";
}

Important implementation detail: the "agent loop" is not magical. It is a normal program with stop conditions:

  • Max steps / max time
  • Goal satisfied (explicit success criteria)
  • Unrecoverable tool error
  • Low confidence or high risk -> ask for approval

Memory in AI agents

Memory is where most agent prototypes break in production. The model is not the problem. The memory product is.

Short-term vs long-term memory

Think in layers:

Short-term (per run)
- current goal, current plan
- intermediate results
- scratchpad / chain-of-thought (usually not stored)

Long-term (across runs)
- user profile/preferences
- project facts (APIs, endpoints, repos)
- decisions and outcomes (what worked, what failed)
- domain knowledge that must be consistent

Short-term memory is usually "what you put in the next prompt". Long-term memory is everything you store outside the prompt.

Vector databases, embeddings, and retrieval (RAG)

Vector databases are a common way to implement long-term, fuzzy recall:

  • You store documents (or chunks) with an embedding vector.
  • At query time you embed the query and do similarity search.
  • You return the top-k chunks and include them in the prompt.

This is RAG (retrieval-augmented generation). In agents, RAG is often the difference between "plausible" and "correct".

Practical details that matter: chunking, metadata filters, re-ranking, and context compression.

Retrieval pipeline (implementation sketch)

async function retrieveContext(input: { userId: string; query: string }) {
  const rewritten = await llmRewriteQuery(input.query);
  const q = await embed(rewritten);

  const candidates = await vectorDb.search(q, {
    topK: 12,
    filter: { userId: input.userId, docType: ["policy", "decision", "runbook"] },
  });

  const reranked = await rerank(candidates, { query: rewritten });
  const top = reranked.slice(0, 6);

  // Keep the prompt small and high-signal.
  return compressForPrompt(top, { maxTokens: 900 });
}

Callout: long-term memory should store facts, not transcripts. Store "refund denied on 2026-01-10 because policy v4" - not 200 lines of chat.

Tools and external actions

Tools are the boundary between language and reality. They are also the main safety risk.

APIs

For APIs, good agent tooling looks like good backend engineering: typed inputs, timeouts/retries, and idempotency for writes.

Example tool schema (conceptual):

{
  "name": "search_tickets",
  "description": "Search support tickets (read-only).",
  "parameters": {
    "type": "object",
    "properties": {
      "query": { "type": "string" },
      "limit": { "type": "integer", "minimum": 1, "maximum": 20 }
    },
    "required": ["query"]
  }
}

Databases

For DB access, most teams learn the same lesson: separate read and write tools.

  • Read tool: safe SELECT queries, strong guards, row limits.
  • Write tool: explicit operations, validated diffs, approvals for high risk.

If you let the model generate arbitrary SQL with write permissions, you are doing prompt engineering as a substitute for access control.

Code execution

Code execution is powerful (and dangerous). If your agent runs code:

  • use a sandbox (containers, timeouts, resource limits)
  • mount read-only by default
  • capture stdout/stderr as structured observations
  • never expose secrets in the execution environment

Browsing

Browsing agents introduce an extra threat model: the web is untrusted input.

Tool output can contain instructions ("ignore previous rules") that the model might follow. Mitigations:

  • treat browsing output as data, not instructions
  • isolate browsing from privileged tools
  • require citations for factual claims

Single-agent vs multi-agent systems

There is a lot of hype around multi-agent setups. They can help, but they also multiply complexity.

Differences

  • Single-agent: one loop, one state, one set of tools. Easier to debug, cheaper, less coordination overhead.
  • Multi-agent: multiple specialized loops (planner, researcher, executor, critic). More parallelism, but more failure modes.

Use cases

Single-agent fits:

  • well-scoped workflows (triage, summarization, form filling)
  • tool-heavy tasks with clear constraints
  • interactive assistants with approvals/checkpoints

Multi-agent fits:

  • large research or analysis tasks (parallel source collection + synthesis)
  • software engineering tasks (separate "design", "implement", "review" roles)
  • operations workflows with separate "monitor" and "remediate" roles

When to choose each

Start with a single agent. Move to multi-agent only when you have evidence that specialization improves outcomes, not just architecture aesthetics.

Multi-agent diagram (a common pattern):

             +------------------+
User/Task -->|  Orchestrator    |
             |  (policy + plan) |
             +---+----------+---+
                 |          |
        +--------+--+   +---+---------+
        | Researcher |   | Executor   |
        | (read-only)|   | (tool run) |
        +--------+---+   +---+--------+
                 |           |
                 +-----+-----+
                       v
                   Critic/Eval

Common failure points (and what they look like in real code)

Hallucinations

Hallucinations are often "missing retrieval" or "unclear stop conditions" in disguise.

Mitigations:

  • retrieve relevant facts (RAG) and quote them in the prompt
  • use structured outputs (schemas) instead of free-form text
  • require the model to cite sources (tool output IDs, document keys)

Bad tool usage

Symptoms:

  • wrong arguments (IDs, formats, types)
  • calling a write tool when a read tool would do
  • repeated tool calls due to unhandled errors

Mitigations:

  • strict validation before execution
  • tool risk levels + approvals
  • deterministic fallbacks (retry/backoff)

Infinite loops

Agents loop when the runtime does not define progress.

Mitigations:

  • max steps + max duration
  • progress heuristics (no new info -> stop)
  • loop detection (same tool call repeated N times)
  • require "next step must change state" in the decision schema

Poor memory design

Symptoms:

  • stale context overrides new data
  • private data leaks into prompts
  • retrieval returns irrelevant chunks (noise wins)

Mitigations:

  • store structured facts with metadata
  • TTL/recency weighting
  • filtering (tenantId, docType)
  • redaction before storage and before retrieval

Simple reference architecture (production-style)

If you want a clean, production-minded design, build an "agent runtime" with explicit components and interfaces.

Client/UI
  |
  v
API (auth, rate limits)
  |
  v
Agent Orchestrator
- builds context (policy + retrieval + tool schemas)
- calls LLM (planner)
- routes tools with guardrails
  |
  +--> Tool Registry
  |    - read tools
  |    - write tools (risk-gated)
  |
  +--> Memory Stores
  |    - relational (facts, tasks, decisions)
  |    - vector DB (docs, embeddings)
  |
  +--> Evaluation + Telemetry
       - traces per step
       - outcome metrics
       - regression suite

Data flow (end-to-end)

Request
  -> Authenticate + authorize
  -> Retrieve memory (RAG + structured facts)
  -> Build prompt/context (constraints + tool schemas)
  -> LLM decides next step (tool call or final answer)
  -> Validate + risk gate
  -> Execute tool (idempotent, traced)
  -> Store observation + update memory
  -> Evaluate outcome
  -> Respond (or continue loop)

A practical engineering rule

Keep the probabilistic parts at the edge:

  • LLM: planning, classification, summarization
  • Deterministic code: validation, authorization, side effects, persistence, metrics

That is the pragmatic essence of "how AI agents actually work" in production.

Conclusion

Key takeaways

  • AI agents are loops, not prompts. The loop is the product.
  • LLM agents need architecture: memory, tools, validation, evaluation, telemetry.
  • Memory is a system, and RAG is only as good as your chunking, filters, and compression.
  • Tools are APIs: schema-validated, risk-gated, idempotent, auditable.
  • Multi-agent is optional. Start single, scale complexity only when necessary.

Where the field is going

Expect the next wave of progress to be less about bigger models and more about:

  • standardized agent runtimes and tool contracts
  • better automatic evaluation (regression suites for agents)
  • safer browsing/tooling (prompt injection-aware pipelines)
  • domain-specific memory products (reliable long-term recall)

If you are building agents, focus on the boring engineering: constraints, testing, and observability. That is what turns a convincing demo into a dependable system.

Build with AI and ship with confidence

Need a developer who can turn ideas into production work?

I help teams ship React, Next.js, Node.js, AI, and automation work with clear scope, practical guardrails, and fast execution.

Share this article

Related articles