Lang v2.0 System Atlas

Концептов: 469 Упражнений: 8 905 Типов: 9 Сервисов: 10 Таблиц: 65 LOC: 83k

Обзор системы

10 сервисов, 3 инфраструктурных компонента, 83k строк кода

flowchart TB
  subgraph "Клиент"
    TG["Telegram Bot
aiogram 3.x
25k LOC"] end subgraph "Gateway" GW["API Gateway :8100
proxy + auth + rate limit
1.8k LOC"] end subgraph "Сервисы" LS["Lesson Service :8101
YAML уроки
2.3k LOC"] ES["Exercise Service :8102
Concept Grid, БД
3.3k LOC"] PS["Progress Service :8103
FSRS, Selector
19k LOC"] PF["Profile Service :8104
Профили, Reading
4.4k LOC"] AI["AI Service :8105
AI Hub, Pipeline
14.6k LOC"] EN["Engagement :8106
XP, Диалоги
2.6k LOC"] EC["Error Clustering :8107
Qdrant кластеры
1.8k LOC"] AA["Answer Analytics
Async worker
0.4k LOC"] end subgraph "Инфраструктура" PG[("PostgreSQL :5433
65 таблиц")] RD[("Redis :6379
DB0 Events + DB1 Cache
DB3 FSM + DB4 Embeddings")] QD[("Qdrant :6333
Векторы 1536 dims")] end TG -->|HTTP| GW GW -->|proxy| LS GW -->|proxy| ES GW -->|proxy| PS GW -->|proxy| PF GW -->|proxy| AI GW -->|proxy| EN GW -->|proxy| EC TG -.->|"Events (Redis Pub/Sub)"| RD PS -.->|Events| RD AI -.->|Events| RD EN -.->|Events| RD AA -.->|Events| RD LS --> PG ES --> PG PS --> PG PF --> PG AI --> PG EN --> PG AI --> QD EC --> QD AA --> QD AI -->|"GPT-4o / Claude"| AIAPI["OpenAI + Anthropic API"] style TG fill:#1f6feb,stroke:#58a6ff,color:#fff style GW fill:#238636,stroke:#3fb950,color:#fff style PG fill:#6e40c9,stroke:#bc8cff,color:#fff style RD fill:#9e6a03,stroke:#d29922,color:#fff style QD fill:#8b4513,stroke:#f0883e,color:#fff style PS fill:#b62324,stroke:#f85149,color:#fff style AI fill:#b62324,stroke:#f85149,color:#fff

Ключевые факты

  • Красным выделены самые большие сервисы: Progress (19k LOC) и AI (14.6k LOC)
  • Все HTTP-запросы идут через Gateway :8100 (JWT авторизация)
  • Events — Redis Pub/Sub (DB0), без persistence (потеря при рестарте)
  • Бот напрямую подключается к Redis для FSM (DB3) и публикации событий (DB0)
  • AI Service вызывает внешние API: OpenAI (GPT-4o, GPT-4o-mini) и Anthropic (Sonnet, Opus)

Путь /go — от кнопки до результата

12 шагов полного цикла урока

sequenceDiagram
  participant U as Ученик
  participant B as Telegram Bot
  participant GW as Gateway :8100
  participant PS as Progress :8103
  participant ES as Exercise :8102
  participant AI as AI :8105

  U->>B: /go
  Note over B: ai_lesson_engine()

  B->>GW: GET /profile/{user_id}
  GW->>B: язык, уровень, настройки

  B->>GW: GET /progress/next-concept/{user_id}
  GW->>PS: ConceptSelector
  Note over PS: ghost → due → weak → new
  PS->>GW: concept_id, review_type, mastery
  GW->>B: Концепт выбран

  B->>GW: GET /exercises/concept/{id}/session
  GW->>ES: block_exercises WHERE concept_id
  ES->>GW: exercises[] + theory_blocks
  GW->>B: Пул 5-15 упражнений

  Note over B: MasterySession создана
  B->>U: Интро: теория + кнопки

  U->>B: "Начать упражнения"
  Note over B: FSM → waiting_for_answer

  loop Каждое упражнение
    B->>U: Задание + варианты/ввод
    U->>B: Ответ
    Note over B: AnswerChecker
8 уровней проверки alt Нужна AI проверка B->>GW: POST /ai/check-answer GW->>AI: GPT-4o-mini AI->>GW: is_correct + reason GW->>B: Результат end B->>GW: POST /progress/attempts GW->>PS: FSRS update + mastery recalc PS->>GW: new_mastery_level B->>U: Фидбек (верно/неверно + объяснение) end Note over B: session.is_ended()? B->>U: Результат: X/Y правильно, +XP

Критические точки

  • ConceptSelector — единственный путь к выбору материала. Приоритеты: ghost → due → weak → new
  • MasterySession — адаптивная сессия 5-15 упражнений. Заканчивается при 5 подряд правильных или 2 подряд неправильных
  • AnswerChecker — 8-уровневый каскад (см. Tab 5). Для translation, open_answer, transformation — сразу AI
  • FSRS update — SM-2 quality(0-5) конвертируется в FSRS rating(1-4), обновляется due_date

Архитектура концептов

469 концептов (235 ES + 735 EN), иерархия и mapping

flowchart LR
  subgraph "Таксономия"
    CAT["Категории
grammar, vocabulary,
pronunciation, culture"] CON["Концепты
469 всего
235 ES / 735 EN"] CB["Content Blocks
Теория + микро-концепты"] EX["Упражнения
8 905 активных
9 типов"] end CAT --> CON CON --> CB CB --> EX subgraph "Поля концепта" F1["concept_key
(articulo_definido)"] F2["russian_l1_difficulty
1=лёгкий → 5=тяжёлый"] F3["fsrs_init_difficulty
начальная сложность"] F4["requires_explicit_cf
нужна Corrective Feedback"] F5["early_intervention_critical
произношение"] end subgraph "Prerequisites (пример)" P1["articles"] --> P2["noun_gender"] P2 --> P3["adjective_agreement"] P3 --> P4["noun_adj_position"] end subgraph "L1 Difficulty (русские)" D5["5 — Артикли
mult 0.7 (больше повторений)"] D4["4 — Предлоги, Perfect
mult 0.75"] D3["3 — Средние
mult 0.85"] D2["2 — Знакомые
mult 1.0"] D1["1 — Когнаты
mult 1.1 (быстрее)"] end style D5 fill:#b62324,stroke:#f85149,color:#fff style D4 fill:#9e6a03,stroke:#d29922,color:#fff style D3 fill:#6e40c9,stroke:#bc8cff,color:#fff style D2 fill:#238636,stroke:#3fb950,color:#fff style D1 fill:#1f6feb,stroke:#58a6ff,color:#fff

Структура данных

  • conceptscontent_blocksblock_exercises — трёхуровневая иерархия в PostgreSQL
  • concept_key — строковый ID (напр. articulo_definido, ser_vs_estar)
  • L1 difficulty — 971 концепт с мультипликатором для русскоговорящих. Артикли (5) повторяются на 30% чаще
  • Prerequisites — граф зависимостей. Новый концепт не предлагается, пока prerequisite не mastered
  • Content Blocks — теория разбита на микро-блоки, к каждому привязаны упражнения

Генерация упражнений

От концепта до экрана: 9 типов, 3-Agent Pipeline, SSOT

flowchart TB
  subgraph "SSOT: exercise_types.py"
    T1["fill_gaps 25%
Input Processing"] T2["transformation 20%
Focus on Form"] T3["error_correction 10%
Metalinguistic"] T4["translation 10%
Pushed Output L1→L2"] T5["minimal_pairs 10%
Meaning Contrast"] T6["open_answer 10%
Free Production"] T7["multiple_choice 5%
Quick Recognition"] T8["matching 5%
Pair Linking"] T9["reorder 5%
Syntax Awareness"] end NORM["NORMALIZATION_MAP
54 legacy → 9 canonical"] NORM --> T1 NORM --> T2 NORM --> T3 NORM --> T4 NORM --> T5 NORM --> T6 NORM --> T7 NORM --> T8 NORM --> T9 subgraph "3-Agent Pipeline (Прокачай)" CP["CurriculumPlanner
Алгоритм
skeleton + gaps"] MP["Methodologist
Claude Sonnet
~$0.03/вызов"] OR["OpusReviewer
Claude Opus
~$0.05/вызов
4 критерия"] end CP --> MP --> OR subgraph "Автоматическая генерация" GEN["generator.py
1130 LOC"] OPT["option_designer.py
782 LOC"] CSD["closed_set_detector.py
36 правил: 26 ES + 10 EN"] end GEN --> OPT GEN --> CSD subgraph "Выход" DB[("block_exercises
8 905 записей")] QS["quality_score
0-100"] end OR --> DB GEN --> DB DB --> QS style T1 fill:#238636,stroke:#3fb950,color:#fff style T2 fill:#1f6feb,stroke:#58a6ff,color:#fff style OR fill:#b62324,stroke:#f85149,color:#fff style QS fill:#9e6a03,stroke:#d29922,color:#fff

TARGET_TYPE_WEIGHTS

  • fill_gaps: 25% — пропуски (VanPatten Input Processing)
  • transformation: 20% — преобразование (Long Focus on Form)
  • error_correction: 10% — исправление ошибок
  • translation: 10% — перевод RU→ES
  • minimal_pairs: 10% — контраст значений
  • open_answer: 10% — свободный ответ
  • multiple_choice: 5% — выбор из 4
  • matching: 5% — сопоставление пар
  • reorder: 5% — собери предложение

Реальность vs цели

  • CRITICAL Факт: 86% fill_gaps vs цель 25%
  • CRITICAL 99% упражнений quality < 80
  • NORMALIZATION_MAP — 54 legacy типа нормализуются в 9
  • CLOSED_SETS — 36 правил для артиклей, предлогов и др.
  • 3-Agent Pipeline вызывается вручную через "Прокачай"

AnswerChecker — каскад проверки

8 уровней: от exact match до AI fallback

flowchart TB
  START["Ответ ученика"] --> L0

  L0{"Level 0
personal_info?
true_sentences?"} L0 -->|Да| ACCEPT["Принять любой ответ"] L0 -->|Нет| AICHECK AICHECK{"requires_ai_check?
translation / open_answer /
transformation"} AICHECK -->|Да| L3["Level 2+: AI сразу
GPT-4o-mini"] AICHECK -->|Нет| L1 L1{"Level 1.0
Exact match?"} L1 -->|Да| CORRECT["Правильно"] L1 -->|Нет| L11 L11{"Level 1.1
Normalized?
lowercase + без акцентов"} L11 -->|Да| CORRECT L11 -->|Нет| L21 L21{"Level 2.1
Опечатка?
Levenshtein ≤ 2"} L21 -->|Да| TYPO["Принято с пометкой
Орфография: correct"] L21 -->|Нет| L22 L22{"Level 2.2
error_correction?
слово из предложения"} L22 -->|Да| CORRECT L22 -->|Нет| L23 L23{"Level 2.3
Core extraction?
ядро ответа совпадает"} L23 -->|Да| CORRECT L23 -->|Нет| L25 L25{"Level 2.5
Disputed?
Sonnet vs Opus"} L25 -->|Оба согласны| WRONG["Неправильно"] L25 -->|Расхождение| DISPUTED["Принято как
альтернативный вариант"] L3 --> L3R{"AI результат"} L3R -->|correct| CORRECT L3R -->|incorrect| WRONG L3R -->|disputed| DISPUTED style CORRECT fill:#238636,stroke:#3fb950,color:#fff style WRONG fill:#b62324,stroke:#f85149,color:#fff style TYPO fill:#9e6a03,stroke:#d29922,color:#fff style DISPUTED fill:#6e40c9,stroke:#bc8cff,color:#fff style ACCEPT fill:#1f6feb,stroke:#58a6ff,color:#fff

Типы, требующие AI проверки

  • translation — перевод может быть правильным в разных формулировках
  • open_answer — свободный текст, нет единственного правильного ответа
  • transformation — преобразование предложения допускает вариации
  • personal_info, true_sentences — принимают любой ответ (Level 0)
  • Disputed — когда Sonnet и Opus дают разные оценки, принимается как альтернативный вариант

FSRS и прогресс

Spaced Repetition + Ghost Review + L1 мультипликаторы

stateDiagram-v2
  [*] --> New: Новый концепт

  New --> Learning: Первый ответ
  Learning --> Review: Правильные ответы
  Review --> Review: Правильный (Good/Easy)
  Review --> Relearning: Неправильный (Again)
  Relearning --> Review: Снова правильный

  state "Ghost Review" as Ghost {
    [*] --> Step0: 2+ ошибки подряд
    Step0: Шаг 0 — через 4 часа
    Step0 --> Step1: Если опять ошибка
    Step1: Шаг 1 — через 12 часов
    Step1 --> Step2: Если опять ошибка
    Step2: Шаг 2 — через 24 часа
    Step2 --> Step3: Если опять ошибка
    Step3: Шаг 3 — через 48 часов
  }

  Review --> Ghost: 2 подряд неправильных
  Ghost --> Review: Правильный ответ
    

SM-2 → FSRS конверсия

  • SM-2 quality 0-2 → FSRS rating 1 (Again)
  • SM-2 quality 3 → FSRS rating 2 (Hard)
  • SM-2 quality 4 → FSRS rating 3 (Good)
  • SM-2 quality 5 → FSRS rating 4 (Easy)
  • Target retention: 87%

L1 мультипликаторы (русские)

  • 5 Артикли — ×0.7 (больше повторений)
  • 4 Предлоги, Perfect — ×0.75
  • 3 Средние — ×0.85
  • 2 Знакомые — ×1.0
  • 1 Когнаты — ×1.1 (быстрее)

ConceptSelector — что учить дальше

4-приоритетная очередь, единственный путь /go

flowchart TB
  START["/go запрос"] --> CHECK["Получить все
progress_records
для user_id"] CHECK --> P1{"P1: Ghost Review?
ghost_review_active = true
ghost_review_next ≤ now"} P1 -->|Есть| G1["Пул Ghost-концептов"] P1 -->|Нет| P2 P2{"P2: Due Review?
fsrs_data.due_date ≤ now
mastery ≥ learning"} P2 -->|Есть| G2["Пул Due-концептов"] P2 -->|Нет| P3 P3{"P3: Weak Spots?
confidence_score ≤ 70%
attempts ≥ 3"} P3 -->|Есть| G3["Пул Weak-концептов"] P3 -->|Нет| P4 P4{"P4: New Concept?
prerequisites met?
не изучался сегодня?"} P4 -->|Есть| G4["Пул New-концептов"] P4 -->|Нет| EMPTY["Нет доступных
концептов"] G1 --> RND["Случайный из пула 5"] G2 --> RND G3 --> RND G4 --> RND RND --> RESULT["concept_id +
review_type +
mastery_level"] style P1 fill:#b62324,stroke:#f85149,color:#fff style P2 fill:#9e6a03,stroke:#d29922,color:#fff style P3 fill:#6e40c9,stroke:#bc8cff,color:#fff style P4 fill:#238636,stroke:#3fb950,color:#fff style G1 fill:#b62324,stroke:#f85149,color:#fff style G2 fill:#9e6a03,stroke:#d29922,color:#fff style G3 fill:#6e40c9,stroke:#bc8cff,color:#fff style G4 fill:#238636,stroke:#3fb950,color:#fff

Алгоритм

  • P1 GHOST 2+ consecutive failures → срочное повторение (fossilization prevention)
  • P2 DUE FSRS scheduled review → плановое повторение
  • P3 WEAK confidence < 70% при 3+ попытках → целевая практика
  • P4 NEW prerequisites выполнены, не изучался сегодня → новый материал
  • Из каждого пула берётся случайный из 5 (разнообразие)
  • Exclude: концепты, изученные сегодня (anti-cramming)

Data Model — ключевые таблицы

PostgreSQL :5433, 65 таблиц, основные связи

erDiagram
  concepts {
    int id PK
    string concept_key UK
    string category
    string name
    string name_ru
    int russian_l1_difficulty
    float fsrs_init_difficulty
    bool requires_explicit_cf
    bool early_intervention_critical
  }

  content_blocks {
    int id PK
    int concept_id FK
    text theory_text
    jsonb theory_blocks
    jsonb source_textbooks
    jsonb source_units
    bool is_active
  }

  block_exercises {
    int id PK
    int concept_id FK
    int block_id FK
    string exercise_type
    string difficulty_tier
    text task
    text correct_answer
    text explanation_ru
    text hint
    text format_hint
    jsonb options
    int quality_score
    bool is_active
    string review_status
  }

  progress_records {
    int id PK
    int user_id
    int concept_id FK
    string context_type
    jsonb attempts
    string srs_algorithm
    jsonb sm2_data
    jsonb fsrs_data
    int confidence_score
    string mastery_level
    bool ghost_review_active
    int ghost_review_step
    timestamp first_practiced
    timestamp last_practiced
  }

  student_profiles {
    int user_id PK
    jsonb preferences
    string target_language
    string current_textbook
  }

  user_answers {
    int id PK
    int user_id
    int exercise_id FK
    text user_answer
    bool is_correct
    int response_time_ms
    string session_id
  }

  concepts ||--o{ content_blocks : "теория"
  content_blocks ||--o{ block_exercises : "упражнения"
  concepts ||--o{ progress_records : "прогресс"
  concepts ||--o{ block_exercises : "напрямую"
  block_exercises ||--o{ user_answers : "ответы"
    

Ключевые JSONB поля

  • fsrs_data: state, stability, difficulty, reps, lapses, due_date, mastery_level
  • theory_blocks: массив {key, title, content} — микро-блоки теории
  • options: массив вариантов для multiple_choice, matching, minimal_pairs
  • preferences: learning_settings (target_language, current_textbook, daily_goal)
  • mastery_level: enum (unknown, beginner, learning, familiar, proficient, mastered)

Event Bus — Redis Pub/Sub

Асинхронные события между сервисами (Redis DB0)

flowchart LR
  subgraph "Публикаторы"
    BOT["Telegram Bot"]
    PS["Progress :8103"]
    AI["AI :8105"]
    ES["Exercise :8102"]
  end

  subgraph "Redis DB0 Pub/Sub"
    E1["exercise.answered"]
    E2["progress.updated"]
    E3["content.pool_low"]
    E4["profile.updated"]
    E5["lesson.completed"]
  end

  subgraph "Подписчики"
    PS2["Progress :8103"]
    PF["Profile :8104"]
    EN["Engagement :8106"]
    AA["Answer Analytics"]
    AI2["AI :8105"]
  end

  BOT -->|ответ ученика| E1
  ES -->|валидация| E1
  PS -->|FSRS update| E2
  ES -->|"пул ≤ 8"| E3
  PF -->|профиль изменён| E4
  BOT -->|урок пройден| E5

  E1 --> PS2
  E1 --> PF
  E1 --> AA
  E2 --> EN
  E3 --> AI2
  E4 --> PS2
  E5 --> EN

  style E1 fill:#b62324,stroke:#f85149,color:#fff
  style E2 fill:#9e6a03,stroke:#d29922,color:#fff
  style E3 fill:#6e40c9,stroke:#bc8cff,color:#fff
    

Важно

  • RISK Redis Pub/Sub не сохраняет события. При рестарте Redis — потеря всех событий в полёте
  • exercise.answered — самое частое событие: каждый ответ ученика
  • content.pool_low — триггер автогенерации когда упражнений < 8
  • Answer Analytics — фоновый worker, записывает embeddings в Qdrant
  • Формат события: {type, data, timestamp, service, correlation_id}

AI Routing — модели и стоимость

Smart routing: дешёвая модель для простых задач, дорогая для сложных

flowchart TB
  REQ["Запрос"] --> ROUTER{"AI Router
Определяет сложность"} ROUTER -->|"Простое: проверка,
batch, fallback"| MINI["GPT-4o-mini
$0.15 / 1M tokens"] ROUTER -->|"Стандартное: генерация,
теория, анализ ошибок"| GPT4["GPT-4o
$2.50 / 1M tokens"] ROUTER -->|"Методическое: prompt
для упражнений"| SONNET["Claude Sonnet
$3.00 / 1M tokens"] ROUTER -->|"Ревью: проверка
качества, disputed"| OPUS["Claude Opus
$15.00 / 1M tokens"] subgraph "Embeddings" EMB["text-embedding-3-small
1536 dims
$0.02 / 1M tokens"] end subgraph "Кэш (Redis DB1)" CACHE["TTL 30 дней
Ключ: hash(prompt)
Экономия ~70%"] end GPT4 --> CACHE SONNET --> CACHE MINI --> CACHE EMB --> QD[("Qdrant :6333")] subgraph "Стоимость за сессию" C1["Проверка ответа: ~$0.001"] C2["Генерация упражнения: ~$0.01"] C3["Методист (Прокачай): ~$0.03"] C4["Ревью Opus: ~$0.05"] C5["Разжуй теорию: ~$0.02"] end style MINI fill:#238636,stroke:#3fb950,color:#fff style GPT4 fill:#1f6feb,stroke:#58a6ff,color:#fff style SONNET fill:#6e40c9,stroke:#bc8cff,color:#fff style OPUS fill:#b62324,stroke:#f85149,color:#fff

Принцип: самая дешёвая подходящая модель

  • GPT-4o-mini — проверка ответов (Level 3 fallback), batch-операции
  • GPT-4o — генерация упражнений, анализ ошибок, теория
  • Claude Sonnet — Methodologist в 3-Agent Pipeline, "Разжуй теорию"
  • Claude Opus — OpusReviewer, disputed answers (высшая инстанция)
  • Кэш Redis DB1 с TTL 30 дней — экономия ~70% на повторных запросах

FSM состояния бота

Все экраны и переходы Telegram бота

flowchart TB
  START(["start / menu"]) --> idle["idle
Главное меню"] idle -->|"/go"| concept_intro["concept_intro
Теория + кнопки"] concept_intro -->|"Начать"| waiting["waiting_for_answer
Ввод ответа"] waiting -->|"Ответ"| feedback["feedback
Результат"] feedback -->|"Следующее"| waiting feedback -->|"Сессия окончена"| complete["concept_complete
Результаты"] complete -->|"Следующий"| concept_intro complete -->|"В меню"| idle concept_intro -->|"Разжуй теорию"| theory_ov["theory_overview
Обзор секций"] theory_ov -->|"Секция"| theory_sec["theory_section
Формула / Ловушки / ..."] theory_sec -->|"Обзор"| theory_ov theory_sec -->|"Другая"| theory_sec theory_ov -->|"Практика"| waiting idle -->|"/reading"| phrase["waiting_for_phrase
Ввод фразы"] phrase -->|"Текст"| analysis["phrase_analysis
Разбор"] analysis -->|"Ещё"| phrase idle -->|"/import_kindle"| vocab["waiting_for_vocab
Ожидание vocab.db"] vocab -->|"Файл"| imported["import_complete"] idle -->|"/lang"| lang["lang_select"] lang -->|"Выбрано"| idle idle -->|"/stats"| stats_view["stats
Статистика"] stats_view -->|"В меню"| idle style idle fill:#238636,stroke:#3fb950,color:#fff style waiting fill:#1f6feb,stroke:#58a6ff,color:#fff style concept_intro fill:#6e40c9,stroke:#bc8cff,color:#fff style phrase fill:#9e6a03,stroke:#d29922,color:#fff style theory_ov fill:#6e40c9,stroke:#bc8cff,color:#fff

FSM States (aiogram)

  • ExerciseStates.waiting_for_answer — основное состояние ввода ответа
  • ExerciseStates.waiting_for_unit_number — ввод номера юнита (YAML path)
  • ReadingStates.waiting_for_phrase — ввод фразы для анализа
  • ReadingStates.waiting_for_vocab_file — ожидание файла Kindle vocab.db
  • FSM storage: Redis DB3
  • Callback patterns: 80+ штук, формат domain:action[:param]

Проблемы и гэпы

Что сломано, что не работает, что отсутствует

flowchart TB
  subgraph "CRITICAL — Сломано"
    C1["Distribution Skew
86% fill_gaps vs 25% цель
Генератор игнорирует
TARGET_TYPE_WEIGHTS"] C2["Качество упражнений
99% quality_score ≤ 80
Нужен массовый re-review"] end subgraph "MEDIUM — Работает плохо" M1["Opus Reviewer
Недостаточно строгий
для translation"] M2["Event Bus
Redis Pub/Sub без persistence
Потеря событий при рестарте"] M3["10 микросервисов
Distributed monolith
для 1 пользователя"] end subgraph "GAP — Отсутствует" G1["Learning Outcomes
Нет метрик D1/D7/D30
Строим вслепую"] G2["Session Analytics
Нет данных о длине сессий
и вовлечённости"] G3["Concept Taxonomy
235 концептов слишком гранулярно
Надо 60-80"] end subgraph "Архитектурный долг" D1["Bot: 25k LOC
Слишком много логики
в presentation layer"] D2["Progress: 19k LOC
Самый большой сервис
нужен рефакторинг"] D3["Shared generator: 1130 LOC
Файл > лимита 300"] end style C1 fill:#b62324,stroke:#f85149,color:#fff style C2 fill:#b62324,stroke:#f85149,color:#fff style M1 fill:#9e6a03,stroke:#d29922,color:#fff style M2 fill:#9e6a03,stroke:#d29922,color:#fff style M3 fill:#9e6a03,stroke:#d29922,color:#fff style G1 fill:#6e40c9,stroke:#bc8cff,color:#fff style G2 fill:#6e40c9,stroke:#bc8cff,color:#fff style G3 fill:#6e40c9,stroke:#bc8cff,color:#fff

Приоритеты (рекомендация экспертов — Tab 13)

  1. P0 Починить distribution: генератор должен следовать TARGET_TYPE_WEIGHTS
  2. P0 Массовый re-review упражнений с quality_score < 50
  3. P1 Добавить метрики learning outcomes (retention D1/D7/D30)
  4. P2 Укрупнить концепты: 235 → 60-80 для испанского
  5. P3 Упростить архитектуру: модульный монолит вместо 10 микросервисов

Анализ экспертов

Что сказали бы лучшие специалисты о системе

Bill VanPatten
SLA Researcher, Input Processing Theory
235 испанских концептов — слишком гранулярно. Студент думает: "когда ставить el, а когда la?", а не articulo_definido_con_sustantivos_masculinos. Таксономия должна быть от коммуникативных задач, не от грамматических категорий. Исключения из правил — часть того же концепта с пометкой "irregular", а не отдельные записи в базе.

Связано: Tab 3 — Концепты, Tab 7 — ConceptSelector

Piotr Wozniak
Создатель SM-2, идеолог Spaced Repetition
FSRS — правильный выбор, он точнее SM-2 на 12%. Но 235 концептов × 5 context_types = 1175 карточек для одного языка. Это scheduling hell — система не может эффективно планировать столько элементов. Ghost review step 0 (через 4 часа) — слишком агрессивно, студент уйдёт. Укрупнить до 50-80 концептов, вариации обрабатывать внутри одного scheduling unit.

Связано: Tab 6 — FSRS, Tab 3 — Концепты

Martin Fowler
Software Architecture, Enterprise Patterns
10 микросервисов для 1 пользователя — это distributed monolith. У вас нет независимого деплоя, нет разных команд, нет разной нагрузки по сервисам. Модульный монолит с чёткими границами модулей даст 90% бенефитов микросервисов при 10% сложности. Event Bus через Redis Pub/Sub без persistence — это потеря данных при каждом рестарте. Если нужны события — используйте Redis Streams с acknowledgment.

Связано: Tab 1 — Обзор, Tab 9 — Event Bus

Duolingo Data Science Team
EdTech, Learning Analytics, A/B Testing
86% fill_gaps при таргете 25% — генератор не работает. Это самый критический баг в системе. Но главная проблема глубже: вы оптимизируете архитектуру вместо learning outcomes. Нет метрик retention (D1/D7/D30), нет данных о длине сессий, нет accuracy trend по времени. Без этих метрик вы строите вслепую — невозможно понять, учится ли вообще студент.

Связано: Tab 4 — Генерация, Tab 12 — Проблемы

Консенсус: приоритеты действий

  1. Сейчас Починить distribution — генератор должен следовать TARGET_TYPE_WEIGHTS. Без этого все упражнения одинаковые.
  2. Неделя Укрупнить концепты 235→60-80. Меньше scheduling units = лучше FSRS, меньше confusion для ученика.
  3. Месяц Добавить learning outcome метрики: retention D1/D7/D30, accuracy trend, session analytics.
  4. Квартал Упростить архитектуру: модульный монолит. 10 сервисов → 1 приложение с модулями.