# RUNBOOK-AGENT-STEP-LATENCY.md
# Agent Step Latency — 診斷與處置 Runbook
# 2026-04-27 Claude Sonnet 4.6: A3 — Agent step latency observability (config A+B Wave 1)
# 對應告警規則: ops/monitoring/grafana/agent_step_latency_rules.yaml

---

## 快速索引

| 告警 | 嚴重度 | 章節 |
|------|--------|------|
| `AgentStepLatencyHigh` | warning | [#agentsteplatencyhigh](#agentsteplatencyhigh) |
| `AgentStepTimeoutSpike` | critical | [#agentsteptimeoutspike](#agentsteptimeoutspike) |
| `DiagnoseFallbackToCloud` | warning | [#diagnosefallbacktocloud](#diagnosefallbacktocloud) |

---

## 系統背景

AWOOOI Phase 2 多 Agent 協作（ADR-082）由三個 agent 串行處理每個 Incident：

```
Incident 接收
    │
    ├─ [diagnostician] 診斷分析 — 主力 Provider: openclaw_nemo (NIM @ 192.168.0.188:8088)
    │                              timeout: 30s（A1 拆分後）
    │
    ├─ [solver] 決策建議       — 主力 Provider: openclaw_nemo
    │                              timeout: 20s
    │
    └─ [critic] 方案審核       — 主力 Provider: openclaw_nemo
                                  timeout: 15s
```

NIM（NVIDIA Inference Microservice）實測延遲：**2-27s**，平均 ~10.6s。  
尾巴 latency 若命中 timeout → agent 輸出 confidence=20%（degraded）→ 飛輪失能。

**根因案例**：INC-20260425-8D17BB / INC-20260425-3B6C39  
共用 `PHASE2_STEP_TIMEOUT_SEC=20.0s`，NIM 27s 尾巴 latency 命中 timeout，全部 Incident 落入「待分析」。

---

## 根因鏈

```mermaid
flowchart TD
    A[NIM GPU 高負載 / 網路抖動] --> B[step latency 尾巴 > 20-30s]
    B --> C[AgentStepLatencyHigh p75 > 25s]
    B --> D[agent timeout → confidence=20%]
    D --> E[AgentStepTimeoutSpike > 3/min]
    D --> F[DIAGNOSE fallback chain 啟動]
    F --> G[openclaw_nemo → gemini]
    G --> H[DiagnoseFallbackToCloud > 5/min]
    H --> I[Gemini 每日配額快速耗盡]
    I --> J[gemini → claude 第二段 fallback]
    J --> K[費用急升 / 飛輪完全失能]

    style A fill:#ff6b6b,color:#fff
    style K fill:#ff6b6b,color:#fff
    style C fill:#ffd93d,color:#000
    style E fill:#ff6b6b,color:#fff
    style H fill:#ffd93d,color:#000
```

---

## AgentStepLatencyHigh

### 告警含義

| 欄位 | 值 |
|------|----|
| 觸發條件 | 任意 agent 的 p75 step latency > 25s，持續 10 分鐘 |
| 嚴重度 | warning |
| 代表什麼 | NIM 推理尾巴偏慢，尚未 timeout，但趨勢惡化 |
| 不代表什麼 | agent 還在正常運作，只是變慢 |

### 立即診斷（3 步）

**步驟 1：看哪個 agent 卡**

在 Grafana 查 (Prometheus 地址: `http://192.168.0.110:9090`)：

```promql
histogram_quantile(
  0.75,
  sum by (agent, le) (
    rate(aiops_agent_step_duration_seconds_bucket[5m])
  )
)
```

看各 agent 的 p75 值，確認哪個 agent 最慢。

也可看 p95 了解最壞情況：

```promql
histogram_quantile(
  0.95,
  sum by (agent, le) (
    rate(aiops_agent_step_duration_seconds_bucket[5m])
  )
)
```

**步驟 2：看 NIM 健康度**

```bash
# 確認 NIM API 回應時間
curl -o /dev/null -s -w "%{time_total}s\n" http://192.168.0.188:8088/v1/models

# 確認 GPU 狀態
ssh wooo@192.168.0.188 'nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total,temperature.gpu --format=csv,noheader'
```

| GPU 指標 | 正常 | 警戒 |
|----------|------|------|
| GPU 使用率 | < 80% | > 90% |
| GPU 記憶體 | < 10GB | > 11GB |
| GPU 溫度 | < 80°C | > 85°C |

**步驟 3：看 provider 路由分布**

```promql
# 過去 5 分鐘各 provider 的呼叫比例
sum by (provider) (rate(ai_router_selected_provider_total[5m]))
```

若 `openclaw_nemo` 佔比大幅下降，代表 fallback 已在發生。

### 處置動作（3 步）

**動作 1：暫時調高 timeout 環境變數（緩解）**

若 NIM 只是暫時慢（< 1 小時），可調高 timeout 讓 agent 等更久：

```bash
# 確認目前設定
kubectl get deployment api -n awoooi-prod -o jsonpath='{.spec.template.spec.containers[0].env}' | python3 -m json.tool | grep -i timeout

# 暫時調高（需統帥授權才能改 ConfigMap）
# 正常路徑：修改 k8s/awoooi-prod/04-configmap.yaml 中的 PHASE2_STEP_TIMEOUT_SEC
# 緊急路徑：kubectl set env deployment/api -n awoooi-prod PHASE2_STEP_TIMEOUT_SEC=35
```

> ⚠️ 調高 timeout 不是根治，只是緩解。timeout 太長會讓 Incident 積壓。

**動作 2：確認 NIM 是否需要重啟**

```bash
# 檢查 NIM 服務狀態
ssh wooo@192.168.0.188 'docker ps --filter name=nim --format "{{.Status}}"'

# 若 NIM 容器 unhealthy，重啟（須確認無其他 session 在使用）
ssh wooo@192.168.0.188 'docker restart <nim_container_name>'

# 重啟後驗證
curl -s http://192.168.0.188:8088/v1/models | python3 -m json.tool
```

**動作 3：升級統帥**

若 NIM 重啟無效且 latency 仍高，Telegram 通知統帥：
- NIM 位置：192.168.0.188:8088
- 目前 p75：[從 Grafana 截圖]
- 影響範圍：diagnostician/solver/critic 全部變慢
- 建議：調查 GPU 硬體問題或考慮暫時切主力 provider 至 Gemini

---

## AgentStepTimeoutSpike

### 告警含義

| 欄位 | 值 |
|------|----|
| 觸發條件 | 任意 agent timeout 速率 > 3/min，持續 5 分鐘 |
| 嚴重度 | critical |
| 代表什麼 | agent 已進入 degraded 模式（confidence=20%），飛輪失能 |
| 影響 | Incident 全部落入「待分析」，自動修復停擺 |

### 立即診斷（3 步）

**步驟 1：確認哪個 agent 在 timeout**

```promql
# 各 agent timeout 速率（/min）
sum by (agent) (
  rate(aiops_agent_step_duration_seconds_count{outcome="timeout"}[5m])
) * 60
```

**步驟 2：確認 NIM 是否已觸發 fallback**

```promql
# NEMO → Gemini fallback 速率（/min）
rate(
  aiops_diagnose_fallback_total{from_provider="openclaw_nemo", to_provider="gemini"}[5m]
) * 60
```

若 fallback > 0，代表 AI Router 已在切換，Gemini 正在被消耗。

**步驟 3：確認飛輪狀態**

```bash
# 確認積壓的 Incident
curl -s http://192.168.0.188:8088/api/v1/incidents?status=investigating | python3 -m json.tool | grep -c '"id"'

# 查 API log 確認 degraded 訊號
kubectl logs -n awoooi-prod deploy/api --tail=50 | grep -E "degraded|confidence=0.2|timeout"
```

### 處置動作（3 步）

**動作 1：立即確認 NIM 是否可用**

```bash
time curl -s -X POST http://192.168.0.188:8088/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"meta/llama-3.1-8b-instruct","messages":[{"role":"user","content":"ping"}],"max_tokens":10}'
```

若回應 > 30s 或 timeout：NIM 已無法使用。進行動作 2。

**動作 2：強制切換主力 Provider（緊急）**

AI Router 的 DIAGNOSE intent 已有 fallback chain（NEMO→GEMINI→CLAUDE）。  
若需要完全跳過 NIM 嘗試，可暫時覆寫 intent override：

```bash
# 緊急設定：跳過 NEMO，直接走 GEMINI（需統帥授權）
kubectl set env deployment/api -n awoooi-prod \
  DIAGNOSE_FORCE_PROVIDER=gemini \
  -n awoooi-prod
```

> ⚠️ 此環境變數需 A2 代碼支援，確認 ai_router.py 是否有讀取此設定。
> 若無，請人工協調 SRE 直接修改 ConfigMap。

**動作 3：升級統帥（必須）**

critical 告警必須在 15 分鐘內升級：
- 告警觸發時間：[從 Telegram 告警中取得]
- 受影響 agent：[從步驟 1 的 Grafana 截圖]
- 積壓 Incident 數：[從步驟 3 取得]
- NIM 狀態：[可用/timeout/離線]

---

## DiagnoseFallbackToCloud

### 告警含義

| 欄位 | 值 |
|------|----|
| 觸發條件 | NEMO→Gemini fallback > 5/min，持續 5 分鐘 |
| 嚴重度 | warning |
| 代表什麼 | NIM 無法服務，Gemini 正在消耗每日配額 |
| 風險 | Gemini 配額耗盡後 fallback 到 Claude（費用更高），或完全失敗 |

### 立即診斷（3 步）

**步驟 1：查目前 fallback 速率與累積數**

```promql
# 當前 fallback 速率（/min）
rate(
  aiops_diagnose_fallback_total{from_provider="openclaw_nemo", to_provider="gemini"}[5m]
) * 60

# 今日累積 fallback 次數（Counter 累積值）
aiops_diagnose_fallback_total{from_provider="openclaw_nemo", to_provider="gemini"}
```

**步驟 2：查 NIM 健康度**

同 `AgentStepLatencyHigh` 步驟 2（`nvidia-smi` + NIM API 回應測試）。

**步驟 3：確認 Gemini 今日配額剩餘**

```promql
# Gemini 配額使用率
gemini_daily_call_count / gemini_daily_quota
```

若比率 > 0.8：`GeminiQuotaApproaching` 告警即將觸發，需立即決定是否限流。

### 處置動作（3 步）

**動作 1：確認 fallback 是否必要（NIM 真的掛了？）**

```bash
# 快速健康測試
curl -s --max-time 5 http://192.168.0.188:8088/v1/models
```

若 NIM 可用（回應 < 5s）：可能是短暫抖動，觀察 5 分鐘是否自動恢復。  
若 NIM 不可用：fallback 是正確行為，轉入動作 2 管理配額。

**動作 2：估算 Gemini 配額剩餘時間**

```
剩餘配額 = gemini_daily_quota - gemini_daily_call_count（從 Prometheus 讀取）
當前消耗速率 = 從 DiagnoseFallbackToCloud 告警值（/min）
預估耗盡時間 = 剩餘配額 / 當前速率（分鐘）
```

若預估耗盡時間 < 2 小時：升級統帥，考慮暫停部分 Incident 自動處理。

**動作 3：升級統帥（若配額不足）**

提供以下資訊：
- Gemini 配額使用率：[從 Prometheus 讀取]
- 預估耗盡時間：[計算結果]
- NIM 狀態：[離線/慢速/已恢復]
- 建議：修復 NIM 或增加 Gemini 配額

---

## 根因案例參照

### INC-20260425-8D17BB

**症狀**：Diagnostician 信心持續降至 20%，所有 Incident 輸出「待分析」。  
**根因**：`PHASE2_STEP_TIMEOUT_SEC=20s` 共用三段 agent，NIM 尾巴 latency 27s 命中 timeout。  
**修復**：A1 拆分三段獨立 timeout（diagnostician=30s / solver=20s / critic=15s）。  
**教訓**：不同 agent 的工作量不同，不應共用同一個 timeout 值。

### INC-20260425-3B6C39

**症狀**：DIAGNOSE fallback 到 Ollama（CPU-only），造成 238s 二次 timeout。  
**根因**：AI Router fallback chain 含 Ollama，Ollama CPU 推理 238s 完全不可用。  
**修復**：A2 將 Ollama 永久移出 `_diagnose_fallback_chain`（NEMO→GEMINI→CLAUDE）。  
**教訓**：fallback chain 的每個節點必須有實測延遲數據，不能假設可用。

---

## 待校準項目

> 以下門檻在 A1/A2 上線後，應根據實際 metric 重新校準。  
> 目前使用 INC-20260425 實測數據（NIM 2-27s）估算。

| 告警 | 目前門檻 | 校準方式 |
|------|----------|----------|
| `AgentStepLatencyHigh` | p75 > 25s | 觀察 7d p75 基線，設為基線 × 1.5 |
| `AgentStepTimeoutSpike` | > 3/min | 觀察正常日的 timeout 率，應接近 0 |
| `DiagnoseFallbackToCloud` | > 5/min | 觀察 NIM 重啟時的 spike 幅度，設為 spike 的 30% |

校準時機：A1+A2 上線後，收集 **7 天**的 metric 數據再調整。
