Skip to content

Building a Chatbot

intermediate

Add persistent conversational memory to a chatbot. Store conversations, recall context, and let your bot remember across sessions.

What you'll build

A chatbot that remembers past conversations across sessions — it learns user preferences, recalls previous topics, and improves over time without re-training.

Prerequisites

RequirementDetails
AccountFree tier or above
API keyFrom your dashboard
SDKPython or JavaScript
Time~15 minutes

The pattern

Most chatbots forget everything between sessions. With Engramma, every conversation turn becomes a memory that the bot can recall later:

User says something → Store it → Next turn, retrieve relevant memories → Use them as context

Steps

1

Initialize the client

Set up the Engramma client alongside your chatbot framework.
2

Store conversation turns

After each user message and bot response, store them as memories with metadata.
3

Retrieve relevant context

Before generating a response, query Engramma for memories related to the current message.
4

Inject context into prompts

Add retrieved memories to your LLM prompt so the bot has conversational history.
5

Let consolidation improve quality

Over time, frequently-accessed memories strengthen and noise fades away automatically.

Complete code

import os
from engramma_cloud import EngrammaClient

client = EngrammaClient(api_key=os.environ["ENGRAMMA_API_KEY"])

def store_conversation_turn(user_id: str, role: str, message: str):
    """Store a conversation turn as a memory."""
    client.store(
        f"[{role}] {message}",
        metadata={
            "user_id": user_id,
            "role": role,
            "type": "conversation"
        }
    )

def get_relevant_context(user_id: str, current_message: str, top_k: int = 5):
    """Retrieve memories relevant to the current message."""
    results = client.retrieve(
        current_message,
        top_k=top_k,
        metadata_filter={"user_id": user_id}
    )
    return [r.text for r in results if r.confidence > 0.6]

def chat(user_id: str, user_message: str):
    # 1. Get relevant past context
    memories = get_relevant_context(user_id, user_message)
    
    # 2. Build prompt with memory context
    context = "\n".join(memories) if memories else "No previous context."
    prompt = f"""You are a helpful assistant with memory of past conversations.

Relevant memories:
{context}

User: {user_message}
Assistant:"""
    
    # 3. Generate response (replace with your LLM call)
    response = call_your_llm(prompt)
    
    # 4. Store both turns for future recall
    store_conversation_turn(user_id, "user", user_message)
    store_conversation_turn(user_id, "assistant", response)
    
    return response

# Example usage
response = chat("user_123", "I prefer dark mode and concise answers")
print(response)

# Later session — the bot remembers
response = chat("user_123", "Can you adjust your style?")
# The bot recalls the dark mode + concise preference from memory

How it works in practice

SessionWhat happens
First visitUser mentions preferences → stored as memories
Second visitBot retrieves past preferences → adjusts behavior
After consolidationRepeated preferences strengthen, one-off mentions fade
Week laterBot remembers core preferences, forgets noise

Filtering by user

Each memory includes a user_id in metadata. When retrieving, filter by user to keep conversations isolated:

# Only retrieve memories from this specific user
results = client.retrieve(
    "What does the user prefer?",
    metadata_filter={"user_id": "user_123"}
)

# Cross-user retrieval (e.g., for shared team knowledge)
results = client.retrieve(
    "team deployment schedule",
    metadata_filter={"type": "team_knowledge"}
)

Tips for production

Tip

Store with intention. Not every message needs to be stored — filter out greetings, acknowledgments, and filler. Focus on facts, preferences, and decisions.

Warning

Don't store sensitive data (passwords, tokens, PII) unless you have appropriate data handling policies in place. Use metadata to tag sensitivity levels if needed.

  1. Confidence threshold — Only inject memories with confidence > 0.6 into your prompt. Lower-confidence results add noise.

  2. Metadata strategy — Use metadata fields like type, topic, and session_id to organize memories and filter retrievals.

  3. Consolidation — Let automatic consolidation clean up. After hundreds of conversations, the memory space self-organizes.

  4. Protected memories — Mark critical preferences as protected so they survive consolidation pruning:

# This preference will never be pruned
client.store(
    "User strongly prefers concise answers",
    metadata={"user_id": "user_123", "protected": True}
)

Next steps