From 5f9a6a7e55bacd821bdcddb69f3e9fa33ee1b074 Mon Sep 17 00:00:00 2001 From: OG T Date: Sun, 29 Mar 2026 15:19:51 +0800 Subject: [PATCH] =?UTF-8?q?fix(ai):=20=E7=A7=BB=E9=99=A4=E5=81=87=E4=BF=A1?= =?UTF-8?q?=E5=BF=83=E5=88=86=E6=95=B8=20+=20=E9=A1=AF=E7=A4=BA=20AI=20?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E4=BE=86=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 問題: AI 仲裁顯示硬編碼信心分數 (0.75/0.88/0.92/0.70) 修復: - decision_manager: 預設 confidence 0.75 → 0.0 - decision_manager: Expert System confidence=0.0 + is_rule_based - openclaw: 所有 Mock Response confidence → 0.0 - telegram_gateway: 新增 ai_provider 欄位 - telegram_gateway: 動態來源標籤 (Ollama/Gemini/Claude/規則匹配) Telegram 卡片顯示: - confidence > 0 + provider=ollama → 🤖 Ollama 仲裁 - confidence > 0 + provider=gemini → 🤖 Gemini 仲裁 - confidence > 0 + provider=claude → 🤖 Claude 仲裁 - confidence == 0 → ⚙️ 規則匹配 Co-Authored-By: Claude Opus 4.5 --- apps/api/src/services/decision_manager.py | 11 +++-- apps/api/src/services/openclaw.py | 25 +++++----- apps/api/src/services/telegram_gateway.py | 56 ++++++++++++++++++++++- docs/LOGBOOK.md | 50 +++++++++++++++++--- 4 files changed, 119 insertions(+), 23 deletions(-) diff --git a/apps/api/src/services/decision_manager.py b/apps/api/src/services/decision_manager.py index 4fe41353d..c2804f221 100644 --- a/apps/api/src/services/decision_manager.py +++ b/apps/api/src/services/decision_manager.py @@ -102,8 +102,9 @@ async def _push_decision_to_telegram( action = proposal_data.get("action", proposal_data.get("kubectl_command", "")) description = proposal_data.get("description", "") reasoning = proposal_data.get("reasoning", "") - confidence = proposal_data.get("confidence", 0.75) + confidence = proposal_data.get("confidence", 0.0) # 🔴 預設 0.0 表示未經 AI 分析 source = proposal_data.get("source", "unknown") + ai_provider = proposal_data.get("provider", "") # 2026-03-29 ogt: AI 模型來源 # 建立 approval_id (使用 incident_id 作為追蹤) # 2026-03-27 ogt: 修復 INC-INC-INC- 重複前綴 bug @@ -119,6 +120,7 @@ async def _push_decision_to_telegram( primary_responsibility="INFRA", confidence=confidence, namespace=incident.signals[0].labels.get("namespace", "default") if incident.signals else "default", + ai_provider=ai_provider, # 2026-03-29 ogt: 顯示 AI 模型來源 ) # 🔴 發送成功後設置去重 key (TTL 10 分鐘) @@ -222,16 +224,19 @@ def expert_analyze(incident: Incident) -> dict[str, Any]: rule = EXPERT_RULES[matched_rule] + # 2026-03-29 ogt: Expert System 不應該假裝有高信心分數 + # 設為 0.0 強制標記為規則匹配,而非 AI 仲裁 return { "source": "expert_system", "action": rule["action"].format(target=target), "description": rule["description"], "risk_level": rule["risk_level"], - "reasoning": rule["reasoning"], - "confidence": 0.75, # Expert System 固定信心分數 + "reasoning": f"[規則匹配] {rule['reasoning']}", # 明確標示來源 + "confidence": 0.0, # 🔴 規則匹配不是 AI 仲裁,信心度設 0 "kubectl_command": rule["action"].format(target=target), "matched_rule": matched_rule, "from_cache": False, + "is_rule_based": True, # 新增標記 } diff --git a/apps/api/src/services/openclaw.py b/apps/api/src/services/openclaw.py index 7b33be2e7..410d92aaa 100644 --- a/apps/api/src/services/openclaw.py +++ b/apps/api/src/services/openclaw.py @@ -520,10 +520,11 @@ class OpenClawService: ) # 根據告警類型生成專業 RCA + 仲裁 + # 🔴 2026-03-29 ogt: Mock 響應必須標示為規則匹配,不是 AI 仲裁 if "oom" in message.lower() or "memory" in alert_type.lower(): mock_response = { "action_title": f"刪除異常 Pod {target} (OOMKilled)", - "description": f"🤖 AI 仲裁: {target} 發生 OOMKilled,根因為 JVM Heap 配置與 K8s memory limit 不匹配或存在記憶體洩漏。{signoz_summary}", + "description": f"⚙️ 規則匹配: {target} 發生 OOMKilled,根因為 JVM Heap 配置與 K8s memory limit 不匹配或存在記憶體洩漏。{signoz_summary}", "suggested_action": "DELETE_POD", "kubectl_command": f"kubectl delete pod {target} -n {namespace}", "target_resource": target, @@ -550,9 +551,9 @@ class OpenClawService: "kubectl_or_config": f"kubectl autoscale deployment {target.rsplit('-', 2)[0]} --memory-percent=80 --min=2 --max=5 -n {namespace}" } ], - "reasoning": f"🤖 Pod OOMKilled 後 ReplicaSet 將自動重建,但需同步修正資源配置防止復發。{signoz_correlation}", + "reasoning": f"⚙️ Pod OOMKilled 後 ReplicaSet 將自動重建,但需同步修正資源配置防止復發。{signoz_correlation}", "deviation_analysis": f"Memory 使用率 {metrics.get('memory_percent', 99)}%,超出基準線 60% 達 +6.5σ", - "confidence": 0.88, + "confidence": 0.0, # 🔴 規則匹配,非 AI 仲裁 "affected_services": [target, "api-gateway"], "signoz_correlation": signoz_correlation, } @@ -564,7 +565,7 @@ class OpenClawService: mock_response = { "action_title": f"擴展 {target} 副本數 + 啟用 HPA", - "description": f"🤖 AI 仲裁: {target} CPU 使用率過高,根因為流量突增或計算密集任務未配置自動擴展。{rps_context}", + "description": f"⚙️ 規則匹配: {target} CPU 使用率過高,根因為流量突增或計算密集任務未配置自動擴展。{rps_context}", "suggested_action": "SCALE_DEPLOYMENT", "kubectl_command": tuning["command"], "target_resource": target, @@ -591,16 +592,16 @@ class OpenClawService: "kubectl_or_config": f"kubectl set resources deployment/{target} --requests=cpu=500m --limits=cpu=2000m -n {namespace}" } ], - "reasoning": f"🤖 水平擴展可即時分散負載,同時建議配置 HPA 防止復發。{signoz_correlation}", + "reasoning": f"[規則匹配] 水平擴展可即時分散負載,同時建議配置 HPA 防止復發。{signoz_correlation}", "deviation_analysis": f"CPU 使用率 {metrics.get('cpu_percent', 95)}%,超出基準線 50% 達 +4.5σ", - "confidence": 0.92, + "confidence": 0.0, # 🔴 規則匹配不是 AI 仲裁,信心度設 0 "affected_services": [target], "signoz_correlation": signoz_correlation, } elif "http" in alert_type.lower() or "5xx" in message.lower() or "502" in message.lower(): mock_response = { "action_title": f"重啟 {target} + 檢查上游服務", - "description": f"🤖 AI 仲裁: {target} 產生 HTTP 5xx 錯誤,可能為應用程式例外或上游服務不可達。{signoz_summary}", + "description": f"⚙️ 規則匹配: {target} 產生 HTTP 5xx 錯誤,可能為應用程式例外或上游服務不可達。{signoz_summary}", "suggested_action": "RESTART_DEPLOYMENT", "kubectl_command": f"kubectl rollout restart deployment/{target} -n {namespace}", "target_resource": target, @@ -627,9 +628,9 @@ class OpenClawService: "kubectl_or_config": "# 檢查 Redis 連線池配置,建議 maxTotal=50" } ], - "reasoning": f"🤖 HTTP 錯誤需協同排查,先重啟恢復服務同時通知相關團隊。{signoz_correlation}", + "reasoning": f"[規則匹配] HTTP 錯誤需協同排查,先重啟恢復服務同時通知相關團隊。{signoz_correlation}", "deviation_analysis": "錯誤率 5%,超出基準線 0.1% 達 +50σ", - "confidence": 0.65, + "confidence": 0.0, # 🔴 規則匹配不是 AI 仲裁,信心度設 0 "affected_services": [target, "nginx-ingress", "upstream-api"], "signoz_correlation": signoz_correlation, } @@ -637,7 +638,7 @@ class OpenClawService: # 通用異常處理 mock_response = { "action_title": f"重新啟動 {target} 服務", - "description": f"🤖 AI 仲裁: {target} 發生異常: {message[:80]}。需進一步診斷確認根因。{signoz_summary}", + "description": f"⚙️ 規則匹配: {target} 發生異常: {message[:80]}。需進一步診斷確認根因。{signoz_summary}", "suggested_action": "RESTART_DEPLOYMENT", "kubectl_command": f"kubectl rollout restart deployment/{target} -n {namespace}", "target_resource": target, @@ -659,9 +660,9 @@ class OpenClawService: "kubectl_or_config": tuning["command"], } ], - "reasoning": f"🤖 根據告警 {alert_type} 先重啟恢復服務,同時安排深入診斷。{signoz_correlation}", + "reasoning": f"[規則匹配] 根據告警 {alert_type} 先重啟恢復服務,同時安排深入診斷。{signoz_correlation}", "deviation_analysis": "監控指標顯示異常偏離基準線", - "confidence": 0.70, + "confidence": 0.0, # 🔴 規則匹配不是 AI 仲裁,信心度設 0 "affected_services": [target], "signoz_correlation": signoz_correlation, } diff --git a/apps/api/src/services/telegram_gateway.py b/apps/api/src/services/telegram_gateway.py index 3ecab1b83..596f8fd83 100644 --- a/apps/api/src/services/telegram_gateway.py +++ b/apps/api/src/services/telegram_gateway.py @@ -142,6 +142,10 @@ class TelegramMessage: # 2026-03-29 ogt: AI Token/Cost 追蹤 ai_tokens: int = 0 # LLM Token 使用量 ai_cost: float = 0.0 # LLM 成本 (USD) + # 2026-03-29 ogt: ADR-037 異常頻率統計 + anomaly_frequency: dict | None = None # AnomalyCounter 統計 + # 2026-03-29 ogt: AI Provider 來源顯示 + ai_provider: str = "" # ollama/gemini/claude/expert_system/mock def format(self) -> str: """ @@ -198,6 +202,43 @@ class TelegramMessage: if self.ai_tokens > 0 or self.ai_cost > 0: ai_cost_display = f"💰 Tokens: {self.ai_tokens:,} / ${self.ai_cost:.4f}\n" + # 2026-03-29 ogt: ADR-037 異常頻率顯示 + frequency_block = "" + if self.anomaly_frequency and self.anomaly_frequency.get("count_24h", 0) > 1: + freq = self.anomaly_frequency + escalation_emoji = { + None: "", + "REPEAT": "⚠️", + "ESCALATE": "🔴", + "PERMANENT_FIX": "🚨", + }.get(freq.get("escalation_level"), "") + + frequency_block = ( + f"━━━━━━━━━━━━━━━━━━━\n" + f"📊 頻率統計 {escalation_emoji}\n" + f"├ 1h: {freq.get('count_1h', 0)} 次\n" + f"├ 24h: {freq.get('count_24h', 0)} 次\n" + f"└ 修復: {freq.get('auto_repair_count', 0)} 次\n" + ) + if freq.get("escalation_level"): + frequency_block += f"🔺 升級: {freq['escalation_level']}\n" + + # 2026-03-29 ogt: 根據 confidence + ai_provider 動態顯示來源 + # confidence > 0 = 真實 AI 分析, confidence == 0 = 規則匹配/降級 + if self.confidence > 0 and self.ai_provider: + # 顯示具體 AI 模型 + provider_names = { + "ollama": "Ollama", + "gemini": "Gemini", + "claude": "Claude", + } + provider_display = provider_names.get(self.ai_provider.lower(), self.ai_provider.upper()) + source_label = f"🤖 {provider_display} 仲裁" + elif self.confidence > 0: + source_label = "🤖 AI 仲裁判定" + else: + source_label = "⚙️ 規則匹配" + # 組裝訊息 message = ( f"═══════════════════════════\n" @@ -206,11 +247,12 @@ class TelegramMessage: f"📋 {html.escape(incident_id)}\n" f"🎯 資源: {safe_resource}\n" f"━━━━━━━━━━━━━━━━━━━\n" - f"🤖 AI 仲裁判定\n" + f"{source_label}\n" f"👥 責任: {resp_display}\n" f"📊 信心: {conf_emoji} {confidence_pct}%\n" f"{ai_cost_display}" f"💡 原因: {safe_root_cause}\n" + f"{frequency_block}" f"{signoz_block}" f"━━━━━━━━━━━━━━━━━━━\n" f"🔧 建議: {safe_action}\n" @@ -437,11 +479,16 @@ class TelegramGateway: # 2026-03-29 ogt: AI Token/Cost 追蹤 ai_tokens: int = 0, ai_cost: float = 0.0, + # 2026-03-29 ogt: ADR-037 異常頻率統計 + anomaly_frequency: dict | None = None, + # 2026-03-29 ogt: AI Provider 來源顯示 + ai_provider: str = "", ) -> dict: """ 推送待簽核卡片到 Telegram (v7.0 含 SignOz 整合) SOUL.md 4.1 + AI 仲裁 + SignOz 訊息格式 + Phase 21 (ADR-037): 含異常頻率統計 Args: approval_id: 簽核單 ID @@ -456,6 +503,7 @@ class TelegramGateway: signoz_*: SignOz Gold Metrics signoz_trace_url: 動態時間參數的 Trace URL auto_tuning_command: kubectl 調優指令 + anomaly_frequency: 異常頻率統計 (ADR-037) Returns: dict: Telegram API 回應 @@ -475,7 +523,7 @@ class TelegramGateway: trace_url=signoz_trace_url, ) - # 建立訊息結構 (含 AI 仲裁 + SignOz + Token/Cost) + # 建立訊息結構 (含 AI 仲裁 + SignOz + Token/Cost + 頻率統計) message = TelegramMessage( status_emoji=emoji, risk_level=risk_level.upper(), @@ -493,6 +541,10 @@ class TelegramGateway: # 2026-03-29 ogt: AI Token/Cost 追蹤 ai_tokens=ai_tokens, ai_cost=ai_cost, + # 2026-03-29 ogt: ADR-037 異常頻率統計 + anomaly_frequency=anomaly_frequency, + # 2026-03-29 ogt: AI Provider 來源顯示 + ai_provider=ai_provider, ) # 格式化訊息 diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index b8bd0bf85..4953a9ab7 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -5,28 +5,66 @@ --- -## 📍 當前狀態 (2026-03-29 11:25 台北) +## 📍 當前狀態 (2026-03-29 14:10 台北) | 項目 | 狀態 | |------|------| -| **當前 Phase** | ✅ **Phase 21 Wave A-D 全部完成** (ADR-037 監控增強) | +| **當前 Phase** | ✅ **Phase 21 Wave A-D 全部完成** + 📋 **Phase 22 戰略規劃完成** | | **Day** | Day 12 | | **K3s 版本** | v1.34.5+k3s1 (mon + mon1) | | **叢集健康** | ✅ **所有 Pod 正常運行** | | **K3s 優化** | ✅ **全部完成 + P1-P3 + PSS** | | **K-MON** | ✅ **監控整合** (VIP/Velero/SignOz/Sentry 告警) | -| **K3 HPA** | ✅ **API/Web 2-6 自動擴展** (P3 maxReplicas 調升) | +| **K3 HPA** | ✅ **API/Web 2-6 自動擴展(Worker HPA 待 Wave 1 後部署)** | | **K4 Kured** | ✅ **自動重啟 (02:00-04:00 維護窗口)** | | **K4 Descheduler** | ✅ **負載均衡 (每 2 小時, threshold 30%)** | -| **K4.3 PSS** | ✅ **Pod Security Standards (6 Namespace labels)** 🆕 | +| **K4.3 PSS** | ✅ **Pod Security Standards (6 Namespace labels)** | | **K-HA** | ✅ **雙 Control-Plane (120+121) + PostgreSQL Datastore** | | **VIP** | ✅ **192.168.0.125 (keepalived + CI/CD 整合)** | | **kube-state-metrics** | ✅ **v2.10.1 @ :30888 + NPD 告警整合** | -| **Grafana Dashboard** | ✅ **K3s Cluster Overview (9 panels)** 🆕 | +| **Grafana Dashboard** | ✅ **K3s Cluster Overview (9 panels)** | | **ArgoCD** | ✅ **ApplicationSet CRD 修復** | | **告警狀態** | ✅ **0 個告警觸發** | -| **首席架構師審查** | ✅ **Wave A-D: 194/200 (97%) OUTSTANDING** 🆕🆕🆕 | +| **首席架構師審查** | ✅ **Wave A-D: 194/200 (97%) OUTSTANDING** | | **模組化合規** | ✅ **100% 通過** | +| **⚠️ Wave 1 待執行** | 🔴 **8 個 P0 安全網代碼修復(XCLAIM + Circuit Breaker + Semaphore 等)** | + +## 📋 Phase 22: 全維度盤點暨戰略規劃 (2026-03-29 完成) + +### 完成項目 + +| 類型 | 文件 | 說明 | +|------|------|------| +| 📊 稽核報告 | `docs/AWOOOI_COMPREHENSIVE_AUDIT_2026Q1.md` | 全維度盤點 10 章,87/100 | +| 🏗️ 設計提案 | `docs/proposals/MONITORING_ARCHITECTURE_DEEP_DIVE.md` | 監控三義分離 | +| 🏗️ 設計提案 | `docs/proposals/INTEGRATION_ARCHITECTURE_MASTER.md` | 整合架構主藍圖 | +| ⚔️ 風險矩陣 | `docs/proposals/ARCHITECTURAL_RISK_WAR_GAME.md` | 6+4+代碼確認深度沙盤(第 1-6 章)| +| 📋 最終排程 | `docs/proposals/MASTER_EXECUTION_SCHEDULE.md` | 最終工作排程(供統帥審核)🆕 | +| 📘 RunBook | `docs/runbooks/RUNBOOK-PHASE-D-SENTRY-COMMENT.md` | Sentry Comment + 補丁 | +| 📘 RunBook | `docs/runbooks/RUNBOOK-PHASE-E-SIGNOZ-WEBHOOK.md` | SignOz Webhook 部署 | +| 📘 RunBook | `docs/runbooks/RUNBOOK-WORKER-HPA.md` | HPA + XCLAIM 前置 + terminationGracePeriodSeconds | +| 📘 RunBook | `docs/runbooks/RUNBOOK-E2E-CI-SCHEDULE.md` | E2E CI + Docker Baseline 強制規格 | +| 📘 RunBook | `docs/runbooks/RUNBOOK-FRONTEND-UIUX-SOVEREIGNTY.md` | 前端主權 + release/v1.x 前置 | +| 📐 ADR | `docs/adr/ADR-038-openclaw-concurrency-governance.md` | OpenClaw Semaphore + Circuit Breaker 🆕 | +| 📐 ADR | `docs/adr/ADR-039-global-autorepair-governance.md` | 全域修復熔斷 + StatefulSet 黑名單 🆕 | + +### 確認待執行的 P0 安全網(Wave 0 + Wave 1) + +**Wave 0(統帥手動,今天)**: +- `0.1` Redis AOF + eviction policy 確認(5 min) +- `0.2` Alertmanager 備援 Telegram 路徑確認(10 min) +- `0.3` release/v1.x 穩定分支建立(5 min)+ GitHub Protected Branch +- `0.4` SENTRY_AUTH_TOKEN 存在確認(3 min) + +**Wave 1(代碼 PR,原子性,2026-03-30~04-01)**: +- `core/circuit_breaker.py`(ADR-038:Semaphore + Circuit Breaker) +- `services/global_repair_cooldown.py`(ADR-039:全域熔斷) +- `anomaly_counter.py`:Redis 故障 Graceful Degrade +- `signal_worker.py`:XCLAIM + Active Sweeper + stop() 75s +- `auto_repair_service.py`:StatefulSet 黑名單 + 全域熔斷整合 +- `sentry_webhook.py` + `signoz_webhook.py`:雙層保護整合 +- `incident_service.py`:Global Incident Debounce +- `08-deployment-worker.yaml`:terminationGracePeriodSeconds: 90 ---