feat(ai): 委派 Incident RCA 給 OpenClaw (Nemo) — 架構鐵律修正
Some checks failed
E2E Health Check / e2e-health (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled

架構鐵律: OpenClaw = AI 大腦,AWOOOI API 透過 HTTP 委派仲裁
修改:
- openclaw.py: 加入 _call_openclaw_analyze(),在 LLM fallback 前先呼叫 OpenClaw
- 04-configmap.yaml: OPENCLAW_URL 修正為 :8088 (新容器 port)
- AI_FALLBACK_ORDER 改為 ["ollama","claude"] (移除 Gemini 付費 API)

OpenClaw /api/v1/analyze/incident → qwen2.5:7b 本機 Ollama (Nemo)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-04-01 21:11:30 +08:00
parent 60d2fbaf8c
commit 5809d3e336
2 changed files with 85 additions and 1 deletions

View File

@@ -255,6 +255,82 @@ class OpenClawService:
}
# =========================================================================
# =========================================================================
# OpenClaw (Nemo) 委派仲裁 — 架構鐵律
# 2026-04-01 ogt: AWOOOI API 不直接打 LLM委派給 OpenClaw (192.168.0.188:8089)
# =========================================================================
async def _call_openclaw_analyze(
self,
incident_id: str,
severity: str,
signals: list[dict],
affected_services: list[str],
expert_context: dict | None = None,
) -> dict | None:
"""
委派 Incident RCA 給 OpenClaw (Nemo) API
Returns:
proposal_dict if success, None if failed (fallback to direct LLM)
"""
try:
client = await self._get_client()
payload = {
"incident_id": incident_id,
"severity": severity,
"signals": signals[:5],
"affected_services": affected_services,
"expert_context": expert_context,
}
resp = await client.post(
f"{settings.OPENCLAW_URL}/api/v1/analyze/incident",
json=payload,
timeout=httpx.Timeout(130.0, connect=5.0),
)
resp.raise_for_status()
data = resp.json()
# 驗證必要欄位
if not data.get("action_title") or not data.get("risk_level"):
logger.warning("openclaw_analyze_invalid_response", incident_id=incident_id)
return None
logger.info(
"openclaw_analyze_success",
incident_id=incident_id,
confidence=data.get("confidence", 0),
risk_level=data.get("risk_level"),
)
# 轉換為 AWOOOI API proposal dict 格式
return {
"action": data.get("action_title", "AI 分析"),
"description": data.get("description", ""),
"kubectl_command": data.get("kubectl_command") or "",
"target_resource": data.get("target_resource", "unknown"),
"namespace": data.get("namespace", "awoooi-prod"),
"risk_level": data.get("risk_level", "medium"),
"reasoning": data.get("reasoning", ""),
"confidence": data.get("confidence", 0.8),
"primary_responsibility": data.get("primary_responsibility", "INFRA"),
"optimization_suggestions": data.get("optimization_suggestions", []),
"signoz_correlation": data.get("signoz_correlation", ""),
"from_cache": False,
"provider": "openclaw_nemo",
"ai_tokens": 0,
"ai_cost": 0.0,
}
except Exception as e:
logger.warning(
"openclaw_analyze_failed",
incident_id=incident_id,
error=str(e),
reason="fallback to direct LLM",
)
return None
# AI Provider Implementations - Enhanced with Structured Output
# =========================================================================
@@ -1312,6 +1388,14 @@ Focus on:
signoz_available=signoz_metrics is not None,
)
# 2026-04-01 ogt: 架構鐵律 — OpenClaw (Nemo) 是 AI 大腦,優先委派仲裁
# AWOOOI K8s Pod 不直接打 Ollama/NVIDIA避免並發逾時
openclaw_result = await self._call_openclaw_analyze(
incident_id, severity, signals, affected_services, expert_context
)
if openclaw_result is not None:
return openclaw_result, "openclaw_nemo", True
# 使用快取呼叫 LLM
alert_context = {
"incident_id": incident_id,