Foundations ⏱️ 10 min read

Memory Stratification: Short-Term Scratchpads to Long-Term Vector Stores

Architecting a multi-tiered memory taxonomy for autonomous agents: managing context window quotas, sliding-window scratchpads, episodic session graphs, and persistent semantic recall.

A stateless LLM remembers nothing between requests. Every interaction begins tabula rasa. While conversational chatbots can get by with appending recent messages into a prompt buffer, autonomous agents operating over hours or days require a sophisticated, tiered memory hierarchy.

If an agent blindly accumulates every intermediate tool output, observation, and scratchpad thought, its context window rapidly overflows, token costs surge exponentially, and the model suffers from attention distraction (the "needle-in-a-haystack" phenomenon where performance degrades over long contexts).

In this post, we engineer a multi-tiered memory architecture that allows agents to maintain coherent long-term state within finite token budgets.


1. The Multi-Tier Memory Taxonomy

Humans do not store every sensory input in permanent memory; we operate across sensory memory, working memory, episodic memory, and semantic archives. A production AI agent requires an identical stratification:

+-------------------------------------------------------------------------+
|                       AGENT MEMORY ARCHITECTURE                         |
|                                                                         |
|  TIER 1: WORKING MEMORY (Context Window)                                |
|  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  |
|  β”‚  Active Goal β€’ Immediate Scratchpad β€’ Current Tool Call Trajectoryβ”‚  |
|  β”‚  Capacity: 8K - 128K Tokens | Latency: 0ms | Ephemeral            β”‚  |
|  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  |
|                                    β–Ό                                    |
|  TIER 2: EPISODIC MEMORY (Session History & Checkpoints)               |
|  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  |
|  β”‚  Summarized Run Traces β€’ Past Interactions β€’ State Checkpoints    β”‚  |
|  β”‚  Storage: Redis / PostgreSQL / SQLite | Latency: 2-15ms           β”‚  |
|  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  |
|                                    β–Ό                                    |
|  TIER 3: SEMANTIC MEMORY (Factual Knowledge & Archives)                |
|  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  |
|  β”‚  Domain Facts β€’ User Profiles β€’ Tool Execution Solutions          β”‚  |
|  β”‚  Storage: Qdrant / Pinecone / pgvector | Latency: 20-80ms         β”‚  |
|  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  |
+-------------------------------------------------------------------------+

Comparative Characteristics:

Memory Tier Storage Backend Retention Lifetime Primary Failure Mode if Unmanaged
Working (Scratchpad) LLM Context Window Single Run / Loop Token exhaustion; context pollution; model confusion.
Episodic (Narrative) Redis / SQLite User Session Stale session context; redundant re-execution of solved tasks.
Semantic (Factual) Vector DB (pgvector) Permanent Semantic drift; retrieval of irrelevant historical fragments.
Procedural (Rules) Static Prompts / Code Immutable per Release Prompt bloat; conflicting instructions.

2. Working Memory Management: Sliding Windows & Summarization

To prevent context window saturation during long-running tasks, we implement a Sliding Buffer with Dynamic LLM Summarization:

class WorkingMemoryBuffer:
    """Manages active scratchpad memory with automated token condensation."""
    def __init__(self, token_limit: int = 4000, keep_recent_turns: int = 4):
        self.token_limit = token_limit
        self.keep_recent_turns = keep_recent_turns
        self.system_prompt = ""
        self.summary_accumulator = ""
        self.active_history = []

    def add_message(self, role: str, content: str):
        self.active_history.append({"role": role, "content": content})
        self._enforce_budget()

    def _estimate_tokens(self, text: str) -> int:
        # Rough heuristic: ~4 characters per token
        return len(text) // 4

    def _enforce_budget(self):
        total_tokens = sum(self._estimate_tokens(m["content"]) for m in self.active_history)

        if total_tokens > self.token_limit and len(self.active_history) > self.keep_recent_turns:
            # Extract older turns for condensation
            overflow_turns = self.active_history[:-self.keep_recent_turns]
            self.active_history = self.active_history[-self.keep_recent_turns:]

            # Condense older turns into summary accumulator
            text_to_compress = "\n".join([f"{m['role']}: {m['content']}" for m in overflow_turns])
            self._compress_and_merge(text_to_compress)

    def _compress_and_merge(self, text_to_compress: str):
        # In production, call a lightweight fast model (e.g. gpt-4o-mini / Haiku)
        print("⚑ [CONDENSING OVERFLOW MEMORY] Compacting older execution steps...")
        # Appends structured key takeaways to self.summary_accumulator
        self.summary_accumulator += f"\n- Executed earlier steps: {text_to_compress[:120]}..."

    def compile_context(self) -> list:
        """Assembles the final context payload for the LLM."""
        messages = [{"role": "system", "content": self.system_prompt}]
        if self.summary_accumulator:
            messages.append({
                "role": "system",
                "content": f"<prior_session_summary>\n{self.summary_accumulator}\n</prior_session_summary>"
            })
        messages.extend(self.active_history)
        return messages

3. Episodic Memory: Checkpointing State with SQLite

When an agent is interruptedβ€”due to an API timeout, rate limit, or awaiting human approvalβ€”it must be able to restore its exact state.

Here is a lightweight SQLite checkpointer for session persistence:

import sqlite3
import json
from datetime import datetime

class SQLiteCheckpointer:
    def __init__(self, db_path: str = "agent_state.db"):
        self.conn = sqlite3.connect(db_path)
        self._init_schema()

    def _init_schema(self):
        with self.conn:
            self.conn.execute("""
                CREATE TABLE IF NOT EXISTS checkpoints (
                    session_id TEXT,
                    step_index INTEGER,
                    state_json TEXT,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    PRIMARY KEY (session_id, step_index)
                )
            """)

    def save_checkpoint(self, session_id: str, step_index: int, state: dict):
        with self.conn:
            self.conn.execute(
                "INSERT OR REPLACE INTO checkpoints (session_id, step_index, state_json) VALUES (?, ?, ?)",
                (session_id, step_index, json.dumps(state))
            )

    def load_latest(self, session_id: str) -> dict:
        cursor = self.conn.cursor()
        cursor.execute(
            "SELECT state_json FROM checkpoints WHERE session_id = ? ORDER BY step_index DESC LIMIT 1",
            (session_id,)
        )
        row = cursor.fetchone()
        return json.loads(row[0]) if row else None

4. Semantic Memory: Vectorized Experience Retrieval

Beyond conversational context, mature agents write their own solution reflections into vector stores. When presented with a complex SQL error or API migration, the agent first checks its semantic memory:

"Have I solved a problem similar to this in prior sessions?"

By storing past trajectory tuples (User Goal, Tools Used, Solution Trace) as vector embeddings, the agent develops accumulated expertise across tasks.


Summary & Next Steps

Memory stratification prevents agent amnesia while safeguarding your context window. By maintaining a lean working scratchpad, checkpointing episodic transitions to durable storage, and retrieving historical solutions semantically, your agents achieve genuine persistence.

In [Post 04: Planning & Reasoning Strategies], we explore how agents break down open-ended objectives: comparing Chain-of-Thought (CoT), Plan-and-Solve, and self-correcting Reflexion architectures.

← Back to All Publications
B

Bharath

AI Engineer / Data Scientist specializing in Generative AI systems, transformer architectures, prompt engineering patterns, and autonomous agent orchestration. Writing technical breakdowns for production engineers.