Skip to content

Engine Reference ​

Mỗi engine ở đây được mô tả theo đúng một khuôn: đầu vào → thuật toán (công thức thật) → đầu ra, kèm đường dẫn file để đối chiếu.

Luật chung cho mọi engine của Nemo12:

  1. Deterministic — cùng input cho cùng output. Không engine nào trong danh sách này gọi LLM (ngoại lệ duy nhất: §8 Content Quality, và nó không chạm Learner Model).
  2. Engine thuần tách khỏi I/O — hàm tính toán nằm ở engine.ts (không đọc DB, test được thẳng); phần đọc/ghi DB nằm ở service.ts.
  3. Mọi lần chạy đều để lại dấu — qua runEngine(), ghi vào engine_runs kể cả khi output không đổi.
  4. Không engine nào được làm hỏng nghiệp vụ gọi nó — hot path dùng runModelsSafely(), lỗi chỉ log model_update_degraded.
  5. Cấm test bằng regex source (RISK-015) — chỉ test hành vi.
#EngineFileVersionLLM
1Mastery & Confidencemodules/knowledge/mastery.ts— (inline)không
2Goalmodules/goals/engine.tsgoal-v1không
3Learner Modelmodules/models/service.tslearner-v2không
4Contextmodules/models/service.tscontext-v1không
5Readinessmodules/knowledge/mastery.ts + servicereadiness-v1không
6Retentionmodules/retention/engine.tsretention-v1không
7Need Signal (chọn bài)modules/learning/routes.ts— (inline)không
8Content Qualitymodules/coral/routes.ts—có (AI Gateway)

1. Mastery & Confidence Engine ​

Vì sao thế này: thuật toán được port nguyên vẹn từ assess-engine.ts của chuyenchon — đã kiểm chứng trên học sinh thật, không phải phát minh lại.

Đầu vào ​

TrườngNguồn
prevlearner_skill_state: { mastery, confidence, evidence_count } — null nếu chưa từng đo
performance1 đúng / 0 sai
difficulty0–1, thuộc tính của item
reliability0–1, từ attemptReliability()

Thuật toán ​

surprise    = correct ? difficulty : (1 − difficulty)
decay       = 1 / (1 + 0.6 × prevCount)
lr          = (0.35 + 0.35 × surprise) × decay × reliability
mastery'    = clamp01(old + lr × (outcome − old))
evidence'   = prevCount + (reliability ≥ 0.15 ? 1 : 0)
confidence' = clamp01(1 − 0.55^evidence')

Đọc bằng lời:

  • surprise — đúng một câu khó, hoặc sai một câu dễ, là thông tin lớn; đúng câu dễ gần như không nói lên điều gì.
  • decay — câu đầu tiên dịch chuyển model mạnh nhất; câu thứ 20 gần như không. Model càng biết nhiều càng khó bị lung lay.
  • confidence — chỉ phụ thuộc lượng bằng chứng, hoàn toàn độc lập với mastery. Học sinh giỏi mới làm 1 câu vẫn có confidence thấp.
  • Prior khi chưa có gì: mastery = 0.5, confidence = 0.

Reliability của một lần trả lời (attemptReliability) ​

Chống rác đầu vào từ đoán bừa (REQ-INT-21/22, SDD-002 §18):

Tình huốngreliability
Bấm "Chưa biết" (trung thực)0.7
Không đo được thời gian1.0
≥ 2500 ms (RAPID_MS)1.0
< 2500 ms, chuỗi rapid 1–20.4
< 2500 ms, chuỗi rapid ≥ 30.05 — gần như không dịch chuyển model, và không tính là "đã đo"

Đầu ra ​

{ mastery, confidence, trajectory, evidence_count, observed_performance }, trong đó trajectory = improving (+0.02) / stable / declining (−0.02) / unknown (lần đầu).

Trạng thái hiển thị (stateFor) ​

confidence < 0.25             → unknown     "Đang làm quen"
mastery ≥ 0.8                 → chac        "Chắc rồi"
mastery ≥ 0.5                 → lung_lay    "Đang lung lay"
còn lại                       → hong        "Cần xây lại từ gốc"

Confidence thấp luôn thắng: chưa đủ bằng chứng thì không được phép kết luận "hổng".


2. Goal Engine ​

buildGoalModel(input) — thuần, không I/O.

Đầu vào ​

examTargets (đích thi đã khai, chỉ status='active') · examSchedule (lịch thi học kỳ) · enrollments · contextBlueprint.

Thuật toán ​

Bước 1 — Exam target → 2 goal. Mỗi đích thi sinh một goal gốc exam_school|graduation|ielts|sat|ap và một goal con subject_readiness cho môn chuyên. Môn không chuyên là thuộc tính của goal gốc, không sinh goal riêng (Q-102).

Bước 2 — Lịch thi học kỳ → goal semester_exam (priority = 1).

Bước 3 — Enrollment → goal nền, chỉ khi chưa có goal nào. Có mục tiêu thật rồi thì không thêm mục tiêu giả.

Bước 4 — Horizon & urgency theo số ngày còn lại:

horizon:  ≤14 ngày → operational · ≤90 → tactical · >90 → strategic · không deadline → undated
urgency:  quá hạn → 1 · ≥365 ngày → 0.05 · còn lại → 1/(1 + days/30)

Hàm 1/(1+d/30) dốc hẳn lên trong 30 ngày cuối — đó là lý do thi học kỳ 5 ngày nữa thắng kỳ thi chuyên 6 tháng nữa, dù kỳ thi chuyên "to" hơn.

Bước 5 — Conflict detection. Engine phát hiện chứ không tự giải quyết (Q-099):

LoạiĐiều kiện
deadline_passeddays_to_deadline < 0
time_competitionhai goal gốc có deadline cách nhau ≤ 7 ngày

Xung đột được escalate cho Planning/phụ huynh — hệ thống không tự ý bỏ mục tiêu của ai.

Bước 6 — Sắp xếp: urgency giảm dần → priority tăng dần → key.

Đầu ra ​

{ algorithm_version, computed_at, goals[], conflicts[], summary }. summary.empty = true là hợp lệ.


3. Learner Model Engine ​

Vào: learner_skill_state join skill_nodes, tổng hợp learner_evidence (kèm phân bố theo type/source), đếm node graph theo môn, assessment_sessions/assessment_responses (behavior), hồ sơ learners, Goal Model version mới nhất. Ra: Learner Model.

Điểm cần biết: gom theo môn → tính avg_mastery/avg_confidence chỉ trên node đã có evidence; coverage = nodes_assessed / cả graph của môn (SRC-528); strengths = top 5, gaps = bottom 5; model confidence = 1 − 0.9^(số evidence). Trường mới nào cũng phải đổi theo dữ liệu, không theo đồng hồ — vì vậy không có freshness_days, và avg_response_ms làm tròn bậc 100ms.


4. Context Engine ​

Vào: learner_context_models, school_enrollments, learners, goal urgent nhất (ORDER BY urgency DESC, priority ASC LIMIT 1). Ra: Context Model — chỉ giữ active_goal_ref, không sao chép goal.


5. Readiness Engine ​

computeReadiness(weights, mastery, maxScore, cutScore).

Thuật toán ​

với mỗi node trong blueprint:
    threshold = REQUIRED_THRESHOLD[required_state]     // chac 0.8 · lung_lay 0.5 · hong 0 · unknown 0
    achieved  = threshold > 0 ? clamp01(mastery / threshold) : 1
    achievedWeight += weight × achieved
    nếu mastery < threshold → ghi vào gaps { weight, deficit }

ratio           = achievedWeight / totalWeight
estimated_score = ratio × max_score
on_track        = estimated_score ≥ cut_score

Xếp hạng gap theo weight × deficit — không theo mức yếu. Một node yếu nhẹ nhưng trọng số cao có thể quan trọng hơn node hổng nặng mà đề gần như không hỏi. Top 1/3 = critical, giữa = important, còn lại = nice_to_have.

largest_uncertainty xếp theo weight × (1 − confidence), lấy node có confidence < 0.5 — đây là danh sách "cần đo", khác hoàn toàn danh sách "cần học".


6. Retention Engine ​

Mô hình: R(t) = R₀ × exp(−Δt / S), S = stability tính bằng ngày. Truy xuất thành công làm S tăng (quên chậm lại); thất bại làm S co (nhắc dày hơn).

Hằng số (CFG) ​

NhómGiá trị
StabilityS_MIN 3 · S_MAX 365 · S₀ = 6 + 14 × mastery
Review LadderT_NONE .85 · T_LIGHT .75 · T_ACTIVE .6 · T_RELEARN .4
Review windowW_EARLIEST .85 · W_IDEAL .75 · W_LATEST .65
Ngưỡng khácMASTERED_MIN .6 · R_CAP .98 · probe khi R < .75 và conf < .4

Phân tầng bằng chứng (evidenceTier) ​

reliability < 0.15                    → exposure    (đoán bừa — không kết luận nhớ hay quên)
sai                                   → failed
reliability < 0.6                     → assisted
đúng và Δt ≥ S (spacingRatio ≥ 1)     → transfer    (bằng chứng mạnh nhất)
còn lại                               → independent

Cập nhật (applyEvidence) ​

TierRetentionStability
exposure+0.05 × w × spacingWeight× (1 + 0.05 × spacingWeight)
failedkéo về min(R×0.5, 0.45) theo w× (1 − 0.5 × spacingWeight × w)
assistedtiến tới sàn 0.8× 1.25
independenttiến tới sàn 0.9× (1.5 + 0.5×min(sr,2))
transfertiến tới sàn 0.94× (1.8 + 0.6×min(sr,2))

Hai lớp giảm chấn quan trọng:

  • spacingWeight = min(1, elapsedDays) — làm lại cùng ngày gần như không đổi stability. Cày 50 câu trong một buổi không tạo trí nhớ dài hạn, và model không được phép giả vờ là có.
  • w = reliability — mọi boost/penalty nhân theo độ tin. Spam đoán bừa không "đánh bóng" được retention.

Một lần sai không kéo retention về 0 (bảo vệ context-failure: mệt, đọc nhầm đề).

Cửa sổ ôn (reviewWindowDays) ​

Nghịch đảo của đường quên: t = S × ln(R / x). Trả về khoảng { earliest, ideal, latest }, không phải một mốc. Đã dưới ngưỡng → 0 (đến hạn ngay).

Ưu tiên & mức gấp ​

ReviewPriority = ForgettingRisk × Importance × GoalRelevance × Timing
  ForgettingRisk = clamp01(historical_mastery − current_retention)
  Importance     = 1 + 0.15 × min(10, blocks_count)
  GoalRelevance  = inGoal ? 1.5 : 0.6
  Timing         = daysToExam ≤14 → 2 · ≤45 → 1.3 · còn lại → 1

urgencyFor() bắt đầu từ thang R (NONE/LOW/MEDIUM/HIGH), rồi +1 bậc nếu thuộc goal và thi trong 14 ngày, +1 bậc nếu đang chặn ≥3 bài sau (prerequisite protection), −1 bậc nếu không thuộc goal nào và không có kỳ thi nào.

Retention thấp một mình KHÔNG đủ để bắt ôn. Quên một thứ không ai cần đến thì cứ để quên.

historical_mastery < 0.6 → luôn NONE và groupLabel = null: chưa từng vững thì không phải chuyện trí nhớ.

Nhãn hiển thị ​

dang_chac (R≥.8) · nhac_lai (≥.65) · nguy_co_quen (≥.45) · nen_on_lai. Không hiện công thức, không phán xét (REQ-INT-28).

Review Queue ​

topReviewCandidates() tính lại mỗi lần đọc, lấy top-k theo priority. Không backlog, không đếm "quá hạn" — hệ thống không tạo cảm giác nợ nần (SDD-017 §9).


📄 Recommendation Engine có trang riêng: recommendation-engine.md — "hôm nay học bài nào", 5 bước chọn việc, và bốn engine đề xuất khác trong hệ thống.

7. Need Signal Engine (chọn bài trong Phòng Lab) ​

Chạy inline trong GET /v1/learners/{learnerId}/labs. Trả lời câu hỏi của learner: "bài này có cần học không?"

state = stateFor(mastery, confidence)
  hong      → need = "urgent"   🔴 Cần học
  lung_lay  → need = "review"   🟡 Nên ôn
  chac      → need = "solid"    🟢 Đã vững
  unknown   → need = "new"      ⚪ Chưa học

Kèm hai tín hiệu ngữ cảnh, đều tính từ dữ liệu thật:

  • blocks_count — số UNIT phía sau bị chặn, từ unit_prereqs (SRC-396) → "🔒 đang chặn 3 bài sau". Trước SRC-396 đọc từ skill_edges cấp node; đổi vì quan hệ tiên quyết nay sống ở cấp Unit.
  • in_goal — node có trong blueprint_weights của goal đang active → "🎯 thuộc mục tiêu".

📄 Quality Engine có trang riêng: quality-engine.md — 4 lớp gác, rubric CC-QAF 8 chiều, cổng publish.

8. Content Quality Engine (AI) ​

Engine duy nhất dùng LLM. Chạy trong Coral (modules/coral/routes.ts), model @cf/meta/llama-3.3-70b-instruct-fp8-fast, bắt buộc qua AI Gateway nemo12 (QG-010, cấm probe-fallback — RISK-022).

Dùng để soạn/đánh giá nội dung. Không chạm vào Learner Model — không có đường nào từ output LLM đi thẳng vào mastery. Chi tiết: AI Registry.


Kiểm chứng ​

EngineTest
Retentionmodules/retention/engine.test.ts — test hành vi
Còn lạiQG-005 (behavior tests), đối chiếu chuyenchon với engine mastery

Trace ​

  • REQ-INT-16/21/22/23..28, REQ-LRN-10/15, REQ-VIS-08.
  • Thiết kế: SDD-002 §7/§8/§16/§17/§18, SDD-008 §5, SDD-017.
  • Kiểm chứng: QG-005, QG-010.