ADR-054: DIAGNOSE Privacy-First Routing (已批准) - _local_fallback_chain 設計決策 - NEMOTRON privacy_level=local 首席架構師裁示 - 全部 local 失敗 → REJECT + Telegram ADR-055: Knowledge Auto-Harvesting (已批准) - AUTO_RUNBOOK DRAFT + ANTI_PATTERN PUBLISHED 設計理由 - compute_hash() 碰撞風險說明 - Fire-and-forget GC 防護強制規範 ADR-056: Config Drift Detection 四層架構 (已批准) - Detector→Analyzer→Interpreter→Remediator 職責邊界 - AI 只做意圖分析不做修復決策 - adopt() 暫停 + _recent_reports Phase 1 限制 ADR-057: adopt() Gitea PR API 實作路徑 (草案,待批准) - 解決 API Pod git add -A 安全風險 - PR review 流程保障 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
122 lines
3.7 KiB
Markdown
122 lines
3.7 KiB
Markdown
# ADR-055: Knowledge Auto-Harvesting(AUTO_RUNBOOK + ANTI_PATTERN)
|
||
|
||
> **狀態**: ✅ 已批准
|
||
> **日期**: 2026-04-04
|
||
> **決策者**: 統帥 + 首席架構師
|
||
> **首席架構師評分**: 技術背書
|
||
> **關聯 ADR**: ADR-052 (AI Provider Registry), ADR-043 (Knowledge Base)
|
||
> **實作**: Phase 25 P1 — commit 3455044
|
||
|
||
---
|
||
|
||
## 背景
|
||
|
||
### 問題陳述
|
||
|
||
AutoRepair 執行修復後,成功/失敗的知識停留在系統日誌中,無法被後續決策利用。特別是:
|
||
|
||
1. **成功修復** → 修復步驟應被收錄為可參考的 Runbook
|
||
2. **失敗修復** → 失敗模式應被記錄以防止重複嘗試相同方法
|
||
|
||
Knowledge Base 存在但靠人工填寫,形成知識孤島。
|
||
|
||
---
|
||
|
||
## 決策
|
||
|
||
### D1: AUTO_RUNBOOK — 成功修復自動產生草稿 Runbook
|
||
|
||
```python
|
||
# auto_repair_service.py — execute_auto_repair() 成功後
|
||
task = asyncio.create_task(gen.generate_runbook(incident, playbook, result))
|
||
self._pending_tasks.add(task)
|
||
task.add_done_callback(self._pending_tasks.discard)
|
||
```
|
||
|
||
- EntryType: `AUTO_RUNBOOK`
|
||
- EntryStatus: `DRAFT`(需要人工審核後才升為 APPROVED)
|
||
- Nemotron 生成內容,失敗時有最小化 fallback
|
||
|
||
**理由**: 自動生成的 Runbook 品質未經驗證,保持 DRAFT 讓 SRE 審核,避免錯誤知識被自動採納。
|
||
|
||
### D2: ANTI_PATTERN — 失敗修復直接發布防災記錄
|
||
|
||
```python
|
||
# auto_repair_service.py — execute_auto_repair() 失敗後
|
||
task = asyncio.create_task(
|
||
gen.generate_anti_pattern(incident, playbook, fail_result, symptoms_hash)
|
||
)
|
||
self._pending_tasks.add(task)
|
||
task.add_done_callback(self._pending_tasks.discard)
|
||
```
|
||
|
||
- EntryType: `ANTI_PATTERN`
|
||
- EntryStatus: `PUBLISHED`(直接發布,無需人工審核)
|
||
- 理由:失敗記錄的目的是「防止重蹈覆轍」,早一秒發布早一秒保護
|
||
|
||
### D3: SymptomPattern.compute_hash() — O(1) 防災閘門
|
||
|
||
```python
|
||
def compute_hash(self) -> str:
|
||
key = (
|
||
"|".join(sorted(self.alert_names)) + "||"
|
||
+ "|".join(sorted(self.affected_services)) + "||"
|
||
+ json.dumps(self.label_patterns, sort_keys=True)
|
||
)
|
||
return hashlib.sha256(key.encode()).hexdigest()[:16]
|
||
```
|
||
|
||
- 16 字元 hex = 2^64 碰撞空間,工程實踐上足夠
|
||
- 碰撞發生最壞結果:某次修復被誤攔截,需人工重試——可接受
|
||
|
||
### D4: evaluate_auto_repair() 加入 ANTI_PATTERN 閘門
|
||
|
||
```python
|
||
# 症狀提取後、Playbook 匹配前
|
||
symptoms_hash = symptoms.compute_hash()
|
||
anti_patterns = await get_knowledge_service().check_anti_pattern(symptoms_hash, days=7)
|
||
if anti_patterns:
|
||
return AutoRepairDecision(
|
||
can_auto_repair=False,
|
||
reason=f"過去 7 天有失敗案例: {anti_patterns[0].title}",
|
||
blocked_by="ANTI_PATTERN",
|
||
)
|
||
```
|
||
|
||
閘門位置:診斷症狀後、開始執行前,屬於預防性攔截。
|
||
|
||
### D5: Fire-and-Forget 必須有 GC 防護
|
||
|
||
所有 `asyncio.create_task()` 必須:
|
||
1. 持有引用至 `self._pending_tasks`
|
||
2. 在 `done_callback` 中從集合移除
|
||
|
||
```python
|
||
task = asyncio.create_task(coro)
|
||
self._pending_tasks.add(task)
|
||
task.add_done_callback(self._pending_tasks.discard)
|
||
```
|
||
|
||
成功分支與失敗分支必須對稱實作,不得有遺漏。
|
||
|
||
---
|
||
|
||
## 後果
|
||
|
||
### 正面影響
|
||
|
||
- Knowledge Base 自動積累修復經驗,形成正向循環
|
||
- 失敗模式即時保護,防止重複損耗
|
||
- SRE 工作聚焦於審核而非撰寫
|
||
|
||
### 負面影響 / 風險
|
||
|
||
- Nemotron 生成的 Runbook 品質參差,需 SRE 審核成本
|
||
- ANTI_PATTERN 直接發布,若症狀 hash 碰撞可能誤攔正常修復
|
||
|
||
### 未決事項(Backlog)
|
||
|
||
- I2: `nvidia.chat()` system prompt 格式是否符合 NIM message format 規範
|
||
- M1: ANTI_PATTERN 是否需要 Telegram 確認視窗(human-in-the-loop 選項)
|
||
- M2: symptoms_hash 16 字元截斷的碰撞監控機制
|