Back to Tutorials
intermediate

Build a Personal AI Tutor

Create an AI tutor that remembers what you've learned, tracks your progress, and adapts to your learning style using Memoid memory.

Prerequisites

  • Python 3.8+
  • Memoid account with API key
  • OpenAI API key (for chat responses)

What You’ll Build

A personalized AI tutor that:

  • Remembers topics you’ve studied
  • Tracks areas where you struggle
  • Adapts explanations to your learning style
  • Provides spaced repetition reminders

Prerequisites

  • Python 3.8+
  • Memoid API key (sign up free, get key from dashboard)
  • OpenAI API key (for generating tutor responses)

Note: Memoid handles all memory storage and search server-side. Your OpenAI key is only used for generating the tutor’s responses.

Setup

pip install openai requests

Full Implementation

import os
import requests
from openai import OpenAI

MEMOID_API_KEY = os.environ["MEMOID_API_KEY"]
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
MEMOID_BASE_URL = "https://api.memoid.dev/v1"

class PersonalAITutor:
    def __init__(self):
        self.openai = OpenAI(api_key=OPENAI_API_KEY)
        self.headers = {
            "Authorization": f"Bearer {MEMOID_API_KEY}",
            "Content-Type": "application/json"
        }

    def get_learning_context(self, student_id: str, topic: str) -> dict:
        """Get student's history with this topic from Memoid."""
        response = requests.post(
            f"{MEMOID_BASE_URL}/search",
            headers=self.headers,
            json={
                "query": f"studying {topic}",
                "user_id": student_id,
                "limit": 10
            }
        )

        context = {"previous_topics": [], "struggles": [], "strengths": []}

        if response.status_code == 200:
            memories = response.json().get("results", [])
            for m in memories:
                memory = m.get("memory", "")
                if "struggled" in memory.lower() or "confused" in memory.lower():
                    context["struggles"].append(memory)
                elif "understood" in memory.lower() or "learned" in memory.lower():
                    context["strengths"].append(memory)
                else:
                    context["previous_topics"].append(memory)

        return context

    def store_learning(self, student_id: str, topic: str, interaction: str, understood: bool):
        """Store learning interaction in Memoid."""
        status = "understood" if understood else "needs_review"
        requests.post(
            f"{MEMOID_BASE_URL}/memories",
            headers=self.headers,
            json={
                "messages": [{"role": "user", "content": interaction}],
                "user_id": student_id,
                "metadata": {"type": "learning", "topic": topic, "status": status}
            }
        )

    def ask(self, student_id: str, topic: str, question: str) -> str:
        """Handle a learning question."""
        context = self.get_learning_context(student_id, topic)

        system_prompt = f"""You are a patient, encouraging AI tutor.

Your student's learning profile:
- Previous topics: {', '.join(context['previous_topics'][:3]) or 'New student'}
- Areas of struggle: {', '.join(context['struggles'][:3]) or 'None identified yet'}
- Strengths: {', '.join(context['strengths'][:3]) or 'Building foundation'}

Teaching guidelines:
1. Build on what the student already knows
2. Use analogies and examples
3. If they've struggled with related concepts, provide extra clarity
4. Be encouraging and celebrate progress"""

        response = self.openai.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": f"Topic: {topic}\n\nQuestion: {question}"}
            ]
        )

        answer = response.choices[0].message.content

        interaction = f"Studying {topic}: Asked about '{question}'. Tutor explained the concept."
        self.store_learning(student_id, topic, interaction, understood=True)

        return answer

    def mark_confusion(self, student_id: str, topic: str, concept: str):
        """Mark a concept as confusing for review."""
        interaction = f"Student struggled with {concept} while studying {topic}"
        self.store_learning(student_id, topic, interaction, understood=False)

    def get_review_suggestions(self, student_id: str) -> list:
        """Get topics that need review."""
        response = requests.get(
            f"{MEMOID_BASE_URL}/memories",
            headers=self.headers,
            params={"user_id": student_id, "limit": 50}
        )

        review_topics = []
        if response.status_code == 200:
            memories = response.json().get("results", [])
            for m in memories:
                metadata = m.get("metadata", {})
                if metadata.get("status") == "needs_review":
                    review_topics.append({
                        "topic": metadata.get("topic", "Unknown"),
                        "memory": m.get("memory", "")
                    })

        return review_topics[:5]


def main():
    tutor = PersonalAITutor()
    student_id = "student_alex"

    print("Personal AI Tutor")
    print("=" * 40)
    print("Commands: 'quit', 'confused', 'review'\n")

    current_topic = None

    while True:
        user_input = input("You: ").strip()

        if not user_input:
            continue
        if user_input.lower() == "quit":
            break

        if user_input.lower() == "confused":
            if current_topic:
                concept = input("What concept is confusing? ")
                tutor.mark_confusion(student_id, current_topic, concept)
                print("Noted! I'll explain this differently next time.\n")
            continue

        if user_input.lower() == "review":
            topics = tutor.get_review_suggestions(student_id)
            if topics:
                print("\nTopics to review:")
                for t in topics:
                    print(f"  - {t['topic']}: {t['memory']}")
            else:
                print("\nNo topics need review right now!")
            print()
            continue

        if ":" in user_input:
            topic, question = user_input.split(":", 1)
            current_topic = topic.strip()
            question = question.strip()
        else:
            question = user_input
            if not current_topic:
                current_topic = input("What topic are you studying? ")

        response = tutor.ask(student_id, current_topic, question)
        print(f"\nTutor: {response}\n")


if __name__ == "__main__":
    main()

Running

export MEMOID_API_KEY="your-memoid-key"
export OPENAI_API_KEY="your-openai-key"
python tutor.py

Example Session

Personal AI Tutor
========================================
Commands: 'quit', 'confused', 'review'

You: Python: What is a list comprehension?

Tutor: A list comprehension is a concise way to create lists in Python.
Instead of:
  squares = []
  for x in range(10):
      squares.append(x ** 2)

You can write:
  squares = [x ** 2 for x in range(10)]

You: confused
What concept is confusing? the syntax order
Noted! I'll explain this differently next time.

You: Can you explain the syntax again?

Tutor: I noticed you found the syntax order confusing, so let me
break it down differently...

Key Features

  • Adaptive Teaching: Memoid tracks struggles and the tutor adjusts explanations
  • Spaced Repetition: Mark topics for review with metadata
  • Knowledge Building: References previous learning when explaining new concepts

Related Tutorials