# ADR-028: 失敗自動修復閉環架構 (Failure Auto-Repair Loop) > **狀態**: 📋 Proposed > **提案日期**: 2026-03-26 > **決策者**: 統帥 > **提案者**: 首席架構師 ## Context AWOOOI 行動日誌頁面顯示大量失敗操作,但系統只是「記錄」: ``` 失敗 → 記錄 → 結束 (死路) ``` 這違反了 AIOps 產品的核心價值。作為 AI 產品,應該是: ``` 失敗 → AI 分析 → 自動/人工修復 → 驗證 → 學習 ``` ## Decision 實作「失敗自動修復閉環」架構,包含以下核心元件: ### 1. FailureWatcher Worker ```python class FailureWatcher: """ 監聽 AuditLog 失敗事件的 Worker 消費 Redis Stream: awoooi:audit_logs:failed """ async def handle_failure(self, audit_log: AuditLog): # 1. AI 分析失敗原因 analysis = await self.repair_analyzer.analyze(audit_log) # 2. 建立修復日誌 repair_log = await self.create_repair_log(audit_log, analysis) # 3. 根據風險等級路由 if analysis.risk_level == "LOW": await self.auto_repair(repair_log) else: await self.request_approval(repair_log) ``` ### 2. RepairAnalyzer (OpenClaw 整合) ```python class RepairAnalyzer: """ 使用 OpenClaw 分析失敗原因並生成修復策略 """ async def analyze(self, audit_log: AuditLog) -> RepairAnalysis: prompt = f""" 分析以下 K8s 操作失敗原因: 操作類型: {audit_log.operation_type} 目標資源: {audit_log.target_resource} 命名空間: {audit_log.namespace} 錯誤訊息: {audit_log.error_message} K8s 回應: {audit_log.k8s_response} 請提供: 1. 失敗原因分析 2. 建議修復策略 3. 風險等級 (LOW/MEDIUM/CRITICAL) 4. 是否可自動修復 """ return await self.openclaw.analyze(prompt) ``` ### 3. 資料模型 ```python # 擴展 AuditLog class AuditLog: # ... 現有欄位 ... authorization_channel: Mapped[str | None] # "web" | "telegram" | "auto" authorized_by: Mapped[str | None] authorized_at: Mapped[datetime | None] # 新增 RepairLog class RepairLog(Base): __tablename__ = "repair_logs" id: Mapped[str] = mapped_column(String(36), primary_key=True) original_audit_id: Mapped[str] = mapped_column(ForeignKey("audit_logs.id")) # AI 分析結果 failure_reason: Mapped[str] = mapped_column(Text) repair_strategy: Mapped[str] = mapped_column(Text) repair_command: Mapped[str | None] = mapped_column(Text) # 風險與狀態 risk_level: Mapped[str] = mapped_column(String(20)) # LOW/MEDIUM/CRITICAL auto_repaired: Mapped[bool] = mapped_column(default=False) repair_status: Mapped[str] = mapped_column(String(20)) # pending/executing/success/failed # 時間戳 created_at: Mapped[datetime] completed_at: Mapped[datetime | None] # 關聯 original_audit: Mapped["AuditLog"] = relationship() ``` ### 4. 修復流程 ``` ┌──────────────────────────────────────────────────────────────────┐ │ 失敗自動修復閉環 │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────┐ ┌──────────────┐ ┌─────────────┐ │ │ │ AuditLog│───▶│FailureWatcher│───▶│RepairAnalyzer│ │ │ │ (失敗) │ │ (偵測) │ │ (AI 分析) │ │ │ └─────────┘ └──────────────┘ └──────┬──────┘ │ │ │ │ │ ▼ │ │ ┌───────────────┐ │ │ │ Trust Engine │ │ │ │ (風險評估) │ │ │ └───────┬───────┘ │ │ │ │ │ ┌──────────────────┼──────────────────┐ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌───────────┐ ┌───────────┐ ┌─────────┐│ │ │ LOW │ │ MEDIUM │ │CRITICAL ││ │ │ 自動執行 │ │ 單人授權 │ │Multi-Sig││ │ └─────┬─────┘ └─────┬─────┘ └────┬────┘│ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌─────────────┐ ┌─────────────────────────────┐ │ │ │AutoRepair │ │ 同步推送 │ │ │ │Executor │ │ • Telegram Bot │ │ │ │(自動修復) │ │ • Web Dashboard (WebSocket) │ │ │ └──────┬──────┘ └────────────┬────────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ 揭露通知 │ │ 等待授權 │ │ │ │ (Dashboard) │ │ (記錄來源) │ │ │ └─────────────┘ └──────┬──────┘ │ │ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ 執行修復 │ │ │ └──────┬──────┘ │ │ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ 驗證 │ │ │ └──────┬──────┘ │ │ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ Playbook │ │ │ │ 學習萃取 │ │ │ └─────────────┘ │ │ │ └──────────────────────────────────────────────────────────────────┘ ``` ### 5. 授權來源追蹤 | Channel | 說明 | 記錄內容 | |---------|------|---------| | `auto` | AI 自動執行 | `authorized_by: "system"` | | `web` | 前端 Dashboard | `authorized_by: "{user_id}"` | | `telegram` | Telegram Bot | `authorized_by: "{telegram_user_id}"` | ### 6. 前端揭露 在 Dashboard 新增「AI 自動修復報告」區塊: - 過去 24 小時自動修復統計 - 最近自動修復列表 - 修復成功/失敗比例 - 需人工介入的項目 ### 7. API 端點 ``` GET /api/v1/repairs # 修復日誌列表 GET /api/v1/repairs/{id} # 修復詳情 POST /api/v1/repairs/{id}/execute # 人工觸發修復 GET /api/v1/repairs/stats # 統計 (自動/人工比例) ``` ## Consequences ### Positive 1. **AI 真正主動** - 不再等人操作,自動偵測並修復 2. **透明揭露** - 用戶清楚知道 AI 做了什麼 3. **授權可追溯** - 記錄每次授權的來源和時間 4. **降低 MTTR** - 低風險問題秒級自動修復 ### Negative 1. **複雜度增加** - 需要新增 Worker、模型、API 2. **風險** - 自動修復可能造成更大問題 (透過 cooldown 緩解) 3. **成本** - 每次分析需要 OpenClaw API 呼叫 ### Risks | 風險 | 機率 | 影響 | 緩解措施 | |------|------|------|---------| | 自動修復失敗 | 中 | 中 | 失敗自動升級為人工審批 | | 修復風暴 | 低 | 高 | Cooldown: 同資源 5 分鐘 3 次上限 | | AI 誤判風險 | 中 | 中 | 保守分類,有疑問升級為 MEDIUM | ## Integration Feasibility (首席架構師評估 2026-03-26) ### 現有架構相容性: ✅ 95% 相容 調研結論:系統已具備所有必要基礎設施,可無縫整合。 | 組件 | 可復用程度 | 說明 | |------|----------|------| | Redis Stream (XREADGROUP) | ✅ 100% | SignalWorker 模式直接複製 | | Worker 消費循環 | ✅ 100% | 代碼結構完全相同 | | AuditLog 持久化 | ✅ 90% | 只需新增 3 欄位 | | Trace Context | ✅ 100% | restore_trace_context() 可用 | | OpenClaw AI | ✅ 70% | 需新增 analyze_failure() | | Telegram 推送 | ✅ 80% | 改為推送修復卡片 | ### 衝突點與緩解 | 風險 | 緩解方案 | |------|---------| | 重試無限迴圈 | `max_retry_count = 3` | | OpenClaw 過載 | backpressure queue (max 50) | | Telegram 風暴 | 10 秒批量聚合 | | 決策二重性 | DecisionManager 優先 | ### 模組化驗證 ``` ✅ leWOOOgo 積木化原則檢查: ├── Protocol 先行: IFailureWatcher, IRepairAnalyzer ├── Router 層乾淨: /api/v1/repairs/* 只做 HTTP 轉發 ├── Service 注入: get_failure_watcher() Singleton ├── Repository 分離: AuditLogRepository.list_failures() └── Worker 獨立: failure-watcher-worker Deployment ``` ## Implementation Plan (修訂版) | Phase | 內容 | 預估 | 優先級 | |-------|------|------|--------| | 18.1 | AuditLog 表擴展 + Migration | 2h | P0 | | 18.2 | FailureWatcher Service | 6h | P0 | | 18.3 | FailureWatcherWorker (K8s) | 4h | P0 | | 18.4 | OpenClaw 失敗分析方法 | 8h | P1 | | 18.5 | Telegram 修復卡片 | 3h | P1 | | 18.6 | E2E 測試 + 部署驗證 | 6h | P0 | **總計: 29h (~3.6 天)** ### 工作依賴順序 ``` 18.1 (DB) ─┬─→ 18.2 (Service) ─┬─→ 18.3 (Worker) ─→ 18.6 (E2E) │ │ │ └─→ 18.5 (Telegram) │ └─→ 18.4 (OpenClaw) ──────────────────→ 整合到 18.2 ``` ## References - [Memory: Phase 18 Failure Loop](~/.claude/projects/-Users-ogt-awoooi/memory/project_phase18_failure_loop.md) - [AWOOOI Agentic Workspace Roadmap](../AWOOOI_AGENTIC_WORKSPACE_ROADMAP.md) - [ADR-009: OpenClaw Agent Teams](./ADR-009-openclaw-agent-teams.md)