# 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 ' # 重啟後驗證 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 數據再調整。