Skip to main content
Build an AI tutor that remembers student progress, identifies knowledge gaps, and personalizes the learning experience. EverOS enables long-term memory that persists across study sessions.

Architecture Overview

AI Tutor Architecture Memory types for tutoring:
  • Profile: Learning style, pace, strengths, goals
  • Episodic Memory: Topic discussions, quiz results, explanations given

Setup: Initialize Tutor

Install the EverOS SDK:
pip install everos
from everos import EverOS
import time

client = EverOS()
memories = client.v1.memories

class AITutor:
    def __init__(self, subject: str):
        self.subject = subject

    def store_interaction(self, student_id: str, student_message: str, tutor_response: str):
        """Store a tutoring interaction."""
        now = int(time.time() * 1000)
        memories.add(
            user_id=student_id,
            messages=[
                {"role": "user", "timestamp": now, "content": student_message},
                {"role": "assistant", "timestamp": now + 1000, "content": tutor_response},
            ],
        )

    def store_student_message(self, student_id: str, content: str):
        """Store a student's message (e.g., learning goals)."""
        memories.add(
            user_id=student_id,
            messages=[
                {"role": "user", "timestamp": int(time.time() * 1000), "content": content},
            ],
        )

    def set_learning_goals(self, student_id: str, learning_goals: list):
        """Record a student's learning goals."""
        goals_text = ", ".join(learning_goals)
        self.store_student_message(
            student_id=student_id,
            content=f"My learning goals for {self.subject}: {goals_text}",
        )

Track Learning Progress

Store quiz results and topic discussions to build a picture of student progress.
def record_quiz_result(self, student_id: str, topic: str, score: int, max_score: int, missed_concepts: list = None):
    """Record a quiz or assessment result."""
    percentage = (score / max_score) * 100

    result_message = f"Quiz completed on {topic}. Score: {score}/{max_score} ({percentage:.0f}%)."

    if missed_concepts:
        result_message += f" Concepts to review: {', '.join(missed_concepts)}."

    if percentage >= 90:
        result_message += " Excellent understanding demonstrated."
    elif percentage >= 70:
        result_message += " Good progress, some areas need reinforcement."
    else:
        result_message += " This topic needs more practice."

    self.store_interaction(student_id, f"I just finished the {topic} quiz.", result_message)

def record_explanation(self, student_id: str, topic: str, difficulty_level: str, understood: bool):
    """Record when a concept is explained."""
    status = "understood" if understood else "needs more explanation"

    message = f"Explained {topic} at {difficulty_level} level. Student {status}."

    if not understood:
        message += " Will revisit with different approach."

    self.store_interaction(
        student_id,
        f"Can you explain {topic} at a {difficulty_level} level?",
        message,
    )

Identify Knowledge Gaps

Search memories to identify areas where the student struggles.
def identify_knowledge_gaps(self, student_id: str) -> list:
    """Analyze memory to find topics needing review."""
    resp = memories.search(
        filters={"user_id": student_id},
        query="needs review struggled difficult missed concepts not understood",
        method="vector",
        memory_types=["episodic_memory"],
        top_k=20,
    )
    results = resp.get("results", [])

    # Extract topics mentioned in struggling contexts
    gaps = []
    for mem in results:
        content = mem.get("memory", "").lower()
        if any(word in content for word in ["review", "struggled", "difficult", "missed", "not understood"]):
            gaps.append(mem.get("memory"))

    return gaps

def get_strong_topics(self, student_id: str) -> list:
    """Find topics the student has mastered."""
    resp = memories.search(
        filters={"user_id": student_id},
        query="excellent mastered understood good progress correct",
        method="vector",
        memory_types=["episodic_memory"],
        top_k=20,
    )
    results = resp.get("results", [])

    strengths = [
        mem.get("memory")
        for mem in results
        if any(word in mem.get("memory", "").lower()
               for word in ["excellent", "mastered", "understood well", "90%", "100%"])
    ]

    return strengths

Schedule Reviews with Episodic Memory

Store review reminders as part of the tutoring conversation. Search for them later to surface due reviews.
def schedule_review(self, student_id: str, topic: str, review_date_str: str):
    """Schedule a topic review by storing it as an episodic memory."""
    self.store_interaction(
        student_id,
        f"When should I review {topic}?",
        f"You should review {topic} on {review_date_str}. This topic needs reinforcement based on recent quiz results.",
    )

def get_due_reviews(self, student_id: str) -> list:
    """Search for stored review reminders."""
    resp = memories.search(
        filters={"user_id": student_id},
        query="review remember study practice scheduled review",
        method="vector",
        memory_types=["episodic_memory"],
        top_k=10,
    )
    return [mem.get("memory") for mem in resp.get("results", [])]

Personalized Question Generation

Use memory context to generate adaptive questions.
def generate_adaptive_question(self, student_id: str, topic: str) -> dict:
    """Generate a question adapted to student's level."""

    # Get student's profile and learning style
    profile_resp = memories.search(
        filters={"user_id": student_id},
        query=f"learning style pace {topic}",
        method="vector",
        memory_types=["profile"],
        top_k=5,
    )
    profile_memories = profile_resp.get("results", [])

    # Get topic progress
    progress_resp = memories.search(
        filters={"user_id": student_id},
        query=f"{topic} quiz score understanding",
        method="vector",
        memory_types=["episodic_memory"],
        top_k=5,
    )
    progress_memories = progress_resp.get("results", [])

    # Format for LLM
    context = {
        "profile": [m.get("memory") for m in profile_memories],
        "progress": [m.get("memory") for m in progress_memories],
        "topic": topic,
    }

    # Generate question with LLM (placeholder)
    return {
        "context": context,
        "prompt": f"Generate a {topic} question appropriate for this student's level",
    }

Complete AI Tutor Implementation

from everos import EverOS
import time
from datetime import datetime, timedelta

client = EverOS()
memories = client.v1.memories

class AITutor:
    def __init__(self, subject: str):
        self.subject = subject

    def _store(self, student_id: str, student_msg: str, tutor_msg: str):
        """Store a tutoring exchange."""
        now = int(time.time() * 1000)
        memories.add(
            user_id=student_id,
            messages=[
                {"role": "user", "timestamp": now, "content": student_msg},
                {"role": "assistant", "timestamp": now + 1000, "content": tutor_msg},
            ],
        )

    def _search(self, student_id: str, query: str,
                memory_types: list = None, top_k: int = 5) -> list:
        """Search student memories."""
        resp = memories.search(
            filters={"user_id": student_id},
            query=query,
            method="vector",
            memory_types=memory_types or ["episodic_memory", "profile"],
            top_k=top_k,
        )
        return resp.get("results", [])

    def study_session(self, student_id: str, student_message: str) -> str:
        """Handle a study session interaction."""
        # Get learning context
        context = self._get_learning_context(student_id, student_message)

        # Get due reminders
        reminders = self._get_reminders(student_id)

        # Generate personalized response (implement with your LLM)
        response = self._generate_response(student_message, context, reminders)

        # Store the full exchange
        self._store(student_id, student_message, response)

        return response

    def record_assessment(self, student_id: str, topic: str, score: int, total: int, notes: str = ""):
        """Record quiz/assessment results."""
        pct = (score / total) * 100
        tutor_msg = f"Assessment on {topic}: {score}/{total} ({pct:.0f}%). {notes}"
        self._store(student_id, f"I just completed the {topic} assessment.", tutor_msg)

        # Schedule review if score is low
        if pct < 80:
            review_date = datetime.now() + timedelta(days=3)
            self._store(
                student_id,
                f"When should I review {topic}?",
                f"You should review {topic} by {review_date.strftime('%B %d')} - you scored {pct:.0f}%.",
            )

    def _get_learning_context(self, student_id: str, query: str) -> dict:
        return {
            "profile": self._search(student_id, query, memory_types=["profile"]),
            "progress": self._search(student_id, query, memory_types=["episodic_memory"]),
            "gaps": self._search(student_id, "struggled difficult needs review"),
        }

    def _get_reminders(self, student_id: str) -> list:
        return self._search(
            student_id,
            "review remember practice scheduled",
            memory_types=["episodic_memory"],
        )

    def _generate_response(self, message: str, context: dict, reminders: list) -> str:
        # Implement with your LLM
        return f"[Tutor response based on {len(context['progress'])} progress memories]"


# Usage Example
tutor = AITutor("Calculus")

# Set learning goals
memories.add(
    user_id="student_emma",
    messages=[
        {"role": "user", "timestamp": int(time.time() * 1000), "content": "My learning goals for Calculus: pass the AP exam, understand derivatives and integrals"},
    ],
)

# Study session
response = tutor.study_session("student_emma",
    "I'm having trouble understanding derivatives. Can you explain?")
print(f"Tutor: {response}")

# Record assessment
tutor.record_assessment("student_emma", "Basic Derivatives", 7, 10,
    "Struggled with chain rule applications")

# Another session - tutor now knows about the struggle
response = tutor.study_session("student_emma",
    "Can we practice more derivative problems?")
# Response will be informed by previous assessment results

Spaced Repetition with Episodic Memory

Implement spaced repetition by storing review schedules as episodic memories and searching for them when needed.
def schedule_spaced_reviews(self, student_id: str, topic: str, mastery_level: int):
    """Schedule reviews using spaced repetition intervals."""
    # Intervals based on mastery (1 = new, 5 = mastered)
    intervals = {
        1: [1, 3, 7],      # New: review in 1, 3, 7 days
        2: [3, 7, 14],     # Learning: 3, 7, 14 days
        3: [7, 14, 30],    # Familiar: 7, 14, 30 days
        4: [14, 30, 60],   # Good: 14, 30, 60 days
        5: [30, 90],       # Mastered: 30, 90 days
    }

    review_days = intervals.get(mastery_level, [7, 14, 30])

    for days in review_days:
        review_date = datetime.now() + timedelta(days=days)
        self._store(
            student_id,
            f"Schedule my next review for {topic}.",
            f"Scheduled review: {topic} on {review_date.strftime('%B %d, %Y')}. "
            f"Current mastery level: {mastery_level}/5.",
        )

Best Practices

Build rich profiles over time. Store learning preferences as messages so EverOS extracts them into profile memories.
# Store learning preferences - EverOS extracts these into profile memories
preferences = [
    "I learn better with visual examples",
    "I prefer to practice problems before theory",
    "I usually study in the evenings",
    "My goal is to pass the AP Calculus exam",
]

for pref in preferences:
    memories.add(
        user_id="student_emma",
        messages=[
            {"role": "user", "timestamp": int(time.time() * 1000), "content": pref},
        ],
    )
Record specific, actionable progress notes.
# Good: Specific and actionable
"Scored 85% on integration by parts. Struggled with choosing u and dv."

# Bad: Too vague
"Did okay on integration quiz."
Use memory to adjust question difficulty.
def get_difficulty_level(context: dict) -> str:
    recent_scores = [m for m in context["progress"] if "%" in m.get("memory", "")]
    if not recent_scores:
        return "medium"

    # Parse scores and adjust
    # High scores -> harder questions
    # Low scores -> easier questions, more scaffolding

Next Steps

Memory Types

Learn about MemCell and how profile and episodic memories work

Python Integration

Production patterns for tutoring applications