diff --git a/apps/api/src/services/decision_manager.py b/apps/api/src/services/decision_manager.py index 86bbb13fe..059ce9625 100644 --- a/apps/api/src/services/decision_manager.py +++ b/apps/api/src/services/decision_manager.py @@ -585,32 +585,54 @@ class DecisionManager: incident: Incident, ) -> dict[str, Any]: """ - 三軌決策分析 (Phase 7.5 升級) + 三軌決策分析 (Phase 7.5 升級 + 2026-03-27 智能診斷重構) 策略: 1. 先檢查 Playbook 是否有高度匹配 (similarity >= 85%) 2. Playbook 命中則直接使用 (最快、經驗驗證) - 3. 否則 LLM + Expert System 雙軌 + 3. Expert System 提供初步診斷 (分類 + 診斷指令) + 4. LLM 基於診斷上下文提供智能建議 + 5. LLM 失敗時,根據 Expert 診斷決定是否需人工介入 - 優先順序: Playbook > LLM > Expert System + 優先順序: Playbook > LLM(with Expert context) > Expert System """ # Phase 7.5: 先嘗試 Playbook 匹配 playbook_result = await self._try_playbook_match(incident) if playbook_result: return playbook_result - # Expert System 同步執行 (立即可用) + # ========== 2026-03-27 重構: 分層智能診斷 ========== + + # Step 1: Expert System 提供初步診斷 (永不失敗) expert_result = expert_analyze(incident) - # LLM 非同步執行 - try: - signals_dict = [s.model_dump() for s in incident.signals] + # Step 2: 測試資源直接返回 (不浪費 LLM 呼叫) + if expert_result.get("is_test_resource"): + logger.info( + "dual_engine_test_resource_skip", + incident_id=incident.incident_id, + target=incident.affected_services[0] if incident.affected_services else "unknown", + ) + return expert_result + # Step 3: 準備 LLM 上下文 (含 Expert 診斷) + signals_dict = [s.model_dump() for s in incident.signals] + expert_context = { + "initial_diagnosis": expert_result.get("matched_rule"), + "diagnosis_description": expert_result.get("description"), + "suggested_diagnosis_commands": expert_result.get("diagnosis_commands", []), + "expert_confidence": expert_result.get("confidence"), + "requires_human_review": expert_result.get("human_review_required", False), + } + + # Step 4: LLM 分析 (帶上 Expert 上下文) + try: llm_result, provider, success = await self._openclaw.generate_incident_proposal( incident_id=incident.incident_id, severity=incident.severity.value, signals=signals_dict, affected_services=incident.affected_services, + expert_context=expert_context, # 傳遞 Expert 診斷上下文 ) if success and llm_result: @@ -618,10 +640,12 @@ class DecisionManager: "dual_engine_llm_win", incident_id=incident.incident_id, provider=provider, + expert_rule=expert_result.get("matched_rule"), ) return { **llm_result, "source": f"llm_{provider}", + "expert_diagnosis": expert_result.get("matched_rule"), } except Exception as e: @@ -629,13 +653,23 @@ class DecisionManager: "dual_engine_llm_failed", incident_id=incident.incident_id, error=str(e), + expert_rule=expert_result.get("matched_rule"), ) - # LLM 失敗,使用 Expert System + # Step 5: LLM 失敗,使用 Expert System 結果 + # 但根據診斷結果調整回應 logger.info( "dual_engine_expert_fallback", incident_id=incident.incident_id, + expert_rule=expert_result.get("matched_rule"), + human_review=expert_result.get("human_review_required", False), ) + + # 如果 Expert 標記需人工介入,降低 confidence + if expert_result.get("human_review_required"): + expert_result["confidence"] = min(expert_result.get("confidence", 0.5), 0.5) + expert_result["description"] += " [LLM 分析失敗,建議人工確認]" + return expert_result async def _try_playbook_match( diff --git a/apps/api/src/services/openclaw.py b/apps/api/src/services/openclaw.py index dd7a7f314..9b05a1fc3 100644 --- a/apps/api/src/services/openclaw.py +++ b/apps/api/src/services/openclaw.py @@ -1068,17 +1068,25 @@ Trace URL: {signoz_trace_url} severity: str, signals: list[dict], affected_services: list[str], + expert_context: dict | None = None, ) -> tuple[dict | None, str, bool]: """ 為 Incident 生成 LLM-based 修復提案 Phase 6.4: 賦予大腦「生成解決方案」的思考能力 + 2026-03-27: 整合 Expert System 診斷上下文 Args: incident_id: Incident ID severity: 嚴重度 (P0/P1/P2/P3) signals: 關聯的告警訊號 affected_services: 受影響服務 + expert_context: Expert System 初步診斷 (可選) + - initial_diagnosis: 規則匹配結果 + - diagnosis_description: 診斷描述 + - suggested_diagnosis_commands: 建議診斷指令 + - expert_confidence: 信心分數 + - requires_human_review: 是否需人工介入 Returns: (proposal_dict, provider, success) @@ -1108,11 +1116,31 @@ Trace URL: {signoz_trace_url} signoz_context = f""" ## 📊 SignOz Real-time Metrics {signoz_metrics.to_summary()} +""" + + # 2026-03-27: 整合 Expert System 診斷上下文 + expert_diagnosis_context = "" + if expert_context: + diagnosis_cmds = expert_context.get("suggested_diagnosis_commands", []) + diagnosis_cmds_str = "\n".join([f" - `{cmd}`" for cmd in diagnosis_cmds]) if diagnosis_cmds else " - (無)" + expert_diagnosis_context = f""" +## 🔍 Expert System Initial Diagnosis +- **Matched Rule**: {expert_context.get('initial_diagnosis', 'unknown')} +- **Diagnosis**: {expert_context.get('diagnosis_description', 'N/A')} +- **Confidence**: {expert_context.get('expert_confidence', 0.5):.0%} +- **Requires Human Review**: {'Yes' if expert_context.get('requires_human_review') else 'No'} +- **Suggested Diagnosis Commands**: +{diagnosis_cmds_str} + +**IMPORTANT**: The Expert System has provided an initial diagnosis. +Consider this context but apply your own analysis. If Expert says "human review required", +provide diagnostic guidance rather than automated fixes. """ proposal_prompt = f"""{OPENCLAW_SYSTEM_PROMPT} {signoz_context} +{expert_diagnosis_context} ## 🚨 Incident Context - **Incident ID**: {incident_id} @@ -1124,13 +1152,14 @@ Trace URL: {signoz_trace_url} {signal_summary} ## 🎯 Your Task -Based on the above incident and signals, generate a remediation proposal. +Based on the above incident, signals, and Expert System diagnosis, generate a remediation proposal. You MUST respond with ONLY valid JSON following the schema above. Focus on: -1. Root cause analysis based on signals and SignOz data -2. Specific kubectl command to remediate +1. Root cause analysis based on signals, SignOz data, and Expert diagnosis +2. Specific kubectl command to remediate (or diagnostic command if root cause unclear) 3. Risk assessment for the proposed action 4. Preventive recommendations +5. If Expert System flagged "human review required", prioritize diagnostic commands over fixes """ logger.info(