feat(wave2+km): LLM 動態按鈕啟用 + KM 自動寫入 + AI Router dead code 標記
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 9m52s

- ConfigMap: USE_LLM_DYNAMIC_BUTTONS=true(B2/B3/B4 handler 全就緒)
- decision_manager: auto_execute 失敗路徑補 KM fire-and-forget 寫入
- ai_router: _build_fallback_chain 標記 DEPRECATED 2026-04-28
- tests: test_golden_regression.py 新增 172 行 golden 回歸測試

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-04-28 15:27:26 +08:00
parent 2e6ae7fe84
commit 143c15f052
4 changed files with 193 additions and 0 deletions

View File

@@ -599,6 +599,7 @@ class AIRouter:
self, selected_provider: AIProviderEnum
) -> list[tuple[AIProviderEnum, str]]:
"""
# DEPRECATED 2026-04-28 — 已由 _build_fallback_chain_for_intent 取代,無呼叫方
建立 Fallback 鏈 (排除已選 Provider)
Fallback 順序: Ollama → Gemini → Claude

View File

@@ -2098,6 +2098,11 @@ class DecisionManager:
except Exception as _cd_err:
logger.debug("auto_execute_cooldown_check_error", error=str(_cd_err))
# P1.1 fix 2026-04-27 ogt + Claude Sonnet 4.6: 失敗路徑 KM 寫入哨兵
# 在 try 外宣告,確保 except 區塊能存取(即使建構失敗)
_km_executor = None
_km_approval = None
try:
# 延遲導入避免循環依賴
from src.models.approval import ApprovalRequest, ApprovalStatus
@@ -2119,6 +2124,7 @@ class DecisionManager:
risk_level=_risk,
matched_playbook_id=_matched_playbook_id,
)
_km_approval = approval # P1.1: 供 except 失敗路徑使用
# ADR-071-I: 執行前抓 metrics_before 快照 (2026-04-11 Claude Sonnet 4.6)
_metrics_before = await _fetch_metrics_snapshot(incident)
@@ -2144,6 +2150,7 @@ class DecisionManager:
# _push_auto_repair_result → Telegram 顯示 ✅ 自動修復完成,即使 K8s 拒絕了指令
# 修復: execute_approved_action 現在返回 bool正確透傳給通知函數
executor = ApprovalExecutionService()
_km_executor = executor # P1.1: 供 except 失敗路徑使用
_exec_success = await executor.execute_approved_action(approval)
# 更新狀態
@@ -2190,6 +2197,16 @@ class DecisionManager:
_push_decision_to_telegram(incident, token.proposal_data)
)
# P1.1 fix 2026-04-27 ogt + Claude Sonnet 4.6: 失敗路徑補 KM 寫入
# 根因auto_execute 拋出例外時,學習飛輪完全拿不到失敗記錄
# 修法:若 executor/approval 已建立fire-and-forget 寫入失敗 KM未建立則跳過
if _km_executor is not None and _km_approval is not None:
_fire_and_forget(
_km_executor._write_execution_result_to_km(
_km_approval, False, str(e)
)
)
async def _query_kb_context_inner(self, incident: Incident) -> str:
"""KB RAG 實際查詢邏輯,由 _query_kb_context 包裝 timeout 後呼叫"""
query_parts = list(incident.affected_services)