Vector Memory

aka Embedding-Indexed Memory, Vector Store Memory

category: memory · status: mature

Store memories as embeddings in a vector index and retrieve the most semantically similar items at query time. A long-running personal agent's append-only thought log grows past a million entries; finding relevant past becomes hopeless and dumping it all into context is impossible. The team embeds each memory item, indexes it in a vector store, and at query time retrieves top-k semantically similar items (plus optional recency boost). Now 'what did I decide about latency three months ago' returns the actual right entries rather than the most recent or none, and prompt size stays bounded as memory grows.

2. Problem

A long-running agent accumulates facts and observations over time, and on each step it needs to find the small subset of past items that is relevant to the current situation. Relevance is best judged by semantic similarity rather than by exact term match or chronological recency: 'find the past notes whose meaning is close to what is happening now'.

An append-only log of everything the agent has seen grows unboundedly and quickly becomes too large to search by linear scan. Without a semantic retrieval layer, the agent has no way to find the relevant past, because keyword search misses paraphrase and chronological recency misses older but topically relevant items. The team needs a memory store that supports similarity queries against an embedding of the current context, so that the agent can pull back exactly the items it should be thinking about now.

Competing forces:

3. When to Use

4. When Not to Use

5. Architecture Diagram

flowchart TD
  Mem[New memory item] --> Emb[Embed]
  Emb --> Idx[(Vector index)]
  Q[Query / current state] --> QEmb[Embed]
  QEmb --> Top[Retrieve top-k similar]
  Idx --> Top
  Top --> Decay[Apply decay / salience weighting]
  Decay --> Ctx[Prepend to context]

6. Components

7. Tools

8. Guardrails

The agent reads memory only through the retriever; full-store scans are not part of the loop.

Therefore: embed every memory item and retrieve the top-k most similar at query time, so that recall is driven by semantic match instead of exact keys or scrollback position.

9. Failure Modes

10. Evaluation Metrics

11. Code Examples

Embed every memory at write; at read, embed the query, fetch top-k, and apply an optional recency/salience reweighting.unverified

def remember(text, meta):
    vec = embed(text)
    index.add(id=uuid(), vector=vec, payload={"text": text,
                                              "ts": now(), **meta})

def recall(query, k=5, decay_half_life_days=30):
    q = embed(query)
    hits = index.search(q, k=k * 3)             # over-fetch for reranking
    for h in hits:
        age_days = (now() - h.payload["ts"]) / 86400
        # Older items decay; salience boost from caller-provided meta.
        h.score *= 0.5 ** (age_days / decay_half_life_days)
        h.score *= h.payload.get("salience", 1.0)
    hits.sort(key=lambda h: h.score, reverse=True)
    return [h.payload["text"] for h in hits[:k]]

Memory.add embeds and indexes; Memory.search returns the top-k semantically similar items for the user namespace. · source: https://docs.mem0.ai/core-concepts/memory-operations · sdk: mem0ai>=0.1

from mem0 import Memory

m = Memory()  # default: local vector store + LLM-driven distillation

# Each .add embeds the distilled fact and writes it into Alice's vector
# namespace. The raw turn is summarised first, then indexed.
m.add(
    [
        {"role": "user",      "content": "I'm allergic to peanuts."},
        {"role": "assistant", "content": "Noted."},
    ],
    user_id="alice",
)
m.add(
    [
        {"role": "user",      "content": "My favourite cuisine is Thai."},
        {"role": "assistant", "content": "Got it."},
    ],
    user_id="alice",
)

# Semantic recall — the query embedding finds the allergy note even
# though the user phrased it differently.
results = m.search("any food restrictions?", user_id="alice", limit=3)
for hit in results.get("results", []):
    print(hit["score"], hit["memory"])

Letta's archival passages are a vector store keyed to an agent; passages.insert embeds + indexes, passages.search returns top-k. · source: https://docs.letta.com/guides/agents/archival-memory · sdk: letta-client>=0.1

import os
from letta_client import Letta

client = Letta(api_key=os.getenv("LETTA_API_KEY"))

agent = client.agents.create(
    model="openai/gpt-4o-mini",
    memory_blocks=[
        {"label": "persona", "value": "travel planner", "limit": 1000},
    ],
)

# Write: each passage is embedded with the agent's configured embedding
# model and stored in the archival vector index.
client.agents.passages.insert(
    agent_id=agent.id,
    content="Alice is allergic to peanuts.",
    tags=["profile", "diet"],
)
client.agents.passages.insert(
    agent_id=agent.id,
    content="Alice's favourite cuisine is Thai.",
    tags=["profile", "diet"],
)

# Read: vector search over the archival index, optionally filtered by tag.
hits = client.agents.passages.search(
    agent_id=agent.id,
    query="food restrictions",
    tags=["diet"],
)
for p in hits:
    print(p.content)

Expected benefits

Known uses

Related patterns

References