AI Learning Path Personalization System Development

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1 servicesAll 1566 services
AI Learning Path Personalization System Development
Medium
~1-2 weeks
FAQ
AI Development Areas
AI Solution Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1212
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822

AI-система персонализации учебного пути

Персонализация учебного пути — задача рекомендательной системы для образовательного контента. Отличие от Netflix: важна не только релевантность, но и педагогическая последовательность. Нельзя рекомендовать advanced-модуль студенту без базы, даже если модель считает его «интересным».

Граф знаний и навигация по нему

import networkx as nx
import numpy as np
import pandas as pd
from sklearn.ensemble import GradientBoostingClassifier

class KnowledgeGraph:
    """Граф зависимостей учебных модулей"""

    def __init__(self):
        self.graph = nx.DiGraph()

    def add_module(self, module_id: str, metadata: dict):
        self.graph.add_node(module_id, **metadata)

    def add_prerequisite(self, module_id: str, prerequisite_id: str):
        """prerequisite → module (нужно изучить prerequisite перед module)"""
        self.graph.add_edge(prerequisite_id, module_id)

    def get_unlocked_modules(self, completed_modules: set[str]) -> list[str]:
        """Модули, доступные после прохождения completed"""
        unlocked = []
        for node in self.graph.nodes():
            if node in completed_modules:
                continue
            predecessors = set(self.graph.predecessors(node))
            if predecessors.issubset(completed_modules):
                unlocked.append(node)
        return unlocked

    def get_shortest_path_to_goal(self, start_modules: set[str],
                                   goal_module: str) -> list[str]:
        """Минимальный путь к цели через граф зависимостей"""
        # Виртуальный стартовый узел
        self.graph.add_node('__start__')
        for m in start_modules:
            self.graph.add_edge('__start__', m)

        try:
            path = nx.shortest_path(self.graph, '__start__', goal_module)
            return [p for p in path if p != '__start__']
        except nx.NetworkXNoPath:
            return []
        finally:
            self.graph.remove_node('__start__')


class LearningPathRecommender:
    """Персонализированный учебный маршрут"""

    def __init__(self, knowledge_graph: KnowledgeGraph):
        self.kg = knowledge_graph
        self.completion_predictor = GradientBoostingClassifier(
            n_estimators=100, random_state=42
        )

    def recommend_path(self, student: dict,
                        goal: str,
                        max_modules: int = 10) -> list[dict]:
        """
        Рекомендация учебного пути к цели.
        Учитывает: завершённые модули, скорость обучения, предпочтения формата.
        """
        completed = set(student.get('completed_modules', []))
        unlocked = self.kg.get_unlocked_modules(completed)

        # Фильтруем только модули на пути к цели
        path_modules = self.kg.get_shortest_path_to_goal(completed, goal)
        relevant = [m for m in unlocked if m in path_modules]

        if not relevant:
            relevant = unlocked[:max_modules]

        # Скоринг каждого модуля
        scored = []
        for module_id in relevant[:20]:  # Ограничиваем перебор
            module = self.kg.graph.nodes[module_id]
            score = self._score_module(module, student)
            scored.append({
                'module_id': module_id,
                'title': module.get('title', ''),
                'type': module.get('type', 'video'),
                'duration_min': module.get('duration_min', 30),
                'difficulty': module.get('difficulty', 3),
                'score': score,
                'reason': self._explain_score(module, student, score)
            })

        scored.sort(key=lambda x: -x['score'])
        return scored[:max_modules]

    def _score_module(self, module: dict, student: dict) -> float:
        """Скоринг: релевантность + формат + сложность"""
        # Сложность относительно уровня студента
        student_level = student.get('avg_score', 0.6)
        module_difficulty = module.get('difficulty', 3) / 5  # 0-1
        difficulty_fit = 1.0 - abs(student_level - 0.7 - (module_difficulty - 0.5) * 0.4)

        # Соответствие предпочтениям формата
        preferred_types = student.get('preferred_content_types', ['video'])
        format_score = 1.2 if module.get('type') in preferred_types else 0.8

        # Популярность (социальное доказательство)
        completion_rate = module.get('completion_rate', 0.5)

        # Оценка ценности с учётом карьерной цели
        goal_relevance = module.get('goal_tags', {}).get(student.get('career_goal', ''), 0.5)

        return difficulty_fit * 0.3 + format_score * 0.2 + completion_rate * 0.2 + goal_relevance * 0.3

    def _explain_score(self, module: dict, student: dict, score: float) -> str:
        reasons = []
        if module.get('completion_rate', 0) > 0.8:
            reasons.append(f"{module['completion_rate']:.0%} студентов завершили")
        if module.get('type') in student.get('preferred_content_types', []):
            reasons.append(f"Ваш предпочтительный формат: {module['type']}")
        if not reasons:
            reasons.append("Рекомендовано на основе прогресса")
        return '; '.join(reasons)


class StudyScheduler:
    """Планировщик учебного расписания"""

    def create_schedule(self, path: list[dict],
                         available_hours_per_week: float,
                         deadline_weeks: int = None) -> pd.DataFrame:
        """Распределение модулей по неделям"""
        total_hours = sum(m['duration_min'] / 60 for m in path)

        if deadline_weeks:
            required_hours_per_week = total_hours / deadline_weeks
            if required_hours_per_week > available_hours_per_week * 1.2:
                # Нереалистичный план — предупреждаем
                return pd.DataFrame({'warning': [
                    f'Для достижения цели к дедлайну нужно {required_hours_per_week:.1f} ч/нед, '
                    f'у вас только {available_hours_per_week} ч/нед'
                ]})

        schedule = []
        current_week = 1
        week_hours = 0

        for module in path:
            module_hours = module['duration_min'] / 60
            if week_hours + module_hours > available_hours_per_week and week_hours > 0:
                current_week += 1
                week_hours = 0
            schedule.append({
                'week': current_week,
                'module_id': module['module_id'],
                'title': module['title'],
                'duration_hours': round(module_hours, 1)
            })
            week_hours += module_hours

        return pd.DataFrame(schedule)

Система персонализации учебных путей сокращает среднее время до первой компетенции на 30-40% за счёт исключения ненужных модулей и правильного порядка изучения. Ключевой KPI — time-to-competency, а не completion rate.