Why Memory Matters
LLMs are like someone with perfect language skills but total amnesia. Every time you start a new API call, the model has zero recollection of anything you have ever said — unless you explicitly replay the history in the prompt. Memory systems solve this by giving your application a structured way to carry context forward, ranging from simple chat buffers (a short-term notepad) to vector databases (a searchable long-term filing cabinet). Without memory, every LLM interaction starts fresh:Memory Architecture Overview
Buffer Memory (Short-Term)
The simplest approach: keep the last N messages. Think of it like a whiteboard in a meeting room — you can only see what is currently written, and when you run out of space you erase the oldest notes to make room for new ones.Token-Based Buffer
Limit by tokens instead of message count:Summary Memory
Compress conversation history into summaries. This is like taking meeting minutes — instead of recording every word spoken, you capture the key decisions, facts, and action items. The trade-off is that you lose detail (exact phrasing, nuance) but gain the ability to maintain context across much longer conversations.Vector Memory (Long-Term)
Store and retrieve memories semantically. If buffer memory is a whiteboard and summary memory is meeting minutes, vector memory is a searchable filing cabinet. Every piece of information gets indexed by its meaning (via embeddings), so you can retrieve the three most relevant memories for any given query — even if the exact words are different.Entity Memory
Track facts about specific entities. Think of this like a CRM for your AI — it maintains a structured profile for every person, place, or thing mentioned in conversation. When the user says “I work at Google and my manager is Sarah,” the entity memory creates entries for the user, Google, and Sarah with their attributes and relationships.Hybrid Memory System
Combine all memory types for maximum effectiveness. This is the architecture that production AI assistants actually use — you would not build a house with just a hammer, and you should not build a memory system with just one memory type. The hybrid approach mirrors how human memory works: you remember the last few minutes in vivid detail (buffer), have a general sense of what happened earlier today (summary), can search through years of experiences when prompted (vector), and maintain an address book of key people and facts (entity).Memory with LangChain
LangChain provides built-in memory implementations:Common Pitfalls
Stuffing all memory into the system prompt
Stuffing all memory into the system prompt
Forgetting to handle contradictory memories
Forgetting to handle contradictory memories
No memory expiration or cleanup
No memory expiration or cleanup
Embedding model mismatch between store and retrieval
Embedding model mismatch between store and retrieval
text-embedding-3-small and later switch to text-embedding-3-large, all your cosine similarities become meaningless — different models produce incompatible vector spaces. Pin your embedding model version and re-embed everything if you upgrade.Key Takeaways
Choose the Right Memory
Hybrid is Best
Persist Important Data
Token Management
What’s Next
Cost Optimization & Token Management
Interview Deep-Dive
You are building a customer support chatbot that needs to remember user preferences across sessions spanning weeks. Walk me through your memory architecture.
You are building a customer support chatbot that needs to remember user preferences across sessions spanning weeks. Walk me through your memory architecture.
- I would use a hybrid memory system with three tiers. Tier one is a buffer memory for the current conversation session — the last 10-20 messages in full detail, kept in the context window. This handles the immediate conversational flow: “as I mentioned earlier in this chat.” Tier two is a summary memory that compresses completed sessions into a paragraph-length summary. When a session ends, I run the full conversation through a cheap model like gpt-4o-mini with a summarization prompt and store the result. When the user returns next week, I inject the session summary into the system prompt. Tier three is an entity memory backed by a simple key-value store — facts about this specific user extracted via structured extraction: their name, plan tier, preferred language, past issues, product preferences.
- The entity memory is the most important for cross-session persistence. Summaries are lossy — you lose nuance and specific details. But entity facts like “user prefers email over phone” or “user is on the Enterprise plan” are precise and stable. I would extract entities after each conversation turn using a structured extraction prompt and upsert into a database keyed by user ID.
- For the retrieval path, when a user starts a new session, I build context in layers: first the entity facts (cheap, always relevant), then the most recent session summary (moderate tokens), and optionally a vector search over all past conversation turns if the user references something specific that is not in the summary. The vector search is the expensive fallback, not the primary path.
- The critical production concern is token budget management. If a user has 50 past sessions, you cannot inject all 50 summaries. I cap the injected context at roughly 2,000 tokens of memory and prioritize recency. The entity store has no token cost until serialized, so it scales to thousands of facts cheaply.
What are the trade-offs between buffer memory and summary memory, and when does each one fail?
What are the trade-offs between buffer memory and summary memory, and when does each one fail?
- Buffer memory keeps the last N messages verbatim. Its strength is zero information loss within the window — every detail, every nuance, every instruction the user gave is preserved exactly. Its failure mode is the cliff edge: message N+1 pushes message 1 out entirely. There is no graceful degradation. If the user gave a critical instruction 15 messages ago and your buffer is 10 messages, that instruction is gone forever. I have seen this cause real production bugs where an agent “forgets” a user constraint mid-conversation because the constraint was stated early and fell out of the buffer.
- Summary memory compresses older messages using an LLM summarization call. Its strength is that nothing is completely forgotten — key facts survive in compressed form. Its failure mode is lossy compression. The summarizer decides what is “important” and it can get that wrong. Specific numbers, exact quotes, nuanced conditions like “only do X if Y and Z are both true” tend to get flattened or dropped during summarization. I have seen summary memory turn “the customer wants a refund only if the item is defective and was purchased within 30 days” into “the customer wants a refund” — losing the critical conditions.
- The deeper trade-off is cost versus fidelity. Buffer memory is free — no extra API calls. Summary memory costs you a summarization call every time the buffer fills up, and each summarization can itself consume 1,000-2,000 tokens. For a high-volume application with thousands of concurrent conversations, those summarization calls add up. A hybrid approach works best: buffer for recent messages, summary for older messages, and entity extraction for critical facts you cannot afford to lose during summarization.
- One nuance most people miss: the summarization quality depends heavily on the prompt. A generic “summarize this conversation” produces generic summaries. A prompt like “extract all commitments, constraints, preferences, and unresolved questions from this conversation” produces dramatically more useful summaries for downstream use.
How does vector memory work for LLM agents, and what are the failure modes of cosine similarity search over conversation history?
How does vector memory work for LLM agents, and what are the failure modes of cosine similarity search over conversation history?
- Vector memory works by embedding each conversation turn (or extracted fact) into a high-dimensional vector using a model like text-embedding-3-small, then storing those vectors in an index. When the agent needs to recall something, you embed the current query and find the stored vectors with the highest cosine similarity. The retrieved memories are injected into the LLM’s context as additional information. This gives you semantic recall — “what did we discuss about pricing?” can find a conversation from three weeks ago where the user mentioned budget constraints, even though the word “pricing” never appeared.
- The first failure mode is the “semantic gap” problem. Embedding models capture semantic similarity, but not all relevant information is semantically similar to the query. If the user asks “what is my account number?” the relevant memory might be “user: my account is 12345” — which is semantically close. But if the relevant memory is “agent: I have verified your identity and updated the record” — that is contextually relevant but semantically distant from “account number.” You miss it entirely.
- The second failure mode is the threshold problem. A cosine similarity threshold of 0.7 sounds reasonable, but in practice, embeddings from the same model cluster around 0.7-0.9 for most text pairs. You get a lot of false positives — memories that score 0.75 but are not actually relevant. And lowering the threshold to 0.6 floods you with noise. The quality of retrieval is extremely sensitive to this threshold, and the optimal value varies by domain, embedding model, and even the length of the text being embedded.
- The third failure mode is temporal blindness. Vector similarity has no concept of time. A preference the user expressed 6 months ago has the same retrieval priority as one from yesterday, unless you explicitly incorporate recency into the scoring. In practice, I add a time-decay factor to the similarity score:
final_score = similarity * decay_factor(age)where the decay might be exponential with a half-life of 30 days. - The fourth and most subtle failure mode is embedding drift. If you switch embedding models or upgrade to a new version, all your stored vectors become incompatible with new query vectors. You have to re-embed your entire memory store, which for a long-running agent could be millions of entries.
1 / (k + rank_in_list) across both lists, where k is typically 60. This naturally boosts memories that appear in both lists while still surfacing memories that only one method finds. The practical value is significant. Vector search finds semantically related memories, keyword search finds exact matches — account numbers, product names, error codes — that embedding models routinely miss because they compress those into generic “technical term” embeddings. In my experience, hybrid search improves recall by 15-25% over pure vector search for agent memory retrieval. The cost is minimal — BM25 is essentially free compared to the embedding API call.Design a memory system for a multi-turn coding assistant that helps developers across multiple projects over months.
Design a memory system for a multi-turn coding assistant that helps developers across multiple projects over months.
- This is a challenging design because the memory needs to be both project-specific and developer-specific. I would structure it around three memory stores. First, a per-project knowledge base that stores: tech stack preferences (this project uses TypeScript, React, Prisma), architectural decisions (we chose event sourcing for the order service), coding conventions (we use kebab-case file names, prefer functional components), and known issues (the auth middleware has a bug with refresh tokens that we are working around). This is extracted from conversations and stored as structured facts, not raw conversation text.
- Second, a developer profile that persists across all projects: experience level, preferred explanation depth, communication style preferences, timezone, and frequently used tools. This is the entity memory from the earlier discussion but scoped to the person, not the project.
- Third, a conversation-level working memory that uses a summary chain. Each session produces a summary that includes: what was accomplished, what was left unresolved, and any decisions that were made. When the developer returns to the same project, I load the project knowledge base and the last 3 session summaries.
- The retrieval strategy is layered. For every query, I always include: the project knowledge base (these are stable facts, usually under 500 tokens), the developer profile (50-100 tokens), and the last session summary (200-300 tokens). Then I do a vector search over all past conversation turns for this project if the query seems to reference something specific. Total memory injection stays under 2,000 tokens in the common case.
- The most important production detail is how facts get into the project knowledge base. I do not rely on the developer explicitly telling the assistant to “remember” things. Instead, after every session, I run an extraction prompt: “What new facts about the project, its architecture, its conventions, or its known issues were discussed? Return as structured JSON.” This passive extraction is what makes the memory feel magical — the assistant just “knows” things without the user having to repeat themselves.