Skip to content
Learn Agentic AI
Learn Agentic AI13 min read1 views

Building a Study Planner Agent: Personalized Learning Schedules with Spaced Repetition

Create an AI study planner agent that builds personalized schedules using spaced repetition algorithms, optimizes review timing, and adapts to individual learning pace and availability.

The Science Behind Spaced Repetition

Research in cognitive science consistently shows that distributing practice over time produces dramatically better retention than massing it into a single session. The spacing effect, first documented by Hermann Ebbinghaus in 1885, demonstrates that memories decay exponentially but each successful review extends the retention interval. A study planner agent leverages this principle to schedule reviews at optimal intervals — just before the student would forget.

The challenge is that optimal intervals vary per student and per topic. An AI agent can personalize these intervals by tracking individual performance and adjusting the schedule dynamically.

The Forgetting Curve Model

Start with a mathematical model of memory decay that the agent uses to predict when a student will forget a given topic:

flowchart TD
    START["Building a Study Planner Agent: Personalized Lear…"] --> A
    A["The Science Behind Spaced Repetition"]
    A --> B
    B["The Forgetting Curve Model"]
    B --> C
    C["Schedule Optimization"]
    C --> D
    D["The Study Planner Agent"]
    D --> E
    E["FAQ"]
    E --> DONE["Key Takeaways"]
    style START fill:#4f46e5,stroke:#4338ca,color:#fff
    style DONE fill:#059669,stroke:#047857,color:#fff
import math
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from typing import Optional

@dataclass
class StudyItem:
    item_id: str
    topic: str
    subject: str
    difficulty: float = 0.3  # 0.0 = easy, 1.0 = hard
    stability: float = 1.0   # days until 90% recall probability
    last_reviewed: Optional[datetime] = None
    review_count: int = 0
    easiness_factor: float = 2.5  # SM-2 style factor
    consecutive_correct: int = 0

    def recall_probability(self, now: Optional[datetime] = None) -> float:
        """Estimate probability the student remembers this item."""
        if self.last_reviewed is None:
            return 0.0
        now = now or datetime.now()
        days_elapsed = (now - self.last_reviewed).total_seconds() / 86400
        # Exponential decay model
        return math.exp(-days_elapsed / self.stability)

    def next_review_date(self, target_recall: float = 0.85) -> datetime:
        """Calculate when recall probability drops to the target."""
        if self.last_reviewed is None:
            return datetime.now()
        # Solve: target = exp(-days / stability) for days
        days_until_target = -self.stability * math.log(target_recall)
        return self.last_reviewed + timedelta(days=days_until_target)

    def update_after_review(self, quality: int):
        """Update stability and easiness after a review.

        quality: 0-5 scale (SM-2 convention)
        0-2 = incorrect/difficult, 3 = correct with hesitation,
        4 = correct, 5 = perfect
        """
        self.review_count += 1
        self.last_reviewed = datetime.now()

        if quality >= 3:
            self.consecutive_correct += 1
            # Increase stability (longer intervals)
            if self.consecutive_correct == 1:
                self.stability = 1.0
            elif self.consecutive_correct == 2:
                self.stability = 6.0
            else:
                self.stability *= self.easiness_factor
        else:
            self.consecutive_correct = 0
            self.stability = 1.0  # Reset to short interval

        # Update easiness factor (SM-2 formula)
        self.easiness_factor = max(
            1.3,
            self.easiness_factor
            + 0.1 - (5 - quality) * (0.08 + (5 - quality) * 0.02),
        )

Schedule Optimization

Given a student's available time slots and a set of items due for review, the agent needs to build an optimal daily schedule:

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

@dataclass
class TimeSlot:
    start: datetime
    end: datetime
    energy_level: str = "medium"  # low, medium, high

    @property
    def duration_minutes(self) -> int:
        return int((self.end - self.start).total_seconds() / 60)

@dataclass
class ScheduleEntry:
    item: StudyItem
    scheduled_time: datetime
    duration_minutes: int
    priority: float

@dataclass
class StudySchedule:
    date: datetime
    entries: list[ScheduleEntry] = field(default_factory=list)
    total_minutes: int = 0

def build_daily_schedule(
    items: list[StudyItem],
    available_slots: list[TimeSlot],
    max_new_items: int = 5,
    minutes_per_review: int = 5,
    minutes_per_new: int = 15,
) -> StudySchedule:
    """Build an optimized study schedule for today."""
    now = datetime.now()
    schedule = StudySchedule(date=now)

    # Separate overdue reviews from new items
    overdue = [
        item for item in items
        if item.last_reviewed and item.recall_probability(now) < 0.85
    ]
    new_items = [
        item for item in items if item.last_reviewed is None
    ][:max_new_items]

    # Sort overdue by urgency (lowest recall first)
    overdue.sort(key=lambda i: i.recall_probability(now))

    # Priority: overdue reviews first, then new items
    # High-energy slots get difficult or new material
    available_slots.sort(
        key=lambda s: {"high": 0, "medium": 1, "low": 2}[s.energy_level]
    )

    slot_idx = 0
    remaining_minutes = (
        available_slots[0].duration_minutes if available_slots else 0
    )

    for item in overdue:
        if slot_idx >= len(available_slots):
            break
        schedule.entries.append(ScheduleEntry(
            item=item,
            scheduled_time=available_slots[slot_idx].start,
            duration_minutes=minutes_per_review,
            priority=1.0 - item.recall_probability(now),
        ))
        remaining_minutes -= minutes_per_review
        schedule.total_minutes += minutes_per_review
        if remaining_minutes <= 0:
            slot_idx += 1
            if slot_idx < len(available_slots):
                remaining_minutes = (
                    available_slots[slot_idx].duration_minutes
                )

    # Add new material in high-energy slots
    for item in new_items:
        if slot_idx >= len(available_slots):
            break
        schedule.entries.append(ScheduleEntry(
            item=item,
            scheduled_time=available_slots[slot_idx].start,
            duration_minutes=minutes_per_new,
            priority=0.5,
        ))
        remaining_minutes -= minutes_per_new
        schedule.total_minutes += minutes_per_new
        if remaining_minutes <= 0:
            slot_idx += 1
            if slot_idx < len(available_slots):
                remaining_minutes = (
                    available_slots[slot_idx].duration_minutes
                )

    return schedule

The Study Planner Agent

The agent uses these scheduling algorithms as tools and communicates the plan in natural language:

from agents import Agent, Runner, function_tool
import json

@function_tool
def get_todays_schedule(
    student_id: str,
    available_hours: float,
    energy_pattern: str,
) -> str:
    """Generate today's optimized study schedule."""
    # In production, load from database
    items = load_student_items(student_id)
    slots = parse_availability(available_hours, energy_pattern)
    schedule = build_daily_schedule(items, slots)

    return json.dumps({
        "total_minutes": schedule.total_minutes,
        "review_count": len([
            e for e in schedule.entries if e.item.review_count > 0
        ]),
        "new_count": len([
            e for e in schedule.entries if e.item.review_count == 0
        ]),
        "entries": [
            {
                "topic": e.item.topic,
                "type": "review" if e.item.review_count > 0 else "new",
                "duration": e.duration_minutes,
                "recall_probability": f"{e.item.recall_probability():.0%}",
            }
            for e in schedule.entries
        ],
    })

study_planner = Agent(
    name="Study Planner",
    instructions="""You are a study planning assistant that creates
personalized schedules based on spaced repetition science.

When presenting a schedule:
1. Start with a brief overview of what is due today and why
2. List each study block with topic, duration, and purpose
3. Explain WHY certain topics are prioritized (low recall probability)
4. Suggest the best order based on energy levels
5. End with encouragement and what to expect tomorrow

Be specific about timing. Instead of 'review math', say 'review
quadratic equations — your recall has dropped to 40%, so this
needs attention today to prevent forgetting.'""",
    tools=[get_todays_schedule],
)

FAQ

How does the spaced repetition algorithm handle topics a student finds consistently easy?

The easiness factor in the SM-2 algorithm increases for items the student consistently rates highly, which extends the stability value exponentially. An item rated "perfect" five times in a row might not appear for review for several months. The system naturally concentrates review time on difficult material while letting easy items fade into long-interval maintenance reviews.

What happens if a student misses several scheduled review sessions?

When a student returns after a gap, the recall probability for overdue items will have dropped significantly. The scheduler prioritizes these by urgency — items with the lowest recall probability appear first. However, it also respects the student's available time, so it will not schedule four hours of reviews just because everything is overdue. Instead, it triages the most critical items and spreads the backlog across several days.

Can the agent account for exam dates and deadlines?

Yes. You extend the scheduling logic with a deadline parameter that overrides the normal spaced repetition intervals. When an exam is approaching, the scheduler increases review frequency for exam-relevant topics and front-loads new material that needs to be learned before the deadline, while still maintaining minimum review intervals for retention.


#SpacedRepetition #StudyPlanning #EducationAI #Python #LearningScience #AgenticAI #LearnAI #AIEngineering

Share
C

Written by

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.

Related Articles You May Like

AI Interview Prep

7 AI Coding Interview Questions From Anthropic, Meta & OpenAI (2026 Edition)

Real AI coding interview questions from Anthropic, Meta, and OpenAI in 2026. Includes implementing attention from scratch, Anthropic's progressive coding screens, Meta's AI-assisted round, and vector search — with solution approaches.

Learn Agentic AI

Building a Multi-Agent Data Pipeline: Ingestion, Transformation, and Analysis Agents

Build a three-agent data pipeline with ingestion, transformation, and analysis agents that process data from APIs, CSVs, and databases using Python.

Learn Agentic AI

OpenAI Agents SDK in 2026: Building Multi-Agent Systems with Handoffs and Guardrails

Complete tutorial on the OpenAI Agents SDK covering agent creation, tool definitions, handoff patterns between specialist agents, and input/output guardrails for safe AI systems.

Learn Agentic AI

Building a Research Agent with Web Search and Report Generation: Complete Tutorial

Build a research agent that searches the web, extracts and synthesizes data, and generates formatted reports using OpenAI Agents SDK and web search tools.

Learn Agentic AI

Build a Customer Support Agent from Scratch: Python, OpenAI, and Twilio in 60 Minutes

Step-by-step tutorial to build a production-ready customer support AI agent using Python FastAPI, OpenAI Agents SDK, and Twilio Voice with five integrated tools.

Learn Agentic AI

LangGraph Agent Patterns 2026: Building Stateful Multi-Step AI Workflows

Complete LangGraph tutorial covering state machines for agents, conditional edges, human-in-the-loop patterns, checkpointing, and parallel execution with full code examples.