Files
ewoooc/docs/adr/ADR-032-rag-autonomous-learning-loop.md
OoO c29ce83653 docs(adr): ADR-032 RAG 自主學習迴圈 + ADR-033 三護欄
Operation Ollama-First v5.0 / Phase 12 Wave 2 收尾

ADR-032 — RAG 自主學習迴圈
- 雙表分離:rag_query_log (audit) / learning_episodes (蒸餾池) / ai_insights (知識庫)
- Distiller 規則引擎(純 Hermes 零 LLM 成本)
- PromotionGate 4 階段晉升閘
- Telegram 反饋環(rag_feedback / promotion_review keyboard)
- feature flag RAG_ENABLED 預設 OFF
- V1-V4 驗收 SQL(命中率 / 晉升通過率 / 反饋分布 / embedding 一致性)

ADR-033 — RAG 三護欄(Owen v5.0 鐵律)
- 護欄 #1 Promotion Gate:強制反饋門檻,weight>=0.8 必經人工驗收
- 護欄 #2 Firecrawl 資源:Docker mem_limit:2g + chrome-reaper sidecar + 1.8GB 告警
- 護欄 #3 BGE-M3 一致性:embedding_signature SHA1[:12] + 啟動跨主機驗證
- 五案否決理由完整(包含「不要反饋按鈕」「不限資源」「:latest 接受漂移」)

Migration Plan 對照:
   migration 026/028 schema + service 已落地
   Phase 12+ 補:embedding 寫入 / worker cron / Telegram 推播 / Firecrawl 部署 / signature 回填

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 00:01:19 +08:00

10 KiB
Raw Permalink Blame History

ADR-032: RAG 自主學習迴圈 — Distiller + PromotionGate + 反饋環

  • Status: Accepted
  • Date: 2026-05-03
  • Decision Maker: 統帥
  • Author: Operation Ollama-First v5.0Phase 11 落地後追認)
  • Supersedes: 無
  • Related: ADR-002pgvector 唯一向量庫、ADR-007持久化雙寫、ADR-028LLM 路由統一準則、ADR-029Hermes-First 雙塔分工、ADR-033RAG 三護欄)

Context

戰役 v5.0 Wave 1 完成後momo-pro 已具備 ai_calls / mcp_calls / ai_call_budgets 觀測層,但仍是「無狀態 LLM 用戶」 — 每次 Hermes/OpenClaw 提問都重新燒 token重複問題沒被攔截。

Phase 0 audit 發現:

  • 統帥 Telegram 答題 30%+ 是同一類問題「PChome 補貼」「家電促銷檔期」「SKU 競爭力分析」)
  • ai_insights 已累積 14k+ 筆pgvector + bge-m3沒有 RAG 攔截層,全部走 LLM
  • 預估30% 流量可被 RAG cache 攔截 = 月省 ~9M Hermes/OpenClaw tokens

Owen 提出三大風險v5.0 強化護欄):

  1. 學習污染LLM 幻覺自動進 RAG → 正反饋錯誤循環ADR-033 護欄 #1
  2. 資源消耗:自建 Firecrawl Playwright 池吃 188 主機記憶體ADR-033 護欄 #2
  3. Embedding 一致性bge-m3 floating tag → RAG 召回率悄悄退化ADR-033 護欄 #3

本 ADR 鎖定 「LLM 結果 → 蒸餾 → Promotion Gate → ai_insights → RAG」自主學習迴圈 的設計與護欄。


Decision

1. 雙表分離設計

用途 保留期 PII 等級
rag_query_log (migration 027) 每次 RAG 查詢的 audit log 90 天 query_text 可能含用戶問題)
learning_episodes (migration 028) LLM/MCP 結果蒸餾池 永久(蒸餾溯源) distilled_text 已過 PII redact
ai_insights (既有) 已驗收的知識庫 永久 經 PromotionGate 過濾

2. 自主學習迴圈

┌─────────────────────────────────────────────────────────────┐
│  LLM 呼叫Hermes/OpenClaw                                 │
│           ↓                                                  │
│  RAG-first 攔截cosine >= 0.85 命中)                      │
│      ↓ 命中                ↓ miss                            │
│  return synthesize     LLM 跑                                │
│  (rag_hit=true)             ↓                                │
│                       Distiller 蒸餾                         │
│                             ↓                                │
│                       learning_episodes (pending)            │
│                             ↓                                │
│                       PromotionGate 4 階段                   │
│                             ↓                                │
│                       ai_insights (approved)                 │
│                             ↓                                │
│                       下次 RAG 查得到                        │
└─────────────────────────────────────────────────────────────┘

3. Distiller 規則引擎(純 Hermes零 LLM 成本)

QUALITY_RULES = {
    'mcp_result':  lambda c: 0.8 if len(c) > 200 and len(keywords(c)) >= 2 else 0.4,
    'llm_json_ok': lambda c: 0.9,                       # 結構化 JSON + status='ok'
    'llm_text':    lambda c: 0.6 if has_zh_numbers(c) else 0.3,
    'thumb_up':    lambda _: 1.0,                        # 用戶 👍 反饋
    'thumb_down':  lambda _: 0.0,                        # 負樣本不晉升
}

為何不用 LLM 蒸餾? 避免循環燒錢Distiller 跑頻率高,用 LLM 等於每次 RAG miss 都燒兩次)。

4. PromotionGate 4 階段晉升閘v5.0 護欄 #1

class PromotionGate:
    STAGE_1_AUTO_QUALITY = 0.7        # 蒸餾品質分
    STAGE_2_HALLUCINATION_RULES = [
        '可能/也許/我猜測 + 缺具體數字',
        '自相矛盾(同段含 A=X 又 A=Y',
        '引用不存在 SKU/品牌(查 DB',
    ]
    STAGE_3_DEDUP_THRESHOLD = 0.95    # cosine 相似度
    STAGE_4_HUMAN_REVIEW_WEIGHT = 0.8 # 高權重必經 👍/👎

鐵律weight ≥ 0.8 的 episode 不能跳 Stage 4,必須推 Telegram 等 24h 反饋。

結果 promotion_status
4 階段全過 approved → 寫入 ai_insights
Stage 1 失敗 rejected_quality
Stage 2 失敗 rejected_hallucination
Stage 3 失敗 rejected_duplicate
Stage 4 推送等待 awaiting_review
24h 無反饋 expiredweight 降為 0.5,不晉升但保留)
用戶 👎 rejected_human

5. Telegram 反饋環(強制晉升門檻)

# services/telegram_templates.py
def rag_feedback_keyboard(rag_query_log_id: int) -> dict:
    return {'inline_keyboard': [[
        {'text': '👍 有用', 'callback_data': f'rag_fb:{id}:5'},
        {'text': '👎 沒用', 'callback_data': f'rag_fb:{id}:1'},
    ]]}

def promotion_review_keyboard(episode_id: int) -> dict:
    return {'inline_keyboard': [[
        {'text': '✅ 通過晉升', 'callback_data': f'pg_ok:{id}'},
        {'text': '❌ 拒絕', 'callback_data': f'pg_no:{id}'},
    ]]}

routes/openclaw_bot_routes.py 三組 callback handler 已就位Phase 11 落地)。

6. Feature Flag 灰度

RAG_ENABLED = os.getenv('RAG_ENABLED', 'false').lower() == 'true'
RAG_DEFAULT_THRESHOLD = float(os.getenv('RAG_DEFAULT_THRESHOLD', '0.85'))
RAG_DEFAULT_TOP_K = int(os.getenv('RAG_DEFAULT_TOP_K', '5'))

預設 OFF,戰前部署後行為與 v4.x 完全相同。灰度開啟條件:

  1. ANTHROPIC_API_KEY 已設Phase 7 已備)
  2. learning_episodes 累積 100+ 筆
  3. RAG_ENABLED=true + threshold=0.90(保守起步)
  4. 1 週後 feedback_score ≥ 4 比率 > 70% → threshold 降至 0.85

7. 失敗安全fire-and-forget 哲學)

失敗模式 行為
DB 寫入 rag_query_log 失敗 主流程不爆logger.warning
embedding 失敗 不查 DB 直接 fallback LLM
signature 不一致 log warning + 不採該筆 hit
Distiller 寫 learning_episodes 失敗 LLM 結果照樣回 caller
PromotionGate Stage 1-3 失敗 episode 留 learning_episodes不晉升即可無 DB 副作用)

Alternatives Considered

方案 否決理由
A. 直接 ai_insights 寫入(無蒸餾池) LLM 幻覺直接污染知識庫,無 PromotionGate 阻擋(核心風險)
B. LLM 蒸餾(用 Gemini 寫 distill prompt 循環燒錢:每次 RAG miss → LLM call → 又燒 LLM 蒸餾 = 2× 成本
C. 純 push 不 pull無反饋按鈕 統帥無法糾正幻覺正反饋錯誤循環Owen 強調的痛點)
D. 跳過 dedupStage 3 ai_insights 將累積大量重複RAG 查詢無謂耗時
E. 用 ChromaDB / Qdrant 替代 pgvector 違反 ADR-002pgvector 唯一)+ 增加運維面

Consequences

正面5

  1. 重複問題攔截:預估月省 ~9M Hermes/OpenClaw tokensHermes 流量 -30%
  2. 自主學習:每次 LLM 結果都進蒸餾池,知識庫持續成長
  3. 錯誤可糾正👎 反饋直接降權,避免幻覺循環污染
  4. 零 LLM 蒸餾成本Distiller 純規則引擎
  5. PII 安全query_text 截 4KB + human_approver SHA1[:8]

負面3

  1. 複雜度↑:兩表 + 4 階段閘 + 反饋環,新人理解曲線陡
  2. Stage 4 人工驗收延遲:高權重 episode 必須等 24h 才能晉升
  3. embedding 寫入路徑暫缺(已知 limitationStage 3 dedup 待 Phase 12+ 補

風險4

  1. Distiller 規則漂移:規則引擎可能漏判幻覺 → mitigate by Stage 4 人工驗收
  2. Stage 4 人工疲勞:統帥不可能 24h 看 Telegram → mitigate by expired 自動降級
  3. ai_insights 膨脹:學習迴圈累積快 → mitigate by Stage 3 dedupPhase 12+ 啟用)
  4. PromotionGate worker cron 未掛(已知):需 Phase 12+ 排程任務

Verification

V1RAG 攔截率(部署 1 週後)

SELECT
  COUNT(*) FILTER (WHERE saved_call) AS hit_count,
  COUNT(*) AS total,
  ROUND(100.0 * COUNT(*) FILTER (WHERE saved_call) / COUNT(*), 1) AS hit_pct
FROM rag_query_log
WHERE queried_at > NOW() - INTERVAL '7 days';
-- 期望 hit_pct >= 25%

V2晉升通過率

SELECT promotion_status, COUNT(*)
FROM learning_episodes
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY promotion_status;
-- 期望 approved + awaiting_review 占 >50%rejected_hallucination < 10%

V3反饋分布

SELECT feedback_score, COUNT(*)
FROM rag_query_log
WHERE feedback_score IS NOT NULL
GROUP BY feedback_score;
-- 期望 score=5 比率 > 60%

V4Embedding 一致性v5.0 護欄 #3

SELECT embedding_signature, COUNT(*)
FROM ai_insights
WHERE embedding IS NOT NULL
GROUP BY embedding_signature;
-- 期望單一簽名(多個 = 模型版本漂移,需處理)

Migration Plan

Phase 工作 狀態
11.1 rag_query_log + learning_episodes schema migration 027/028 commit 2f20d8d
11.2 rag_service.py + learning_pipeline.py commit c7d6db3
11.3 Hermes/OpenClaw RAG-first 整合 commit c7d6db3
11.4 Telegram 反饋按鈕 + callback commit c7d6db3
11.5 learning_episodes.embedding 寫入 Phase 12+
11.6 PromotionGate worker cron 掛排程 Phase 12+
11.7 awaiting_review Telegram 推播 Phase 12+callback 已就位)
11.8 RAG_ENABLED=true 灰度啟用 1 週觀察期後

References

  • migrations/027_create_rag_query_log.sql
  • migrations/028_create_learning_episodes.sql
  • services/rag_service.py532 行)
  • services/learning_pipeline.py750 行)
  • tests/test_rag_service.py + test_learning_pipeline.py + test_promotion_gate.py70 unit tests
  • docs/phase11_db_design_20260503.md
  • ADR-002pgvector 唯一向量庫)
  • ADR-007雙寫保證
  • ADR-029Hermes-First 雙塔分工)
  • ADR-033RAG 三護欄)— 即將補