dramaling-vocab-learning/note/智能複習/智能複習系統-演算法規格書.md

500 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 智能複習系統 - 演算法規格書 (ASD)
**目標讀者**: 演算法工程師、數據科學家
**版本**: 1.0
**日期**: 2025-09-25
---
## 🧮 **算法概述**
### **核心問題**
現有 `2^成功次數` 算法增長過快,需要設計更科學的間隔重複算法。
### **設計目標**
- 間隔增長平緩,避免過早達到最大間隔
- 結合用戶表現動態調整
- 處理逾期復習的記憶衰減
---
## 📐 **數學模型**
### **主算法公式**
```
新間隔 = (當前間隔 × 增長係數 × 表現係數) × 逾期懲罰係數
下次復習日期 = 復習行為當日 + 新間隔
```
### **⏰ 時間基準定義 (關鍵)**
```python
# 關鍵時間定義
scheduled_date = flashcard.next_review_date # 預定復習日期
actual_review_date = datetime.now().date() # 復習行為當日
overdue_days = (actual_review_date - scheduled_date).days
# 下次復習計算基準:以復習行為當日為準
next_review_date = actual_review_date + timedelta(days=new_interval)
```
**設計原則**:
-**以復習行為當日為基準** - 用戶在哪天復習,就從那天開始計算下次復習
-**避免累積逾期** - 不會因為一次逾期導致後續復習都逾期
-**用戶友好** - 符合用戶直覺,任何時候復習都是"重新開始"
**具體範例**:
```
詞卡應該 2025-09-20 復習,用戶 2025-09-25 才復習 (逾期5天)
- 逾期天數 = 5天 (中度逾期)
- 原間隔 = 14天答對信心等級4
- 新間隔 = 14 × 1.4 × 1.1 × 0.75 = 16天
- 下次復習 = 2025-09-25 + 16天 = 2025-10-11 ✅
- 而非 = 2025-09-20 + 16天 = 2025-10-06 ❌
```
### **1. 增長係數函數**
```python
def get_growth_factor(current_interval):
if current_interval <= 7:
return 1.8 # 短期:快速增長
elif current_interval <= 30:
return 1.4 # 中期:中等增長
elif current_interval <= 90:
return 1.2 # 長期:緩慢增長
else:
return 1.1 # 超長期:極緩增長
```
**設計理念**: 分段函數避免指數爆炸,早期快速建立記憶,後期維持長期記憶。
### **2. 表現係數函數**
```python
def get_performance_factor(is_correct, confidence_level=None, question_type="flipcard"):
"""
根據不同題型計算表現係數
"""
if question_type == "flipcard":
# 翻卡題:信心等級映射 (1-5 → 0.5-1.4)
confidence_mapping = {1: 0.5, 2: 0.7, 3: 0.9, 4: 1.1, 5: 1.4}
return confidence_mapping.get(confidence_level, 0.9)
elif question_type in ["multiple_choice", "fill_blank", "sentence_reconstruction"]:
# 客觀題:正確性導向
return 1.1 if is_correct else 0.6
elif question_type in ["vocabulary_listening", "sentence_listening"]:
# 聽力題:正確性 + 輕微加權 (聽力更困難)
return 1.2 if is_correct else 0.5
elif question_type == "sentence_speaking":
# 口說題:主觀評估 (通常標記為成功)
return 1.0 # 口說練習重在參與,不重罰
else:
# 預設情況
return 0.9
```
**設計理念**: 翻卡題依據主觀信心,客觀題依據正確性,反映不同題型的認知特點。
### **3. 逾期懲罰函數**
```python
def calculate_overdue_penalty(overdue_days):
if overdue_days <= 0:
return 1.0 # 準時,無懲罰
elif overdue_days <= 3:
return 0.9 # 輕度逾期
elif overdue_days <= 7:
return 0.75 # 中度逾期
elif overdue_days <= 30:
return 0.5 # 重度逾期
else:
return 0.3 # 極度逾期
```
**設計理念**: 階梯式懲罰,鼓勵按時復習,但不過度懲罰偶爾延遲。
### **4. 記憶衰減模型**
```python
def calculate_memory_decay(original_mastery, overdue_days):
# 基於 Ebbinghaus 遺忘曲線的指數衰減
decay_rate = 0.05 # 每天5%衰減率
max_decay_days = 30 # 最多考慮30天衰減
effective_days = min(overdue_days, max_decay_days)
decay_factor = (1 - decay_rate) ** effective_days
return max(0, int(original_mastery * decay_factor))
```
**設計理念**: 符合認知科學的遺忘曲線,逾期越久記憶衰減越多。
### **6. 複習方式選擇算法**
#### **6.1 學習程度適配算法**
```python
def get_review_types_by_difficulty(user_level, word_level):
"""
根據學習者程度和詞彙難度決定可用的複習方式
Args:
user_level: 學習者程度 (1-100)
word_level: 詞彙難度 (1-100)
Returns:
List[str]: 適合的複習題型列表
"""
difficulty = word_level - user_level
if user_level <= 20:
# A1學習者 - 統一基礎題型,建立信心
return ['flipcard', 'multiple_choice', 'vocabulary_listening']
elif difficulty < -10:
# 簡單詞彙 (學習者程度 > 詞彙程度)
# 重點練習應用和拼寫
return ['sentence_reconstruction', 'fill_blank']
elif difficulty >= -10 and difficulty <= 10:
# 適中詞彙 (學習者程度 ≈ 詞彙程度)
# 全方位練習,包括口說
return ['fill_blank', 'sentence_reconstruction', 'sentence_speaking']
else:
# 困難詞彙 (學習者程度 < 詞彙程度)
# 回到基礎,重建記憶
return ['flipcard', 'multiple_choice']
```
**設計原則**:
- **A1優先**: 初學者使用最基本的3種題型避免挫折
- **能力匹配**: 難度適中時使用高階題型 (口說、重組)
- **困難降級**: 詞彙太難時回歸基礎題型
- **逐步進階**: 隨著能力提升,逐漸解鎖更多題型
#### **6.2 智能題型推薦算法**
```python
def select_review_mode(available_modes, flashcard, review_history=None):
"""
從可用題型中智能選擇當前最適合的複習方式
Args:
available_modes: 可用的複習題型列表
flashcard: 當前詞卡資訊
review_history: 最近的復習歷史 (可選)
Returns:
str: 推薦的複習題型
"""
if not review_history:
review_history = []
# 1. 避免連續重複 (反單調算法)
recent_modes = [r.question_type for r in review_history[-3:]]
if recent_modes:
last_mode = recent_modes[-1]
consecutive_count = 0
for mode in reversed(recent_modes):
if mode == last_mode:
consecutive_count += 1
else:
break
# 連續2次以上強制切換
if consecutive_count >= 2:
available_modes = [m for m in available_modes if m != last_mode]
if not available_modes: # 如果沒有其他選項,保留原選項
available_modes = [last_mode]
# 2. A1學習者權重分配
if flashcard.user_level <= 20:
weights = {
'flipcard': 0.4, # 40% - 主要熟悉方式
'multiple_choice': 0.4, # 40% - 概念強化
'vocabulary_listening': 0.2 # 20% - 發音練習
}
return weighted_random_select(available_modes, weights)
# 3. 根據最近表現調整
if review_history:
recent_performance = sum([r.is_correct for r in review_history[-5:]]) / len(review_history[-5:])
if recent_performance < 0.6:
# 表現不佳,偏向基礎題型
priority_order = ['flipcard', 'multiple_choice', 'fill_blank',
'sentence_reconstruction', 'vocabulary_listening', 'sentence_speaking']
else:
# 表現良好,偏向挑戰題型
priority_order = ['sentence_speaking', 'sentence_reconstruction', 'fill_blank',
'vocabulary_listening', 'multiple_choice', 'flipcard']
for mode in priority_order:
if mode in available_modes:
return mode
# 4. 預設隨機選擇
return random.choice(available_modes)
def weighted_random_select(items, weights):
"""權重隨機選擇"""
total_weight = sum(weights.get(item, 1.0/len(items)) for item in items)
random_num = random.random() * total_weight
for item in items:
weight = weights.get(item, 1.0/len(items))
random_num -= weight
if random_num <= 0:
return item
return items[0] # 備用返回
```
**演算法特點**:
- **反單調性**: 避免連續使用相同題型超過2次
- **適應性**: 根據最近表現動態調整題型偏好
- **穩定性**: A1學習者有固定的權重分配
- **魯棒性**: 各種邊界情況都有合理的備用方案
### **5. 熟悉程度計算 (雙重概念)**
#### **5.1 基礎熟悉度計算 (存入資料庫)**
```python
def calculate_base_mastery_level(times_correct, total_reviews, current_interval):
"""
計算基礎熟悉度,在復習完成時更新並存入資料庫
這是熟悉度的「基準值」,不考慮時間衰減
"""
success_rate = times_correct / total_reviews if total_reviews > 0 else 0
base_score = min(times_correct * 8, 60) # 60% 權重
interval_bonus = min(current_interval / 365 * 25, 25) # 25% 權重
accuracy_bonus = success_rate * 15 # 15% 權重
return min(100, round(base_score + interval_bonus + accuracy_bonus))
```
#### **5.2 當前熟悉度計算 (實時計算)**
```python
def calculate_current_mastery_level(base_mastery, last_review_date):
"""
計算當前熟悉度,考慮記憶衰減的實時值
用於前端顯示,不存入資料庫
"""
days_since_review = (datetime.now().date() - last_review_date).days
# 如果是當日復習,返回基礎熟悉度
if days_since_review <= 0:
return base_mastery
# 套用記憶衰減
return calculate_memory_decay(base_mastery, days_since_review)
```
**設計理念**:
- **基礎熟悉度**: 學習成果的基準值,反映用戶的學習進度
- **當前熟悉度**: 考慮時間因素的實時值,反映當下的記憶強度
### **6. 熟悉度計算時機**
#### **6.1 基礎熟悉度更新時機**
-**復習完成時**: 計算並更新到資料庫
-**查詢時**: 不重新計算,直接讀取資料庫值
-**定期批次**: 不需要排程任務更新
#### **6.2 當前熟悉度計算時機**
-**API 查詢時**: 每次請求都實時計算
-**前端顯示時**: 根據 API 返回的基礎值和參數計算
-**列表頁面**: 批次計算多個詞卡的當前熟悉度
#### **6.3 計算流程圖**
```
用戶復習 → 更新基礎熟悉度 → 存入資料庫
用戶查詢 → 讀取基礎熟悉度 → 計算當前熟悉度 → 返回前端
前端展示 → 顯示當前熟悉度 (會隨時間動態變化)
```
---
## 📊 **算法特性分析**
### **收斂性分析**
- **間隔上限**: 365天確保不會無限增長
- **收斂速度**: 約15-20次復習達到長期記憶階段
- **穩定性**: 表現波動不會導致劇烈間隔變化
- **題型收斂**: A1學習者在基礎題型間穩定切換進階學習者逐步使用高階題型
### **複習方式算法分析**
- **覆蓋性**: 保證每個學習者都有適合的題型可用
- **多樣性**: 避免單一題型平均每次復習切換1-2種題型
- **適應性**: 根據表現調整,表現好→挑戰題型,表現差→基礎題型
- **公平性**: A1學習者有專屬的保護機制不會被推薦困難題型
### **參數敏感性**
| 參數 | 影響程度 | 調優建議 |
|------|---------|----------|
| 增長係數 | 高 | 謹慎調整,影響整體學習節奏 |
| 逾期懲罰 | 中 | 可根據用戶行為數據調優 |
| 衰減率 | 中 | 建議基於記憶實驗數據設定 |
| 權重分配 | 低 | 相對穩定,微調即可 |
| A1題型權重 | 中 | 影響初學者體驗,需謹慎調整 |
| 連續重複限制 | 低 | 2-3次為佳過低影響深入練習 |
### **邊界條件處理**
```python
# 關鍵邊界條件
def validate_inputs(interval, times_correct, total_reviews):
assert 0 <= interval <= 365, "間隔必須在 0-365 範圍內"
assert times_correct >= 0, "成功次數不能為負"
assert total_reviews >= times_correct, "總次數不能少於成功次數"
assert total_reviews >= 0, "總次數不能為負"
```
---
## 🔬 **算法驗證**
### **理論驗證**
-**單調性**: 連續答對時間隔遞增
-**有界性**: 間隔不會超過365天
-**連續性**: 參數小幅變化不會導致間隔劇變
-**收斂性**: 學習軌跡收斂到穩定狀態
### **數值穩定性**
- 浮點運算精度: 使用 `Math.Round()` 處理
- 溢出保護: 所有中間結果都有上下界
- 零除防護: `total_reviews = 0` 時返回預設值
### **性能複雜度**
- **基礎熟悉度**: O(1) - 常數時間計算
- **當前熟悉度**: O(1) - 常數時間計算
- **題型選擇**: O(k) - k為可用題型數量 (通常≤7)
- **智能推薦**: O(h) - h為歷史記錄查看數量 (通常≤5)
- **空間複雜度**: O(1) - 無額外存儲需求
- **預期性能**:
- 單次計算: < 1ms
- 題型推薦: < 5ms
- 列表頁批次計算: < 10ms (100個詞卡)
- A1邏輯檢查: < 1ms
---
## 🎛️ **參數調優指南**
### **A/B 測試建議**
```json
{
"interval_algorithm": {
"conservative": {
"growth_factors": [1.6, 1.3, 1.1, 1.05],
"description": "保守增長,更多復習機會"
},
"aggressive": {
"growth_factors": [2.0, 1.5, 1.3, 1.15],
"description": "積極增長,減少復習負擔"
},
"current": {
"growth_factors": [1.8, 1.4, 1.2, 1.1],
"description": "當前推薦參數"
}
},
"review_type_strategy": {
"diversity_focused": {
"consecutive_limit": 1,
"a1_weights": {"flipcard": 0.33, "multiple_choice": 0.33, "vocabulary_listening": 0.34},
"description": "最大多樣性,每次都換題型"
},
"stability_focused": {
"consecutive_limit": 3,
"a1_weights": {"flipcard": 0.5, "multiple_choice": 0.3, "vocabulary_listening": 0.2},
"description": "允許深入練習,偏重翻卡題"
},
"current": {
"consecutive_limit": 2,
"a1_weights": {"flipcard": 0.4, "multiple_choice": 0.4, "vocabulary_listening": 0.2},
"description": "平衡多樣性和穩定性"
}
},
"a1_protection": {
"strict": {
"level_threshold": 25,
"allowed_types": ["flipcard", "multiple_choice"],
"description": "更嚴格保護只允許2種題型"
},
"moderate": {
"level_threshold": 20,
"allowed_types": ["flipcard", "multiple_choice", "vocabulary_listening"],
"description": "當前標準"
},
"relaxed": {
"level_threshold": 15,
"allowed_types": ["flipcard", "multiple_choice", "vocabulary_listening", "fill_blank"],
"description": "較寬鬆,允許填空題"
}
}
}
```
### **監控指標**
- **學習軌跡分布**: 檢查間隔分布是否合理
- **用戶滿意度**: 復習頻率是否符合預期
- **記憶效果**: 長期記憶率是否提升
- **題型使用分布**: 各題型使用率是否平衡
- **A1用戶體驗**: 初學者完成率和信心提升
- **推薦算法準確率**: 用戶接受推薦題型的比例
- **切換頻率**: 平均每次復習的題型切換次數
- **表現關聯性**: 不同題型的答對率差異
---
## 🔮 **未來優化方向**
### **個人化參數**
```python
# 未來可考慮的個人化係數
personal_factor = calculate_personal_learning_ability(user_id)
new_interval *= personal_factor
# 個人化題型偏好
def get_personal_type_preference(user_id):
user_stats = get_user_performance_by_type(user_id)
# 根據各題型的歷史表現調整權重
return calculate_preference_weights(user_stats)
```
### **遺忘曲線整合**
```python
# 更精確的記憶強度模型
memory_strength = math.exp(-time_since_review / forgetting_constant)
review_urgency = 1 - memory_strength
# 題型特定的遺忘曲線
def get_type_specific_decay(question_type):
# 不同題型可能有不同的記憶保持率
decay_rates = {
'flipcard': 0.05, # 概念記憶
'fill_blank': 0.07, # 拼寫記憶衰減較快
'sentence_speaking': 0.03 # 口說記憶保持較久
}
return decay_rates.get(question_type, 0.05)
```
### **多維度考量**
- **詞彙難度係數**: 基於語料庫統計的客觀難度
- **學習時間分布**: 用戶的學習時間偏好和效率
- **情境相關性**: 詞彙在不同情境下的重要性
- **認知負荷**: 不同題型的認知負荷評估
- **學習風格適配**: 視覺型聽覺型動覺型學習者的偏好
- **進度同步**: 多設備間的學習進度同步策略
### **高級算法方向**
- **深度學習預測**: 使用神經網路預測最佳復習時間
- **強化學習優化**: 基於用戶反饋動態優化推薦策略
- **群體智慧**: 利用相似用戶的學習軌跡改進推薦
- **多目標優化**: 同時優化學習效率用戶滿意度長期留存
---
**算法設計者**: Claude AI
**審核狀態**: 待算法團隊 Review