diff --git a/apps/api/src/services/approval_execution.py b/apps/api/src/services/approval_execution.py index d0cc829d..aa97417d 100644 --- a/apps/api/src/services/approval_execution.py +++ b/apps/api/src/services/approval_execution.py @@ -411,38 +411,79 @@ class ApprovalExecutionService: 執行結果沉澱到 KM (Knowledge Base) 2026-04-04 ogt: 統帥鐵律 — 成功/失敗執行記錄都必須回寫 KM + 2026-04-14 Claude Sonnet 4.6 (BP-1 B.1 精修): 區分 auto_approve vs 人工路徑, + 補齊 alert_category / alertname / affected_services 供 RAG 檢索。 """ try: from src.models.knowledge import EntrySource, EntryType, KnowledgeEntryCreate from src.services.knowledge_service import get_knowledge_service + # 來源辨識(B.1 精修) + _is_auto = (approval.requested_by or "").lower() == "auto_approve" + _mode_prefix = "[自動修復]" if _is_auto else "[人工修復]" + _mode_tag = "auto_executed" if _is_auto else "human_approved" + status_icon = "✅" if success else "❌" status_text = "成功" if success else f"失敗: {error_message or '未知原因'}" + _status_tag = "success" if success else "failure" + + # 從關聯 Incident 提取豐富元資料 + alertname = "unknown" + alert_category = "general" + affected_services: list[str] = [] + if approval.incident_id: + try: + from src.services.incident_service import get_incident_service + _inc = await get_incident_service().get_incident(approval.incident_id) + if _inc: + if _inc.signals: + alertname = _inc.signals[0].labels.get("alertname", "unknown") or "unknown" + alert_category = getattr(_inc, "alert_category", "") or "general" + affected_services = list(_inc.affected_services or []) + except Exception as _ie: + logger.debug("km_incident_enrich_failed", + incident_id=approval.incident_id, error=str(_ie)) + + _services_str = ", ".join(affected_services) if affected_services else "未關聯" content = ( - f"# {status_icon} 執行記錄: {approval.action[:80]}\n\n" - f"**Approval ID**: {approval.id}\n" - f"**Incident ID**: {approval.incident_id or '未關聯'}\n" + f"# {status_icon} {_mode_prefix} {alertname}\n\n" + f"**告警名稱**: {alertname}\n" + f"**告警類別**: {alert_category}\n" + f"**受影響服務**: {_services_str}\n" + f"**執行命令**: `{approval.action[:200]}`\n" f"**執行結果**: {status_text}\n" - f"**風險等級**: {approval.risk_level.value if approval.risk_level else '未知'}\n\n" - f"## 操作內容\n{approval.description or '無描述'}\n" + f"**風險等級**: {approval.risk_level.value if approval.risk_level else '未知'}\n" + f"**執行路徑**: {'自動執行 (confidence >= 0.65)' if _is_auto else '人工審核批准'}\n" + f"**Incident ID**: {approval.incident_id or '未關聯'}\n" + f"**Approval ID**: {approval.id}\n\n" + f"## 操作描述\n{approval.description or '無描述'}\n" ) + # Tags: 模式 + 狀態 + 類別(供 RAG 多維度檢索) + tags = [_mode_tag, _status_tag, alert_category, "execution"] + if not success: + tags.append("execution_failed") + entry_data = KnowledgeEntryCreate( - title=f"[執行記錄] {status_icon} {approval.action[:60]}", + title=f"{_mode_prefix} {alertname}: {approval.action[:50]}", content=content, entry_type=EntryType.INCIDENT_CASE, - category="execution_result", - tags=["execution", "auto_repair" if success else "execution_failed"], + category=alert_category, # 用真實類別取代硬編 "execution_result" + tags=tags, source=EntrySource.AI_EXTRACTED, related_incident_id=approval.incident_id or None, - created_by="approval_execution", + created_by="auto_execute" if _is_auto else "approval_execution", ) await get_knowledge_service().create_entry(entry_data) - logger.debug( + logger.info( "execution_result_written_to_km", approval_id=str(approval.id), + incident_id=approval.incident_id, + alertname=alertname, + alert_category=alert_category, + mode=_mode_tag, success=success, ) except Exception as e: