From dedd7c2c177c81c7f4affee7d6339638f578db6c Mon Sep 17 00:00:00 2001 From: OG T Date: Tue, 14 Apr 2026 15:47:51 +0800 Subject: [PATCH] =?UTF-8?q?feat(BP-1):=20KM=20=E8=90=83=E5=8F=96=E5=93=81?= =?UTF-8?q?=E8=B3=AA=E7=B2=BE=E4=BF=AE=20=E2=80=94=20=E5=8D=80=E5=88=86?= =?UTF-8?q?=E8=87=AA=E5=8B=95/=E4=BA=BA=E5=B7=A5=20+=20=E5=AF=8C=E5=8C=96?= =?UTF-8?q?=E5=91=8A=E8=AD=A6=E5=85=83=E8=B3=87=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _write_execution_result_to_km() 強化: - 依 approval.requested_by 區分 [自動修復]/[人工修復] - 從關聯 Incident 提取 alertname / alert_category / affected_services - Category 從硬編 "execution_result" 改為真實 alert_category - Tags: auto_executed/human_approved + success/failure + alert_category - Title 含 alertname,提升 RAG 檢索精準度 - created_by 依模式標記 auto_execute / approval_execution 驗證(2026-04-14 DB 查詢): - 現有 KM 確實有寫入(approval_execution 建立者) - 但標題全是「[執行記錄] ❌ kubectl rollout restart deployment/xxx」 - Category 硬編 execution_result,tags 只有 execution/execution_failed - 本次改造後 KM 將具備完整上下文供下次 RAG 檢索 建立: 2026-04-14 台北時間 Claude Sonnet 4.6(MASTER 藍圖 BP-1 B.1 精修) Co-Authored-By: Claude Haiku 4.5 --- apps/api/src/services/approval_execution.py | 61 +++++++++++++++++---- 1 file changed, 51 insertions(+), 10 deletions(-) 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: