229 lines
5.8 KiB
Markdown
229 lines
5.8 KiB
Markdown
|
|
# Phase M.2:遗忘曲线系统
|
|||
|
|
|
|||
|
|
日期:2026-04-04
|
|||
|
|
状态:规划中
|
|||
|
|
依赖:M.1 (重要性评分)
|
|||
|
|
工作量:3 天
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 本阶段目的
|
|||
|
|
|
|||
|
|
实现「选择性遗忘」机制,让 Jarvis 知道「什么可以忘记」。
|
|||
|
|
|
|||
|
|
核心问题:
|
|||
|
|
- 冷门知识不应该一直占存储
|
|||
|
|
- 但不能直接删,要有归档机制
|
|||
|
|
- 重要记忆应该被强化,不容易忘
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 核心架构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────────────┐
|
|||
|
|
│ ForgettingCurve │
|
|||
|
|
├─────────────────────────────────────────────────────────────┤
|
|||
|
|
│ decay_score = exp(-time_since_access / half_life) │
|
|||
|
|
│ │
|
|||
|
|
│ 遗忘策略: │
|
|||
|
|
│ - decay_score < 0.2 → 归档到 cold_storage │
|
|||
|
|
│ - decay_score < 0.5 → 降权,不参与主动提醒 │
|
|||
|
|
│ - importance_level=high → 半衰期延长 3x │
|
|||
|
|
└─────────────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 艾宾浩斯遗忘曲线模型
|
|||
|
|
|
|||
|
|
### 3.1 基础遗忘曲线
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
保留率
|
|||
|
|
100% |████████████
|
|||
|
|
80% |██████████
|
|||
|
|
60% |███████
|
|||
|
|
40% |█████
|
|||
|
|
20% |██
|
|||
|
|
0% |________________________ 时间
|
|||
|
|
1天 7天 30天 90天
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.2 Jarvis 遗忘策略
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 基础半衰期:30 天
|
|||
|
|
BASE_HALF_LIFE_DAYS = 30
|
|||
|
|
|
|||
|
|
# 重要性影响半衰期
|
|||
|
|
if importance_level == "high":
|
|||
|
|
half_life = BASE_HALF_LIFE_DAYS * 3 # 90 天
|
|||
|
|
elif importance_level == "medium":
|
|||
|
|
half_life = BASE_HALF_LIFE_DAYS * 1 # 30 天
|
|||
|
|
else:
|
|||
|
|
half_life = BASE_HALF_LIFE_DAYS * 0.5 # 15 天
|
|||
|
|
|
|||
|
|
# 遗忘分数
|
|||
|
|
decay_score = exp(-days_since_access / half_life)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 核心文件
|
|||
|
|
|
|||
|
|
### 4.1 新增文件
|
|||
|
|
|
|||
|
|
| 文件 | 职责 |
|
|||
|
|
|------|------|
|
|||
|
|
| `services/memory/forgetting_curve.py` | 遗忘曲线计算 |
|
|||
|
|
| `services/memory/memory_decay.py` | 记忆衰减处理 |
|
|||
|
|
| `services/memory/reinforcement.py` | 记忆强化触发 |
|
|||
|
|
|
|||
|
|
### 4.2 修改文件
|
|||
|
|
|
|||
|
|
| 文件 | 修改内容 |
|
|||
|
|
|------|---------|
|
|||
|
|
| `models/memory.py` | 增加 decay_score, is_archived, last_accessed_at 字段 |
|
|||
|
|
| `services/memory_service.py` | 集成遗忘逻辑 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. API 设计
|
|||
|
|
|
|||
|
|
### 5.1 ForgettingCurve
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
class ForgettingCurve:
|
|||
|
|
def calculate_decay(self, memory: UserMemory) -> float:
|
|||
|
|
"""返回 0.0-1.0 的保留分数"""
|
|||
|
|
|
|||
|
|
def should_archive(self, memory: UserMemory) -> bool:
|
|||
|
|
"""是否应该归档"""
|
|||
|
|
|
|||
|
|
def should_deprioritize(self, memory: UserMemory) -> bool:
|
|||
|
|
"""是否应该降权(不参与主动提醒)"""
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.2 Reinforcement
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
class MemoryReinforcement:
|
|||
|
|
def trigger(self, memory_id: int) -> None:
|
|||
|
|
"""被召回时触发强化"""
|
|||
|
|
# 频率 +1
|
|||
|
|
# decay_score 重置
|
|||
|
|
|
|||
|
|
def auto_reinforce(self, user_id: int) -> None:
|
|||
|
|
"""定期自动强化高重要性记忆"""
|
|||
|
|
# 每周检查,对 high 级别记忆做轻量强化
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 归档机制
|
|||
|
|
|
|||
|
|
### 6.1 热/冷存储分离
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 热存储:活跃记忆,参与检索和主动提醒
|
|||
|
|
HOT_MEMORIES = []
|
|||
|
|
|
|||
|
|
# 冷存储:归档记忆,不参与主动提醒,按需恢复
|
|||
|
|
COLD_MEMORIES = []
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 归档恢复
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
async def restore_from_archive(self, memory_id: int) -> UserMemory:
|
|||
|
|
"""从归档恢复记忆"""
|
|||
|
|
# 恢复后 decay_score 重置为 0.8
|
|||
|
|
# 重新加入热存储
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 调度任务
|
|||
|
|
|
|||
|
|
### 7.1 每日遗忘检查
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 每天凌晨执行
|
|||
|
|
@scheduler.scheduled_task("cron", hour=3)
|
|||
|
|
async def daily_forgetting_check():
|
|||
|
|
"""每日遗忘检查"""
|
|||
|
|
# 1. 计算所有记忆的 decay_score
|
|||
|
|
# 2. 归档 decay < 0.2 的记忆
|
|||
|
|
# 3. 降权 decay < 0.5 的记忆
|
|||
|
|
# 4. 强化被召回的记忆
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 7.2 每周自动强化
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
@scheduler.scheduled_task("cron", day_of_week="mon", hour=4)
|
|||
|
|
async def weekly_reinforcement():
|
|||
|
|
"""每周自动强化"""
|
|||
|
|
# 对 high 重要性记忆做轻量强化
|
|||
|
|
# frequency_count *= 1.1 (上限 10)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. 测试设计
|
|||
|
|
|
|||
|
|
### 8.1 遗忘曲线测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def test_decay_after_30_days():
|
|||
|
|
memory = create_memory(last_accessed_at=days_ago(30))
|
|||
|
|
decay = curve.calculate_decay(memory)
|
|||
|
|
assert 0.4 < decay < 0.6 # 约 50% 保留
|
|||
|
|
|
|||
|
|
def test_high_importance_slower_decay():
|
|||
|
|
high = create_memory(importance_level="high", last_accessed_at=days_ago(30))
|
|||
|
|
low = create_memory(importance_level="low", last_accessed_at=days_ago(30))
|
|||
|
|
assert curve.calculate_decay(high) > curve.calculate_decay(low)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.2 归档测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def test_archive_low_decay():
|
|||
|
|
memory = create_memory(decay_score=0.15)
|
|||
|
|
assert curve.should_archive(memory) == True
|
|||
|
|
|
|||
|
|
def test_restore_from_archive():
|
|||
|
|
memory = service.restore_from_archive(memory_id)
|
|||
|
|
assert memory.is_archived == False
|
|||
|
|
assert memory.decay_score > 0.5
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. 验收标准
|
|||
|
|
|
|||
|
|
| 标准 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| 遗忘曲线正确 | 30 天后 decay ≈ 0.5 |
|
|||
|
|
| 高重要性记忆衰减慢 | high 级别衰减速度是 low 的 1/6 |
|
|||
|
|
| 归档正常 | decay < 0.2 自动归档 |
|
|||
|
|
| 恢复正常 | 归档记忆可以恢复 |
|
|||
|
|
| 调度任务正常 | 每日检查、周强化执行 |
|
|||
|
|
| 单元测试覆盖率 | > 80% |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. 工作量估算
|
|||
|
|
|
|||
|
|
| 任务 | 工作量 |
|
|||
|
|
|------|--------|
|
|||
|
|
| ForgettingCurve | 0.5 天 |
|
|||
|
|
| MemoryDecay | 0.5 天 |
|
|||
|
|
| Reinforcement | 0.5 天 |
|
|||
|
|
| 归档机制 | 0.5 天 |
|
|||
|
|
| 调度任务 | 0.5 天 |
|
|||
|
|
| 测试 | 0.5 天 |
|
|||
|
|
| **合计** | **3 天** |
|