Обзор пайплайна — от ответа до рекомендации
Эта страница — компактный «бирд-вью» всего, что делает модель: что поступает на вход, какие 4 числа на каждый микро-навык, как один ответ ученика обновляет оценку владения и как мы выбираем ему следующую задачу. Подходит как точка входа в учебник или как шпаргалка для разговора с командой.
0. Что обозначают сокращения
Заголовок раздела «0. Что обозначают сокращения»Все термины ниже — аббревиатуры или заимствования из английского. Чтобы не вспоминать их каждый раз, вот декодер:
| Сокращение | Английское полное | По-русски |
|---|---|---|
| BKT | Bayesian Knowledge Tracing | байесовское отслеживание знания |
| EM | Expectation–Maximization | алгоритм «ожидание–максимизация» |
| HMM | Hidden Markov Model | скрытая марковская модель |
| ZPD | Zone of Proximal Development | зона ближайшего развития (Выготский) |
| P(L) | Probability(Learned) | вероятность, что ученик владеет навыком |
| P(L₀) / pInit | prior P(Learned), | априорная P(L) до первой попытки |
| pT | probability of Transit | вероятность научиться за одну попытку |
| pS | probability of Slip | вероятность ошибиться, зная (slip = «промах») |
| pG | probability of Guess | вероятность угадать, не зная |
| P(solve) | Probability(Solve) | вероятность правильно решить задачу |
| closeness | (буквально «близость») | насколько P(solve) близко к target ≈ 0.7 |
| mastery | (буквально «владение») | численное P(L) ученика по всем навыкам |
| microskill | micro-skill | атомарный навык, на нём считается один P(L) |
| prereq | prerequisite | предшественник навыка в графе зависимостей |
| rarity bonus | bonus for rare skills | бонус за «недотренированные» навыки в задаче |
| Baum–Welch | (фамилии авторов) | конкретный вариант EM для HMM |
Дальше в тексте используются короткие формы — возвращайся в эту таблицу при первой встрече с любым «pS» или «pT».
1. С высоты птичьего полёта
Заголовок раздела «1. С высоты птичьего полёта»🔧 Офлайн — раз в N недель
Заголовок раздела «🔧 Офлайн — раз в N недель»flowchart LR classDef off fill:#fde68a,stroke:#a16207,color:#0f172a A1[Лог]:::off --> A2[EM]:::off --> A3[Параметры]:::off| Шаг | Что это и зачем |
|---|---|
| Лог | Все ответы всех учеников за всё время — (ученик, задача, верно/неверно, время). Десятки тысяч строк в БД. Это вход для офлайн-этапа. |
| EM | Алгоритм машинного обучения, который смотрит на лог и подбирает 4 числа BKT для каждого микро-навыка так, чтобы эти числа лучше всего объясняли, как ученики на практике отвечали. Запускается один раз перед запуском платформы (потом раз в N недель), не во время сессии ученика. На профессиональном жаргоне конкретный вариант EM, применяемый к BKT, называется Baum–Welch — это частный случай EM для скрытых марковских цепей. |
| Параметры | Готовые 4 числа на каждый из 9 микро-навыков — выход EM. «Зашиваются» в онлайн-движок до следующего цикла фитинга. На хакатоне используем литературные дефолты для всех навыков, в v2 — реальные числа из EM. |
Параметры передаются онлайн-движку и живут там до следующего цикла фитинга.
⚡ Онлайн — на каждый ответ ученика
Заголовок раздела «⚡ Онлайн — на каждый ответ ученика»flowchart LR classDef onl fill:#bbf7d0,stroke:#15803d,color:#0f172a classDef sel fill:#e9d5ff,stroke:#7e22ce,color:#0f172a B1[applyAttempt]:::onl --> B2["P(L)"]:::onl --> B3["P(solve)"]:::onl --> B4[ZPD-скор]:::sel --> B5[Top-N]:::sel| Шаг | Что это и зачем |
|---|---|
| applyAttempt | Функция, которая на каждый ответ ученика обновляет его P(L) для каждого микро-навыка, помеченного в задаче. Принимает (текущий P(L), верно/неверно, параметры BKT). |
| P(L) | «Mastery-вектор» ученика: для каждого из 9 микро-навыков — число от 0 до 1, отражающее уверенность модели «знает ли ученик этот навык». Обновляется на каждом ответе. |
| P(solve) | Вероятность правильно решить конкретную задачу прямо сейчас. Считается из P(L) ученика по микро-навыкам задачи (геом. среднее) и тех же параметров BKT. |
| ZPD-скор | Финальный приоритет задачи. Складывается из «насколько P(solve) близок к 0.7» (closeness) и «сколько недотренированных навыков она задействует» (rarity bonus). |
| Top-N | Лучшие N задач по ZPD-скору. Первая попадает ученику, остальные — резерв (на случай «недавно решал», см. §5). |
Две фазы. Офлайн — медленная: раз в N недель прогоняем EM по большому архиву ответов и достаём 4 числа на каждый микро-навык. Онлайн — быстрая: на каждый клик «Готово» ученика обновляем один P(L) и пересчитываем рекомендацию.
2. Что на входе у модели
Заголовок раздела «2. Что на входе у модели»| Поле | Тип | Пример | Откуда |
|---|---|---|---|
student_id | string | "u_142" | сессия / БД пользователей |
mastery | Record<skillId, number> | { "define.t1.add": 0.31 } | накапливается онлайн |
history | AttemptRecord[] | см. ниже | журнал ответов |
task.id | string | "q_007" | пул задач |
task.microskills | string[] | ["define.t2.mix"] | разметка задач |
task.difficulty | number ∈ [0,1] | 0.55 | оценка автора (tie-breaker) |
Пример AttemptRecord (как фиксируется один ответ):
{ "task_id": "q_007", "correct": true, "ts": "2026-05-07T18:42:11Z", "per_skill": { "define.t2.mix": true }}Пример Task:
{ "id": "q_007", "topic": "linear", "microskills": ["define.t2.mix"], "difficulty": 0.55, "prompt_et": "Pille on 3 aastat vanem kui Mart…", "answer": "x = 12"}3. Параметры BKT (4 числа на микро-навык)
Заголовок раздела «3. Параметры BKT (4 числа на микро-навык)»| Имя | Смысл | Дефолт |
|---|---|---|
| Априорная P(знал до первой попытки) | 0.20 | |
| Вероятность научиться за одну попытку | 0.10 | |
| Slip — знал, но ошибся | 0.10 | |
| Guess — не знал, но угадал | 0.20 |
Источник: packages/bkt-core/src/microskills.ts → DEFAULT_BKT.
Почему «консервативные». — это литературные дефолты для школьной математики (Корбетт & Андерсон, 1995, и более поздние работы). Они не агрессивны: модель не делает резких выводов после одного ответа. — медленное обучение (один ответ редко «выучивает»); — толерантность к случайным промахам и угадываниям. Это страховка от перепрогноза «одна правильная попытка → выучил».
Почему фиксированы на хакатоне. Правильный фит требует ~3000 наблюдений на каждый навык, и EM-пайплайн в проде ещё не подключен. Литературные дефолты дают разумное стартовое поведение «из коробки», без необходимости что-то фитить.
Что изменится в v2. Запустим EM-fitting (подробно — в §6 «Откуда берутся параметры») на собранных данных и получим свои 4 числа на каждый из 9 микро-навыков — но всё ещё общие для всех учеников.
4. Шаг обучения (онлайн, на каждый ответ)
Заголовок раздела «4. Шаг обучения (онлайн, на каждый ответ)»Для одного микро-навыка задачи:
затем шаг «обучения»:
Реализация — bkt-core/src/bkt.ts:36-46 (bktUpdate).
Для multi-skill задач это делается для каждого микро-навыка независимо
(applyAttempt, строки 65–84).
Интерактив: BktSimulator — пощёлкать «ответил верно / не верно» и смотреть, как двигается .
5. Шаг выбора задачи
Заголовок раздела «5. Шаг выбора задачи»Для каждой задачи в пуле считаем «совместный» — геометрическое среднее по микро-навыкам (строже арифметического: одна слабая компонента сильнее тянет вниз):
Скор задачи:
Гауссиана даёт пик на 0.7 (ZPD), rarity bonus подталкивает к задачам, где много «недотренированных» навыков.
Реализация — bkt-core/src/bkt.ts:102-135 (scoreTaskForStudent),
top-N выбирается в recommend (строки 137–152) с исключением последних
5 task_id из истории.
Числовой пример (из главы про Ивана)
Заголовок раздела «Числовой пример (из главы про Ивана)»- для микро-навыка «скобки».
- задачи на одни скобки: .
- Closeness: — почти ноль, не выбирается.
- Multi-skill (скобки + знакомая арифметика): — попадает в ZPD.
Полная иллюстрация ниже:
closeness = exp(−(p−target)²/σ²). Выше у пика, быстро падает к краям. Чем меньше σ², тем уже «ZPD-окно».
6. Откуда берутся параметры (EM-fitting, офлайн)
Заголовок раздела «6. Откуда берутся параметры (EM-fitting, офлайн)»Цель — восстановить из массива ответов. Алгоритм: EM (Baum–Welch) для скрытых марковских цепей (HMM) с двумя состояниями «знает / не знает».
Сам алгоритм:
- Берём массив наблюдений: ~3000 ответов на навык.
- Гадаем стартовые значения 4 параметров (например, литературные дефолты).
- E-шаг: при текущих параметрах считаем, какова вероятность каждой скрытой последовательности «знал / не знал» в каждый момент.
- M-шаг: переоцениваем параметры так, чтобы наблюдаемые данные стали наиболее вероятными.
- Повторяем 3–4, пока параметры не стабилизируются (~20 итераций).
| Пункт | Значение |
|---|---|
| Объём данных на навык | ~3000 наблюдений |
| Итераций до сходимости | ~20 |
| Точность параметра | ±0.01 |
Подробнее — NB-3 EM-fitting.
7. Используем ли мы граф зависимостей?
Заголовок раздела «7. Используем ли мы граф зависимостей?»Короткий ответ — нет. Граф нарисован в UI для людей, но код селектора его не читает.
Два разных понятия — не путаем
Заголовок раздела «Два разных понятия — не путаем»| Что | Где живёт | Кто заполняет | Используется в коде? |
|---|---|---|---|
DAG зависимостей навыков (t3.mix → t1.add, t2.mix…) | data/matx-define/microskills.json, поле prereq | автор curriculum один раз | ❌ нет — только рендерится в UI |
Метки задачи (task.microskills = ["t3.mix", "t1.add", …]) | data/matx-define/tasks.json | учитель при добавлении каждой задачи | ✅ да — читается каждый запуск recommend() |
В microskills.json граф зависимостей выглядит так:
define.t2.mix → prereq: [t1.add, t1.mul, t2.add, t2.mul] ← 4 предкаdefine.t3.mix → prereq: [t1.add, t1.mix, t1.mul, t2.add, t2.mix, t2.mul, t3.add, t3.mul] ← 8 предковЭтот граф рисуется в виджете ProgressionMatrix.tsx для UI
(см. в книге), но recommend() его в память
не загружает.
Что делает учитель
Заголовок раздела «Что делает учитель»Когда учитель добавляет задачу в банк, он:
- Пишет текст задачи и правильный ответ.
- Руками перечисляет в
task.microskillsвсе микро-навыки, которые эта задача задействует, включая предков.
Например, для задачи на t3.mix учитель указывает:
{ "id": "MD-15", "microskills": [ "define.t3.mix", "define.t2.mix", "define.t1.add", "define.t1.mul" ], "prompt_et": "...", "answer": "..."}То есть учитель сам разворачивает граф в плоский список при разметке. Из 20 задач в банке у нас 16 — multi-skill (см. таблицу ниже).
Почему модель работает без чтения графа
Заголовок раздела «Почему модель работает без чтения графа»Селектор смотрит только в task.microskills и state.mastery. Когда
он считает геом. среднее
P(solve),
слабый t1.add (например, P(L)=0.0 у новичка) тащит общий P(solve)
к 0.2 → closeness
уходит в ~0 → задача автоматически не выбирается.
То есть проверка prereq
случается «бесплатно» — потому что предок уже в task.microskills
и попадает в формулу.
Что мы теряем, не читая графа напрямую
Заголовок раздела «Что мы теряем, не читая графа напрямую»- Уязвимость к ошибкам разметки. Если учитель забыл добавить
t1.addв задачу наt3.mix, модель не узнает, что у ученика пробел в основах — и может выдать слишком сложную задачу. - Нельзя написать явные правила вида «не показывать t3.mix, пока
t2.mixне достигнет » — нет точки в коде, где такое условие можно вычислить без чтения графа. - UI не может подсказать «вот навыки, которые надо освоить до этой задачи», потому что нужная информация (DAG) в селекторе отсутствует.
Распределение задач по навыкам (из текущих данных)
Заголовок раздела «Распределение задач по навыкам (из текущих данных)»9 микро-навыков, 20 задач. Multi-skill — 16 / 20:
| Навыков в задаче | Задач |
|---|---|
| 1 | 4 |
| 2 | 6 |
| 3 | 5 |
| 5 | 3 |
| 6 | 1 |
| 9 | 1 |
То есть 80% задач завязаны на 2+ навыка → геометрическое среднее действительно работает почти на каждой попытке.
Открытые вопросы для разговора
Заголовок раздела «Открытые вопросы для разговора»Каждый вопрос — про дизайн-решение, на которое надо ответить с командой. Структура одна: «как сейчас → как могло бы → о чём говорить».
1. Будем ли в v2 учить код читать граф зависимостей?
Заголовок раздела «1. Будем ли в v2 учить код читать граф зависимостей?»Сейчас: код смотрит только на список навыков задачи
(task.microskills) и на P(L) ученика. Файл с графом «t3 нужен t1»
лежит рядом, но код его не открывает.
Если бы читал: код сам бы знал «без t1.add задачу на t3.mix
давать рано» — даже если учитель забыл указать t1.add в этой задаче.
Что отвечать команде:
- Делаем явное правило вроде «
t3закрыт, покаt2< 0.5»? Это даёт предсказуемость, но добавляет код и возможные конфликты с ZPD-логикой. - Или оставляем как сейчас (правило срабатывает «случайно» через геом. среднее)? Меньше кода, но завязано на дисциплину учителя.
2. Кто отвечает за разметку — учитель или код?
Заголовок раздела «2. Кто отвечает за разметку — учитель или код?»Сейчас: учитель. Добавляя задачу, перечисляет вручную все навыки, которые она задействует, включая предков. Это рутина и место для ошибок.
Если бы помогал код: учитель указывает только «верхний» навык
(например, t3.mix), а код через граф сам добавляет всех его предков
(t2.mix, t1.add, t1.mul).
Что отвечать команде:
- Доверяем дисциплине учителя? Тогда нужен инструмент валидации разметки (линтер).
- Или доверяем графу? Тогда учтите — одна ошибка в графе тиражируется на все задачи разом.
3. Один комплект — или свой на каждый навык?
Заголовок раздела «3. Один комплект pT,pS,pGp_T, p_S, p_GpT,pS,pG — или свой на каждый навык?»Сейчас: все 9 микро-навыков делят одни и те же 4 числа
. То есть «вероятность ошибиться по
невнимательности» (slip) одинакова и для простой арифметики (t1.add),
и для длинного трёхсоставного уравнения (t3.mix).
По жизни они разные: на длинной задаче ошибиться легче (slip выше). В простой угадать без знания почти невозможно (guess ниже). Идеально — свои 4 числа на каждый из 9 навыков.
Что отвечать команде:
- Когда у нас будет ~3000 ответов на каждый навык, чтобы фитить EM-ом per-skill?
- Стоит ли начать собирать данные с этой целью прямо сейчас?
4. Принудительное «закрытие пробелов» против ZPD
Заголовок раздела «4. Принудительное «закрытие пробелов» против ZPD»Кейс: Маша зашла впервые. У неё на базовой арифметике
t1.add.
Когда селектор смотрит на любую задачу с t1.add в навыках,
геом. среднее даёт → closeness ≈ 0 →
задача отбрасывается. Остаются только чистые задачи на t1.add.
Это правильно образовательно — заставляем закрыть базу.
Но может быть скучно — если в банке всего 3 чистые задачи на
t1.add, Маша решает их по кругу 6 раз. Демотивация.
Что отвечать команде:
- Добавить «спасательный режим»: если ученик 5 раз подряд получает задачу на один навык, ZPD-окно автоматически расширяется и в пул попадают «соседние» задачи?
- Или жёстко закрываем пробелы, даже ценой одинаковых задач?
5. Когда подключим MATx — будут навыки из разных тем
Заголовок раздела «5. Когда подключим MATx — будут навыки из разных тем»Сейчас: все 9 наших навыков — из одной темы (define,
моделирование задач).
После интеграции с MATx: добавятся 9 навыков из 3 других тем —
protsendid (проценты), vorrandid (уравнения), abivalemid
(вспомогательные формулы). Итого 18 навыков, 4 темы.
Появится новый класс задач — межтемные. Например, «текстовая
задача на проценты, где надо составить уравнение» — это
define.t2.mul (моделирование) + vorrandid.lihtsad (вычисление).
Что отвечать команде:
- Считаем такую задачу одной формулой по всем навыкам (математически работает, но семантически странно)?
- Или вводим параллельные треки и переключаемся между темами?
- Балансируем ли рекомендации — «не больше 5 задач подряд из одной темы»?
6. Жёсткость ZPD-окна () — статика или динамика?
Заголовок раздела «6. Жёсткость ZPD-окна (σ2=0.03\sigma^2 = 0.03σ2=0.03) — статика или динамика?»Что это число: в формуле скоринга задачи управляет тем, насколько близко должен быть к 0.7. Меньше σ² — уже окно (только задачи с проходят). Больше σ² — шире.
Сейчас: (статика). Допускает .
Если бы σ² двигалась:
- Новичок только пришёл — (широкое окно: «любая задача, дающая хоть какой-то прогресс — годится»).
- Опытный ученик — (узкое окно: «строго в зону роста, без скучной середины»).
- После серии правильных — сужаем (поднимаем планку), после серии неправильных — расширяем (даём передышку).
Что отвечать команде:
- Стоит ли автоматизировать, или оставить ручкой для учителя?
- Если автоматизировать — на каких сигналах основываться (длина серии, средний P(L), скорость роста)?
8. Куда смотреть в коде
Заголовок раздела «8. Куда смотреть в коде»- Типы и параметры —
packages/bkt-core/src/microskills.ts - Update / select —
packages/bkt-core/src/bkt.ts - Skill-граф —
data/matx-bridge.json - Виджеты-симуляторы —
study-guide/src/widgets/