# ADR-030: 智能自動修復系統 (Intelligent Auto-Remediation)

**狀態**: 已實作 ✅
**日期**: 2026-03-27 (台北時區)
**決策者**: 統帥
**觸發**: Expert System 只會重啟，缺乏根因診斷能力

---

## 一、問題陳述

### 1.1 當前痛點

| 問題 | 影響 | 根因 |
|------|------|------|
| Expert System 盲目重啟 | 治標不治本，問題反覆發生 | 規則太粗糙，只看關鍵字 |
| 測試資源告警轟炸 | 浪費人力審核假告警 | 沒有資源分類過濾 |
| LLM 超時導致 fallback | 使用者看到的都是 Expert 建議 | Ollama CPU 太慢 |
| 缺乏學習機制 | 相同問題重複發生 | 反饋沒有回饋到決策 |
| 沒有自動修復 | 所有事件都需人工審核 | 缺乏信任度機制 |

### 1.2 目標

1. **根因優先**: 先診斷問題，再決定行動
2. **智能分類**: 自動過濾測試/臨時資源
3. **持續學習**: 從執行結果中學習
4. **漸進自動化**: 低風險操作可自動執行

---

## 二、完整解決方案架構

### 2.1 四層診斷引擎

```
┌─────────────────────────────────────────────────────────────────┐
│                    Layer 4: Decision Layer                       │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │ Auto-Approve Engine (Phase 4)                           │    │
│  │ - 信任度 > 90% + 風險 LOW → 自動執行                    │    │
│  │ - 重複 Playbook 成功 3+ 次 → 自動放行                   │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘
                              ↑
┌─────────────────────────────────────────────────────────────────┐
│                    Layer 3: Intelligence Layer                   │
│  ┌──────────────────┐  ┌──────────────────┐  ┌───────────────┐  │
│  │ LLM Engine       │  │ Playbook Engine  │  │ ML Anomaly    │  │
│  │ (Gemini/Claude)  │  │ (RAG + Vector)   │  │ Detection     │  │
│  │                  │  │                  │  │ (Future)      │  │
│  │ - 根因分析       │  │ - 歷史案例匹配   │  │               │  │
│  │ - 修復建議       │  │ - 成功率評估     │  │ - 異常偵測    │  │
│  │ - 預防措施       │  │ - 信任度計算     │  │ - 趨勢預測    │  │
│  └──────────────────┘  └──────────────────┘  └───────────────┘  │
└─────────────────────────────────────────────────────────────────┘
                              ↑
┌─────────────────────────────────────────────────────────────────┐
│                    Layer 2: Diagnosis Layer                      │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │ Expert System v2 (智能診斷規則引擎)                      │   │
│  │                                                          │   │
│  │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │   │
│  │ │ Classifier  │ │ Diagnoser   │ │ Action Recommender  │ │   │
│  │ │ 問題分類    │ │ 根因診斷    │ │ 行動建議            │ │   │
│  │ │             │ │             │ │                     │ │   │
│  │ │ - OOM       │ │ - 日誌分析  │ │ - 診斷指令          │ │   │
│  │ │ - CrashLoop │ │ - 指標相關  │ │ - 修復建議          │ │   │
│  │ │ - Network   │ │ - 配置檢查  │ │ - 風險評估          │ │   │
│  │ │ - Config    │ │             │ │                     │ │   │
│  │ └─────────────┘ └─────────────┘ └─────────────────────┘ │   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              ↑
┌─────────────────────────────────────────────────────────────────┐
│                    Layer 1: Data Collection Layer                │
│  ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌─────────────┐   │
│  │ Alertmgr   │ │ SignOz     │ │ K8s Events │ │ Pod Logs    │   │
│  │ Webhook    │ │ Metrics    │ │ kubectl    │ │ Stern/Log   │   │
│  │            │ │            │ │            │ │             │   │
│  │ - 告警     │ │ - RPS      │ │ - Events   │ │ - Error     │   │
│  │ - 嚴重度   │ │ - Error%   │ │ - Status   │ │ - Panic     │   │
│  │ - 影響     │ │ - P99      │ │ - Restart  │ │ - OOM       │   │
│  └────────────┘ └────────────┘ └────────────┘ └─────────────┘   │
└─────────────────────────────────────────────────────────────────┘
```

### 2.2 完整診斷決策流程

```
                    ┌─────────────────────┐
                    │   Incident 進入     │
                    └──────────┬──────────┘
                               │
                    ┌──────────▼──────────┐
                    │ Step 1: 資源分類    │
                    │ 是測試/臨時資源嗎？  │
                    └──────────┬──────────┘
                               │
              ┌────────────────┼────────────────┐
              │ Yes            │                │ No
              ▼                │                ▼
    ┌─────────────────┐        │      ┌─────────────────┐
    │ 標記為測試資源   │        │      │ Step 2: 資料收集│
    │ 建議手動清理     │        │      │ - SignOz 指標   │
    │ 不觸發 LLM      │        │      │ - K8s Events    │
    └─────────────────┘        │      │ - Pod 日誌      │
                               │      └────────┬────────┘
                               │               │
                               │      ┌────────▼────────┐
                               │      │ Step 3: 問題分類│
                               │      │ Expert Classifier│
                               │      └────────┬────────┘
                               │               │
              ┌────────────────┴───────────────┴────────────────┐
              │                                                  │
              ▼                ▼                ▼                ▼
    ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐
    │ OOM/Memory  │  │ CrashLoop   │  │ Network/DNS │  │ Unknown     │
    └──────┬──────┘  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘
           │                │                │                │
           ▼                ▼                ▼                ▼
    ┌─────────────────────────────────────────────────────────────┐
    │ Step 4: 根因診斷 (Expert Diagnoser)                         │
    │ - 執行診斷指令 (kubectl describe/logs/top)                  │
    │ - 關聯 SignOz 指標 (RPS, Error%, P99)                       │
    │ - 檢查歷史 Playbook 匹配                                    │
    └─────────────────────────────────────────────────────────────┘
                               │
                    ┌──────────▼──────────┐
                    │ Step 5: Playbook 檢索│
                    │ 有匹配的歷史案例嗎？  │
                    └──────────┬──────────┘
                               │
              ┌────────────────┼────────────────┐
              │ Yes (>85%)     │                │ No
              ▼                │                ▼
    ┌─────────────────┐        │      ┌─────────────────┐
    │ 使用 Playbook    │        │      │ Step 6: LLM 分析│
    │ 成功率 + 信任度  │        │      │ 含診斷上下文    │
    └────────┬────────┘        │      └────────┬────────┘
             │                 │               │
             │      ┌──────────┴───────────────┤
             │      │                          │
             ▼      ▼                          ▼
    ┌─────────────────────────────────────────────────────────────┐
    │ Step 7: 信任度評估 (Trust Engine)                           │
    │ - 歷史成功率 (Playbook)                                     │
    │ - 操作風險等級                                              │
    │ - 影響範圍 (爆炸半徑)                                       │
    └─────────────────────────────────────────────────────────────┘
                               │
                    ┌──────────▼──────────┐
                    │ Step 8: 自動執行？   │
                    │ 信任度 > 90%         │
                    │ AND 風險 = LOW       │
                    │ AND 成功率 > 95%     │
                    └──────────┬──────────┘
                               │
              ┌────────────────┼────────────────┐
              │ Yes            │                │ No
              ▼                │                ▼
    ┌─────────────────┐        │      ┌─────────────────┐
    │ 自動執行         │        │      │ 人工審核        │
    │ 記錄到 AuditLog │        │      │ Telegram/Web    │
    └────────┬────────┘        │      └────────┬────────┘
             │                 │               │
             └─────────────────┴───────────────┘
                               │
                    ┌──────────▼──────────┐
                    │ Step 9: 執行與驗證   │
                    │ K8s Executor        │
                    └──────────┬──────────┘
                               │
                    ┌──────────▼──────────┐
                    │ Step 10: 結果反饋    │
                    │ - 更新 Playbook 成功率│
                    │ - 調整信任度          │
                    │ - 萃取新 Playbook     │
                    └─────────────────────┘
```

---

## 三、實施計畫

### Phase 1: 智能診斷基礎 (1-2 週) ✅ 已完成

**目標**: 改進 Expert System，從「盲目重啟」變成「根因診斷」

| 任務 | 狀態 | 說明 |
|------|------|------|
| 測試資源過濾 | ✅ | 自動識別 test/demo/tmp 資源 |
| 分類規則優化 | ✅ | OOM/CrashLoop/ImagePull 各有對應診斷 |
| 診斷指令提供 | ✅ | 每個規則包含 kubectl 診斷命令 |
| 人工標記機制 | ✅ | 未知問題標記 `human_review_required` |
| LLM 上下文整合 | ✅ | Expert 診斷傳遞給 LLM |

**已修改檔案**:
- `apps/api/src/services/decision_manager.py`
- `apps/api/src/services/openclaw.py`

---

### Phase 2: 資料收集強化 (2-3 週)

**目標**: 收集更多診斷資料，提供更精確的根因分析

#### 2.1 K8s Events 整合

```python
# 新增 apps/api/src/services/k8s_diagnostics.py

class K8sDiagnosticsService:
    """K8s 診斷資料收集"""

    async def get_pod_events(
        self,
        pod_name: str,
        namespace: str = "awoooi-prod",
        limit: int = 20,
    ) -> list[K8sEvent]:
        """取得 Pod 相關 Events"""
        ...

    async def get_pod_logs(
        self,
        pod_name: str,
        namespace: str = "awoooi-prod",
        tail_lines: int = 100,
        previous: bool = False,
    ) -> str:
        """取得 Pod 日誌"""
        ...

    async def get_resource_usage(
        self,
        pod_name: str,
        namespace: str = "awoooi-prod",
    ) -> ResourceUsage:
        """取得 CPU/Memory 使用量"""
        ...
```

#### 2.2 SignOz 深度整合

```python
# 擴展 apps/api/src/services/signoz_client.py

class SignOzClient:
    async def get_error_traces(
        self,
        service_name: str,
        time_range_minutes: int = 10,
        limit: int = 5,
    ) -> list[TraceInfo]:
        """取得錯誤 Trace 詳情"""
        ...

    async def get_anomaly_detection(
        self,
        service_name: str,
        metric: str,  # rps, error_rate, p99_latency
    ) -> AnomalyResult:
        """異常偵測 (基於歷史基線)"""
        ...
```

#### 2.3 診斷資料聚合

```python
# 新增 apps/api/src/services/diagnosis_aggregator.py

@dataclass
class DiagnosisContext:
    """完整診斷上下文"""
    incident: Incident

    # K8s 資料
    k8s_events: list[K8sEvent]
    pod_logs: str
    resource_usage: ResourceUsage

    # SignOz 資料
    gold_metrics: GoldMetrics
    error_traces: list[TraceInfo]
    anomaly_result: AnomalyResult | None

    # Expert 初步診斷
    expert_classification: str
    expert_diagnosis: str
    suggested_commands: list[str]

    # Playbook 匹配
    matched_playbooks: list[PlaybookMatch]

class DiagnosisAggregator:
    """診斷資料聚合器"""

    async def collect_diagnosis_context(
        self,
        incident: Incident,
    ) -> DiagnosisContext:
        """並行收集所有診斷資料"""
        async with asyncio.TaskGroup() as tg:
            k8s_task = tg.create_task(self._collect_k8s_data(incident))
            signoz_task = tg.create_task(self._collect_signoz_data(incident))
            expert_task = tg.create_task(self._run_expert_diagnosis(incident))
            playbook_task = tg.create_task(self._match_playbooks(incident))

        return DiagnosisContext(
            incident=incident,
            k8s_events=k8s_task.result().events,
            pod_logs=k8s_task.result().logs,
            resource_usage=k8s_task.result().usage,
            gold_metrics=signoz_task.result().metrics,
            error_traces=signoz_task.result().traces,
            anomaly_result=signoz_task.result().anomaly,
            expert_classification=expert_task.result().classification,
            expert_diagnosis=expert_task.result().diagnosis,
            suggested_commands=expert_task.result().commands,
            matched_playbooks=playbook_task.result(),
        )
```

**預計修改檔案**:
- 新增 `apps/api/src/services/k8s_diagnostics.py`
- 新增 `apps/api/src/services/diagnosis_aggregator.py`
- 修改 `apps/api/src/services/signoz_client.py`
- 修改 `apps/api/src/services/decision_manager.py`

---

### Phase 3: Playbook 向量化 + RAG (3-4 週)

**目標**: 使用向量資料庫儲存 Playbook，實現語意搜尋

#### 3.1 向量化架構

```
┌─────────────────────────────────────────────────────────────┐
│                   Playbook RAG System                        │
│                                                              │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐  │
│  │ Embedding    │    │ Vector Store │    │ Retriever    │  │
│  │ (Ollama)     │───▶│ (Redis)      │◀───│              │  │
│  │              │    │              │    │              │  │
│  │ - Playbook   │    │ - Index      │    │ - Top-K      │  │
│  │ - Incident   │    │ - Search     │    │ - Similarity │  │
│  └──────────────┘    └──────────────┘    └──────────────┘  │
└─────────────────────────────────────────────────────────────┘
```

#### 3.2 實作細節

```python
# 新增 apps/api/src/services/playbook_rag.py

class PlaybookRAGService:
    """Playbook RAG 服務"""

    def __init__(self):
        # Redis Vector Search (已有 192.168.0.188:6380)
        self.redis = Redis(host="192.168.0.188", port=6380)
        self.embedding_model = "nomic-embed-text"  # Ollama 本地

    async def embed_playbook(
        self,
        playbook: Playbook,
    ) -> list[float]:
        """將 Playbook 向量化"""
        text = f"""
        症狀: {playbook.symptom_pattern.to_text()}
        修復步驟: {playbook.repair_steps_text}
        """
        return await self._get_embedding(text)

    async def search_similar(
        self,
        incident: Incident,
        top_k: int = 5,
        min_similarity: float = 0.75,
    ) -> list[PlaybookMatch]:
        """語意搜尋相似 Playbook"""
        query_text = f"""
        告警: {incident.signals_summary}
        影響服務: {incident.affected_services}
        """
        query_vec = await self._get_embedding(query_text)

        # Redis Vector Search
        results = await self.redis.ft("playbook_idx").search(
            Query(f"*=>[KNN {top_k} @embedding $vec AS score]")
            .return_fields("playbook_id", "score")
            .dialect(2),
            query_params={"vec": query_vec},
        )

        return [
            PlaybookMatch(
                playbook_id=r.playbook_id,
                similarity=1 - float(r.score),  # 距離轉相似度
            )
            for r in results.docs
            if 1 - float(r.score) >= min_similarity
        ]
```

**預計修改檔案**:
- 新增 `apps/api/src/services/playbook_rag.py`
- 修改 `apps/api/src/services/playbook_service.py`
- 修改 `k8s/awoooi-prod/04-configmap.yaml` (新增向量索引配置)

---

### Phase 4: 自動執行機制 (2-3 週)

**目標**: 低風險操作自動執行，無需人工審核

#### 4.1 自動執行條件

```python
# 擴展 apps/api/src/services/trust_engine.py

class AutoApprovePolicy:
    """自動執行策略"""

    # 自動執行條件 (全部滿足才放行)
    MIN_TRUST_SCORE = 0.90        # 信任度 >= 90%
    MIN_PLAYBOOK_SUCCESS = 0.95   # Playbook 成功率 >= 95%
    MIN_PLAYBOOK_COUNT = 3        # Playbook 成功次數 >= 3
    ALLOWED_RISK_LEVELS = ["low"] # 只有 LOW 風險可自動

    @classmethod
    def should_auto_approve(
        cls,
        proposal: ProposalData,
        playbook_match: PlaybookMatch | None,
        trust_score: float,
    ) -> tuple[bool, str]:
        """判斷是否自動執行"""

        # 條件 1: 風險等級
        if proposal.risk_level not in cls.ALLOWED_RISK_LEVELS:
            return False, f"風險等級 {proposal.risk_level} 不允許自動執行"

        # 條件 2: 信任度
        if trust_score < cls.MIN_TRUST_SCORE:
            return False, f"信任度 {trust_score:.0%} 低於閾值"

        # 條件 3: Playbook 匹配
        if playbook_match:
            if playbook_match.success_rate < cls.MIN_PLAYBOOK_SUCCESS:
                return False, f"Playbook 成功率 {playbook_match.success_rate:.0%} 低於閾值"
            if playbook_match.success_count < cls.MIN_PLAYBOOK_COUNT:
                return False, f"Playbook 成功次數 {playbook_match.success_count} 低於閾值"
            return True, "Playbook 匹配，符合自動執行條件"

        return False, "無匹配 Playbook，需人工審核"
```

#### 4.2 自動執行流程

```python
# 擴展 apps/api/src/services/approval_service.py

class ApprovalService:
    async def process_proposal(
        self,
        incident: Incident,
        proposal: ProposalData,
    ) -> ApprovalRequest:
        """處理提案，決定是否自動執行"""

        # 取得 Playbook 匹配和信任度
        playbook_match = await self._playbook_service.get_best_match(incident)
        trust_score = await self._trust_engine.calculate_trust(
            incident=incident,
            proposal=proposal,
            playbook_match=playbook_match,
        )

        # 判斷是否自動執行
        should_auto, reason = AutoApprovePolicy.should_auto_approve(
            proposal=proposal,
            playbook_match=playbook_match,
            trust_score=trust_score,
        )

        if should_auto:
            # 自動建立已簽核的 Approval
            approval = await self._create_approval(
                incident=incident,
                proposal=proposal,
                status=ApprovalStatus.APPROVED,
                signature_source=SignatureSource.SYSTEM,
                auto_approved_reason=reason,
            )

            # 自動執行
            await self._execution_service.execute_approved_action(approval)

            # 記錄自動執行
            logger.info(
                "auto_approved_execution",
                incident_id=incident.incident_id,
                reason=reason,
                trust_score=trust_score,
            )

            return approval

        # 需人工審核
        return await self._create_approval(
            incident=incident,
            proposal=proposal,
            status=ApprovalStatus.PENDING,
            needs_human_review=True,
            auto_reject_reason=reason,
        )
```

**預計修改檔案**:
- 修改 `apps/api/src/services/trust_engine.py`
- 修改 `apps/api/src/services/approval_service.py`
- 修改 `apps/api/src/services/proposal_service.py`

---

### Phase 5: 持續學習迴圈 (2-3 週)

**目標**: 從執行結果中學習，持續優化決策

#### 5.1 反饋處理流程

```python
# 新增 apps/api/src/services/learning_service.py

class LearningService:
    """持續學習服務"""

    async def process_execution_result(
        self,
        approval: ApprovalRecord,
        result: ExecutionResult,
    ):
        """處理執行結果，觸發學習"""

        # 1. 更新 Playbook 統計
        if approval.matched_playbook_id:
            await self._update_playbook_stats(
                playbook_id=approval.matched_playbook_id,
                success=result.success,
            )

        # 2. 調整信任度
        await self._adjust_trust_score(
            incident_type=approval.incident_type,
            action_type=approval.action_type,
            success=result.success,
        )

        # 3. 萃取新 Playbook (成功案例)
        if result.success and not approval.matched_playbook_id:
            await self._try_extract_playbook(approval)

    async def process_human_feedback(
        self,
        incident_id: str,
        feedback: FeedbackRequest,
    ):
        """處理人工反饋"""

        # 1. 更新 Playbook 有效性
        if feedback.effectiveness_score >= 4:
            await self._promote_playbook_confidence(incident_id)
        elif feedback.effectiveness_score <= 2:
            await self._demote_playbook_confidence(incident_id)

        # 2. 記錄學習筆記 (未來用於 LLM fine-tuning)
        await self._store_learning_note(
            incident_id=incident_id,
            note=feedback.learning_notes,
        )
```

#### 5.2 信任度動態調整

```python
# 擴展 apps/api/src/services/trust_engine.py

class TrustEngine:
    # 信任度調整參數
    SUCCESS_BOOST = 0.02      # 成功 +2%
    FAILURE_PENALTY = 0.10    # 失敗 -10%
    HUMAN_OVERRIDE_PENALTY = 0.05  # 人工覆蓋 -5%

    async def adjust_trust(
        self,
        incident_type: str,
        action_type: str,
        success: bool,
        human_override: bool = False,
    ):
        """動態調整信任度"""
        key = f"trust:{incident_type}:{action_type}"
        current = await self._get_trust(key)

        if human_override:
            # 人工覆蓋 AI 決策，降低信任度
            new_trust = max(0.0, current - self.HUMAN_OVERRIDE_PENALTY)
        elif success:
            # 執行成功，提高信任度
            new_trust = min(1.0, current + self.SUCCESS_BOOST)
        else:
            # 執行失敗，降低信任度
            new_trust = max(0.0, current - self.FAILURE_PENALTY)

        await self._set_trust(key, new_trust)

        logger.info(
            "trust_adjusted",
            incident_type=incident_type,
            action_type=action_type,
            old_trust=current,
            new_trust=new_trust,
            reason="success" if success else "failure",
        )
```

**預計修改檔案**:
- 新增 `apps/api/src/services/learning_service.py`
- 修改 `apps/api/src/services/trust_engine.py`
- 修改 `apps/api/src/services/approval_execution.py`

#### 5.3 Playbook 自動狀態轉換 (2026-03-30 補充)

> **實作位置**: `apps/api/src/repositories/playbook_repository.py:adjust_confidence()`

| 狀態轉換 | 觸發條件 | 說明 |
|---------|---------|------|
| **DRAFT → APPROVED** | `confidence >= 0.9` | 高信心度自動升級 |
| **任意 → DEPRECATED** | `confidence < 0.3` + `failure_rate > 50%` + `executions >= 5` | 低效 Playbook 自動棄用 |

```python
# Playbook 信心度調整常數
CONFIDENCE_PROMOTE_THRESHOLD = 0.9   # 自動升級閾值
CONFIDENCE_DEPRECATE_THRESHOLD = 0.3 # 自動棄用閾值
FAILURE_RATE_THRESHOLD = 0.5         # 失敗率閾值
MIN_EXECUTIONS_FOR_DEPRECATE = 5     # 最小執行次數

# Learning Service 信心度調整
PROMOTE_DELTA = +0.1   # 高評分 (>=4) +10%
DEMOTE_DELTA = -0.15   # 低評分 (<=2) -15%
```

---

## 四、架構相容性分析

### 4.1 與現有架構的整合點

| 現有元件 | 整合方式 | 衝突風險 |
|---------|----------|----------|
| `decision_manager.py` | 擴展 `_dual_engine_analyze()` | 低 - 加法修改 |
| `openclaw.py` | 新增 `expert_context` 參數 | 低 - 向下相容 |
| `signoz_client.py` | 擴展新方法 | 低 - 加法修改 |
| `playbook_service.py` | 加入 RAG 整合 | 中 - 需重構 |
| `trust_engine.py` | 加入動態調整 | 中 - 需重構 |
| `approval_service.py` | 加入自動執行 | 高 - 核心流程變更 |
| `executor.py` | 無需修改 | 無 |

### 4.2 需要調整的介面

```python
# 1. IDecisionManager 需擴展
class IDecisionManager(Protocol):
    async def get_or_create_decision(
        self,
        incident: Incident,
        timeout_sec: float = 30.0,
        diagnosis_context: DiagnosisContext | None = None,  # 新增
    ) -> DecisionToken:
        ...

# 2. ProposalService 需擴展
class IProposalService(Protocol):
    async def generate_proposal(
        self,
        incident: Incident,
        diagnosis_context: DiagnosisContext | None = None,  # 新增
        playbook_match: PlaybookMatch | None = None,  # 新增
    ) -> ProposalData:
        ...

# 3. ApprovalService 需擴展
class IApprovalService(Protocol):
    async def create_approval(
        self,
        incident: Incident,
        proposal: ProposalData,
        auto_approve: bool = False,  # 新增
    ) -> ApprovalRequest:
        ...
```

### 4.3 資料庫 Schema 變更

```sql
-- 新增欄位到 approval_records
ALTER TABLE approval_records ADD COLUMN IF NOT EXISTS
    auto_approved BOOLEAN DEFAULT FALSE;
ALTER TABLE approval_records ADD COLUMN IF NOT EXISTS
    auto_approved_reason TEXT;
ALTER TABLE approval_records ADD COLUMN IF NOT EXISTS
    matched_playbook_id UUID REFERENCES playbooks(id);
ALTER TABLE approval_records ADD COLUMN IF NOT EXISTS
    trust_score FLOAT;

-- 新增表: trust_scores (信任度追蹤)
CREATE TABLE IF NOT EXISTS trust_scores (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    incident_type VARCHAR(100) NOT NULL,
    action_type VARCHAR(100) NOT NULL,
    trust_score FLOAT NOT NULL DEFAULT 0.5,
    success_count INT DEFAULT 0,
    failure_count INT DEFAULT 0,
    last_updated_at TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(incident_type, action_type)
);

-- 新增表: learning_notes (學習筆記)
CREATE TABLE IF NOT EXISTS learning_notes (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    incident_id VARCHAR(100) NOT NULL,
    note TEXT NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW()
);
```

---

## 五、風險評估與緩解

### 5.1 技術風險

| 風險 | 影響 | 緩解措施 |
|------|------|----------|
| 自動執行出錯 | 服務中斷 | Shadow Mode 先行、Dry-Run 驗證 |
| 信任度計算錯誤 | 該自動的沒自動 | 保守閾值 (90%)、人工複查 |
| Playbook 匹配錯誤 | 執行錯誤修復 | 最低相似度閾值 (85%) |
| 學習迴圈偏差 | 錯誤累積 | 定期人工審查、信任度上限 |

### 5.2 回滾計畫

```yaml
# 每個 Phase 都可以獨立回滾

Phase 1 回滾:
  - git revert 相關 commit
  - 恢復舊版 EXPERT_RULES

Phase 2 回滾:
  - 停用 K8sDiagnosticsService
  - decision_manager 使用舊流程

Phase 3 回滾:
  - 停用 PlaybookRAGService
  - playbook_service 使用傳統匹配

Phase 4 回滾:
  - AUTO_APPROVE_ENABLED=false
  - 所有請求走人工審核

Phase 5 回滾:
  - 停用 LearningService
  - 信任度凍結當前值
```

---

## 六、驗收標準

### Phase 1 (已完成)
- [x] Expert System 不再盲目重啟
- [x] 測試資源自動識別
- [x] 診斷指令包含在回應中
- [x] LLM 收到 Expert 上下文

### Phase 2
- [ ] K8s Events 整合到診斷流程
- [ ] Pod 日誌自動擷取
- [ ] SignOz 異常偵測功能

### Phase 3
- [ ] Playbook 向量化完成
- [ ] RAG 搜尋正確率 > 85%
- [ ] 查詢延遲 < 100ms

### Phase 4
- [ ] 自動執行功能上線
- [ ] 低風險操作自動通過率 > 30%
- [ ] 零誤執行 (連續 7 天)

### Phase 5
- [ ] 信任度動態調整正常
- [ ] Playbook 成功率持續提升
- [ ] 學習迴圈運作正常

---

## 七、時程總覽

```
2026-03-27 ──────────────────────────────────────────────▶ 2026-05-15

Phase 1: 智能診斷基礎 [██████████] 100% ✅ 已完成
         ├─ Expert System 重構
         └─ LLM 上下文整合

Phase 2: 資料收集強化 [░░░░░░░░░░] 0%   (2-3 週)
         ├─ K8s Events 整合
         ├─ SignOz 深度整合
         └─ 診斷資料聚合

Phase 3: Playbook RAG  [░░░░░░░░░░] 0%   (3-4 週)
         ├─ 向量化架構
         ├─ Redis Vector Search
         └─ 語意搜尋

Phase 4: 自動執行機制 [░░░░░░░░░░] 0%   (2-3 週)
         ├─ 自動執行策略
         ├─ 信任度評估
         └─ 安全防護

Phase 5: 持續學習     [░░░░░░░░░░] 0%   (2-3 週)
         ├─ 反饋處理
         ├─ 信任度調整
         └─ Playbook 萃取
```

**總預估時間**: 10-15 週 (含測試驗證)

---

## 7.1 Phase 6: 非同步分析優化 (2026-03-27 新增)

> **觸發**: LLM 分析 (llama3.2:3b CPU) 需 2-3 分鐘，導致告警回應延遲

### 問題分析

| 現狀 | 影響 | 根因 |
|------|------|------|
| LLM 同步等待 2-3 分鐘 | 告警回應延遲 | Ollama 純 CPU 模式 |
| 超時後 Fallback Expert System | 用戶只看到 75% 信心度 | 超時設定不合理 |
| 等待期間 API 阻塞 | 批量告警處理緩慢 | 非非同步設計 |

### 解決方案

```
優化前:
  告警 → 等 LLM (2-3分鐘) → 發 Telegram
         ↑_____________↑
           阻塞等待

優化後:
  告警 → Expert System 立即發 (75%) → Telegram
           ↓
         背景 LLM 分析 (2-3分鐘)
           ↓
         edit_message 更新 Telegram (90%+)
```

### 實作細節

```python
# decision_manager.py 修改

async def get_or_create_decision(
    incident: Incident,
    timeout_sec: float = 180.0,  # 已修改
) -> DecisionToken:
    # Phase 6 優化: 非同步雙軌

    # Step 1: Expert System 立即返回
    expert_result = await self._expert_analyze(incident)
    await _push_decision_to_telegram(incident, expert_result)

    # Step 2: 背景啟動 LLM 分析
    asyncio.create_task(
        self._background_llm_analyze(incident, token)
    )

    return token

async def _background_llm_analyze(
    self,
    incident: Incident,
    token: DecisionToken,
) -> None:
    """背景 LLM 分析，完成後更新 Telegram"""
    try:
        llm_result = await self._llm_analyze(incident)

        # 更新 Token
        token.proposal_data = llm_result
        await self._save_token(token)

        # 更新 Telegram 訊息
        await self._update_telegram_message(incident, llm_result)
    except Exception as e:
        logger.warning("background_llm_failed", error=str(e))
```

### 驗收標準

- [ ] Expert System 告警回應 < 5 秒
- [ ] LLM 結果 2-3 分鐘後更新 Telegram
- [ ] 更新使用 `edit_message` 而非新發訊息
- [ ] 錯誤處理：LLM 失敗不影響已發送的 Expert 結果

### 依賴

- 需修改 `decision_manager.py` (Tier 3 紅區)
- 需擴展 `telegram_gateway.py` 支援 `edit_message`
- 需首席架構師簽核

### 狀態

| 項目 | 狀態 |
|------|------|
| 設計文件 | ✅ 完成 (本章節) |
| 首席架構師審查 | 🔴 待審 |
| 實作 | 🔴 待開始 |

---

## 7.5 Phase D-G P0 修正: Learning Repository Layer (2026-03-29)

### 背景

首席架構師審查發現原設計違反 leWOOOgo 積木化原則:
- Service 直接依賴 Redis Client
- 未遵循 Repository Pattern

### 修正內容

#### 1. 新增 ILearningRepository Interface

```python
# src/repositories/interfaces.py
@runtime_checkable
class ILearningRepository(Protocol):
    async def record_repair(...) -> bool
    async def get_repair_stats(...) -> dict
    async def get_all_repair_stats(...) -> dict[str, dict]
    async def get_repair_history(...) -> list[dict]
    async def get_learning_summary(...) -> dict
```

#### 2. 新增 LearningRepository 實作

```python
# src/repositories/learning_repository.py
class LearningRepository:
    """Redis 持久化層 - 學習數據存取"""

    # Redis Key 結構:
    # - learning:repair:{anomaly_key}:{action} -> List[JSON]
    # - learning:stats:{anomaly_key}:{action} -> Hash
```

#### 3. 擴展 LearningService

```python
# src/services/learning_service.py
class LearningService:
    def __init__(self, repository: ILearningRepository | None = None):
        self._repository = repository or get_learning_repository()

    # 新增方法
    async def record_repair_result(...)    # 記錄修復結果
    async def get_recommended_fix(...)     # 修復推薦
    async def get_learning_summary(...)    # 學習摘要
```

#### 4. 新增 Learning API

```
GET /api/v1/learning/summary/{anomaly_key}
GET /api/v1/learning/recommendation/{anomaly_key}
```

### 架構圖

```
┌───────────────────────────────────────────────────────────┐
│ API Layer (Router)                                         │
│ src/api/v1/learning.py                                    │
│ - 只做 HTTP 轉發，不含業務邏輯                              │
└─────────────────────────┬─────────────────────────────────┘
                          │
┌─────────────────────────▼─────────────────────────────────┐
│ Service Layer                                              │
│ src/services/learning_service.py                          │
│ - 業務邏輯編排                                              │
│ - 透過 Interface 依賴 Repository                           │
└─────────────────────────┬─────────────────────────────────┘
                          │ ILearningRepository
┌─────────────────────────▼─────────────────────────────────┐
│ Repository Layer                                           │
│ src/repositories/learning_repository.py                   │
│ - Redis 資料存取                                           │
│ - 90 天 TTL 持久化                                         │
└───────────────────────────────────────────────────────────┘
```

### 符合原則

| 原則 | 狀態 |
|------|------|
| Service 不直接存取 Redis | ✅ 透過 Repository |
| Interface 先行 | ✅ ILearningRepository Protocol |
| 依賴注入 | ✅ 可注入測試 Repository |
| Router 薄層 | ✅ 只做 HTTP 轉發 |

---

## 八、結論

本方案提供了一個**完整的智能自動修復系統**，從「盲目重啟」進化到「根因診斷 + 智能決策 + 持續學習」。

**核心理念**:
1. **診斷優先**: 先了解問題，再決定行動
2. **漸進信任**: 從人工審核逐步過渡到自動執行
3. **持續學習**: 從每次執行結果中學習改進
4. **安全防護**: 多層防護確保不會誤操作

**與現有架構的相容性**:
- Phase 1-2: 純加法修改，風險極低
- Phase 3: 需要重構 Playbook 服務，風險中等
- Phase 4-5: 核心流程變更，需要嚴格測試

**建議**: 按 Phase 順序實施，每個 Phase 完成後驗證穩定性再進入下一階段。
---


## 九、2026-04-04 實作完成 (台北時間)

> **更新者**: Claude Code
> **Commit**: d0f0970, 72d7536, df3ef90

### 9.1 根本原因診斷 (19筆 PENDING 清查)

| 根因 | 說明 | 修復 |
|------|------|------|
| playbooks 表從未建立 | Playbook 庫空白，RAG 永遠無匹配 | phase7_playbooks_table.sql |
| Ollama embedding is_closed=True | 滾動重啟後 http_client 失效，vector_count:0 | _get_http_client() 偵測重建 |
| 9筆殭屍 PENDING (3/26) | mock_fallback CRITICAL 測試記錄 | 直接清除 |

### 9.2 完成項目

| 檔案 | 修改 | 說明 |
|------|------|------|
| `playbook_rag.py` | 新增 `_get_http_client()` | 偵測 is_closed 自動重建 HTTP client |
| `playbook_rag.py` | `embed_playbook()` Bug 修復 | `s.sequence`→`s.step_number`, `s.description`→`s.command` |
| `telegram_gateway.py` | 新增 `ai_model` 欄位 | format/format_with_nemotron 顯示底層模型 |
| `openclaw.py` | proposal_dict 加 `"model"` | 傳入底層模型名稱 |
| `decision_manager.py` | 讀取 `ai_model` 傳入 approval card | 決策路徑完整 |
| `migrations/phase7_playbooks_table.sql` | 新增 | playbooks 表，PRIMARY KEY + 5 GIN 索引 |
| `playbook_service.py` | `_write_to_km()` fire-and-forget | extract_from_incident() 後自動 KM 沉澱 |
| `playbook_service.py` | `_get_rag_service()` 改走工廠 | 每次重建，避免快取 is_closed client |
| `approval_execution.py` | `_write_execution_result_to_km()` | 移出 try/except，保證執行記錄寫入 KM |
| `approval_execution.py` | 冷啟動修復 | 執行成功自動設定 execution_success=True, effectiveness_score=4, status=RESOLVED |
| `approval_execution.py` | skip 路徑 debug→info | 可觀測性提升 |
| Ollama | 刪除 smollm2:135m | 0.3GB CPU 機器不需要的模型 |

### 9.3 首席架構師 Review 結果

| 評分 | 修復項目 | 說明 |
|------|----------|------|
| 初版 21/25 | — | 72d7536 |
| **Critical #1** | KM write task 移出 try/except | 保證無論 learning 成敗都寫 KM |
| **Important #1** | PlaybookService 快取繞過工廠 | 每次走工廠避免 is_closed |
| **Important #2** | Migration 缺 PRIMARY KEY | prod DB 已 ALTER TABLE 補齊 |
| **Important #3** | embed_playbook() s.sequence AttributeError | 修正欄位名稱靜默失敗 bug |
| 修復後 ~25/25 | **PASSED** | df3ef90 |

### 9.4 完整閉環

```
告警 → AI分析(OpenClaw/Nemotron) → 查Playbook(RAG語意搜尋)
→ 有匹配且LOW風險 → 自動執行
→ MEDIUM/CRITICAL → Telegram等人工批准
→ 執行成功
    → _trigger_playbook_extraction():
        自動設定 execution_success=True, effectiveness_score=4, status=RESOLVED
        → Playbook萃取 → 存Redis → KM沉澱(_write_to_km)
    → incident_service.resolve() → KM萃取(knowledge_extractor)
    → _trigger_learning() 後 → KM執行記錄(_write_execution_result_to_km)
→ 下次相似告警 → Playbook命中(RAG) → 加速決策
```

**狀態**: ✅ 閉環已通 (2026-04-04 台北時間)
