Files
Learn_System/plans/ai-trainer/PLAN.md
T
Maxim Dolgolyov 7cc2a9d526 feat(trainer): P5 — несколько корней, эквивалентность выражений, новые темы
- движок: gen.answers → несколько корней (_checkMultiRoot, ввод через «;», сверка мультимножеством)
- kind simplify: эквивалентность выражений численным сэмплингом (_sampleEquiv, _checkEquiv), фикс. точки без Math.random
- exprToLatex: знаковые коэффициенты — -5x, x²−5x+6, a−(−b)→a+b (вынос ведущего минуса, схлопывание)
- темы: Упрощение (подобные, скобки) + Квадратные (Виета x²+bx+c=0, разность квадратов) → 17 генераторов, 5 тем
- страница: префикс «x=»/подсказка ввода и ответ-лейбл по типу задачи
- смоук движка 291/291 (T11 roots, T12 simplify, T13 latex), страница 26/26, adaptive 12/12; план P5 → DONE

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 14:15:21 +03:00

14 KiB
Raw Blame History

ИИ-Тренажёр — план развития модуля

Модуль /trainer: бесконечные задачи, которые рождаются из данных-генераторов, а математика считается и проверяется детерминированно через SimExpr (без eval). LLM в ядре не участвует — его роль (Уровень 1+) сочинять генераторы и текстовые задачи, которые тот же слой верифицирует подстановкой. Тема-пилот: уравнения, 7 класс.

Инвариант корректности (не нарушать)

Любой источник задачи (генератор, шаблон, LLM) обязан пройти TrainerEngine.verifyRoot: заявленный корень подставляется в уравнение, расходится → задача отбрасывается. Та же подстановка проверяет ответ ученика (принимает 5, x=5, 10/2, 2+3). Выражения — ТОЛЬКО SimExpr (whitelist, без eval/new Function). Цвета/текст от пользователя — только в безопасные стоки или с escape.

Состояние: Phase 0 — DONE (прототип, в этом коммите)

  • Движок frontend/js/trainer/_trainer_engine.js: instantiate / generateBatch / verifyRoot / checkStudentAnswer / exprToLatex (AST→LaTeX, reusable) / makeRng.
  • Генераторы frontend/js/trainer/generators.js: 5 типов (линейное ax+b=c, скобки, переменная с двух сторон, дробь x/a+b=c, дробный коэффициент ax/b=c). Приём «корень-вперёд» → гарантированно целые ответы, самопроверка всегда проходит.
  • Страница frontend/trainer.html: KaTeX-рендер уравнений и шагов, чипы-темы, мгновенная проверка, подсказка/решение, авто-выбор первого неосвоенного навыка.
  • Прогресс на сервере: practice_progress (мигр.081), practiceController + routes/practice (/api/practice/progress|attempt), клиент LS.practiceProgressList/Submit. Мастерство = серия 5 верных подряд (липкое).
  • Фича-флаг trainer: тумблер в админке (Модули), requireFeature('trainer'), скрытие из сайдбара + редирект страницы (FEATURE_HREFS), запись в MODULE_CATALOG.
  • Тесты: practice.test.js (10/10), headless-смоуки движка/страницы. lint:routes 0.

Phase 1 — Ширина контента (генераторы) — DONE

Сделано: таксономия тема → навык с метаданными (topic/order/subject/grade), TrainerGenerators.topics()/byTopic(). 13 генераторов в 3 темах: Уравнения (7: ax+b=c, a(x+b)=c, ax+b=cx+d, a(x+b)=c(x+d), x/a+b=c, ax/b=c, (ax+b)/c=d), Пропорции (3), Проценты (3, kind:'compute' — текстовый prompt + проверка подстановкой). UI: выбор темы (вкладки) → навыки (чипы) с бейджами мастерства, авто-выбор первой неосвоенной темы/навыка. Подробные объяснения: каждый шаг расписан словами + шаг «Проверка» (подстановка корня). Движок: exprToLatex чинит отрицательные множители (7·(5)), kind:'compute'. Смоуки 238/238 (движок) + 19/19 (страница).

Цель (исходная): перестать быть «демкой одной темы». Структура класс → предмет → тема → навык.

  • Реестр генераторов: вынести в данные с метаданными { grade, subject, topic, skill, order, difficulty }. Группировка чипов по темам/классам; выбор класса/предмета вверху.
  • Новые генераторы 7 кл: пропорции, раскрытие скобок с обеих сторон a(x+b)=c(x+d), уравнения с дробью-уравнением (ax+b)/c = d, простые буквенные преобразования.
  • Соседние темы (параметрические, без LLM): упрощение выражений, степени, проценты, линейные неравенства (расширить checkStudentAnswer под интервалы — см. P5).
  • Acceptance: ≥3 темы × ≥3 навыка, у каждого generateBatch(50) даёт 50 разных корректных задач; solvability-смоук на сетке параметров.

Phase 2 — Адаптивность и интервальное повторение — DONE

Сделано: frontend/js/trainer/adaptive.js (window.TrainerAdaptive, чистая логика) — nextSkill (приоритет: in-session повтор → серверный due → прогрессия → удержание по box), onWrong/onCorrect (in-session очередь повторения), sessionStats. Умная тренировка на странице (по умолчанию вкл, тумблер): авто-подбор навыка, ведёт от простого к сложному, возвращает ошибки; сессия из 10 задач с итогом (верно/точность/ навыки/«стоит повторить»). Неверный ответ авто-показывает решение. Сервер: SR-поля box+due_at на practice_progress (мигр.082, Leitner-интервалы 0/1/3/7/16/30 дней), listProgress отдаёт box/due_at/due. Смоуки: adaptive 12/12, страница 23/23, practice.test.js 11/11 (+SR box/due).

Цель (исходная): вести ученика, а не давать случайное.

  • Диагностика на входе (по 1–2 задачи на навык) → стартовый уровень.
  • Подбор следующего навыка по мастерству (escalate при серии, откат при ошибках).
  • Ошибки уходят в очередь повторения (свой лёгкий SR или reuse flashcards Tier-1).
  • «Продолжить тренировку», дневная норма/цель, сводка сессии (что освоено, над чем работать).
  • Сервер: расширить practice_progress (или новая practice_review_queue); агрегаты для аналитики.
  • Acceptance: сессия из N задач сама ведёт от простого к сложному; промахнутый навык всплывает повторно; прогресс переживает перезаход.

Phase 3 — Уровень 1: LLM-задачи с верификацией — DONE

Сделано: серверная проверка backend/src/utils/practiceVerify.js (грузит SimExpr в Node через require, verifyRoot подстановкой). Сервис practiceGenService.js: buildMessages→LLM→parseProblemvalidateAndVerify (компиляция SimExpr + подстановка корня + санитизация story/шагов) с авторетраем по фидбэку; LLM-вызов инъектируется (opts.ask, дефолт — assistantController.callLLMFailover). Пул practice_problems (мигр.083, status approved/draft). Эндпоинты: POST /api/practice/generate (учитель/админ) + GET /api/practice/pool (ученикам). Клиент: LS.practicePool/Generate, тема «Текстовые задачи» на странице (берёт из пула; учителю — кнопка «Сгенерировать»). Гарантия: невалидная/неверная задача в БД НЕ пишется → ученику не попадёт. Тесты practice-gen.test.js 13/13 (verify, ретраи, off→503, 403 ученику, пул).

Цель (исходная): текстовые/контекстные задачи, которых не даёт параметрика.

  • LLM (через провайдеров админки) генерирует { lhs, rhs, answer, story }; сервер прогоняет verifyRoot; расхождение → авторетрай с фидбэком («корень не удовлетворяет, исправь»).
  • Кэш-пул practice_problems (предгенерация, ревью учителем) — не платить за каждый показ.
  • Генерация «по теме урока» (связка с theory/exam-prep).
  • Acceptance: доля задач, прошедших верификацию с 1–2 ретраев, ≥95%; пул кэшируется; ни одна неверная задача не доходит до ученика (гарантирует инвариант).

Phase 4 — Авторинг учителем

Цель: учитель создаёт свои наборы и раздаёт классу (как sim-builder/Quantik Ф5).

  • Конструктор генераторов: шаблон lhs/rhs, диапазоны параметров, формула ответа, шаги решения; превью + клиентская валидация через SimExpr.compile.
  • Хранение (таблица по образцу custom_sims), серверная validateSpec без исполнения, раздача классу + уведомление, привязка к ДЗ/уроку.
  • Acceptance: учитель собирает рабочий генератор без кода; ученик решает; права/видимость как у custom-sim (own + раздано).

Phase 5 — Типы ответов и проверки — DONE (частично)

Сделано: движок получил несколько корней (gen.answersproblem.answers; _checkMultiRoot — ввод всех корней через «;», сверка мультимножеством) и эквивалентность выражений (kind:'simplify', gen.srcExpr/answerExpr; _sampleEquiv — численный сэмплинг в фикс. точках, без Math.random; _checkEquiv). exprToLatex чинит знаковые коэффициенты (-5x, x²−5x+6, a(b)→a+b). Новые темы: Упрощение (привести подобные, раскрыть скобки) и Квадратные (Виета x²+bx+c=0, разность квадратов — 2 корня). Страница: префикс «x=» и подсказка ввода по типу, ответ-лейбл (корни/выражение). Смоук движка 291/291 (T11 roots, T12 simplify, T13 latex). Осталось (стретч): неравенства (нужен парсер отношений) — не вошло.

Цель (исходная): не только «корень-число».

  • Множество корней (квадратные/факторизация), интервалы (неравенства), упрощение выражений (эквивалентность через численный сэмплинг по диапазону, а не строковое равенство).
  • Пошаговый ввод (проверять каждый шаг подстановкой), несколько форматов ответа.
  • Acceptance: квадратное уравнение принимает оба корня в любом порядке; (x+1)^2x^2+2x+1 через сэмплинг; неравенство принимает x>3 и эквивалент.

Phase 6 — Геймификация, аналитика, UX

  • XP/энергия/стрики (reuse инфраструктуры Квантика), бейджи мастерства на чипах (есть основа).
  • Учительская аналитика: кто на каком навыке застрял, тепловая карта класса, отчёты.
  • UX: виртуальная клавиатура для дробей/степеней, «почему неверно» (разбор ошибки), сократические подсказки через Квантик-ассистента, мобильная раскладка, доступность.

Сквозное

  • Безопасность: только SimExpr; авторские генераторы — серверная validateSpec без исполнения (длины/лимиты, escape текста), как custom_sims.
  • Тесты: на каждый генератор — solvability-смоук (сетка параметров → есть корректные задачи + достижим целевой ответ); бэкенд-тесты на новые роуты; headless-смоук страницы.
  • Контент = данные: генераторы и темы — JS-данные/таблицы, не код.

Рекомендуемый следующий шаг

Phase 1 (ширина контента) — даёт наибольшую пользу при минимальном риске и переиспользует готовый движок/проверку/страницу. Затем Phase 2 (адаптивность) для удержания.