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

3.6 KiB
Raw Permalink Blame History

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_quality0~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

-- 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
# 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

ALTER TABLE ai_insights ADD COLUMN decay_exempt BOOLEAN DEFAULT FALSE;
CREATE INDEX ON ai_insights (insight_type, decay_exempt);
  • ADR-001三 Agent 分工OpenClaw 應用層 RAG 的取數來源)
  • ADR-002pgvector儲存層含 HNSW 索引)
  • ADR-003本地 embedding採集層與品質分數無關但同表