How Zep stores facts, entities, and user preferences — and how it differs from Mem0 and LangGraph memory

The memory problem

Most AI agents are stateless within a session and completely amnesiac across sessions. LangGraph checkpoints solve the within-session problem. But when a user returns a week later and says 'remember what we discussed about my budget?', a checkpointer cannot help — it only knows about the current thread.

Zep is a dedicated memory server that stores facts, entities, and conversation history across sessions, extracts structured knowledge from conversations automatically, and provides semantic search over that knowledge.

What Zep stores

Memory type What it is Example
Facts Discrete facts extracted from conversations 'User prefers monthly billing'
Entities Named entities with relationships 'Alice' is a 'Customer' with 'Account #12345'
Summaries Auto-generated summaries of past sessions Rolling summary of last 20 exchanges
Raw messages Original conversation messages Full message history for a session
Custom data Arbitrary key-value data you add manually User's subscription tier, onboarding status

Core data model: Users and Sessions

Zep organises memory around two concepts: Users (persistent identities) and Sessions (individual conversations). A user can have many sessions. Memories at the user level persist forever; session memories are associated with a specific conversation.

from zep_cloud.client import AsyncZep
import asyncio
 
client = AsyncZep(api_key='YOUR_ZEP_API_KEY')
 
async def setup_user_and_session():
    # Create a user (idempotent — safe to call on every login)
    await client.user.add(
        user_id='user-123',
        email='alice@example.com',
        first_name='Alice',
        metadata={'plan': 'pro', 'signup_date': '2026-01-15'}
    )
 
    # Create a session for this conversation
    await client.memory.add_session(
        session_id='session-abc',
        user_id='user-123',
        metadata={'channel': 'web_chat'}
    )
 
asyncio.run(setup_user_and_session())
 

Adding messages to memory

from zep_cloud.types import Message
 
async def add_exchange(session_id: str, user_msg: str, ai_msg: str):
    await client.memory.add(
        session_id=session_id,
        messages=[
            Message(role='user',      role_type='user',      content=user_msg),
            Message(role='assistant', role_type='assistant', content=ai_msg),
        ]
    )
 
# Zep automatically:
# - Extracts facts ('user wants to cancel subscription')
# - Identifies entities ('subscription', 'user')
# - Updates rolling summary
# - Builds/updates knowledge graph edges
 

Retrieving memory

async def get_context_for_agent(session_id: str) -> str:
    memory = await client.memory.get(session_id=session_id)
 
    # memory.context is a pre-formatted string — ready to inject into system prompt
    print(memory.context)
    # Example output:
    # Facts about Alice:
    # - Prefers monthly billing
    # - Account number is 12345
    # - Last session: discussed Q1 budget review
 
    # Or access individual facts
    for fact in memory.facts:
        print(f'  Fact: {fact.fact} (rating: {fact.rating})')
 
    return memory.context
 
Use memory.context directly as your system prompt suffix — it is already formatted for LLM injection. Do not try to reconstruct it from individual facts unless you need custom formatting.

Semantic search across all memories

async def search_user_memory(user_id: str, query: str) -> list:
    results = await client.memory.search_sessions(
        user_id=user_id,
        text=query,
        search_scope='facts',    # 'facts', 'messages', or 'summary'
        limit=5,
    )
    for r in results.results:
        print(f'Score: {r.score:.3f} | {r.fact.fact}')
    return results.results
 
# Example: find memories relevant to a current query
relevant = await search_user_memory('user-123', 'budget preferences')
 

Zep vs Mem0 vs LangGraph Store

Feature Zep Mem0 LangGraph Store
Automatic fact extraction Yes — from messages Yes — from messages No — manual put()
Knowledge graph Yes — entity relationships Yes No
Self-hostable Yes (open source) Yes (open source) Yes
Cloud managed Yes (Zep Cloud) Yes (Mem0 Platform) No
LangChain integration First-class First-class Via LangGraph
Semantic search Yes Yes Yes (with embeddings)
Best for Conversational apps, CRM enrichment Agent memory, multi-framework LangGraph-native apps

When NOT to use Zep

  • You are building with LangGraph and want to stay in the same ecosystem — use LangGraph Store
  • You only need within-session memory — a simple list of messages is enough
  • Your conversations are short and do not accumulate meaningful facts over time
  • You cannot justify the extra dependency or hosting cost for your use case

Zep Cloud vs self-hosted

Aspect Zep Cloud Self-hosted
Setup API key only Docker compose or Kubernetes
Knowledge graph Yes Yes
Data residency US/EU regions Fully controlled
Pricing Usage-based (free tier available) Infrastructure costs only
Maintenance None You manage updates