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:
- 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).
- 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. - Mọi lần chạy đều để lại dấu — qua
runEngine(), ghi vàoengine_runskể cả khi output không đổi. - Không engine nào được làm hỏng nghiệp vụ gọi nó — hot path dùng
runModelsSafely(), lỗi chỉ logmodel_update_degraded. - Cấm test bằng regex source (RISK-015) — chỉ test hành vi.
| # | Engine | File | Version | LLM |
|---|---|---|---|---|
| 1 | Mastery & Confidence | modules/knowledge/mastery.ts | — (inline) | không |
| 2 | Goal | modules/goals/engine.ts | goal-v1 | không |
| 3 | Learner Model | modules/models/service.ts | learner-v2 | không |
| 4 | Context | modules/models/service.ts | context-v1 | không |
| 5 | Readiness | modules/knowledge/mastery.ts + service | readiness-v1 | không |
| 6 | Retention | modules/retention/engine.ts | retention-v1 | không |
| 7 | Need Signal (chọn bài) | modules/learning/routes.ts | — (inline) | không |
| 8 | Content Quality | modules/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ường | Nguồn |
|---|---|
prev | learner_skill_state: { mastery, confidence, evidence_count } — null nếu chưa từng đo |
performance | 1 đúng / 0 sai |
difficulty | 0–1, thuộc tính của item |
reliability | 0–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ống | reliability |
|---|---|
| Bấm "Chưa biết" (trung thực) | 0.7 |
| Không đo được thời gian | 1.0 |
≥ 2500 ms (RAPID_MS) | 1.0 |
| < 2500 ms, chuỗi rapid 1–2 | 0.4 |
| < 2500 ms, chuỗi rapid ≥ 3 | 0.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_passed | days_to_deadline < 0 |
time_competition | hai 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_scoreXế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óm | Giá trị |
|---|---|
| Stability | S_MIN 3 · S_MAX 365 · S₀ = 6 + 14 × mastery |
| Review Ladder | T_NONE .85 · T_LIGHT .75 · T_ACTIVE .6 · T_RELEARN .4 |
| Review window | W_EARLIEST .85 · W_IDEAL .75 · W_LATEST .65 |
| Ngưỡng khác | MASTERED_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 → independentCập nhật (applyEvidence)
| Tier | Retention | Stability |
|---|---|---|
exposure | +0.05 × w × spacingWeight | × (1 + 0.05 × spacingWeight) |
failed | kéo về min(R×0.5, 0.45) theo w | × (1 − 0.5 × spacingWeight × w) |
assisted | tiến tới sàn 0.8 | × 1.25 |
independent | tiến tới sàn 0.9 | × (1.5 + 0.5×min(sr,2)) |
transfer | tiế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 → 1urgencyFor() 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ọcKè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_edgescấp node; đổi vì quan hệ tiên quyết nay sống ở cấp Unit.in_goal— node có trongblueprint_weightscủ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
| Engine | Test |
|---|---|
| Retention | modules/retention/engine.test.ts — test hành vi |
| Còn lại | QG-005 (behavior tests), đối chiếu chuyenchon với engine mastery |