Files
ewoooc/docs/adr/ADR-005-quality-score-time-decay.md
ogt 1b4f3a7bbe
Some checks failed
CD Pipeline / deploy (push) Failing after 59s
feat: EwoooC 初始化 — 完整專案推版至 Gitea
- 建立 Gitea Actions CD pipeline (.gitea/workflows/cd.yaml)
- 部署模式: rsync Python 檔案至 188 → docker restart (volume mount)
- Dockerfile/requirements 變動時自動重建 Docker image
- 部署通知: Telegram (開始/成功/失敗)
- 健康檢查: https://mo.wooo.work/health (最多 5 次重試)
- 同步最新 CLAUDE.md / ADR-008 / memory (2026-04-19)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 01:21:13 +08:00

107 lines
3.6 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.
# ADR-005KM 品質分數加入時間衰減
- **Status**: Accepted
- **Date**: 2026-04-18
- **Decision Maker**: 統帥(顧問補充建議第 3 條)
- **Author**: Claude
## Context
`ai_insights` 表中的 KM 記錄有一個「品質分數(`avg_quality`)」欄位,由用戶的 👍/👎 回饋計算。
問題:原始設計只取回饋的 **靜態平均分**,沒有考慮時間因素。
**失效場景**
- 半年前的「換季保濕策略洞察」被判定為高品質(當時收到 5 個 👍)
- 但今天是夏天RAG 仍優先抓取它 → OpenClaw 回答品質下降
- 競品策略也在演化6 個月前的競品分析今日已完全無效
## Decision
**KM 品質分數採用時間衰減公式**
```
Effective_Score = Base_Score × exp(−λ × days_since_created)
```
| 參數 | 值 | 說明 |
|---|---|---|
| `λ` (decay_rate) | `0.01` | 半衰期約 70 天ln(2)/0.01 |
| `Base_Score` | `avg_quality`0~1 | 原始回饋分數平均 |
| `days_since_created` | `NOW() - created_at` | 洞察建立至今天數 |
**實際效果**
| 天數 | Effective Score假設 Base=1.0 |
|---|---|
| 0 天(剛建立) | 1.00 |
| 30 天 | 0.74 |
| 70 天 | 0.50(半衰期) |
| 180 天 | 0.16 |
| 365 天 | 0.03(幾乎不被選中) |
**例外**(不套時間衰減):
- `insight_type = 'structural'`結構性規則如「MOMO 商品代碼格式永遠是 I...」)
- `insight_type = 'constitutional'`(專案憲法類)
- 手動標記 `decay_exempt = true` 的記錄
## Alternatives Considered
| 方案 | 拒絕原因 |
|---|---|
| 固定天數截斷(只看近 90 天) | 硬截斷損失部分有效的長期記憶 |
| 不做衰減(原始設計) | 舊記錄永遠佔據 RAG top 5導致回答跑偏 |
| 每隔一段時間批次刪除老記錄 | 不可逆,人工操作風險大 |
## Consequences
### Positive
- RAG 自動偏好新鮮知識,回答隨業務演化自我更新
- 舊洞察不消失(審計/回溯仍可查),只是自然淡出 ranking
- 半衰期可調(λ 改小 = 記得更久,λ 改大 = 遺忘更快)
### Negative / Trade-offs
- `ORDER BY` 子句需在 SQL 中即時計算 exponential有輕微效能影響
- 緩解pgvector HNSW 先做 ANN 近似過濾,再在 Python 層做衰減重排
- 開發者需理解「分數不是靜態的」debug 時要考慮時間因素
## Implementation Notes
```sql
-- RAG 查詢時計算有效分數
SELECT
insight_text,
created_at,
avg_quality,
avg_quality * EXP(-0.01 * EXTRACT(EPOCH FROM (NOW() - created_at)) / 86400.0)
AS effective_score
FROM ai_insights
WHERE insight_type NOT IN ('structural', 'constitutional')
AND decay_exempt IS NOT TRUE
ORDER BY embedding <-> :query_vector -- 先做語意過濾
LIMIT 20;
-- 然後在 Python 層取 effective_score 前 5
```
```python
# services/openclaw_learning_service.py
import math
from datetime import datetime, timezone
def compute_effective_score(base_score: float, created_at: datetime, decay_rate: float = 0.01) -> float:
"""時間衰減品質分數"""
days = (datetime.now(timezone.utc) - created_at.replace(tzinfo=timezone.utc)).days
return base_score * math.exp(-decay_rate * days)
```
**新欄位需求**Migration 005
```sql
ALTER TABLE ai_insights ADD COLUMN decay_exempt BOOLEAN DEFAULT FALSE;
CREATE INDEX ON ai_insights (insight_type, decay_exempt);
```
## Related ADRs
- ADR-001三 Agent 分工OpenClaw 應用層 RAG 的取數來源)
- ADR-002pgvector儲存層含 HNSW 索引)
- ADR-003本地 embedding採集層與品質分數無關但同表