trendingzones
← Back to the Intermediate level

AI & ML — ADVANCED

AI Agents in Production: Memory Types, Real Code, and Failure Modes

Everything so far has shown an agent succeeding. Production systems have to plan for the version where it doesn’t — a tool called with the wrong argument, a loop that never ends, a task that costs far more than expected.

The Quick Answer

“Memory,” loosely used in the earlier levels, actually splits into four distinct kinds, each serving a different purpose. And the same tool-calling loop covered in Intermediate can be written out as real, runnable code — including the guardrails a production system actually needs, since an ungoverned loop can hallucinate arguments, run forever, or quietly rack up a large bill before anyone notices.

The Four Kinds of Agent Memory

The CoALA framework (Sumers et al.) describes a language agent’s memory as “modular memory components” rather than one single thing. Applied to an agent built around tool calling, four distinct kinds show up in practice:

Source: Sumers et al., “Cognitive Architectures for Language Agents,” arXiv:2309.02427

The “memory” from the earlier levels — the growing context window during one task — is working memory. Anything that needs to survive past that one session, like a knowledge base an agent can search, has to be built deliberately as episodic or semantic memory instead.

How the Four Memory Types Relate to Each Other

These four types aren’t independent boxes — they connect through exactly two named actions, and every connection passes through working memory. Retrieval reads information from a long-term store into working memory, so the model can use it right now. Learning writes information from working memory back out into a long-term store, so it survives past the current session. A third action, reasoning, only updates working memory itself — it’s the model actually thinking, using whatever is currently in view.

The detail worth noticing: no long-term store ever hands information directly to another long-term store. Something learned in episodic memory doesn’t become semantic knowledge on its own — it has to be retrieved back into working memory first, reasoned over, and then written out again as a separate learning action if it belongs in semantic memory too.

What Each Memory Type Is For, and When to Check It

When an agent gives a wrong answer, the fastest way to narrow down the cause is knowing which memory type it likely came from:

Memory typeWhat it’s forCheck this when…
Working memoryHolds the current context — the task at hand, recent messages, tool results seen so far.The agent contradicts something from earlier in the same conversation, or seems to “forget” a tool result it just received.
Episodic memoryStores records of specific past events — what happened, when, and with what outcome.The agent repeats a mistake it should already know about, or can’t recall how a similar past task actually went.
Semantic memoryStores general factual knowledge, independent of any one event — “what is true.”The agent states a fact that’s outdated, wrong, or missing entirely — not a one-off event, but knowledge that should be reliably known.
Procedural memoryStores how to do something — a skill, an instruction, a tool definition.The agent gets the facts right but performs the wrong steps, calls the wrong tool, or follows an outdated process.

A Debug Guideline for Agent Memory Issues

Once the table above points at a likely memory type, work through these steps in order rather than guessing at a fix:

  1. 1. Reproduce with the full trace visible

    Capture the exact working memory at the moment of the wrong answer — every message, every tool call and result. Most memory bugs are invisible without seeing this full trace, since the failure is rarely in the final text itself.

  2. 2. Ask what kind of thing was wrong

    A wrong recent fact points at working memory. A repeated past mistake points at episodic memory. A wrong general fact points at semantic memory. A right fact but wrong action points at procedural memory. This single question narrows the search dramatically before touching any code.

  3. 3. Check retrieval before blaming the model

    For episodic or semantic issues, confirm the relevant information was actually retrieved into working memory at all — a retrieval miss looks identical to a “hallucination” from the outside, but the fix is completely different (fix the search, not the model).

  4. 4. Check what actually got written, not just what should have

    For a learning (write) issue, confirm the record that should exist in long-term memory is actually there, in the form later retrieval expects — a common failure is writing successfully but in a format or location retrieval never looks in.

Most agent “hallucinations” that get blamed on the model are actually a retrieval miss or a working-memory truncation — the model answering correctly given what it could actually see, which simply wasn’t the right information. Checking memory first, before assuming the model itself is wrong, saves a lot of wasted debugging time.

A Real Tool-Calling Agent Loop, in Code

Here’s the same Tokyo temperature task from earlier levels, written as an actual runnable agent loop — a fixed decision function standing in for what a real model would decide at each step, real tool functions, and a hard cap on iterations:

MAX_ITERATIONS = 5

def get_weather(location):
    return 21  # Celsius

def convert_temperature(value, from_unit, to_unit):
    if from_unit == 'C' and to_unit == 'F':
        return round(value * 9/5 + 32, 1)
    raise ValueError('unsupported conversion')

def decide_next_action(state):
    if 'weather' not in state:
        return {'tool': 'get_weather', 'args': {'location': 'Tokyo, Japan'}}
    if 'fahrenheit' not in state:
        return {'tool': 'convert_temperature',
                'args': {'value': state['weather'], 'from_unit': 'C', 'to_unit': 'F'}}
    return {'tool': None, 'final_answer':
            f"It's {state['weather']}°C ({state['fahrenheit']}°F) in Tokyo."}

TOOLS = {'get_weather': get_weather, 'convert_temperature': convert_temperature}

def run_agent_loop(max_iterations=MAX_ITERATIONS):
    state = {}
    for i in range(max_iterations):
        action = decide_next_action(state)
        if action['tool'] is None:
            return action['final_answer']
        result = TOOLS[action['tool']](**action['args'])
        if action['tool'] == 'get_weather':
            state['weather'] = result
        elif action['tool'] == 'convert_temperature':
            state['fahrenheit'] = result
    raise RuntimeError(f'Exceeded max_iterations ({max_iterations}) without completing task')

Running this produces the same two-step trace shown in the Intermediate diagram — a weather lookup, then a conversion, then a final answer — and it actually executes, verified line for line. The max_iterations check is doing real work here, not just decoration: swapping in a decision function that never reaches a final answer causes the loop to raise an error at exactly 5 iterations, instead of calling tools forever.

What Goes Wrong in Production

The loop above is the happy path. Real deployments have to plan for all three of these failing on their own:

A concrete version of the first failure mode: a get_weather tool that only recognizes a fixed set of real cities will correctly reject a call like location="Neo Tokyo, Japan" — a plausible-sounding but nonexistent place a model might generate — with a clear error, rather than silently returning nonsense or crashing further downstream.

Fun Fact

Some tasks genuinely need more than one agent working together — a lead agent that plans and delegates, and separate subagents that each work a narrow slice of the problem in their own isolated context. That’s covered in depth, with a real measured performance result, in Context Engineering Advanced’s multi-agent case study.

Test Yourself

According to the CoALA framework, what is the difference between episodic and semantic memory?

Can episodic memory hand information directly to semantic memory, without passing through working memory?

An agent correctly recalls a fact but performs the wrong sequence of steps to use it. Which memory type does the debug guideline point to first?

In the worked agent-loop code on this page, why does the loop include a max_iterations cap?

Why is validating a tool’s arguments inside the tool itself important, rather than trusting the model’s output?