feat(api): LLM 整合 Expert System 診斷上下文
長期方案實作: Expert 診斷 + LLM 智能分析 變更: 1. decision_manager._dual_engine_analyze(): - 測試資源跳過 LLM (省錢) - 傳遞 Expert 診斷上下文給 LLM - LLM 失敗時根據診斷調整回應 2. openclaw.generate_incident_proposal(): - 新增 expert_context 參數 - Prompt 包含 Expert 診斷結果 - 引導 LLM 基於診斷做決策 流程: Playbook → Expert診斷 → LLM(with context) → 智能建議 這是「先診斷根因,再決定行動」的正確實作 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user