ADR 編號修正: - ADR-023 failure-auto-repair → ADR-028 - ADR-025 cicd-ai-integration → ADR-029 新增 ADR: - ADR-021: Playbook 更新驗證 - ADR-022: Sentry 整合架構 - ADR-027: Incident-Approval 同步 - ADR-028: 失敗自動修復閉環 - ADR-029: CI/CD AI 整合 (原 ADR-025) 更新: - ADR-018: LLM 測試策略狀態更新 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
283 lines
12 KiB
Markdown
283 lines
12 KiB
Markdown
# 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)
|