What is flat vector store memory?

Short answer: Pattern Two keeps durable facts as embedded records outside the prompt and retrieves top matches each turn beside a short chat slice.

Engram implements this with extract, embed, reconcile, and hybrid search scoped by user. Flat means similarity over memory text is the primary index, not a graph. Failure modes include vector haze, append-only piles, and weak multi-hop entity questions. Stay here for personalization until you need explicit tiers or relationships.

Pattern Two is the first persistent memory architecture most teams ship. Facts live outside the prompt as embedded records in a vector store. Each turn, the agent embeds the user message, retrieves top matches, and injects them beside a short recent chat slice. Session can end. The store remains. Weaviate Engram is this pattern with the operational pieces already attached. You send conversations or strings through memories.add. Pipelines extract discrete memories, embed them, reconcile duplicates, and commit to Weaviate. You search with hybrid retrieval scoped by user_id and optional properties. Flat does not mean careless. It means the primary index is similarity over memory text, not a graph of entities or an OS-style tier of paging.

This chapter defines the flat vector pattern, how Engram implements it, where vector haze and stale siblings hurt, how to run the dual loop of recent messages plus search, and when to graduate toward tiered memory. Pattern One had no store. Pattern Two adds one flat, searchable layer.

What makes a memory store “flat” rather than just “external”?

After context-only agents, any database can look like progress. Flat vector memory has a specific shape. Each memory is a chunk of text with an embedding and metadata. Retrieval is nearest neighbor, optionally mixed with BM25. There is no mandatory walk across relationship edges to answer “what does this user prefer.” There is no separate hot cache tier required to boot. Write, embed, search, inject. That simplicity is why agency catalogs recommend vector memory as the default first production store.

Engram fits the shape while raising the floor. Memories are not raw transcript dumps by default. Extraction pulls topic-shaped facts. Transform can rewrite or drop duplicates before commit. Scopes isolate users at the storage layer. Search offers vector, BM25, hybrid, and fetch. The index is still flat in the architectural sense. Complexity lives in the pipeline, not in a hand-built graph.

Contrast this with document RAG alone. A shared knowledge collection answers product questions for everyone. Flat agent memory answers “what is true for this user or this run.” Engram personalization groups target that second job. Many products run both in parallel.

How does Engram realize Pattern Two in practice?

Once the shape is clear, the loop is fixed. Before the model answers, call memories.search with the current user text, a user_id, and usually HybridRetrieval. Format hits into the system prompt. Keep only the last few raw exchanges for pronouns and local coherence. After the turn, fire-and-forget memories.add with the new messages so extraction can update the store asynchronously. Poll runs.wait only when tests or the next search must see the write immediately.

Scoping is part of the pattern, not an optional filter. User-scoped topics never return another user’s memories. Property scopes such as conversation_id or a bench id soft-isolate working sets. Omitting a property at search time widens to all values for that user. That is how you recall across sessions without replaying every transcript.

Topics keep the flat store navigable. UserKnowledge holds durable personal facts. Other topics can hold stack preferences or workflow notes. Filtering topics at search time is how a flat index still feels structured without becoming a graph.

Where does flat vector memory fail if you stop at embed-and-hope?

Knowing Engram’s happy path, respect the failure modes that made the decay chapters necessary. Vector haze retrieves semantically similar but situationally wrong lines. An old adhesive preference can outrank a newer one when embeddings sit close. Append-only raw chats recreate Pattern One’s cost problem inside the database. Without transform reconciliation, paraphrases pile up and the agent cites two truths.

Flat stores also under-serve multi-hop entity questions. “Which suppliers both failed SLA and touch the same SKU family?” wants relationships. Similarity over sentence memories may miss the path. That does not invalidate Pattern Two for personalization and fact recall. It marks the graduation line toward graphs or richer tiering later.

Maintenance remains mandatory. Soft-forget, prune, supersede, and purposeful delete all apply to Engram-backed flat memory. The architecture gives you persistence. It does not exempt you from custodianship.

What does a Pattern Two chat loop look like with Engram?

Imagine a pottery studio agent on pottery-wheel-centering-desk-4. Returning throwers expect the agent to remember clay body and centering faults without pasting last month’s notes.

import os
from engram import EngramClient, HybridRetrieval

engram = EngramClient(api_key=os.environ["ENGRAM_API_KEY"])
thrower = "thrower-cass-nguyen"
desk = {"desk_id": "pottery-wheel-centering-desk-4"}
recent = []  # last few turns only

def seed_profile():
    run = engram.memories.add(
        "On pottery-wheel-centering-desk-4 I throw mostly B-mix. "
        "My recentering fault is pressing too hard at three o'clock.",
        user_id=thrower,
        group="personalization",
        properties=desk,
    )
    engram.runs.wait(run.run_id)

def remember(query: str):
    return engram.memories.search(
        query,
        user_id=thrower,
        group="personalization",
        properties=desk,
        retrieval_config=HybridRetrieval(limit=5),
    )

def build_system(memories) -> str:
    lines = "\n".join(f"- {m.content}" for m in memories)
    return (
        "You are a throwing coach for pottery-wheel-centering-desk-4.\n"
        "Known memories for this thrower:\n"
        f"{lines or '- (none yet)'}\n"
        "Prefer these memories over generic advice when they apply."
    )

def turn(user_text: str, reply_fn):
    memories = remember(user_text)
    system = build_system(memories)
    recent.append({"role": "user", "content": user_text})
    # reply_fn stands in for your LLM provider call.
    assistant_text = reply_fn(system, recent[-6:])
    recent.append({"role": "assistant", "content": assistant_text})
    # Flat-store write: async extract into the vector memory layer.
    engram.memories.add(
        [recent[-2], recent[-1]],
        user_id=thrower,
        group="personalization",
        properties=desk,
    )
    return assistant_text, memories

seed_profile()
answer, hits = turn(
    "The wall is wobbling again after I open the form.",
    reply_fn=lambda system, msgs: f"[draft using {len(msgs)} msgs]\n{system}",
)
print(answer)
for m in hits:
    print("hit:", m.content)

Recent messages stay tiny. Durable facts come from hybrid search over Engram. Writes do not block the user path. That is Pattern Two as a product loop, not a weekend FAISS demo.

When should you keep Pattern Two, and when should you tier it?

Keep flat vector memory while your questions are mostly “recall the right facts for this user and query.” Keep it while Engram topics and maintenance jobs control duplication and drift. Move on when long-horizon agents need explicit working memory versus long-term stores, or when hot scratchpads must page in and out of the window like an OS. Those needs point to tiered architectures.

Many production systems stay on Pattern Two for personalization even after they add other layers for documents or tools. Engram remains the experiential memory plane. The next pattern is about organizing multiple memory speeds, not abandoning vectors.

Our next chapter, What are tiered memory architectures?, shows how short-term context, mid-term working notes, and long-term Engram stores can work as coordinated tiers.