From c27709d11bd1a20c10dbac017f57ea7466137a76 Mon Sep 17 00:00:00 2001 From: OG T Date: Thu, 16 Apr 2026 14:32:32 +0800 Subject: [PATCH] =?UTF-8?q?fix(diagnostician):=20=E7=9B=B8=E5=AE=B9=20open?= =?UTF-8?q?claw=5Fnemo=20=E5=9B=9E=E5=82=B3=E6=A0=BC=E5=BC=8F=20=E2=86=92?= =?UTF-8?q?=20=E8=A7=A3=E9=99=A4=E5=85=A8=E9=9D=A2=20ABSTAIN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因: AI Router DIAGNOSE→openclaw_nemo 回傳 ClawBot 格式: {"action_title":"...","risk_level":"...","confidence":0.85} Diagnostician 只解析 {"hypotheses":[...]} → 永遠 0 hypotheses → ABSTAIN 修復: _extract_hypotheses() 新增 openclaw_nemo 格式檢測與轉換 action_title→description, confidence→confidence, risk_level→category 影響: 所有 critical alert 自 2026-04-15 收到後一律 ABSTAIN,無任何修復動作 Co-Authored-By: Claude Sonnet 4.6 --- apps/api/src/agents/diagnostician_agent.py | 30 +++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/apps/api/src/agents/diagnostician_agent.py b/apps/api/src/agents/diagnostician_agent.py index 15367e13..aed2f8b2 100644 --- a/apps/api/src/agents/diagnostician_agent.py +++ b/apps/api/src/agents/diagnostician_agent.py @@ -202,7 +202,35 @@ Phase 4 動態異常偵測(AI 主動巡檢結果,可作為高信心佐證) # ───────────────────────────────────────────────────────────────────────────── def _extract_hypotheses(parsed: dict[str, Any]) -> list[Hypothesis]: - """從 LLM 解析結果提取假設列表(按信心降序)。""" + """從 LLM 解析結果提取假設列表(按信心降序)。 + + 支援兩種格式: + 1. 標準格式:{"hypotheses": [{description, confidence, evidence_chain, category}]} + 2. OpenClaw Nemo 格式:{"action_title": "...", "risk_level": "...", "confidence": 0.85} + (openclaw_nemo 呼叫 ClawBot /api/v1/analyze/incident 回傳) + + 2026-04-16 ogt + Claude Sonnet 4.6: 修復 openclaw_nemo 格式不相容 + 根因: ai_router DIAGNOSE→openclaw_nemo 回傳 action_title 格式, + diagnostician 只解析 hypotheses 格式 → 永遠 0 hypotheses → ABSTAIN + """ + # OpenClaw Nemo 格式轉換(有 action_title 但無 hypotheses) + if "action_title" in parsed and "hypotheses" not in parsed: + action_title = str(parsed.get("action_title", "")) + confidence = float(parsed.get("confidence", 0.5)) + risk_level = str(parsed.get("risk_level", "medium")) + # risk_level → category 映射 + risk_to_cat = {"critical": "CriticalFailure", "high": "HighRisk", + "medium": "ModerateIssue", "low": "LowRisk"} + category = risk_to_cat.get(risk_level.lower(), "Unknown") + if action_title and confidence > 0: + return [Hypothesis( + description=action_title[:500], + confidence=confidence, + evidence_chain=[], + category=category, + )] + return [] + raw = parsed.get("hypotheses", []) hypotheses = [] for item in raw: