PLRS combines SAKTWithDecay knowledge tracing with a DAG prerequisite constraint layer and a pluggable LLM explainability layer — producing personalized recommendations that are both accurate and pedagogically sound.
Trained on the full OULAD dataset — 23,295 students, 173,739 assessment interactions, 20 skill buckets — on a Kaggle T4 GPU. The forgetting curve decay contributes +0.042 AUC over vanilla SAKT, a gap consistent across val and test sets.
| Model | Val AUC | Test AUC | Test Acc |
|---|---|---|---|
| SAKTWithDecay (Ebbinghaus decay) | 0.8613 | 0.8152 | 0.7629 |
| SAKTModel (vanilla) | 0.8194 | 0.7823 | 0.7318 |
| FYP baseline (synthetic data) | 0.7692 | — | — |
| System | Prerequisite Violation Rate | Notes |
|---|---|---|
| PLRS (SAKT + DAG) | 0.0% | DAG constraint layer — structural |
| Collaborative Filtering | 81.3% | No prerequisite awareness |
| Matrix Factorization | 83.7% | No prerequisite awareness |
The forgetting curve decay (Ebbinghaus/ACT-R) modifies attention weights in the transformer so recent interactions contribute more than older ones. The constraint layer makes prerequisite violations structurally impossible. The LLM layer is fully pluggable — use any model, local or hosted.
PLRS is an open-source framework — developers choose their own LLM. No vendor lock-in. Use a hosted API or run a local model with zero cost and full privacy.
pip install plrs[ollama]
pip install plrs[huggingface]
pip install plrs[openai]
pip install plrs[claude]
from plrs.llm import LLMProvider class MyProvider(LLMProvider): def complete(self, prompt, system=None, max_tokens=1024, temperature=0.0): return my_model.generate(prompt) # Works with curriculum builder + explainer + API pipeline = PLRSPipeline(curriculum, llm=MyProvider())
from plrs import PLRSPipeline from plrs.curriculum import load_dag pipeline = PLRSPipeline(load_dag("math_dag.json"), model_path="sakt_decay_best.pt") results = pipeline.recommend_from_mastery({"whole_numbers": 0.90, "fractions": 0.75}) for rec in results["approved"]: print(f"✅ {rec['topic_label']} — {rec['reasoning']}")
from plrs.curriculum.llm_builder import CurriculumBuilder from plrs.llm import OllamaProvider # free, local, no API key result = CurriculumBuilder(OllamaProvider()).from_topics( topics=["Mechanics", "Kinematics", "Dynamics", "Energy"], domain="A-Level Physics", ) result.save("physics_dag.json")
$ python scripts/serve.py # → http://127.0.0.1:8000/docs $ curl -X POST http://localhost:8000/recommend \ -H "X-API-Key: plrs_your_key" \ -d '{"domain":"math","mastery_scores":{"whole_numbers":0.9}}' $ curl -X POST http://localhost:8000/explain \ -H "X-API-Key: plrs_your_key" \ -d '{"topic_label":"Fractions","mastery":0.3,"status":"approved",...}'
The live demo runs the full SAKTWithDecay pipeline. Adjust mastery sliders, simulate students, explore the curriculum graph.