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(
|
||||
|
||||
Reference in New Issue
Block a user