feat(BP-1): KM 萃取品質精修 — 區分自動/人工 + 富化告警元資料
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled

_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 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-04-14 15:47:51 +08:00
parent a71f09e30a
commit dedd7c2c17

View File

@@ -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: