Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
S1 Critical:
- S1-1: asyncio 觸發移至 _call_with_fallback async 上下文,移除 sync 中的 get_event_loop()
- S1-2: _append_rule_to_yaml 加 textwrap.dedent() 正規化 LLM 輸出縮排
- S1-3: _matches() 對 alertname=["*"] 直接回傳 False,防意外命中
S2 Major:
- S2-1: auto_generate_rule() 改為 DI 參數注入 (ollama_url/model/gemini_api_key),移除 import settings
- S2-4: _generate_mock_response docstring 澄清為規則引擎生產路徑,非假數據
- S2-5: suggested_action .strip() 防空白字串繞過 or
S3 Minor:
- S3-2: priority 上界 min(next, 890)
- S3-3: alertname sanitize re.sub([{}]) 防 format KeyError
- S3-4: model_registry.py 最後修改時間戳更新
文件:
- ADR-064: Alert Rule Engine YAML 驅動 + AI 自動學習
- Skills 02: 告警規則引擎 DI 規範 + asyncio 禁止事項
- Skills 03: _generate_mock_response 語意澄清 + 規則引擎降級流程
- LOGBOOK: 本次 Session 完整記錄
2026-04-09 ogt: 首席架構師審查修正
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
103 lines
3.5 KiB
Markdown
103 lines
3.5 KiB
Markdown
# ADR-064: Alert Rule Engine — YAML 驅動規則匹配 + AI 自動學習
|
||
|
||
**狀態**: 已批准
|
||
**日期**: 2026-04-09
|
||
**作者**: ogt + Claude Sonnet 4.6
|
||
**審查**: 首席架構師(2026-04-09)
|
||
|
||
---
|
||
|
||
## 背景
|
||
|
||
`openclaw.py` 中的 `_generate_mock_response` 用硬編碼 if/elif 實作規則匹配,每次新增告警類型都要改 Python 代碼並重新部署。隨著監控目標增加,此模式不可持續。
|
||
|
||
## 決策
|
||
|
||
### D1: 規則外化為 YAML(`apps/api/alert_rules.yaml`)
|
||
|
||
規則引擎從 YAML 檔載入,Pod 重啟即生效,不需要改代碼。
|
||
|
||
**規則結構**:
|
||
```yaml
|
||
rules:
|
||
- id: docker_container_unhealthy
|
||
priority: 10
|
||
match:
|
||
alertname: [DockerContainerUnhealthy]
|
||
message: [unhealthy]
|
||
response:
|
||
kubectl_command: "ssh {host} 'docker inspect {container}...'"
|
||
suggested_action: RESTART_DEPLOYMENT
|
||
risk: medium
|
||
responsibility: INFRA
|
||
```
|
||
|
||
**Priority 體系**:
|
||
| 範圍 | 用途 |
|
||
|------|------|
|
||
| 1–499 | 手寫規則(高優先,不被 AI 覆蓋) |
|
||
| 500–890 | AI 自動生成規則 |
|
||
| 999 | `generic_fallback` 通用兜底 |
|
||
|
||
### D2: AI 自動規則學習機制
|
||
|
||
當告警命中 `generic_fallback` 時,觸發 `auto_generate_rule()`:
|
||
|
||
1. 呼叫 Ollama (deepseek-r1:14b) 生成 YAML 規則片段
|
||
2. Ollama 失敗 → Gemini 2.0 Flash 備援
|
||
3. 驗證格式(id/match/response/kubectl_command 必填)
|
||
4. `textwrap.dedent()` 正規化縮排(防 LLM 輸出前置空格)
|
||
5. append 到 `alert_rules.yaml`
|
||
6. `lru_cache.cache_clear()` — 同 Pod 立即生效
|
||
|
||
### D3: 模組邊界
|
||
|
||
- `alert_rule_engine.py` = Service 層,只讀 YAML,不直接存取 Redis/DB
|
||
- `auto_generate_rule()` 採用 DI 參數注入(`ollama_url`, `model`, `gemini_api_key`),不 import settings 全域單例
|
||
- asyncio 觸發在上層 async `_call_with_fallback()` 執行,不在 sync `_generate_mock_response()` 中操作 event loop
|
||
|
||
### D4: 匹配邏輯
|
||
|
||
優先順序:alertname 完全匹配 > alert_type 部分匹配 > message 關鍵字
|
||
|
||
`generic_fallback`(`alertname: ["*"]`)在 `_matches()` 中永遠回傳 False,由 `match_rule()` 的第二輪迴圈單獨選取,防止其 alert_type/message 關鍵字意外命中。
|
||
|
||
## 已知限制
|
||
|
||
### L1: 多 Pod 環境下規則可能重複生成
|
||
|
||
`_generating` set 是進程記憶體級去重,多 Pod 各自維護。同一告警可能在不同 Pod 同時觸發生成,產生重複規則 append。
|
||
|
||
**緩解**: `_rule_id_exists()` 提供二次去重,但有 lru_cache 的時間窗口 race condition。
|
||
|
||
**計劃**: 若未來 Pod 數 > 2,需 Redis 分散式鎖。目前 prod 為 2 Pod,可接受。
|
||
|
||
### L2: `lru_cache` 跨 Pod 不同步
|
||
|
||
新規則寫入後,只有寫入的 Pod 清除了 cache,其他 Pod 需重啟才能載入新規則。這是已知行為,下次告警觸發時仍會走 `generic_fallback`,但不會再次生成(`_rule_id_exists` 讀 YAML 直接確認)。
|
||
|
||
## 測試策略
|
||
|
||
`auto_generate_rule()` 採 DI,可在不啟動 FastAPI 的情況下單獨測試:
|
||
|
||
```python
|
||
await auto_generate_rule(
|
||
alert_context={"labels": {"alertname": "TestAlert"}},
|
||
ollama_url="http://mock",
|
||
model="test-model",
|
||
)
|
||
```
|
||
|
||
## 相關檔案
|
||
|
||
- `apps/api/alert_rules.yaml` — 規則定義
|
||
- `apps/api/src/services/alert_rule_engine.py` — 規則引擎
|
||
- `apps/api/src/services/openclaw.py` — `_generate_mock_response` + `_call_with_fallback` 整合點
|
||
- `apps/api/Dockerfile` — COPY alert_rules.yaml
|
||
|
||
## 參考
|
||
|
||
- ADR-006: AI 模型路由配置
|
||
- ADR-052: Phase 24 AIRouter
|
||
- `feedback_lewooogo_modular_enforcement.md`: 積木化 5 問
|