# ADR-023: Phase 13.3 智能路由架構 > **狀態**: 已接受 > **日期**: 2026-03-26 > **決策者**: CTO, CEO > **相關**: ADR-006 (AI Fallback Strategy), ADR-016 (Smart Routing) > **Phase**: 13.3 --- ## 1. 背景與問題 ### 問題描述 ADR-006 建立了固定順序的 AI 備援策略 (Ollama → Gemini → Claude),ADR-016 引入了智能路由概念。然而,隨著 AWOOOI 從「告警響應」升級為「全方位 AIOps 平台」(Phase 13),需要更完整的架構設計: 1. **意圖分類不夠精細**: 缺少針對 K8s 操作的專屬意圖類型 2. **複雜度評估不完整**: 缺少跨系統、有狀態資源的風險評估 3. **Token 用量無追蹤**: 無法掌握成本分佈與趨勢 4. **配置分散**: 模型選擇邏輯散落各處,難以維護 ### 目標 - 建立完整的 **Intent → Complexity → Model** 決策流程 - 定義 K8s 專屬意圖 (RESTART/SCALE/CONFIG/DIAGNOSE) - 建立 1-5 分複雜度評分系統 - 整合 Token 用量監控 (SignOz + Langfuse) --- ## 2. 決策: Intent Classifier + Complexity Scorer + AI Router ### 核心策略 ``` Intent (意圖) + Complexity (複雜度) + Context (上下文) → Model Selection (模型選擇) ``` ### 三元件架構 ``` ┌──────────────────────────────────────────────────────────────────┐ │ Phase 13.3 Smart Router │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ Request / Alert / Webhook │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Intent Classifier (意圖分類器) │ │ │ │ ├── 關鍵字匹配 (< 1ms) │ │ │ │ └── LLM 備援 (qwen2.5:1b, < 100ms) │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Complexity Scorer (複雜度評分器) │ │ │ │ ├── 服務數量 / 指標數量 │ │ │ │ ├── 跨系統判斷 / 有狀態風險 │ │ │ │ └── 歷史案例匹配 │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ AI Router (智能路由器) │ │ │ │ ├── 意圖覆寫規則 │ │ │ │ ├── 複雜度 → 模型映射 │ │ │ │ └── Circuit Breaker + Fallback │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌────┴────────────────────┬───────────────────┐ │ │ ▼ ▼ ▼ │ │ ┌─────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Ollama │ │ Gemini │ │ Claude │ │ │ │ (Local) │ │ (Cloud) │ │ (Cloud) │ │ │ │ $0 │ │ $0.001/1K │ │ $0.008/1K │ │ │ └─────────┘ └─────────────┘ └─────────────┘ │ │ │ ├──────────────────────────────────────────────────────────────────┤ │ Token Usage Monitor (SignOz + Langfuse) │ │ └── llm.tokens.* / llm.cost.* / trace.generation() │ └──────────────────────────────────────────────────────────────────┘ ``` --- ## 3. 架構圖 ### 完整請求流程 ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ AWOOOI Phase 13.3 │ │ Smart Routing Architecture │ └─────────────────────────────────────────────────────────────────────────┘ ┌────────────────────┐ │ Alert / Request │ │ (Telegram/API) │ └─────────┬──────────┘ │ ▼ ┌─────────────────────┐ │ Intent Classifier │ │ 目標: < 100ms │ └─────────┬───────────┘ │ ┌─────────────────────┼─────────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────┐ ┌───────────┐ ┌────────────┐ │ RESTART │ │ SCALE │ │ CONFIG │ │ 重啟類 │ │ 擴縮容 │ │ 配置變更 │ └────┬────┘ └─────┬─────┘ └─────┬──────┘ │ │ │ └─────────┬──────────┴─────────────────────┘ │ ▼ ┌─────────────────────┐ │ Complexity Scorer │ │ 輸出: 1-5 分 │ └─────────┬───────────┘ │ ┌─────────────┼─────────────┬─────────────┬─────────────┐ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ 1 │ │ 2 │ │ 3 │ │ 4 │ │ 5 │ │簡單 │ │低風險│ │中等 │ │高複雜│ │極複雜│ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ │ │ │ │ │ └────────────┴─────┬──────┴────────────┴────────────┘ │ ▼ ┌─────────────────┐ │ AI Router │ │ 模型選擇 │ └────────┬────────┘ │ ┌────────────────┼────────────────────┐ │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌──────────────┐ ┌──────────────┐ │ Ollama │ │ Gemini │ │ Claude │ │ llama3.2 │ │ gemini-1.5 │ │ claude-3.5 │ │ qwen2.5 │ │ │ │ │ └────┬─────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ └─────────────────┼───────────────────┘ │ ▼ ┌─────────────────┐ │ Token Monitor │ │ SignOz/Langfuse│ └─────────────────┘ ``` --- ## 4. 意圖分類 (Intent Classification) ### 四大核心意圖 | IntentType | 說明 | 典型場景 | 關鍵字 | |------------|------|----------|--------| | `RESTART` | 重啟 Pod/Deployment/StatefulSet | Pod CrashLoopBackOff、服務無回應 | restart, 重啟, 重新啟動, rollout restart | | `SCALE` | 擴縮容、HPA 調整 | CPU 高負載、流量激增 | scale, 擴容, 縮容, replicas, hpa | | `CONFIG` | ConfigMap/Secret/ENV 變更 | 配置錯誤、環境變數缺失 | config, 配置, configmap, secret, env | | `DIAGNOSE` | 日誌查詢、健康檢查、RCA | 錯誤追蹤、根因分析 | diagnose, 診斷, log, describe, rca | ### 輔助意圖 | IntentType | 說明 | 典型場景 | |------------|------|----------| | `DEPLOY` | 部署操作 | kubectl apply, helm upgrade | | `ROLLBACK` | 回滾操作 | rollout undo, 版本回滾 | | `QUERY` | 資訊查詢 | 狀態查詢、資源列表 | | `CODE_REVIEW` | 程式碼審查 | PR Review, Commit 分析 | | `ALERT_TRIAGE` | 告警分流 | 高負載告警、OOM、服務 Down | | `UNKNOWN` | 未知意圖 | 無法分類的請求 | ### 分類策略 (兩階段) ```python class IntentClassifier: """ 意圖分類器 - 兩階段策略 階段 1: 關鍵字匹配 (< 1ms) 階段 2: LLM 備援 (qwen2.5:1b, < 100ms) """ async def classify(self, text: str) -> IntentType: # 階段 1: 關鍵字快速匹配 intent = self._keyword_match(text.lower()) if intent != IntentType.UNKNOWN: return intent # 階段 2: LLM 分類 (備援) return await self._llm_classify(text) def _keyword_match(self, text: str) -> IntentType: """ 關鍵字映射 (優先級: 越上面越優先) """ INTENT_KEYWORDS = { IntentType.RESTART: [ "restart", "重啟", "重新啟動", "rollout restart", "kill", "recreate", "delete pod", ], IntentType.SCALE: [ "scale", "擴容", "縮容", "replicas", "hpa", "autoscale", "capacity", "節點", ], IntentType.CONFIG: [ "config", "配置", "configmap", "secret", "env", "環境變數", "yaml", "設定", ], IntentType.DIAGNOSE: [ "diagnose", "診斷", "log", "describe", "rca", "root cause", "根因", "排查", "debug", "trace", ], # ... 其他意圖 } for intent, keywords in INTENT_KEYWORDS.items(): if any(kw in text for kw in keywords): return intent return IntentType.UNKNOWN ``` --- ## 5. 複雜度評分 (Complexity Scoring) ### 評分維度與權重 | 維度 | 權重 | 說明 | |------|------|------| | `service_count` | +0.5/服務 | 每增加一個受影響服務 | | `metric_count` | +0.3/指標 | 每增加一個相關指標 | | `cross_namespace` | +1.0 | 跨命名空間操作 | | `cross_cluster` | +2.0 | 跨叢集操作 | | `stateful_resource` | +1.0 | 有狀態資源 (StatefulSet, PVC) | | `database_operation` | +1.5 | 涉及資料庫操作 | | `critical_severity` | +1.0 | CRITICAL 嚴重程度 | | `has_playbook` | -0.5 | 有歷史 Playbook (降低複雜度) | | `requires_multisig` | +1.0 | 需要 Multi-Sig 審核 | ### 複雜度等級定義 | 分數 | 等級 | 定義 | 範例 | |------|------|------|------| | **1** | 簡單 | 單一資源、無狀態、可立即回滾 | 重啟單一 Pod | | **2** | 低風險 | 多資源但同命名空間、低風險 | 擴容 Deployment | | **3** | 中等 | 跨命名空間、需要上下文收集 | 多服務診斷 | | **4** | 高複雜 | 有狀態資源、需要 Multi-Sig | StatefulSet 操作 | | **5** | 極複雜 | 跨叢集、資料庫操作、需要人工審核 | 資料庫 Schema 變更 | ### 評分邏輯 ```python class ComplexityScorer: """ 複雜度評分器 - 純規則引擎 (< 10ms) """ def score(self, context: dict) -> ComplexityScore: score = 1.0 # 基礎分 # 服務數量 service_count = len(context.get("affected_services", [])) score += service_count * 0.5 # 指標數量 metric_count = len(context.get("metrics", [])) score += metric_count * 0.3 # 跨命名空間 if context.get("cross_namespace"): score += 1.0 # 跨叢集 if context.get("cross_cluster"): score += 2.0 # 有狀態資源 if context.get("stateful_resource"): score += 1.0 # 資料庫操作 if context.get("database_operation"): score += 1.5 # CRITICAL 嚴重程度 if context.get("severity") == "CRITICAL": score += 1.0 # 歷史 Playbook (降低) if context.get("has_playbook"): score -= 0.5 # Multi-Sig 需求 if context.get("requires_multisig"): score += 1.0 # 限制範圍 1-5 final_score = min(5, max(1, round(score))) return ComplexityScore( score=final_score, factors=self._extract_factors(context), ) ``` --- ## 6. Provider 選擇邏輯 ### 複雜度 → 模型映射 | 複雜度 | 主要模型 | Fallback 順序 | 理由 | |--------|----------|---------------|------| | **1** | `llama3.2:3b` | qwen2.5:7b → gemini → claude | 快速回應,資源節省 | | **2** | `qwen2.5:7b-instruct` | llama3.2:3b → gemini → claude | 平衡品質與延遲 | | **3** | `qwen2.5:7b-instruct` | gemini → claude | 需要較強推理能力 | | **4** | `gemini` | claude → qwen2.5:7b | 需要雲端能力 | | **5** | `claude` | gemini → qwen2.5:7b | 最強模型處理 | ### 意圖強制覆寫 某些意圖無論複雜度如何,都強制使用特定模型: | 意圖 | 強制模型 | 原因 | |------|---------|------| | `DIAGNOSE` | `qwen2.5:7b-instruct` (本地) | 日誌可能含敏感資料,禁止送雲端 | | `CODE_REVIEW` | `qwen2.5:7b-instruct` | 程式碼分析需要較強能力 | | `QUERY` | `llama3.2:3b` | 簡單查詢不需大模型 | ### 路由決策流程 ```python class AIRouter: """ 智能路由器 - 動態模型選擇 """ COMPLEXITY_ROUTING = { 1: "llama3.2:3b", 2: "qwen2.5:7b-instruct", 3: "qwen2.5:7b-instruct", 4: "gemini", 5: "claude", } INTENT_OVERRIDES = { IntentType.DIAGNOSE: "qwen2.5:7b-instruct", # 隱私優先 IntentType.CODE_REVIEW: "qwen2.5:7b-instruct", IntentType.QUERY: "llama3.2:3b", } async def route( self, text: str, context: dict | None = None ) -> RoutingDecision: # Step 1: 意圖分類 intent = await self._intent_classifier.classify(text) # Step 2: 複雜度評分 complexity = self._complexity_scorer.score(context or {}) # Step 3: 模型選擇 (考慮意圖覆寫) if intent in self.INTENT_OVERRIDES: model = self.INTENT_OVERRIDES[intent] reason = f"意圖 {intent.value} 強制使用 {model}" else: model = self.COMPLEXITY_ROUTING[complexity.score] reason = f"複雜度 {complexity.score} → {model}" # Step 4: 建立 Fallback 列表 fallbacks = self._build_fallback_list(model) return RoutingDecision( model=model, intent=intent, complexity=complexity, reason=reason, fallback_models=fallbacks, ) def _build_fallback_list(self, primary: str) -> list[str]: """ 建立 Fallback 順序 (ADR-006) """ FALLBACK_ORDER = [ "qwen2.5:7b-instruct", "llama3.2:3b", "gemini", "claude", ] return [m for m in FALLBACK_ORDER if m != primary] ``` --- ## 7. Token 用量監控 ### 監控架構 ``` ┌─────────────────────────────────────────────────────────────────┐ │ Token Usage Monitoring │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ SignOz │ │ Langfuse │ │ │ │ (Infra 層) │ │ (LLMOps 層) │ │ │ └────────┬────────┘ └────────┬────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ OTEL Metrics │ │ Trace/Generation│ │ │ │ - llm.tokens.* │ │ - cost tracking │ │ │ │ - llm.latency.* │ │ - model compare │ │ │ └─────────────────┘ └─────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 關鍵指標 | 指標 | 說明 | 類型 | |------|------|------| | `llm.tokens.input` | 輸入 Token 數 | Counter | | `llm.tokens.output` | 輸出 Token 數 | Counter | | `llm.cost.usd` | 估算成本 (雲端 Provider) | Counter | | `llm.latency.p99` | 延遲 P99 | Histogram | | `llm.requests.total` | 總請求數 | Counter | | `llm.requests.failed` | 失敗請求數 | Counter | ### 成本警報閾值 (ADR-006 延伸) | Provider | 每日上限 | 每月上限 | 告警閾值 | |----------|---------|---------|---------| | Gemini | 100K tokens | 2M tokens | 70% | | Claude | 50K tokens | 500K tokens | 70% | ### Langfuse 追蹤整合 ```python from langfuse.decorators import langfuse_context, observe class AIRouter: @observe(name="smart_routing") async def route(self, text: str, context: dict) -> RoutingDecision: decision = await self._make_decision(text, context) # 記錄路由決策 langfuse_context.update_current_trace( metadata={ "intent": decision.intent.value, "complexity": decision.complexity.score, "model": decision.model, "reason": decision.reason, } ) return decision @observe(name="llm_generation") async def generate(self, model: str, prompt: str) -> str: result = await self._call_model(model, prompt) # 記錄 Token 用量 langfuse_context.update_current_observation( usage={ "input_tokens": result.input_tokens, "output_tokens": result.output_tokens, }, model=model, ) return result.content ``` --- ## 8. 與 ADR-006 的關係 ### 架構層次 ``` ┌─────────────────────────────────────────────────────────────────┐ │ ADR-023 (Phase 13.3) │ │ 智能路由架構 │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Intent Classifier → Complexity Scorer → AI Router │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ ADR-016 (Smart Routing 基礎實作) │ │ │ │ - IntentClassifier / ComplexityScorer / AIRouter │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ ADR-006 (AI Fallback Strategy) │ │ │ │ - Circuit Breaker / Token 配額 / 固定 Fallback 順序 │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 協作關係 | 面向 | ADR-006 (基礎) | ADR-016 (實作) | ADR-023 (架構) | |------|---------------|----------------|----------------| | **範疇** | Fallback 策略 | 路由實作 | 完整架構 | | **觸發時機** | 服務失敗時 | 每個請求 | 架構設計層面 | | **選擇邏輯** | 固定順序 | 意圖 + 複雜度 | 三元件協作 | | **目標** | 高可用性 | 資源最佳化 | 全方位 AIOps | | **狀態** | 仍然有效 | 已實作 | 本文件 | ### 請求流程整合 ``` Request │ ▼ [ADR-023: 三元件決策] │ ├── Intent Classifier ├── Complexity Scorer └── AI Router → 選擇 Model A │ 失敗 ▼ [ADR-006: Fallback Chain] │ ├── Model B ├── Model C └── Static Response ``` --- ## 9. 後果分析 ### 優點 | 面向 | 效益 | |------|------| | **資源優化** | 簡單任務用小模型 (3B),節省 GPU 資源 30%+ | | **品質提升** | 複雜任務自動升級到強模型,減少人工介入 | | **成本可控** | 只有真正需要時才使用雲端 API | | **延遲改善** | 簡單查詢回應 < 5s (llama3.2:3b) | | **可觀測性** | Token 用量透明,成本趨勢可預測 | | **隱私保護** | DIAGNOSE 意圖強制本地,敏感日誌不送雲端 | ### 缺點 | 面向 | 風險 | 緩解措施 | |------|------|---------| | **分類錯誤** | 意圖分類可能有邊界情況 | 關鍵字優先 + LLM 備援 | | **複雜度誤判** | 規則可能需要持續調優 | 收集數據 + 定期調整權重 | | **延遲增加** | 分類 + 評分 增加約 100ms | 限制 LLM 分類僅作備援 | | **維護成本** | 需維護關鍵字映射表 | 集中管理於 models.json | ### 風險 | 風險 | 等級 | 緩解策略 | |------|------|---------| | LLM 分類器 Timeout | 中 | 設定 100ms Timeout,fallback 到 UNKNOWN | | 全部 Provider 失敗 | 低 | ADR-006 靜態回應兜底 | | Token 預算超支 | 中 | 告警閾值 70%,超支自動切本地 | | 意圖覆寫邏輯錯誤 | 低 | 嚴格測試 + 監控路由決策分佈 | --- ## 10. 實作位置 ``` apps/api/src/services/ ├── intent_classifier.py # IntentClassifier ├── complexity_scorer.py # ComplexityScorer ├── ai_router.py # AIRouter └── token_tracker.py # TokenTracker (SignOz + Langfuse) ``` --- ## 11. 配置集中管理 ### 單一事實來源: `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 } }, "gemini": { "model": "gemini-1.5-flash", "daily_quota": 100000, "monthly_quota": 2000000 }, "claude": { "model": "claude-3-5-sonnet", "daily_quota": 50000, "monthly_quota": 500000 } }, "complexity_routing": { "1": "llama3.2:3b", "2": "qwen2.5:7b-instruct", "3": "qwen2.5:7b-instruct", "4": "gemini", "5": "claude" }, "intent_overrides": { "DIAGNOSE": "qwen2.5:7b-instruct", "CODE_REVIEW": "qwen2.5:7b-instruct", "QUERY": "llama3.2:3b" } } ``` --- ## 12. 變更記錄 | 日期 | 版本 | 變更 | 作者 | |------|------|------|------| | 2026-03-26 | v1.0 | 初版建立 (Phase 13.3 #85-88) | 首席架構師 | --- ## 參考 - [ADR-006: AI 降級備援策略](./ADR-006-ai-fallback-strategy.md) - [ADR-016: 智能路由 (基礎實作)](./ADR-016-smart-routing.md) - [Skill 08: Model Router Expert](../../.agents/skills/08-model-router-expert.md) - [Phase 13.3 Smart Router 設計](~/.claude/projects/-Users-ogt-awoooi/memory/project_model_router_design.md) - [Phase 13 Enterprise AIOps](~/.claude/projects/-Users-ogt-awoooi/memory/project_phase13_enterprise_aiops.md) --- *此 ADR 記錄 Phase 13.3 智能路由架構的完整決策過程,整合 ADR-006 Fallback 策略與 ADR-016 路由實作。*