# Skill 08: Model Router Expert

> 版本: v1.1
> 建立: 2026-03-26 (台北時區)
> 更新: 2026-03-29 (加入 NVIDIA Nemotron 整合)
> 管轄: Phase 13.3 智能路由、複雜度評估、意圖分類、Tool Calling 路由

---

## 觸發條件

修改以下檔案時自動載入:
- `services/*router*.py`
- `services/complexity*.py`
- `services/intent*.py`
- `models.json`

---

## 核心職責

### 1. 意圖分類 (Intent Classifier)

```
四大意圖類別:
┌─────────────┬─────────────────────────────────┐
│ RESTART     │ 重啟 Pod/Deployment/StatefulSet │
│ SCALE       │ 擴縮容、HPA 調整                │
│ CONFIG      │ ConfigMap/Secret/ENV 變更       │
│ DIAGNOSE    │ 日誌查詢、健康檢查、RCA         │
└─────────────┴─────────────────────────────────┘

目標延遲: < 100ms (使用 qwen2.5:1b 或規則引擎)
```

### 2. 複雜度評分 (Complexity Scorer)

```
1-5 分級:
┌───┬──────────────────────────────────────────┐
│ 1 │ 單一資源、無狀態、可立即回滾             │
│ 2 │ 多資源但同命名空間、低風險               │
│ 3 │ 跨命名空間、需要上下文收集               │
│ 4 │ 有狀態資源、需要 Multi-Sig               │
│ 5 │ 跨叢集、資料庫操作、需要人工審核         │
└───┴──────────────────────────────────────────┘
```

### 3. AI Router 決策邏輯

```python
def select_provider(complexity: int, intent: str) -> str:
    """
    動態選擇 AI Provider

    決策矩陣:
    ┌───────────┬─────────────────────────────┐
    │ 複雜度 1-2│ Ollama (qwen2.5:7b)         │
    │ 複雜度 3  │ Ollama → Gemini fallback    │
    │ 複雜度 4-5│ Gemini → Claude fallback    │
    └───────────┴─────────────────────────────┘

    🆕 Tool Calling 規則 (ADR-036):
    ┌───────────┬─────────────────────────────┐
    │ Tool Call │ Nemotron (精準度 83%)       │
    │ Fallback  │ Gemini → Claude → 拒絕      │
    └───────────┴─────────────────────────────┘

    例外規則:
    - DIAGNOSE 意圖: 優先 Ollama (本地日誌，隱私)
    - TOOL_CALLING: 優先 Nemotron (精準度高) 🆕
    - 高峰時段: 考慮 Gemini (避免 Ollama 排隊)
    """
```

---

## 配置集中管理

### 單一事實來源: `models.json`

```json
{
  "providers": {
    "ollama": {
      "models": {
        "default": "qwen2.5:7b-instruct",
        "fast": "llama3.2:3b",
        "intent": "qwen2.5:1b"
      },
      "circuit_breaker": {
        "failure_threshold": 3,
        "recovery_timeout": 60
      }
    }
  },
  "complexity_routing": {
    "1-2": "ollama",
    "3": ["ollama", "gemini"],
    "4-5": ["gemini", "claude"]
  }
}
```

### 禁止 Hardcode

```python
# ❌ 禁止
model = "qwen2.5:7b-instruct"

# ✅ 正確
model = model_registry.get_model("ollama", "default")
```

---

## Token 用量監控

### SignOz Dashboard

```
關鍵指標:
- llm.tokens.input: 輸入 Token 數
- llm.tokens.output: 輸出 Token 數
- llm.cost.usd: 估算成本 (Cloud Provider)
- llm.latency.p99: 延遲 P99
```

### 成本警報閾值

```yaml
alerts:
  - name: daily_token_budget
    threshold: 100000  # tokens/day
    action: switch_to_local
  - name: monthly_cost_budget
    threshold: 50  # USD
    action: notify_admin
```

---

## Fallback 策略 (ADR-006 v1.3 + ADR-036)

```
┌─────────────────────────────────────────────────┐
│           Intent Classifier (< 100ms)           │
└─────────────────────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────┐
│           Complexity Scorer                     │
└─────────────────────────────────────────────────┘
                      │
           ┌─────────┴─────────┐
           │                   │
    Tool Calling?          General Chat
           │                   │
           ▼                   ▼
┌─────────────────────┐ ┌─────────────────────────┐
│ Nemotron (精準83%)  │ │       AI Router         │
│ → Gemini fallback   │ │  ┌─────────┐            │
│ → Claude fallback   │ │  │ Ollama  │→ Gemini   │
│ → 拒絕執行          │ │  │ (Local) │→ Claude   │
└─────────────────────┘ └─────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────┐
│           Langfuse 追蹤                         │
│  - trace.generation() 記錄每次呼叫              │
│  - trace.score() 記錄成功評分                   │
└─────────────────────────────────────────────────┘
```

---

## 測試要求

### 必須覆蓋的測試案例

```python
# test_model_router.py
def test_complexity_1_uses_ollama(): ...
def test_complexity_5_uses_claude(): ...
def test_ollama_timeout_fallback_to_gemini(): ...
def test_all_providers_fail_returns_mock(): ...
def test_intent_diagnose_prefers_local(): ...
def test_token_budget_exceeded_switches_provider(): ...

# test_nvidia_provider.py (2026-03-29 新增)
def test_tool_call_success(): ...
def test_high_risk_tool_detection(): ...
def test_router_tool_calling_uses_nvidia(): ...
def test_fallback_chain_nvidia_to_gemini(): ...
```

---

## NVIDIA Nemotron 整合 (ADR-036)

### NvidiaProvider 使用方式

```python
from src.services.nvidia_provider import get_nvidia_provider, create_tool_definition
from src.services.ai_router import get_ai_router

# 方法 1: 透過 AIRouter (推薦)
router = get_ai_router()
provider, model, fallback = router.route_tool_calling()
# provider = AIProvider.NVIDIA

# 方法 2: 直接使用 NvidiaProvider
provider = get_nvidia_provider()
result = await provider.tool_call(
    messages=[{"role": "user", "content": "重啟 awoooi-api pod"}],
    tools=[restart_tool],
)
```

### 高風險 Tool 保護 (HITL)

```python
HIGH_RISK_TOOLS = {
    "delete_pod", "delete_deployment", "delete_namespace",
    "scale_to_zero", "drain_node", "cordon_node"
}

# 自動檢測
if provider.is_high_risk_tool(tool_name):
    # 需要 Telegram 人工確認
    await request_approval(tool_name, args)
```

### 可觀測性

- OTEL: `_tracer.start_as_current_span("nvidia_tool_call")`
- Langfuse: `LangfuseTraceContext` + `generation()`
- Metrics: latency_ms, prompt_tokens, completion_tokens

---

---

## OpenClaw + Nemotron 協作路由 (ADR-044)

> **新增**: 2026-03-31 (首席架構師批准)

### 協作觸發路由

```
Incident 進入
    ↓
┌─────────────────────────────────────────┐
│ OpenClaw.generate_incident_proposal()   │
│ → 輸出: risk_level, reasoning           │
└─────────────────────────────────────────┘
    ↓
┌─────────────────────────────────────────┐
│ 風險等級判斷                             │
│ ├─ LOW → 跳過 Nemotron                  │
│ └─ MEDIUM/HIGH/CRITICAL → 觸發 Nemotron │
└─────────────────────────────────────────┘
    ↓ (if MEDIUM+)
┌─────────────────────────────────────────┐
│ Nemotron.tool_call()                    │
│ → 輸出: kubectl 指令 + 驗證狀態          │
└─────────────────────────────────────────┘
    ↓
┌─────────────────────────────────────────┐
│ 組合結果 → Telegram 卡片                 │
└─────────────────────────────────────────┘
```

### 路由決策表

| 場景 | Provider 1 | Provider 2 | Fallback |
|------|------------|------------|----------|
| RCA 分析 | Ollama | Gemini | Expert System |
| Tool Calling | Nemotron | Gemini | 拒絕執行 |
| **協作模式** | OpenClaw (RCA) | Nemotron (Tool) | 只顯示 OpenClaw |

### 程式碼整合

```python
from src.services.ai_router import get_ai_router
from src.services.openclaw import get_openclaw_service

router = get_ai_router()
openclaw = get_openclaw_service()

# 使用協作方法
proposal, provider, success = await openclaw.generate_incident_proposal_with_tools(
    incident_id="INC-001",
    severity="high",
    signals=[...],
    affected_services=["awoooi-api"],
)

# proposal 包含:
# - OpenClaw 仲裁結果 (reasoning, risk_level, confidence)
# - Nemotron 執行方案 (nemotron_tools, nemotron_validation) - 如果啟用
```

### Feature Flag

```bash
ENABLE_NEMOTRON_COLLABORATION=true  # 預設啟用
```

---

## 相關文件

- ADR-006: AI Fallback Strategy (v1.3 含 Nemotron)
- ADR-023: 智能路由架構
- ADR-036: Nemotron Tool Calling 整合
- ADR-044: OpenClaw + Nemotron 協作架構 🆕
- `project_model_router_design.md`
- `project_phase13_3_smart_router.md`
- `project_nemotron_integration.md`
- `project_phase22_nemotron_collab.md` 🆕
