Skip to main content
What you’ll build: A production-ready chatbot with persistent memory, document knowledge, and conversation history.Time: 20 minutes | Difficulty: Intermediate

Overview

Most chatbots forget everything after each conversation. In this tutorial, you’ll build a chatbot that:
  • Remembers past conversations
  • Learns from documents you provide
  • Answers questions using its knowledge base
  • Gets smarter over time

Prerequisites

1

Install Dependencies

pip install memvid-sdk openai langchain langchain-openai
2

Set API Key

export OPENAI_API_KEY=your-api-key

Step 1: Create the Memory Store

First, let’s create a memory file to store conversations and knowledge:
from memvid_sdk import use
import os

# Create or open memory file
mem = use('langchain', 'chatbot-memory.mv2', mode='auto')

# Add some initial knowledge
mem.put(
    "Product Overview",
    "knowledge",
    {},
    text="""Our product is an AI-powered analytics platform that helps businesses
understand their data. Key features include:
- Real-time dashboards
- Automated insights
- Custom reports
- API access for developers"""
)

mem.put(
    "Pricing Information",
    "knowledge",
    {},
    text="""Pricing tiers:
- Starter: $29/month - Up to 10,000 events
- Pro: $99/month - Up to 100,000 events
- Enterprise: Custom pricing - Unlimited events
All plans include 14-day free trial."""
)

print("Memory initialized with knowledge base")

Step 2: Build the Conversation Manager

Create a class to manage conversations and memory:
from datetime import datetime
from typing import List, Dict
import json

class ConversationMemory:
    def __init__(self, memory_path: str):
        self.mem = use('langchain', memory_path, mode='auto')
        self.session_id = datetime.now().strftime("%Y%m%d_%H%M%S")

    def add_message(self, role: str, content: str):
        """Store a message in memory."""
        self.mem.put(
            f"Conversation - {self.session_id}",
            "conversation",
            {
                "session_id": self.session_id,
                "role": role,
                "timestamp": datetime.now().isoformat()
            },
            text=f"[{role.upper()}]: {content}"
        )

    def get_relevant_context(self, query: str, k: int = 5) -> str:
        """Retrieve relevant information for the query."""
        results = self.mem.find(query, k=k)

        context_parts = []
        for hit in results.hits:
            if hit.label == "knowledge":
                context_parts.append(f"[Knowledge] {hit.text}")
            elif hit.label == "conversation":
                context_parts.append(f"[Previous conversation] {hit.text}")

        return "\n\n".join(context_parts)

    def get_recent_messages(self, limit: int = 10) -> List[Dict]:
        """Get recent conversation messages."""
        timeline = self.mem.timeline(limit=limit)

        messages = []
        for entry in timeline.entries:
            if entry.label == "conversation":
                messages.append({
                    "role": entry.metadata.get("role", "unknown"),
                    "content": entry.text,
                    "timestamp": entry.metadata.get("timestamp")
                })

        return messages

Step 3: Create the Chatbot

Now let’s build the main chatbot class:
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage, AIMessage, SystemMessage

class MemvidChatbot:
    def __init__(self, memory_path: str = "chatbot-memory.mv2"):
        self.memory = ConversationMemory(memory_path)
        self.llm = ChatOpenAI(model="gpt-4o", temperature=0.7)

        self.system_prompt = """You are a helpful AI assistant with access to a knowledge base and conversation history.

When answering questions:
1. Use the provided context to give accurate, relevant answers
2. Reference specific information from the knowledge base when applicable
3. Remember details from previous conversations
4. Be conversational and helpful

If you don't have enough information, say so honestly."""

    def chat(self, user_message: str) -> str:
        """Process a user message and return a response."""

        # Store the user message
        self.memory.add_message("user", user_message)

        # Get relevant context from memory
        context = self.memory.get_relevant_context(user_message)

        # Build the prompt with context
        messages = [
            SystemMessage(content=self.system_prompt),
            HumanMessage(content=f"""Context from knowledge base and previous conversations:
{context}

---

User message: {user_message}

Please respond helpfully based on the context above.""")
        ]

        # Get response from LLM
        response = self.llm.invoke(messages)
        assistant_message = response.content

        # Store the assistant's response
        self.memory.add_message("assistant", assistant_message)

        return assistant_message

    def add_knowledge(self, title: str, content: str):
        """Add new knowledge to the chatbot's memory."""
        self.memory.mem.put(title, "knowledge", {}, text=content)
        print(f"Added knowledge: {title}")

Step 4: Run the Chatbot

Create an interactive chat loop:
def main():
    print("Memvid Chatbot initialized")
    print("Commands: /add (add knowledge), /history (view recent), /quit (exit)")
    print("-" * 50)

    bot = MemvidChatbot()

    while True:
        user_input = input("\nYou: ").strip()

        if not user_input:
            continue

        if user_input.lower() == "/quit":
            print("Goodbye!")
            break

        elif user_input.lower() == "/history":
            messages = bot.memory.get_recent_messages(10)
            print("\nRecent conversation:")
            for msg in messages:
                print(f"  [{msg['role']}]: {msg['content'][:100]}...")

        elif user_input.lower().startswith("/add "):
            # Format: /add Title | Content
            parts = user_input[5:].split("|", 1)
            if len(parts) == 2:
                bot.add_knowledge(parts[0].strip(), parts[1].strip())
            else:
                print("Usage: /add Title | Content")

        else:
            response = bot.chat(user_input)
            print(f"\nBot: {response}")

if __name__ == "__main__":
    main()

Step 5: Add Advanced Features

Conversation Summarization

Add automatic summarization for long conversations:
def summarize_conversation(self) -> str:
    """Generate a summary of the current conversation."""
    recent = self.memory.get_recent_messages(20)

    if not recent:
        return "No conversation history yet."

    conversation_text = "\n".join([
        f"{m['role']}: {m['content']}" for m in recent
    ])

    summary_prompt = f"""Summarize this conversation in 2-3 sentences:

{conversation_text}

Summary:"""

    response = self.llm.invoke([HumanMessage(content=summary_prompt)])
    return response.content

Topic Detection

Automatically tag conversations by topic:
def detect_topics(self, message: str) -> List[str]:
    """Detect topics in a message for better retrieval."""
    prompt = f"""Extract 1-3 topic tags from this message. Return only comma-separated tags.

Message: {message}

Tags:"""

    response = self.llm.invoke([HumanMessage(content=prompt)])
    tags = [t.strip() for t in response.content.split(",")]
    return tags

Multi-Session Support

Handle multiple users/sessions:
class MultiUserChatbot:
    def __init__(self, memory_path: str):
        self.mem = use('langchain', memory_path, mode='auto')
        self.sessions = {}

    def get_session(self, user_id: str) -> MemvidChatbot:
        """Get or create a session for a user."""
        if user_id not in self.sessions:
            self.sessions[user_id] = MemvidChatbot(self.mem)
            self.sessions[user_id].session_id = user_id
        return self.sessions[user_id]

    def chat(self, user_id: str, message: str) -> str:
        """Chat with session isolation."""
        session = self.get_session(user_id)
        return session.chat(message)

Complete Code

Here’s the full implementation:
#!/usr/bin/env python3
"""
Memvid Chatbot with Persistent Memory

A production-ready chatbot that remembers conversations
and learns from documents.
"""

from datetime import datetime
from typing import List, Dict, Optional
from memvid_sdk import use
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage, SystemMessage


class ConversationMemory:
    """Manages conversation history and knowledge retrieval."""

    def __init__(self, memory_path: str):
        self.mem = use('langchain', memory_path, mode='auto')
        self.session_id = datetime.now().strftime("%Y%m%d_%H%M%S")

    def add_message(self, role: str, content: str, tags: Optional[List[str]] = None):
        self.mem.put(
            f"Conversation - {self.session_id}",
            "conversation",
            {
                "session_id": self.session_id,
                "role": role,
                "timestamp": datetime.now().isoformat()
            },
            text=f"[{role.upper()}]: {content}",
            tags=tags or []
        )

    def get_relevant_context(self, query: str, k: int = 5) -> str:
        results = self.mem.find(query, k=k)
        context_parts = []

        for hit in results.hits:
            prefix = "[Knowledge]" if hit.label == "knowledge" else "[History]"
            context_parts.append(f"{prefix} {hit.text}")

        return "\n\n".join(context_parts)

    def get_recent_messages(self, limit: int = 10) -> List[Dict]:
        timeline = self.mem.timeline(limit=limit)
        return [
            {
                "role": e.metadata.get("role", "unknown"),
                "content": e.text,
                "timestamp": e.metadata.get("timestamp")
            }
            for e in timeline.entries
            if e.label == "conversation"
        ]


class MemvidChatbot:
    """AI chatbot with persistent memory."""

    def __init__(self, memory_path: str = "chatbot-memory.mv2"):
        self.memory = ConversationMemory(memory_path)
        self.llm = ChatOpenAI(model="gpt-4o", temperature=0.7)
        self.system_prompt = """You are a helpful AI assistant with memory.
Use the provided context to give accurate answers.
Reference the knowledge base when relevant.
Remember details from previous conversations."""

    def chat(self, user_message: str) -> str:
        self.memory.add_message("user", user_message)
        context = self.memory.get_relevant_context(user_message)

        messages = [
            SystemMessage(content=self.system_prompt),
            HumanMessage(content=f"Context:\n{context}\n\nUser: {user_message}")
        ]

        response = self.llm.invoke(messages)
        self.memory.add_message("assistant", response.content)

        return response.content

    def add_knowledge(self, title: str, content: str):
        self.memory.mem.put(title, "knowledge", {}, text=content)


def main():
    print("Memvid Chatbot")
    print("Commands: /add Title | Content, /history, /quit")
    print("-" * 50)

    bot = MemvidChatbot()

    while True:
        user_input = input("\nYou: ").strip()

        if not user_input:
            continue
        if user_input == "/quit":
            break
        if user_input == "/history":
            for m in bot.memory.get_recent_messages(10):
                print(f"  [{m['role']}]: {m['content'][:80]}...")
            continue
        if user_input.startswith("/add "):
            parts = user_input[5:].split("|", 1)
            if len(parts) == 2:
                bot.add_knowledge(parts[0].strip(), parts[1].strip())
            continue

        print(f"\n{bot.chat(user_input)}")


if __name__ == "__main__":
    main()

Deployment

As a FastAPI Service

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()
bot = MemvidChatbot()

class ChatRequest(BaseModel):
    message: str
    user_id: str = "default"

class ChatResponse(BaseModel):
    response: str

@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    response = bot.chat(request.message)
    return ChatResponse(response=response)

@app.post("/knowledge")
async def add_knowledge(title: str, content: str):
    bot.add_knowledge(title, content)
    return {"status": "added"}

With Docker

FROM python:3.11-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Next Steps