Files
awoooi/docs/adr/ADR-092-ai-decision-llm-expansion-layer.md
Your Name e2742ce9f3 docs: BUTTON_DATA_INVALID 根治 + Gitea Code Review 修復 記錄
LOGBOOK + ADR-092 附錄 C — 2026-04-21 修復紀錄

E2E 驗證: telegram_approval_card_sent message_id=25045 (SignOzDown) ✓

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

9.8 KiB
Raw Blame History

ADR-092: AI Decision Layer — LLM 擴展架構

狀態: Accepted 日期: 2026-04-19 (台北時區) 作者: ogt + Claude Opus 4.7 (1M context, 亞太) 關聯: ADR-090 盲區治理 / MASTER §3 D1-D6 / feedback_ai_autonomous_direction


背景

2026-04-19 session 完成 Phase 7 盲區治理後14 個新 scanner8 張 0 writer 表全活化),首席架構師 Review 發現嚴重 Gap

  • AI 層淺14 個新 scanner 中 8 個純 thresholdrule-based,只 Hermes 1 個真用 LLM 做決策
  • autonomy_score 實測63/100starter 起步級),ai_diversity 子項僅 6/20
  • 統帥鐵律:「朝 AI 自主化方向」— infrastructure 不等於 AI

違反 feedback_ai_autonomous_direction.md 核心原則:「禁寫死規則做最終決策」。


決策

1. AI Decision 層的 4 個 LLM Service本 session 完成)

Service LLM 判斷 required_key 觸發條件 職責
hermes_rule_quality recommended_actions 每日 04:00 Taipei 分析 noise_rate > 0.5 rule 的假報真因 + 改進建議
capacity_forecaster priority_actions 每日 05:00 Taipeipredict_linear 命中) 分析 7d 容量預測高風險 host 的修復策略
compliance_scanner posture_grade 每日 03:00 Taipei有 warning/violation 產整體 compliance posture 評級 + top 3 action
coverage_evaluator worst_dimension 每 1hred_ratio > 30% 且 scanned > 50 分析 7 維 red 缺口 + 補覆蓋建議

2. LLM 調用統一 patternservices/llm_json_parser.py

原問題4 個 LLM scanner 各自重複 3-path JSON parse 邏輯(~80 行 × 4 = 320 行) 新 patternparse_llm_json_response(text, required_key, logger_context)

# 統一 3-path fallback
Path 1:  markdown fence + 直接 JSON  required_key
Path 2: NemoTron wrapper  description/action_title/reasoning 內嵌 JSON
Path 3: 所有失敗 return None + logger.warning

所有 LLM service 都用此 helper未來擴加 LLM service 直接呼叫。

3. LLM Service 架構約束(鐵律)

必須遵守

  1. 失敗永不 raiseLLM 掛掉/parse 失敗 → return None → 呼叫者 fallback 硬編規則
  2. AI 只建議不動作:所有 LLM 輸出都寫 requires_human_decision=True,推 Telegram 等人工
  3. openclaw 統一入口:不直接呼叫 Ollama/NVIDIA/Geminiget_openclaw().call(prompt) 多 provider fallback
  4. aol 留痕LLM 結果進 automation_operation_log.output.llm_analysis
  5. 繁中 + JSON schemaprompt 明確 required_keysystem prompt 要求 LLM 產純 JSON

禁止

  • 硬編 threshold 做最終決策(只做「觸發討論」)
  • LLM 結果直接執行破壞性動作(必過人工)
  • 內嵌多 provider 判斷(統一走 openclaw

4. 觸發條件設計原則

節流避免 token 成本爆炸

  • Daily cron每日一次compliance/forecaster/hermes
  • 事件觸發coverage 只在 red_ratio > 30% 且 scanned >= 50 才跑 LLM
  • 避免 bootstrap 首次必觸發的浪費

5. autonomy_score 量化追蹤

新增 GET /api/v1/aiops/kpi 回 5 子項 × 20 分總分0-100

  • asset_coverage: green 比例 × 20
  • rule_quality: 1 - (noisy/total) × 20
  • capacity_health: critical 扣 10 / warning 扣 3
  • automation_flow: log10(24h_ops) 標準化 × 20
  • ai_diversity: ai_generated rules + op_type 多樣性 × 20

Grade: mature(90+) / in_progress(70-90) / starter(50-70) / initial(<50)


實作成果

達成指標

  • LLM decision service: 1/9 → 4/9
  • autonomy_score: 未量化 → 63/100 (starter) 可持續追蹤
  • LLM JSON parse 重複碼: 320 行 → 1 份共用 helper90 行)

Commits

  • ba18ad2 Hermes LLM 升級Hermes 從 threshold 改 LLM
  • d6b854a Gap 3.1 capacity_forecaster LLM
  • f6cb938 Gap 3.2 compliance_scanner LLM
  • 2f5cab2 Gap 3.3 coverage_evaluator LLM
  • fa643eb P1 重構llm_json_parser helper + coverage 雙條件

相關檔案

  • apps/api/src/services/llm_json_parser.py(共用 helper
  • apps/api/src/services/openclaw.py(多 provider
  • apps/api/src/jobs/{hermes_rule_quality,capacity_forecaster,compliance_scanner,coverage_evaluator}_job.py
  • apps/api/src/services/aiops_kpi_service.pyautonomy_score 計算)
  • apps/api/src/api/v1/aiops_kpi.pyKPI endpoint

後續工作(下 session

P1 剩餘優化(首席架構師 Review 指出)

  1. Prometheus HTTP helper 抽出 — 5 scanner 重複 httpx + 錯誤處理 pattern
  2. 14 scanner first_delay 錯開 — 避免並行啟動搶 DB pool建議 60/90/120/180 階梯)
  3. LLM budget guardaiops_kpi_servicellm_call_count_24h 指標超過閾值 Telegram 告警
  4. asset_scanner 918 行拆分providers/ + writers/ 兩層

可擴展 LLM 方向

  • rule_catalog_sync: 新規則 import 時 LLM 驗證 expr 合理性
  • asset_change_tracker: 重大 lifecycle 變化時 LLM 評估爆炸半徑
  • drift_interpreter (既有): 升級更精細 prompt

回滾計畫

若 LLM service 造成成本或穩定性問題,可分層關閉:

  1. 改 config AIOPS_LLM_ENABLED=false(需新增,目前未實作)
  2. 或 kubectl exec 進 Pod kill 單個 loop task
  3. 各 LLM try/except return None → fallback 原設計保護主流程不受影響

相關 ADR

  • ADR-067 Phase 30 AI 五大應用OpenClaw + drift_narrator + runbook_generator 等原 LLM service
  • ADR-081 PreDecisionInvestigator + EvidenceSnapshot
  • ADR-083 學習閉環重建
  • ADR-090 監控盲區治理 + 自動化覆蓋矩陣11 張 + 8 張新表)

附錄 A2026-04-20 四修B1-B4— 全流程斷鏈緊急修復

觸發:統帥截圖 Telegram 顯示「採納失敗」+ 兩天無任何告警。 指令:全景、全流程、全節點、全架構比對,找到所有斷點再修。

Root Cause 鏈

症狀 斷點 根因
Playbook 學習失敗 163次/48h playbook_service.update_with_validation evolver.valuestrsetattr 不觸發 Pydantic → .value
Telegram 永久靜默 2 天 approval_db.find_by_fingerprint PENDING = 「已發 TG」謊言TG 失敗後 approval 永 PENDING → 永遠收斂跳過
採納變更失敗 telegram_gateway._handle_drift_action 呼叫 DriftAdoptService.adopt_drift() 但方法不存在AttributeError
AI 無法感知自身故障 main.py 無 background watchdog MASTER §1.1 盲區SLO 計算只是 API endpoint

修復6 檔 / 230 行 / commit 156a52f

  1. B1 playbook_service.pyupdate_with_validation setattr 前強制 enum 轉型
  2. B2a approval_db.pyfind_by_fingerprint debounce 窗外 PENDING 必須 Redis tg_sent:{fp} 確認;新 mark_telegram_confirmed()
  3. B2b webhooks.py_push_to_telegram_background 成功後 setex tg_sent:{fp} 24h3 call site 傳 fingerprint
  4. Drift drift_adopt_service.py — 新 adopt_drift(report_id) wrapper
  5. B3 jobs/ai_slo_watchdog_job.py — 新建:每 15 分鐘 W-1/W-2/W-3 → TYPE-8M
  6. B3 main.py lifespan 註冊 watchdog loop

附錄 B2026-04-20 C1-C4 — Playbook 鏈路結構性斷點修復

觸發:統帥全景盤查後,發現 Playbook 自動修復鏈路有 3 個結構性斷點。

# 斷點 根因 修復 commit
C1 evolver 封存 yaml_rule playbooks YAML_RULE source guard playbook_evolver.py 兩處加 if source == YAML_RULE: continue de2d34d
C2 seeder 不復活 DEPRECATED yaml_rule idempotency SQL 包含 DEPRECATED AND status != 'deprecated' de2d34d
C3 AI 新規則不即時建立 Playbook _append_rule_to_yaml 後無 seeder 呼叫 create_task(seed_playbooks_from_rules()) de2d34d
C4 watchdog 不偵測鏈路斷裂 W-4 缺失 _count_approved_playbooks();為 0 → TYPE-8M de2d34d

架構鐵律PlaybookSource.YAML_RULE playbooks 是自動修復鏈路的「基礎設施」evolver 的 trust-based 退場邏輯不得觸及此類 playbooks。


附錄 C2026-04-21 — BUTTON_DATA_INVALID 根治 + Gitea Code Review 修復

觸發Telegram 所有 devops_tool 類別告警卡片發送失敗HTTP 400 BUTTON_DATA_INVALID+ Gitea PR Code Review 顯示「AI 分析失敗」。

Root Cause 鏈

症狀 斷點 根因
Telegram 400 BUTTON_DATA_INVALID generate_callback_nonce UUID(36) + action(20) + ts(10) + rand(8) + colons = 77B > 64B Telegram 限制
Gitea PR "AI 分析失敗" _call_openclaw_code_review OpenClaw 只有 /analyze/incident/analyze/error/analyze/code-review 從未實作404
Push review AttributeError _call_openclaw_push_review local_code_review_service.review_push() 回傳 dict呼叫端對 dict 做屬性訪問(analysis.issues

修復

  1. nonce 壓縮 security_interceptor.pygenerate_callback_nonce 用 base64url encode UUID bytes36→22 charsparse_callback_data 對應 decodehost_restart_service nonce = 63B
  2. code review 改 local gitea_webhook_service.py_call_openclaw_code_review 改用 local_code_review_service.review_pr()Ollama + Gemini fallback
  3. push review dict→model gitea_webhook_service.py_call_openclaw_push_review 加 dict→CodeReviewResult 轉換

E2E 驗證2026-04-21 21:57 台北)

  • host_restart_service nonce = 63B ✓,所有 7 個 actions ≤ 64B ✓
  • UUID round-trip decode = True ✓
  • telegram_approval_card_sent message_id=25045SignOzDown devops_tool✓ 無 BUTTON_DATA_INVALID

Commits

  • acab1cd fix(gitea): code-review 改 local service + push review dict→CodeReviewResult
  • bd73548 fix(telegram): BUTTON_DATA_INVALID nonce 超 64B 根因修復
  • 8fd31ec fix(telegram): nonce UUID base64url 壓縮(徹底解決)