docs(adr): ADR-073 補充 ADR-071 整合工作序 + ADR-074 監控補全 Sprint
新增: - Sprint ADR-073-B 補充:DB Migration + 檢傷分類站 + KMConversionService(ADR-071-A/A0/B/C/G/H) - Sprint ADR-074:飛輪健康度Exporter + 主機間網路 + DNS + Gitea CD + 備份還原測試等9項監控缺口 - 參考指向完整規格書 2026-04-12-aiops-complete-flywheel-repair-design.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
288
docs/adr/ADR-073-flywheel-full-audit.md
Normal file
288
docs/adr/ADR-073-flywheel-full-audit.md
Normal file
@@ -0,0 +1,288 @@
|
||||
# ADR-073: AIOps 飛輪完整盤點 — 問題根因 + 長期解決方案
|
||||
|
||||
**狀態**: Accepted — 等待實作批准
|
||||
**日期**: 2026-04-12 (台北時間)
|
||||
**作者**: Claude Sonnet 4.6 + 首席架構師
|
||||
**觸發**: 資料庫審計顯示飛輪從未真正運轉
|
||||
|
||||
---
|
||||
|
||||
## 一、飛輪設計圖(截圖定案版)
|
||||
|
||||
### 正常模式(自主運行)
|
||||
|
||||
```
|
||||
監控觀察 → 接入去重 → 環境診斷 → 推理匹配 → 執行燒橇 → 學習固化
|
||||
↑ ↓
|
||||
└─────────────────── 飛輪閉環 ──────────────────────────────┘
|
||||
```
|
||||
|
||||
**六個節點定義**:
|
||||
|
||||
| 節點 | 功能 | 對應程式碼 |
|
||||
|------|------|-----------|
|
||||
| 監控觀察 | Prometheus/Alertmanager 接收告警,Fingerprint 去重 | `webhooks.py` alertmanager_webhook |
|
||||
| 接入去重 | Debounce 30 分鐘,相同 fingerprint 只建一個 Incident | `webhooks.py` fingerprint + debounce |
|
||||
| 環境診斷 | MCP 收集真實環境狀態(SSH/K8s/Prometheus)| `decision_manager._collect_mcp_context()` |
|
||||
| 推理匹配 | 查 KM Playbook → 有匹配直接執行;無匹配呼叫 LLM 推理 | `decision_manager._dual_engine_analyze()` |
|
||||
| 執行燒橇 | 透過 MCP Provider 執行修復動作 | `decision_manager._auto_execute()` |
|
||||
| 學習固化 | 成功→生成 Playbook;失敗→生成 Anti-Pattern;寫入 KM | `decision_manager._generate_playbook_draft_if_new()` |
|
||||
|
||||
### 人工介入模式(需人工路徑)
|
||||
|
||||
```
|
||||
推理匹配
|
||||
├→ TYPE-3(高風險審核): AI 找到方案但動作風險高 → 人工批准 → 執行 → 學習固化
|
||||
└→ TYPE-4(根因確認): AI 無法判斷 → 人工手動處理 → 記錄手動步驟 → 生成新 Playbook
|
||||
```
|
||||
|
||||
**人工介入只發生在兩種情況**:
|
||||
1. `risk_level = critical` 或 DESTRUCTIVE_PATTERNS 命中 → TYPE-3 卡片
|
||||
2. `confidence < 0.5` 或 MCP 全失敗 → TYPE-4 卡片,人工確認後轉 Playbook
|
||||
|
||||
---
|
||||
|
||||
## 二、資料庫實際數據(2026-04-12 統計)
|
||||
|
||||
### Incidents(132 筆)
|
||||
|
||||
| 欄位 | 數值 | 正常應有 |
|
||||
|------|------|---------|
|
||||
| severity P3 | 108(82%) | P3 應是少數 |
|
||||
| severity P2 | 18(14%) | |
|
||||
| severity P0 | 6(4%) | |
|
||||
| status INVESTIGATING | 87(66%) | 應該接近 0 |
|
||||
| status RESOLVED | 45(34%) | |
|
||||
| alertname | **全部 NULL** | 應有 alertname |
|
||||
| alert_category | **全部 NULL** | 應有分類 |
|
||||
| notification_type | **全部 NULL** | 應記錄卡片類型 |
|
||||
| vectorized | **全部 False** | 應 True(已向量化進 KM)|
|
||||
| outcome | **全部 null** | 應記錄修復結果 |
|
||||
|
||||
### Approvals(380 筆)
|
||||
|
||||
| status | 數量 | 說明 |
|
||||
|--------|------|------|
|
||||
| EXECUTION_FAILED | 211(55%) | 超過一半執行失敗 |
|
||||
| APPROVED | 132(35%) | 已核准,未執行或執行中 |
|
||||
| REJECTED | 30(8%) | 人工拒絕 |
|
||||
| EXPIRED | 5 | 超時未處理 |
|
||||
| **EXECUTION_SUCCESS** | **2(0.5%)** | **實際成功修復只有 2 次** |
|
||||
|
||||
### Top Actions(失敗根因)
|
||||
|
||||
| action | 數量 | 問題 |
|
||||
|--------|------|------|
|
||||
| 未知操作 \|(空) | 93 | action 解析失敗,完全不知道要做什麼 |
|
||||
| 重新啟動 postgres-primary-0 | 30 | 同一問題反覆重啟,未解決根因 |
|
||||
| 重新啟動 postgresql-native | 25 | 同上 |
|
||||
| 重新啟動 harbor-core-7d4b8c9f5-xk2m3 | 21 | Pod hash 寫死,每次不同 |
|
||||
| OBSERVE | 16 | LLM 判斷無法修復,只觀察 |
|
||||
|
||||
### Playbooks = **0**
|
||||
### Knowledge Entries(699 筆)
|
||||
- INCIDENT_CASE: 690(有案例,**但全部未向量化**,無法 RAG 查詢)
|
||||
- RUNBOOK: 7
|
||||
- BEST_PRACTICE: 2
|
||||
|
||||
---
|
||||
|
||||
## 三、飛輪每個節點的實際狀態 vs 設計目標
|
||||
|
||||
### 節點 1:監控觀察 ✅ 部分正常
|
||||
- Prometheus → Alertmanager → webhooks.py 接收 ✅
|
||||
- **問題**:alertname 存入 signals JSONB,但 `signals->0->>'alertname'` 全為 NULL,代表 signals 結構不對
|
||||
|
||||
### 節點 2:接入去重 ⚠️ 部分異常
|
||||
- Fingerprint 機制存在 ✅
|
||||
- **問題**:debounce window 只有 5 分鐘,Prometheus 每 1 分鐘 fire 一次,5 分鐘後重新建 Incident,導致同一問題產生多個 Incident,反覆發 Telegram
|
||||
|
||||
### 節點 3:環境診斷 ❌ 未運作
|
||||
- `_collect_mcp_context()` 已實作(commit c439277)
|
||||
- **問題**:`8be87b0` 的修復程式碼 CD 失敗未部署,目前 Pod 是舊 image(`a86ecf3`),該 image 沒有 `_collect_mcp_context()`
|
||||
- MCP Providers 雖然 enabled,但沒有在分析前被呼叫
|
||||
|
||||
### 節點 4:推理匹配 ❌ 嚴重問題
|
||||
- LLM 分析有在跑(Nemotron NIM)✅
|
||||
- **問題 A**:Playbooks = 0,`evaluate_auto_repair()` 在 Playbook 匹配步驟永遠失敗,**100% 走人工審核**
|
||||
- **問題 B**:`signals` JSONB 裡 alertname = NULL,LLM 拿到的是空告警名稱
|
||||
- **問題 C**:target_resource 解析失敗(DockerContainerUnhealthy → target = alertname or unknown)
|
||||
- **問題 D**:LLM 習慣性回傳 `risk_level = high`,但 YAML 規則的 risk 沒有覆蓋 LLM 結果
|
||||
|
||||
### 節點 5:執行燒橇 ❌ 從未成功(0.5%)
|
||||
- `_auto_execute()` 三層安全守衛存在 ✅
|
||||
- **問題 A**:93 次 `未知操作|` → action 解析失敗,LLM 回傳的 action 包含 `|` 分隔符,解析邏輯出錯
|
||||
- **問題 B**:`target = unknown` 或 `target = alertname` → 安全守衛攔截 → 發 `❌ 自動修復失敗`(而非 TYPE-4 卡片)
|
||||
- **問題 C**:K8s deployment 名稱含 hash(`harbor-core-7d4b8c9f5-xk2m3`),K8s 驗證失敗
|
||||
- **問題 D**:Docker/Host 層告警(DockerContainerUnhealthy / HostBackupFailed)走 K8s 路徑,根本路徑就錯
|
||||
|
||||
### 節點 6:學習固化 ❌ 完全失效
|
||||
- `_generate_playbook_draft_if_new()` 已實作(commit 7eb49f9)✅
|
||||
- **問題 A**:Playbooks 仍為 0,代表觸發條件從未成立,或有 exception 被靜默吞掉
|
||||
- **問題 B**:690 筆 INCIDENT_CASE 全部 `vectorized = False`,RAG 查詢永遠找不到歷史案例
|
||||
- **問題 C**:outcome / target_resource / alert_category 全為 NULL,KM 記錄的案例沒有分類,無法被有效查詢
|
||||
- **問題 D**:重複發生的告警(postgres-primary-0 被重啟 30 次)沒有任何學習,每次重新走全流程
|
||||
|
||||
---
|
||||
|
||||
## 四、與設計定案的落差對照表
|
||||
|
||||
| 設計定案要求 | 實際狀況 | 落差等級 |
|
||||
|------------|---------|---------|
|
||||
| 告警 → 自動修復閉環 | Playbooks=0,100% 人工審核 | 🔴 P0 |
|
||||
| 重複告警不重複觸發 | 5 分鐘 debounce,每次重建 | 🔴 P0 |
|
||||
| 失敗 → 學習 → 建立規則 | 690 案例未向量化,Playbook 從未生成 | 🔴 P0 |
|
||||
| KM 三段資料完整 | outcome/vectorized 全 NULL | 🔴 P0 |
|
||||
| target 動態解析(Docker/Host)| target = unknown/alertname | 🔴 P0 |
|
||||
| NO_ACTION 告警不顯示按鈕 | HostBackupFailed 仍有六個按鈕 | 🟠 P1 |
|
||||
| 通知類型正確分類 | notification_type 全 NULL | 🟠 P1 |
|
||||
| severity/risk_level 正確 | P3 佔 82%,risk 被 LLM 覆蓋 | 🟠 P1 |
|
||||
| 人工修復後轉 Playbook | 無 handle_manual_fix_done 呼叫 | 🟠 P1 |
|
||||
| 前端顯示飛輪狀態 | 截圖顯示 Playbook=0,飛輪靜止 | 🟡 P2 |
|
||||
|
||||
---
|
||||
|
||||
## 五、長期解決方案(按優先順序)
|
||||
|
||||
### P0-A:修復 CD + 部署新 image
|
||||
**問題**:`8be87b0` 的三大修復未上線
|
||||
**解法**:確認 Harbor 有 `8be87b0` 的 web image;若沒有,重新觸發 build
|
||||
**驗收**:Pod image = 8be87b0,`_collect_mcp_context` 存在於 /app/src
|
||||
|
||||
### P0-B:修復 signals 結構 — alertname 存入正確欄位
|
||||
**問題**:`signals->0->>'alertname'` = NULL
|
||||
**解法**:`webhooks.py` 在建 Incident 時,確認 signal 的 alertname 正確寫入 JSONB;或新增獨立欄位 `alertname VARCHAR(100)`
|
||||
**驗收**:新 Incident 的 alertname 不為 NULL
|
||||
|
||||
### P0-C:debounce window 延長到 30 分鐘
|
||||
**問題**:5 分鐘 debounce → 同一問題每 5 分鐘重新建 Incident + 發 Telegram
|
||||
**解法**:`webhooks.py` fingerprint debounce window 從 5 分鐘 → 30 分鐘
|
||||
**驗收**:同一告警 30 分鐘內只有 1 個 INVESTIGATING Incident
|
||||
|
||||
### P0-D:冷啟動 Playbook 生成
|
||||
**問題**:Playbooks = 0,自動修復永遠失敗
|
||||
**解法**:一次性腳本,讀取 approval_records 裡 EXECUTION_SUCCESS 的 2 筆 + APPROVED 的 top 10,用 LLM 生成初始 Playbook 草稿,寫入 DB 標記 APPROVED
|
||||
**驗收**:Playbooks >= 10,evaluate_auto_repair 至少有匹配
|
||||
|
||||
### P0-E:690 筆 INCIDENT_CASE 向量化
|
||||
**問題**:vectorized = False,RAG 永遠找不到歷史案例
|
||||
**解法**:一次性腳本,批次向量化所有 `vectorized=False` 的 knowledge_entries
|
||||
**驗收**:vectorized = True,RAG 查詢返回相關案例
|
||||
|
||||
### P0-F:Docker/Host 層告警走 SSH MCP 路徑
|
||||
**問題**:DockerContainerUnhealthy → K8s 路徑 → deployment 不存在 → 失敗
|
||||
**解法**:`_auto_execute()` 判斷 alertname prefix(Docker*/Host*)→ 走 SSH MCP `ssh_docker_restart`;不走 K8s 路徑
|
||||
**驗收**:DockerContainerUnhealthy 觸發 → SSH MCP 執行 → 成功
|
||||
|
||||
### P1-A:action 解析修復(93 筆「未知操作|」)
|
||||
**問題**:LLM 回傳含 `|` 的 action,解析後為空
|
||||
**解法**:`_push_decision_to_telegram()` 的 action 佔位符替換邏輯,加 `|` 分隔符清理
|
||||
**驗收**:新的 approval_records action 不出現「未知操作|」
|
||||
|
||||
### P1-B:NO_ACTION → TYPE-1(無按鈕)
|
||||
**問題**:HostBackupFailed 仍有六個按鈕
|
||||
**解法**:`classify_notification()` 加判斷:`suggested_action == "NO_ACTION"` → TYPE-1
|
||||
**驗收**:HostBackupFailed Telegram 卡片無操作按鈕
|
||||
|
||||
### P1-C:outcome / alert_category / notification_type 寫入
|
||||
**問題**:三個欄位全 NULL,KM 無法分類
|
||||
**解法**:
|
||||
- `_auto_execute()` 完成後寫 `incident.outcome`
|
||||
- `webhooks.py` 建 Incident 時寫 `alert_category`(從 YAML 規則取)
|
||||
- `_push_decision_to_telegram()` 發完寫 `notification_type`
|
||||
|
||||
### P1-D:risk_level YAML 優先覆蓋 LLM
|
||||
**問題**:LLM 習慣性回傳 high,YAML 規則的 risk 沒有覆蓋
|
||||
**解法**:`_dual_engine_analyze()` 中,若 YAML 規則有 risk 值,優先用 YAML 的,不採用 LLM 的
|
||||
**驗收**:HostHighCpuLoad(YAML risk=medium)→ Telegram 顯示 MEDIUM
|
||||
|
||||
### P2-A:前端飛輪狀態即時顯示
|
||||
**問題**:截圖顯示飛輪靜止,Playbook=0,成功率 0.5%,需人工介入
|
||||
**解法**:前端飛輪元件(已有)連接以下 API:
|
||||
- `GET /api/v1/stats/flywheel` → 返回六節點狀態(活躍/靜止/錯誤)
|
||||
- `GET /api/v1/stats/summary` → 返回 Playbook 數量、成功率、今日處理數
|
||||
- WebSocket 推送:每次節點狀態變化即時更新
|
||||
**驗收**:飛輪動畫跟隨真實告警流轉動;Playbook 數量即時更新
|
||||
|
||||
### P2-B:前端顯示人工介入路徑
|
||||
**問題**:截圖第二張「需人工介入」時,飛輪顯示 TYPE-4(根因確認)和 TYPE-3(高風險審核)路徑
|
||||
**解法**:飛輪元件增加「顯示人工干預路徑」toggle(已有),觸發時:
|
||||
- 紅色虛線顯示從「推理匹配」到「人工處理中心」的路徑
|
||||
- TYPE-3 / TYPE-4 標籤顯示在對應節點旁邊
|
||||
|
||||
---
|
||||
|
||||
## 六、實作優先順序與批准等待
|
||||
|
||||
> 以下所有變更等待首席架構師批准後才開始實作
|
||||
|
||||
### Sprint ADR-073-A(本週):讓飛輪真的動起來
|
||||
|
||||
| # | 任務 | 風險等級 | 估計工時 |
|
||||
|---|------|---------|---------|
|
||||
| 1 | CD 修復 + 8be87b0 部署確認 | Tier 2 | 30 分鐘 |
|
||||
| 2 | signals alertname NULL 修復 | Tier 2 | 1 小時 |
|
||||
| 3 | debounce 5→30 分鐘 | Tier 2 | 30 分鐘 |
|
||||
| 4 | 冷啟動 Playbook 生成腳本(一次性)| Tier 2 | 2 小時 |
|
||||
| 5 | 690 筆 KM 向量化腳本(一次性)| Tier 1 | 1 小時 |
|
||||
|
||||
### Sprint ADR-073-B(下週):修復路由 + 通知品質
|
||||
|
||||
| # | 任務 | 風險等級 | 估計工時 |
|
||||
|---|------|---------|---------|
|
||||
| 6 | Docker/Host 告警 → SSH MCP 路徑 | Tier 3 | 3 小時 |
|
||||
| 7 | action 解析「未知操作|」修復 | Tier 2 | 1 小時 |
|
||||
| 8 | NO_ACTION → TYPE-1 無按鈕 | Tier 2 | 1 小時 |
|
||||
| 9 | outcome/alert_category/notification_type 寫入 | Tier 3 | 2 小時 |
|
||||
| 10 | risk_level YAML 優先 | Tier 2 | 1 小時 |
|
||||
|
||||
### Sprint ADR-073-C(再下週):前端飛輪即時化
|
||||
|
||||
| # | 任務 | 風險等級 | 估計工時 |
|
||||
|---|------|---------|---------|
|
||||
| 11 | `/api/v1/stats/flywheel` API | Tier 1 | 2 小時 |
|
||||
| 12 | 前端飛輪元件連接真實 API | Tier 2 | 3 小時 |
|
||||
| 13 | WebSocket 即時推送 | Tier 2 | 2 小時 |
|
||||
|
||||
---
|
||||
|
||||
### Sprint ADR-073-B 補充(整合 ADR-071 工作序,2026-04-12 更新)
|
||||
|
||||
| # | 任務 | 風險等級 | ADR-071 對應 |
|
||||
|---|------|---------|-------------|
|
||||
| B-DB | DB Migration: incidents +9 欄位 | Tier 1 | ADR-071-A |
|
||||
| B1 | 檢傷分類站前移(decision_manager 入口)| Tier 3 | ADR-071-A0+B |
|
||||
| B2 | TYPE-1 純資訊卡片 | Tier 2 | ADR-071-C |
|
||||
| B3 | KMConversionService(RESOLVED→KM→向量化)| Tier 2 | ADR-071-G |
|
||||
| B4 | TYPE-4 手動修復記錄 | Tier 2 | ADR-071-H |
|
||||
|
||||
### Sprint ADR-074(監控補全,依賴 ADR-073-A/B 完成後)
|
||||
|
||||
| # | 任務 | 告警名稱 | 嚴重度 |
|
||||
|---|------|---------|-------|
|
||||
| M1 | 飛輪健康度 Prometheus Exporter + 告警規則 | `FlywheelPlaybookZero` / `FlywheelExecutionSuccessLow` | P0 Critical |
|
||||
| M2 | 主機間網路 Blackbox probe | `HostNetworkPartition` | P0 Critical |
|
||||
| M3 | CoreDNS 解析失敗監控 | `CoreDNSResolutionFailed` | P0 Critical |
|
||||
| M4 | Gitea CI/CD 管線失敗 webhook | `GiteaCIPipelineFailed` | P0 Critical |
|
||||
| M5 | 備份還原週排程測試 | `BackupRestoreTestFailed` | P0 Critical |
|
||||
| M6 | Docker 188 容器詳細健康 | `DockerContainerUnhealthyDetailed` | P1 Warning |
|
||||
| M7 | Redis Streams 積壓 | `RedisStreamBacklogHigh` | P1 Warning |
|
||||
| M8 | PostgreSQL 磁碟增長率 | `PostgreSQLDiskGrowthRate` | P1 Warning |
|
||||
| M9 | Gemini API 錯誤率 | `GeminiAPIErrorRateHigh` | P1 Warning |
|
||||
|
||||
> **完整規格**: `docs/superpowers/specs/2026-04-12-aiops-complete-flywheel-repair-design.md`
|
||||
|
||||
---
|
||||
|
||||
## 七、驗收標準(飛輪真正運轉的指標)
|
||||
|
||||
完成後 7 天內,以下指標必須達到:
|
||||
|
||||
| 指標 | 當前 | 目標 |
|
||||
|------|------|------|
|
||||
| Playbooks 數量 | 0 | ≥ 20 |
|
||||
| EXECUTION_SUCCESS 率 | 0.5% | ≥ 30% |
|
||||
| 重複告警同 Incident 率 | < 10% | ≥ 70% |
|
||||
| KM vectorized | 0% | ≥ 90% |
|
||||
| alertname NULL | 100% | 0% |
|
||||
| 飛輪節點有活動的告警 | 0 | ≥ 1 筆/小時 |
|
||||
Reference in New Issue
Block a user