Building an AI Agent for Tutoring Centers: Student Matching and Session Scheduling
Build an AI agent for tutoring centers that matches students with the right tutors based on subject, level, and learning style, schedules sessions, tracks progress, and communicates with parents.
The Tutoring Center Coordination Challenge
Running a tutoring center means juggling dozens of variables: which tutor teaches which subjects, student schedules, parent preferences, session frequency, progress tracking, and makeup sessions. A center with 10 tutors and 50 students creates hundreds of scheduling combinations. Most centers manage this with spreadsheets and phone calls, which breaks down as they grow. An AI agent handles the matching, scheduling, and parent communication that consumes staff hours every week.
Student and Tutor Data Models
The matching engine needs rich profiles for both students and tutors to make intelligent pairings.
from dataclasses import dataclass, field
from datetime import datetime, date, time, timedelta
from enum import Enum
from typing import Optional
class Subject(Enum):
MATH_ALGEBRA = "algebra"
MATH_CALCULUS = "calculus"
MATH_GEOMETRY = "geometry"
PHYSICS = "physics"
CHEMISTRY = "chemistry"
ENGLISH = "english"
SAT_PREP = "sat_prep"
ACT_PREP = "act_prep"
SPANISH = "spanish"
COMPUTER_SCIENCE = "computer_science"
class GradeLevel(Enum):
ELEMENTARY = "elementary" # K-5
MIDDLE_SCHOOL = "middle_school" # 6-8
HIGH_SCHOOL = "high_school" # 9-12
COLLEGE = "college"
class LearningStyle(Enum):
VISUAL = "visual"
HANDS_ON = "hands_on"
VERBAL = "verbal"
MIXED = "mixed"
@dataclass
class Tutor:
id: str
name: str
subjects: list[Subject]
grade_levels: list[GradeLevel]
teaching_style: LearningStyle
hourly_rate: float
availability: dict[str, list[tuple[time, time]]] = field(default_factory=dict)
max_students: int = 15
current_students: int = 0
rating: float = 5.0
bio: str = ""
@dataclass
class Student:
id: str
name: str
grade_level: GradeLevel
subjects_needed: list[Subject]
learning_style: LearningStyle
parent_name: str
parent_phone: str
parent_email: str
assigned_tutor_id: Optional[str] = None
sessions_completed: int = 0
notes: str = ""
@dataclass
class TutoringSession:
id: str
student_id: str
tutor_id: str
subject: Subject
date_time: datetime
duration_minutes: int = 60
status: str = "scheduled"
progress_notes: str = ""
homework_assigned: str = ""
Student-Tutor Matching Engine
The matching engine scores tutor-student compatibility based on subject overlap, grade level match, learning style alignment, and tutor capacity.
class MatchingEngine:
def __init__(self, tutors: list[Tutor]):
self.tutors = {t.id: t for t in tutors}
def find_matches(
self, student: Student, subject: Subject
) -> list[dict]:
candidates = []
for tutor in self.tutors.values():
score = self._calculate_match_score(student, tutor, subject)
if score > 0:
candidates.append({
"tutor": tutor,
"score": score,
"reasons": self._explain_match(student, tutor, subject),
})
candidates.sort(key=lambda c: c["score"], reverse=True)
return candidates[:3] # top 3 matches
def _calculate_match_score(
self, student: Student, tutor: Tutor, subject: Subject
) -> float:
score = 0.0
# Subject match (required)
if subject not in tutor.subjects:
return 0
score += 30
# Grade level match
if student.grade_level in tutor.grade_levels:
score += 25
# Learning style alignment
if student.learning_style == tutor.teaching_style:
score += 20
elif tutor.teaching_style == LearningStyle.MIXED:
score += 10
# Capacity (prefer tutors with fewer students)
utilization = tutor.current_students / tutor.max_students
score += (1 - utilization) * 15
# Rating bonus
score += tutor.rating * 2 # max 10 points
return round(score, 1)
def _explain_match(
self, student: Student, tutor: Tutor, subject: Subject
) -> list[str]:
reasons = [f"Teaches {subject.value}"]
if student.grade_level in tutor.grade_levels:
reasons.append(f"Experienced with {student.grade_level.value} students")
if student.learning_style == tutor.teaching_style:
reasons.append(f"Teaching style matches ({student.learning_style.value})")
if tutor.rating >= 4.5:
reasons.append(f"Highly rated ({tutor.rating}/5.0)")
return reasons
Progress Tracking
Parents want to know their child is improving. The agent should be able to report on session history and progress trends.
See AI Voice Agents Handle Real Calls
Book a free demo or calculate how much you can save with AI voice automation.
class ProgressTracker:
def __init__(self):
self.sessions: list[TutoringSession] = []
def add_session(self, session: TutoringSession):
self.sessions.append(session)
def get_student_summary(self, student_id: str) -> dict:
student_sessions = [
s for s in self.sessions if s.student_id == student_id
]
completed = [s for s in student_sessions if s.status == "completed"]
subjects_covered = set(s.subject.value for s in completed)
recent = sorted(completed, key=lambda s: s.date_time, reverse=True)[:3]
return {
"total_sessions": len(completed),
"subjects_covered": list(subjects_covered),
"recent_sessions": [
{
"date": s.date_time.strftime("%B %d"),
"subject": s.subject.value,
"notes": s.progress_notes,
"homework": s.homework_assigned,
}
for s in recent
],
}
Agent Tools and Assembly
from agents import Agent, Runner, function_tool
# Initialize with sample data
tutors = [
Tutor(
"t1", "Dr. Sarah Kim",
[Subject.MATH_ALGEBRA, Subject.MATH_CALCULUS, Subject.SAT_PREP],
[GradeLevel.HIGH_SCHOOL, GradeLevel.COLLEGE],
LearningStyle.VERBAL, 65.0,
availability={"tuesday": [(time(15, 0), time(19, 0))],
"thursday": [(time(15, 0), time(19, 0))]},
current_students=8, rating=4.9,
),
Tutor(
"t2", "Mike Torres",
[Subject.MATH_ALGEBRA, Subject.MATH_GEOMETRY, Subject.PHYSICS],
[GradeLevel.MIDDLE_SCHOOL, GradeLevel.HIGH_SCHOOL],
LearningStyle.HANDS_ON, 55.0,
availability={"monday": [(time(16, 0), time(20, 0))],
"wednesday": [(time(16, 0), time(20, 0))]},
current_students=6, rating=4.7,
),
Tutor(
"t3", "Emily Park",
[Subject.ENGLISH, Subject.SAT_PREP, Subject.ACT_PREP],
[GradeLevel.HIGH_SCHOOL],
LearningStyle.VISUAL, 60.0,
availability={"monday": [(time(15, 0), time(18, 0))],
"friday": [(time(14, 0), time(18, 0))]},
current_students=10, rating=4.8,
),
]
matching_engine = MatchingEngine(tutors)
progress_tracker = ProgressTracker()
STUDENTS_DB = {
"ethan-williams": Student(
"s1", "Ethan Williams", GradeLevel.HIGH_SCHOOL,
[Subject.MATH_ALGEBRA, Subject.SAT_PREP],
LearningStyle.HANDS_ON,
"Diana Williams", "555-0401", "diana@email.com",
assigned_tutor_id="t2", sessions_completed=8,
),
}
@function_tool
def find_tutor_match(
student_name: str, subject: str
) -> str:
"""Find the best tutor matches for a student and subject."""
key = student_name.lower().replace(" ", "-")
student = STUDENTS_DB.get(key)
if not student:
return f"Student '{student_name}' not found. Please register first."
try:
subj = Subject(subject.lower())
except ValueError:
available = [s.value for s in Subject]
return f"Subject not found. Available: {', '.join(available)}"
matches = matching_engine.find_matches(student, subj)
if not matches:
return f"No tutors available for {subject} at the {student.grade_level.value} level."
lines = []
for i, m in enumerate(matches, 1):
t = m["tutor"]
reasons = "; ".join(m["reasons"])
lines.append(
f"{i}. {t.name} (${t.hourly_rate}/hr, {t.rating}/5.0 rating)\n"
f" Why: {reasons}\n"
f" Match score: {m['score']}/100"
)
return "\n".join(lines)
@function_tool
def schedule_session(
student_name: str, tutor_name: str,
subject: str, date_time: str
) -> str:
"""Schedule a tutoring session."""
return (
f"Session scheduled:\n"
f"Student: {student_name}\n"
f"Tutor: {tutor_name}\n"
f"Subject: {subject}\n"
f"Date/Time: {date_time}\n"
f"Duration: 60 minutes\n"
f"Confirmation sent to parent."
)
@function_tool
def get_progress_report(student_name: str) -> str:
"""Get a progress summary for a student."""
key = student_name.lower().replace(" ", "-")
student = STUDENTS_DB.get(key)
if not student:
return "Student not found."
return (
f"Progress report for {student.name}:\n"
f"Sessions completed: {student.sessions_completed}\n"
f"Subjects: {', '.join(s.value for s in student.subjects_needed)}\n"
f"Current tutor: {student.assigned_tutor_id or 'Not assigned'}\n"
f"Learning style: {student.learning_style.value}"
)
@function_tool
def register_student(
name: str, grade: str, subjects: str,
learning_style: str, parent_name: str, parent_phone: str
) -> str:
"""Register a new student at the tutoring center."""
return (
f"Student registered: {name}\n"
f"Grade level: {grade}\n"
f"Subjects: {subjects}\n"
f"Parent: {parent_name} ({parent_phone})\n"
f"Next step: We will match {name} with the best available tutor."
)
tutoring_agent = Agent(
name="Tutoring Center Assistant",
instructions="""You are a helpful assistant for BrightMinds Tutoring Center.
1. For new families, use register_student to sign up, then
find_tutor_match to recommend tutors.
2. Present tutor matches with their qualifications, rates, and
match scores. Let the parent choose.
3. Once a tutor is selected, use schedule_session to book.
4. For existing students, use get_progress_report to share updates.
5. Always address the parent by name and refer to the student
by their first name.
6. Recommend session frequency based on goals: test prep needs
2-3x/week, maintenance needs 1x/week.""",
tools=[find_tutor_match, schedule_session, get_progress_report, register_student],
)
FAQ
How does the matching engine handle tutor availability conflicts?
Before confirming a match, the scheduling tool checks the tutor's availability dictionary against the requested time. If a tutor is the best match but unavailable at the preferred time, the agent presents alternative time slots from that tutor's schedule. If no times work, it suggests the next-best match who has availability at the preferred time.
Can the agent handle cancellations and makeup sessions?
Add a cancel_session tool that marks the session as cancelled and a reschedule_session tool that finds the next available slot with the same tutor. Many tutoring centers have a 24-hour cancellation policy — encode this as a check in the cancellation tool that warns the parent if they are cancelling within the policy window.
How do I enable parent communication through the agent?
The agent already communicates with parents during calls. For asynchronous communication, add a send_parent_update tool that sends SMS or email summaries after each session. The tutor fills in progress notes and homework assignments, and the agent formats and sends a parent-friendly summary within an hour of session completion.
#Tutoring #StudentMatching #SessionScheduling #EducationTech #Python #AgenticAI #LearnAI #AIEngineering
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.