fix(flywheel): 自動化飛輪六大能力修復(ADR-092 B3)
Some checks failed
run-migration / migrate (push) Failing after 22s
Deploy Alert Rules / Deploy Prometheus Alert Rules (push) Successful in 53s
Type Sync Check / check-type-sync (push) Successful in 2m54s
CD Pipeline / build-and-deploy (push) Has been cancelled
Ansible Lint / lint (push) Has been cancelled
Some checks failed
run-migration / migrate (push) Failing after 22s
Deploy Alert Rules / Deploy Prometheus Alert Rules (push) Successful in 53s
Type Sync Check / check-type-sync (push) Successful in 2m54s
CD Pipeline / build-and-deploy (push) Has been cancelled
Ansible Lint / lint (push) Has been cancelled
【根因鏈修復】 MCP Provider bugs → PreDecisionInvestigator 失敗 → Agent Debate 無上下文 → LLM 逾時 → description="待分析" → ADR-091 鐵閘攔截 → tg_sent 未設 → W-2 Watchdog 誤報「靜默故障」 【六大修復】 1. MCP Provider 三蟲修復 - ssh_provider: asyncssh.run() → conn.run() - prometheus_provider: KeyError 'query' → .get() 容錯 - k8s_provider: 空 pod_name → 早返回錯誤字典 2. Agent Debate / 決策品質 - decision_manager: 逾時降級文字改為明確描述(繞過 ADR-091 鐵閘) - intent_classifier: LLM 逾時降級至關鍵字分類(非 None) 3. Watchdog 誤報修復(ADR-092 B3) - W-2: tg_sent Redis TTL → telegram_message_id IS NULL(DB 真值) - W-5 新增: suggested_action IN 空/待分析/NO_ACTION + tg_id IS NULL - approval_timeout_resolver: 60min → 15min,batch 50 → 200 4. Config Drift 自動化 - drift_adopt_service: auto_adopt_if_safe() 六條件安全閘 - drift.py: 背景任務先嘗試自動採納再發人工 Telegram 卡片 5. Playbook 飛輪穩定 - playbook_seed_service: 修復幂等性(deprecated 不視為缺失) - playbook_evolver: 只載 DRAFT+APPROVED(非全部 294 筆) 6. 可觀測性 - alert_rule_engine: auto_rule 結構化日誌 + Redis 計數器(pipeline) - auto_approve: reject 原因 Redis 計數器 - heartbeat_report_service: 新增「⚙️ 自動化統計(今日)」區塊 【待人工執行】 psql $DATABASE_URL -f apps/api/migrations/cleanup_duplicate_deprecated_playbooks.sql Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -603,7 +603,16 @@ class IntentClassifier:
|
||||
error=str(e),
|
||||
response_preview=result_text[:100],
|
||||
)
|
||||
return self._llm_fallback_result("JSON 解析失敗")
|
||||
# 2026-04-24 ogt + Claude Sonnet 4.6: JSON 解析失敗也降級至關鍵字結果
|
||||
_kw_result = self._keyword_classify(text)
|
||||
return IntentResult(
|
||||
intent=_kw_result.intent,
|
||||
confidence=_kw_result.confidence,
|
||||
method="llm_parse_failed_keyword",
|
||||
matched_keywords=_kw_result.matched_keywords,
|
||||
detected_resources=_kw_result.detected_resources,
|
||||
reasoning=f"LLM JSON 解析失敗降級 → {_kw_result.reasoning}",
|
||||
)
|
||||
|
||||
except httpx.TimeoutException:
|
||||
elapsed_ms = (time.time() - start_time) * 1000
|
||||
@@ -611,7 +620,20 @@ class IntentClassifier:
|
||||
"intent_llm_timeout",
|
||||
elapsed_ms=round(elapsed_ms, 1),
|
||||
)
|
||||
return self._llm_fallback_result("LLM 超時")
|
||||
# 2026-04-24 ogt + Claude Sonnet 4.6: LLM 超時直接降級至關鍵字結果
|
||||
# 問題:_llm_fallback_result 返回 confidence=0.0/UNKNOWN,和 keyword 結果 confidence 相同
|
||||
# classify() 比較 0.0 > 0.0 = False → 走 keyword(正確),但已浪費 5s 超時時間
|
||||
# 若 Ollama 後端不通,每次都等 5s 才降級 → ai_router/ci_auto_repair 延遲累積
|
||||
# 修法:超時直接回 keyword 結果,method 標記 "llm_timeout_keyword" 供可觀測性追蹤
|
||||
_kw_result = self._keyword_classify(text)
|
||||
return IntentResult(
|
||||
intent=_kw_result.intent,
|
||||
confidence=_kw_result.confidence,
|
||||
method="llm_timeout_keyword",
|
||||
matched_keywords=_kw_result.matched_keywords,
|
||||
detected_resources=_kw_result.detected_resources,
|
||||
reasoning=f"LLM 超時降級({round(elapsed_ms, 0):.0f}ms)→ {_kw_result.reasoning}",
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
@@ -619,7 +641,16 @@ class IntentClassifier:
|
||||
error=str(e),
|
||||
error_type=type(e).__name__,
|
||||
)
|
||||
return self._llm_fallback_result(f"LLM 錯誤: {type(e).__name__}")
|
||||
# 2026-04-24 ogt + Claude Sonnet 4.6: LLM 錯誤同樣降級至關鍵字結果
|
||||
_kw_result = self._keyword_classify(text)
|
||||
return IntentResult(
|
||||
intent=_kw_result.intent,
|
||||
confidence=_kw_result.confidence,
|
||||
method="llm_error_keyword",
|
||||
matched_keywords=_kw_result.matched_keywords,
|
||||
detected_resources=_kw_result.detected_resources,
|
||||
reasoning=f"LLM 錯誤降級({type(e).__name__})→ {_kw_result.reasoning}",
|
||||
)
|
||||
|
||||
def _parse_intent_type(self, intent_str: str) -> IntentType:
|
||||
"""解析意圖字串為 IntentType"""
|
||||
|
||||
Reference in New Issue
Block a user