docs: ADR 整理與新增 (021-029)
ADR 編號修正: - ADR-023 failure-auto-repair → ADR-028 - ADR-025 cicd-ai-integration → ADR-029 新增 ADR: - ADR-021: Playbook 更新驗證 - ADR-022: Sentry 整合架構 - ADR-027: Incident-Approval 同步 - ADR-028: 失敗自動修復閉環 - ADR-029: CI/CD AI 整合 (原 ADR-025) 更新: - ADR-018: LLM 測試策略狀態更新 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
| 屬性 | 值 |
|
||||
|------|-----|
|
||||
| **狀態** | 提案中 |
|
||||
| **狀態** | 延緩 (Deferred) - 方案 A 先行 |
|
||||
| **建立日期** | 2026-03-26 |
|
||||
| **決策者** | 首席架構師 + 統帥 |
|
||||
| **關聯** | Phase 12.3, #68, #69 |
|
||||
@@ -170,3 +170,27 @@ async def test_semantic_similarity(llm_response, golden_response):
|
||||
- [LLM Evaluation Best Practices](https://www.anthropic.com/research/evaluations)
|
||||
- [Property-Based Testing](https://hypothesis.readthedocs.io/)
|
||||
- [Sentence Transformers](https://www.sbert.net/)
|
||||
|
||||
---
|
||||
|
||||
## 2026-03-26 決策更新
|
||||
|
||||
**狀態**: 延緩 (Deferred)
|
||||
|
||||
**實際採用方案**: 方案 A - 最小改動優先
|
||||
|
||||
| 項目 | 實作內容 |
|
||||
|------|---------|
|
||||
| 確定性參數 | `temperature: 0.0`, `seed: 42` |
|
||||
| CI 分層 | LLM 測試移至 Nightly |
|
||||
| 超時調整 | 300 秒 (CPU 推理) |
|
||||
| 繁體中文 | System Prompt 強制繁中 |
|
||||
|
||||
**原因**:
|
||||
1. 三層策略實作成本高 (~1000 行代碼)
|
||||
2. 方案 A 已解決 CI 不穩定問題
|
||||
3. 優先確保 CI 穩定,後續再評估是否需要完整框架
|
||||
|
||||
**評估文件**: `docs/evaluations/2026-03-26_llm_testing_evaluation.md`
|
||||
|
||||
**後續**: 若方案 A 效果良好,此 ADR 維持 Deferred;若仍有問題,再實施三層策略
|
||||
|
||||
79
docs/adr/ADR-021-playbook-update-validation.md
Normal file
79
docs/adr/ADR-021-playbook-update-validation.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# ADR-021: Playbook 更新驗證策略
|
||||
|
||||
| 屬性 | 值 |
|
||||
|------|-----|
|
||||
| **狀態** | Accepted |
|
||||
| **建立日期** | 2026-03-26 |
|
||||
| **決策者** | 首席架構師 |
|
||||
| **關聯** | Phase 8 P1 修復, leWOOOgo 積木化原則 |
|
||||
|
||||
## 背景
|
||||
|
||||
Router 層 (`playbooks.py`) 使用 `setattr()` 動態更新 Playbook 欄位,繞過 Pydantic 驗證:
|
||||
|
||||
```python
|
||||
# ❌ 問題代碼 (Router 層)
|
||||
update_data = request.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(playbook, field, value) # 無驗證!
|
||||
```
|
||||
|
||||
問題:
|
||||
1. **資料完整性** - 非法狀態值可直接寫入
|
||||
2. **違反分層** - Router 層執行業務邏輯
|
||||
3. **安全風險** - 可修改 `playbook_id`, `success_count` 等欄位
|
||||
|
||||
## 決策
|
||||
|
||||
將更新邏輯移至 Service 層,實作 `update_with_validation()` 方法。
|
||||
|
||||
### 驗證規則
|
||||
|
||||
| 規則 | 說明 |
|
||||
|------|------|
|
||||
| **禁止修改欄位** | `playbook_id`, `created_at`, `success_count`, `failure_count`, `last_used_at` |
|
||||
| **狀態轉換** | DRAFT → APPROVED (允許), APPROVED → DEPRECATED (允許), 反向 (禁止) |
|
||||
| **DEPRECATED 狀態** | 不可修改任何欄位 |
|
||||
|
||||
### 實作
|
||||
|
||||
```python
|
||||
# ✅ Service 層 (playbook_service.py)
|
||||
async def update_with_validation(
|
||||
self,
|
||||
playbook_id: str,
|
||||
update_data: dict,
|
||||
) -> Playbook | None:
|
||||
# 1. 過濾禁止修改的欄位
|
||||
# 2. 驗證狀態轉換
|
||||
# 3. 應用更新
|
||||
# 4. 儲存
|
||||
```
|
||||
|
||||
```python
|
||||
# ✅ Router 層 (playbooks.py)
|
||||
updated = await service.update_with_validation(
|
||||
playbook_id=playbook_id,
|
||||
update_data=request.model_dump(exclude_unset=True),
|
||||
)
|
||||
```
|
||||
|
||||
## 影響
|
||||
|
||||
| 檔案 | 變更 |
|
||||
|------|------|
|
||||
| `src/services/playbook_service.py` | 新增 `update_with_validation()` |
|
||||
| `src/api/v1/playbooks.py` | 改用 Service 方法 |
|
||||
|
||||
## 替代方案
|
||||
|
||||
| 方案 | 優點 | 缺點 | 決定 |
|
||||
|------|------|------|------|
|
||||
| 維持現狀 (setattr) | 無需改動 | 繞過驗證 | ❌ |
|
||||
| Pydantic validator | 自動驗證 | 無法檢查狀態轉換 | ❌ |
|
||||
| **Service 層驗證** | 完整控制 | 需新增方法 | ✅ |
|
||||
|
||||
## 相關
|
||||
|
||||
- ADR-003: leWOOOgo 積木化架構
|
||||
- Skill 02: leWOOOgo Backend Core
|
||||
144
docs/adr/ADR-022-sentry-integration-architecture.md
Normal file
144
docs/adr/ADR-022-sentry-integration-architecture.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# ADR-022: Sentry 整合架構
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| **狀態** | ✅ 已採用 |
|
||||
| **日期** | 2026-03-26 |
|
||||
| **決策者** | 首席架構師 + 統帥 |
|
||||
| **Phase** | Phase 10 |
|
||||
|
||||
## 背景
|
||||
|
||||
AWOOOI 需要完整的錯誤追蹤能力,補強 SignOz APM 的不足:
|
||||
- SignOz 專注效能監控 (Traces, Metrics)
|
||||
- Sentry 專注錯誤追蹤 (Stacktrace, Context, Session Replay)
|
||||
|
||||
## 決策
|
||||
|
||||
採用 **BFF + AI 分析** 三層架構:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ AWOOOI Web UI │
|
||||
│ /errors 頁面 (React + next-intl) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ AWOOOI API (BFF Layer) │
|
||||
│ Router: /api/v1/errors/* │
|
||||
│ Service: SentryService + ErrorAnalyzerService │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌───────────────┼───────────────┐
|
||||
▼ ▼
|
||||
┌──────────────────────┐ ┌──────────────────────────┐
|
||||
│ Sentry Self-Hosted │ │ OpenClaw LLM │
|
||||
│ 192.168.0.110:9000 │ │ 192.168.0.188:8088 │
|
||||
└──────────────────────┘ └──────────────────────────┘
|
||||
```
|
||||
|
||||
## 架構組件
|
||||
|
||||
### 1. SentryService (`services/sentry_service.py`)
|
||||
|
||||
**職責**: 封裝 Sentry API 呼叫
|
||||
|
||||
```python
|
||||
class SentryService:
|
||||
async def list_projects() -> list[dict]
|
||||
async def list_issues(query, limit, cursor) -> list[dict]
|
||||
async def get_issue(issue_id) -> dict
|
||||
async def get_issue_events(issue_id, limit, full) -> list[dict]
|
||||
async def get_project_stats(stat, resolution) -> list
|
||||
def get_issue_url(issue_id) -> str
|
||||
```
|
||||
|
||||
**設計原則**:
|
||||
- Singleton 模式
|
||||
- 配置從 `core/config.py` Settings 取得
|
||||
- 支援 DI 測試替換
|
||||
|
||||
### 2. ErrorAnalyzerService (`services/error_analyzer_service.py`)
|
||||
|
||||
**職責**: AI 根因分析
|
||||
|
||||
```python
|
||||
class ErrorAnalyzerService:
|
||||
async def analyze_error(
|
||||
issue_id, title, level, culprit,
|
||||
count, stacktrace, context
|
||||
) -> tuple[ErrorAnalysisResult | None, str, bool]
|
||||
```
|
||||
|
||||
**分析結果**:
|
||||
- root_cause: 根因分析
|
||||
- category: CODE_BUG | DEPENDENCY | CONFIGURATION | ...
|
||||
- severity: LOW | MEDIUM | HIGH | CRITICAL
|
||||
- fix_recommendation: 修復建議
|
||||
- prevention: 預防措施
|
||||
- confidence: 信心度 (0.0-1.0)
|
||||
|
||||
### 3. Router Layer (`api/v1/errors.py`)
|
||||
|
||||
**職責**: HTTP 轉發 (符合 leWOOOgo 積木化)
|
||||
|
||||
| 端點 | 功能 |
|
||||
|------|------|
|
||||
| `GET /stats` | 錯誤統計概覽 |
|
||||
| `GET /issues` | 列出 Issues (分頁、過濾) |
|
||||
| `GET /issues/{id}` | Issue 詳情 |
|
||||
| `GET /trends` | 趨勢圖表數據 |
|
||||
| `POST /issues/{id}/analyze` | 觸發 AI 分析 |
|
||||
|
||||
## 配置管理
|
||||
|
||||
所有 Sentry 配置集中於 `core/config.py`:
|
||||
|
||||
```python
|
||||
SENTRY_SELF_HOSTED_URL: str = "http://192.168.0.110:9000"
|
||||
SENTRY_ORG: str = "sentry"
|
||||
SENTRY_PROJECT: str = "awoooi-api"
|
||||
SENTRY_AUTH_TOKEN: str = "" # K8s Secret
|
||||
```
|
||||
|
||||
## 與 SignOz 的關係
|
||||
|
||||
| 工具 | 職責 | 查看時機 |
|
||||
|------|------|----------|
|
||||
| **SignOz** | APM + Traces | 慢、效能問題 |
|
||||
| **Sentry** | Error Tracking | 壞、錯誤堆疊 |
|
||||
|
||||
**互補策略**: 兩者皆部署,各司其職。
|
||||
|
||||
## 前端整合
|
||||
|
||||
- 使用 `next-intl` 100% i18n (禁止 hardcode)
|
||||
- Nothing.tech 視覺規範 (白底、細邊框、無陰影)
|
||||
- React Hook: `useErrors()` 自動刷新 60 秒
|
||||
|
||||
## 替代方案 (已拒絕)
|
||||
|
||||
| 方案 | 拒絕原因 |
|
||||
|------|----------|
|
||||
| 直接嵌入 Sentry Iframe | 違反視覺主權,無法自訂 UI |
|
||||
| 前端直接呼叫 Sentry API | 違反 BFF 原則,CORS 問題 |
|
||||
| 只用 SignOz | 錯誤追蹤能力不足 |
|
||||
|
||||
## 後果
|
||||
|
||||
### 正面
|
||||
- 完整的錯誤追蹤能力
|
||||
- AI 輔助根因分析
|
||||
- 符合 leWOOOgo 架構
|
||||
|
||||
### 負面
|
||||
- 多一個服務需維護 (Sentry Self-Hosted)
|
||||
- 額外的 API 呼叫延遲
|
||||
|
||||
## 相關文件
|
||||
|
||||
- `project_phase10_arch_review.md` - 架構審查報告
|
||||
- `project_sentry_full_integration.md` - 整合計畫
|
||||
- ADR-005: BFF Architecture
|
||||
- ADR-006: AI Fallback Strategy
|
||||
243
docs/adr/ADR-027-incident-approval-sync.md
Normal file
243
docs/adr/ADR-027-incident-approval-sync.md
Normal file
@@ -0,0 +1,243 @@
|
||||
# ADR-027: Incident-Approval 同步架構
|
||||
|
||||
**狀態**: 批准
|
||||
**日期**: 2026-03-26 (台北時區)
|
||||
**決策者**: 統帥
|
||||
**觸發**: 活躍事件顯示 0 + Telegram 告警鏈異常 (2026-03-26 首席架構師審查)
|
||||
|
||||
## 問題陳述
|
||||
|
||||
```
|
||||
事故時間線:
|
||||
├── 2026-03-26: 活躍事件顯示 0 件,但 Telegram 有新告警
|
||||
├── 首席架構師審查: 發現 Incident-Approval 狀態同步機制缺失
|
||||
│
|
||||
├── CRITICAL-001: Incident + Approval 建立不是原子事務
|
||||
│ └─ 後果: 孤兒 Incident、狀態不一致
|
||||
│
|
||||
├── CRITICAL-002: 雙層寫入非原子 (Redis + PostgreSQL)
|
||||
│ └─ 後果: 資料遺失、狀態分歧
|
||||
│
|
||||
├── HIGH-001: Approval 狀態變更未同步 Incident
|
||||
│ └─ 後果: 前端 get_active 查詢結果錯誤
|
||||
│
|
||||
├── HIGH-002: Redis TTL 過期導致資料遺失
|
||||
│ └─ 後果: 長時間未處理事件消失
|
||||
│
|
||||
└── HIGH-003: 前端狀態一致性問題
|
||||
└─ 後果: 簽核後內容立即消失
|
||||
```
|
||||
|
||||
**核心問題**:
|
||||
1. Incident 和 Approval 沒有事務保證
|
||||
2. Redis (Working Memory) 和 PostgreSQL (Episodic Memory) 同步機制不完整
|
||||
3. 狀態變更沒有雙向傳播
|
||||
|
||||
---
|
||||
|
||||
## 決策:UnitOfWork + Saga Pattern
|
||||
|
||||
### 為什麼選擇這個方案?
|
||||
|
||||
| 方案 | 優點 | 缺點 | 選擇 |
|
||||
|------|------|------|------|
|
||||
| 兩階段提交 (2PC) | 強一致性 | Redis 不支援、效能差 | ❌ |
|
||||
| **UnitOfWork + Saga** | PostgreSQL 事務 + Redis 補償 | 需處理補償邏輯 | ✅ |
|
||||
| 事件溯源 | 完整審計軌跡 | 改動太大 | ❌ |
|
||||
| 最終一致性 | 簡單 | 不適合關鍵業務 | ❌ |
|
||||
|
||||
### 架構設計
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Incident-Approval 同步架構 (ADR-027) │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Alertmanager │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ IncidentApprovalService.create_with_approval() │
|
||||
│ │ │
|
||||
│ ├─────────────────────────────────────────┐ │
|
||||
│ ▼ ▼ │
|
||||
│ UnitOfWork (PostgreSQL) Redis Write │
|
||||
│ │ │ │
|
||||
│ ├─ incident = Incident.create() │ │
|
||||
│ ├─ approval = Approval.create() │ │
|
||||
│ │ │ │
|
||||
│ ├─────── 事務 commit ─────────────────────┤ │
|
||||
│ │ │ │
|
||||
│ │ 成功 ────────────────────────────────→ 完成 │
|
||||
│ │ │ │
|
||||
│ │ 失敗 ────────────────────────────────→ Saga 補償 │
|
||||
│ │ (rollback PostgreSQL, │
|
||||
│ │ delete Redis keys) │
|
||||
│ ▼ │
|
||||
│ 同步 Hook │
|
||||
│ │ │
|
||||
│ └─ on_approval_status_change() │
|
||||
│ ├─ update Incident.status │
|
||||
│ ├─ refresh Redis TTL │
|
||||
│ └─ emit SSE event │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 實作細節
|
||||
|
||||
### 1. UnitOfWork 模式 (`src/core/unit_of_work.py`)
|
||||
|
||||
```python
|
||||
class UnitOfWork:
|
||||
"""PostgreSQL 事務管理器"""
|
||||
|
||||
def __init__(self, session_factory):
|
||||
self.session_factory = session_factory
|
||||
self._session = None
|
||||
|
||||
async def __aenter__(self):
|
||||
self._session = self.session_factory()
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||
if exc_type:
|
||||
await self.rollback()
|
||||
else:
|
||||
await self.commit()
|
||||
await self._session.close()
|
||||
|
||||
async def commit(self):
|
||||
await self._session.commit()
|
||||
|
||||
async def rollback(self):
|
||||
await self._session.rollback()
|
||||
```
|
||||
|
||||
### 2. IncidentApprovalService (`src/services/incident_approval_service.py`)
|
||||
|
||||
```python
|
||||
class IncidentApprovalService:
|
||||
"""Incident-Approval 同步服務 (ADR-027)"""
|
||||
|
||||
async def create_with_approval(
|
||||
self,
|
||||
incident_data: IncidentCreate,
|
||||
approval_data: ApprovalCreate
|
||||
) -> tuple[Incident, Approval]:
|
||||
"""原子建立 Incident + Approval"""
|
||||
|
||||
async with UnitOfWork(self.session_factory) as uow:
|
||||
# 1. PostgreSQL 寫入
|
||||
incident = await self.incident_repo.create(uow.session, incident_data)
|
||||
approval = await self.approval_repo.create(uow.session, approval_data)
|
||||
|
||||
# 2. Redis 寫入 (事務外,需補償)
|
||||
try:
|
||||
await self._write_to_redis(incident, approval)
|
||||
except RedisError as e:
|
||||
# Saga 補償: rollback PostgreSQL
|
||||
await uow.rollback()
|
||||
raise IncidentApprovalCreateError(f"Redis 寫入失敗: {e}")
|
||||
|
||||
return incident, approval
|
||||
|
||||
async def on_approval_status_change(
|
||||
self,
|
||||
approval_id: str,
|
||||
new_status: ApprovalStatus
|
||||
):
|
||||
"""Approval 狀態變更 Hook"""
|
||||
|
||||
# 1. 更新 PostgreSQL
|
||||
approval = await self.approval_repo.update_status(approval_id, new_status)
|
||||
|
||||
# 2. 同步更新關聯 Incident
|
||||
incident = await self.incident_repo.get_by_approval_id(approval_id)
|
||||
if incident:
|
||||
incident_status = self._map_approval_to_incident_status(new_status)
|
||||
await self.incident_repo.update_status(incident.id, incident_status)
|
||||
|
||||
# 3. 更新 Redis TTL
|
||||
await self._refresh_redis_ttl(incident.id, approval_id)
|
||||
|
||||
# 4. 觸發 SSE 事件
|
||||
await self._emit_status_change_event(incident, approval)
|
||||
```
|
||||
|
||||
### 3. 統一常量 (`src/core/constants.py`)
|
||||
|
||||
```python
|
||||
# TTL 設定 (秒)
|
||||
INCIDENT_TTL_SECONDS = 7 * 24 * 3600 # 7 天
|
||||
APPROVAL_TTL_SECONDS = 7 * 24 * 3600 # 7 天
|
||||
|
||||
# Redis Key 前綴
|
||||
REDIS_KEY_INCIDENT = "incidents:"
|
||||
REDIS_KEY_APPROVAL = "approvals:"
|
||||
REDIS_KEY_PENDING = "pending_approvals"
|
||||
|
||||
# 狀態映射
|
||||
APPROVAL_TO_INCIDENT_STATUS = {
|
||||
"pending": "active",
|
||||
"approved": "resolved",
|
||||
"rejected": "rejected",
|
||||
"expired": "expired",
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四階段實作計畫
|
||||
|
||||
| Phase | 內容 | 估時 | 優先級 |
|
||||
|-------|------|------|--------|
|
||||
| 1 | UnitOfWork + IncidentApprovalService | 3-4h | P0 |
|
||||
| 2 | 狀態同步 Hook + TTL 延長 | 2-3h | P0 |
|
||||
| 3 | 分散式鎖 + TTL 同步 | 2-3h | P1 |
|
||||
| 4 | 整合測試 | 2h | P1 |
|
||||
|
||||
**總估時**: 9-12h
|
||||
|
||||
---
|
||||
|
||||
## 驗收標準
|
||||
|
||||
| 項目 | 狀態 |
|
||||
|------|------|
|
||||
| Incident + Approval 原子建立 | 🔲 待實作 |
|
||||
| PostgreSQL 事務回滾生效 | 🔲 待實作 |
|
||||
| Redis 補償機制 (Saga) | 🔲 待實作 |
|
||||
| Approval 狀態變更同步 Incident | 🔲 待實作 |
|
||||
| TTL 統一管理 | 🔲 待實作 |
|
||||
| 整合測試通過 | 🔲 待實作 |
|
||||
|
||||
---
|
||||
|
||||
## 關聯文件
|
||||
|
||||
- ADR-011: NetworkPolicy 變更治理架構
|
||||
- ADR-026: CoreDNS GitOps 管控架構
|
||||
- [project_incident_approval_sync.md](~/.claude/projects/-Users-ogt-awoooi/memory/project_incident_approval_sync.md)
|
||||
- [feedback_incident_approval_sync.md](~/.claude/projects/-Users-ogt-awoooi/memory/feedback_incident_approval_sync.md)
|
||||
|
||||
---
|
||||
|
||||
## 附錄:驗證指令
|
||||
|
||||
```bash
|
||||
# 檢查活躍事件
|
||||
curl -s http://localhost:8000/api/v1/incidents/active | jq '.count'
|
||||
|
||||
# 檢查 Redis Incident
|
||||
redis-cli KEYS "incidents:*"
|
||||
|
||||
# 檢查 PostgreSQL Incident
|
||||
psql -c "SELECT id, status, created_at FROM incidents WHERE status = 'active'"
|
||||
|
||||
# 驗證同步
|
||||
# 1. 建立測試事件
|
||||
# 2. 簽核
|
||||
# 3. 確認 Incident 狀態同步更新
|
||||
```
|
||||
282
docs/adr/ADR-028-failure-auto-repair-loop.md
Normal file
282
docs/adr/ADR-028-failure-auto-repair-loop.md
Normal file
@@ -0,0 +1,282 @@
|
||||
# ADR-028: 失敗自動修復閉環架構 (Failure Auto-Repair Loop)
|
||||
|
||||
> **狀態**: 📋 Proposed
|
||||
> **提案日期**: 2026-03-26
|
||||
> **決策者**: 統帥
|
||||
> **提案者**: 首席架構師
|
||||
|
||||
## Context
|
||||
|
||||
AWOOOI 行動日誌頁面顯示大量失敗操作,但系統只是「記錄」:
|
||||
|
||||
```
|
||||
失敗 → 記錄 → 結束 (死路)
|
||||
```
|
||||
|
||||
這違反了 AIOps 產品的核心價值。作為 AI 產品,應該是:
|
||||
|
||||
```
|
||||
失敗 → AI 分析 → 自動/人工修復 → 驗證 → 學習
|
||||
```
|
||||
|
||||
## Decision
|
||||
|
||||
實作「失敗自動修復閉環」架構,包含以下核心元件:
|
||||
|
||||
### 1. FailureWatcher Worker
|
||||
|
||||
```python
|
||||
class FailureWatcher:
|
||||
"""
|
||||
監聽 AuditLog 失敗事件的 Worker
|
||||
|
||||
消費 Redis Stream: awoooi:audit_logs:failed
|
||||
"""
|
||||
|
||||
async def handle_failure(self, audit_log: AuditLog):
|
||||
# 1. AI 分析失敗原因
|
||||
analysis = await self.repair_analyzer.analyze(audit_log)
|
||||
|
||||
# 2. 建立修復日誌
|
||||
repair_log = await self.create_repair_log(audit_log, analysis)
|
||||
|
||||
# 3. 根據風險等級路由
|
||||
if analysis.risk_level == "LOW":
|
||||
await self.auto_repair(repair_log)
|
||||
else:
|
||||
await self.request_approval(repair_log)
|
||||
```
|
||||
|
||||
### 2. RepairAnalyzer (OpenClaw 整合)
|
||||
|
||||
```python
|
||||
class RepairAnalyzer:
|
||||
"""
|
||||
使用 OpenClaw 分析失敗原因並生成修復策略
|
||||
"""
|
||||
|
||||
async def analyze(self, audit_log: AuditLog) -> RepairAnalysis:
|
||||
prompt = f"""
|
||||
分析以下 K8s 操作失敗原因:
|
||||
|
||||
操作類型: {audit_log.operation_type}
|
||||
目標資源: {audit_log.target_resource}
|
||||
命名空間: {audit_log.namespace}
|
||||
錯誤訊息: {audit_log.error_message}
|
||||
K8s 回應: {audit_log.k8s_response}
|
||||
|
||||
請提供:
|
||||
1. 失敗原因分析
|
||||
2. 建議修復策略
|
||||
3. 風險等級 (LOW/MEDIUM/CRITICAL)
|
||||
4. 是否可自動修復
|
||||
"""
|
||||
|
||||
return await self.openclaw.analyze(prompt)
|
||||
```
|
||||
|
||||
### 3. 資料模型
|
||||
|
||||
```python
|
||||
# 擴展 AuditLog
|
||||
class AuditLog:
|
||||
# ... 現有欄位 ...
|
||||
authorization_channel: Mapped[str | None] # "web" | "telegram" | "auto"
|
||||
authorized_by: Mapped[str | None]
|
||||
authorized_at: Mapped[datetime | None]
|
||||
|
||||
# 新增 RepairLog
|
||||
class RepairLog(Base):
|
||||
__tablename__ = "repair_logs"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True)
|
||||
original_audit_id: Mapped[str] = mapped_column(ForeignKey("audit_logs.id"))
|
||||
|
||||
# AI 分析結果
|
||||
failure_reason: Mapped[str] = mapped_column(Text)
|
||||
repair_strategy: Mapped[str] = mapped_column(Text)
|
||||
repair_command: Mapped[str | None] = mapped_column(Text)
|
||||
|
||||
# 風險與狀態
|
||||
risk_level: Mapped[str] = mapped_column(String(20)) # LOW/MEDIUM/CRITICAL
|
||||
auto_repaired: Mapped[bool] = mapped_column(default=False)
|
||||
repair_status: Mapped[str] = mapped_column(String(20)) # pending/executing/success/failed
|
||||
|
||||
# 時間戳
|
||||
created_at: Mapped[datetime]
|
||||
completed_at: Mapped[datetime | None]
|
||||
|
||||
# 關聯
|
||||
original_audit: Mapped["AuditLog"] = relationship()
|
||||
```
|
||||
|
||||
### 4. 修復流程
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ 失敗自動修復閉環 │
|
||||
├──────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────┐ ┌──────────────┐ ┌─────────────┐ │
|
||||
│ │ AuditLog│───▶│FailureWatcher│───▶│RepairAnalyzer│ │
|
||||
│ │ (失敗) │ │ (偵測) │ │ (AI 分析) │ │
|
||||
│ └─────────┘ └──────────────┘ └──────┬──────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌───────────────┐ │
|
||||
│ │ Trust Engine │ │
|
||||
│ │ (風險評估) │ │
|
||||
│ └───────┬───────┘ │
|
||||
│ │ │
|
||||
│ ┌──────────────────┼──────────────────┐ │
|
||||
│ │ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌───────────┐ ┌───────────┐ ┌─────────┐│
|
||||
│ │ LOW │ │ MEDIUM │ │CRITICAL ││
|
||||
│ │ 自動執行 │ │ 單人授權 │ │Multi-Sig││
|
||||
│ └─────┬─────┘ └─────┬─────┘ └────┬────┘│
|
||||
│ │ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌─────────────┐ ┌─────────────────────────────┐ │
|
||||
│ │AutoRepair │ │ 同步推送 │ │
|
||||
│ │Executor │ │ • Telegram Bot │ │
|
||||
│ │(自動修復) │ │ • Web Dashboard (WebSocket) │ │
|
||||
│ └──────┬──────┘ └────────────┬────────────────┘ │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ 揭露通知 │ │ 等待授權 │ │
|
||||
│ │ (Dashboard) │ │ (記錄來源) │ │
|
||||
│ └─────────────┘ └──────┬──────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ 執行修復 │ │
|
||||
│ └──────┬──────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ 驗證 │ │
|
||||
│ └──────┬──────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ Playbook │ │
|
||||
│ │ 學習萃取 │ │
|
||||
│ └─────────────┘ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 5. 授權來源追蹤
|
||||
|
||||
| Channel | 說明 | 記錄內容 |
|
||||
|---------|------|---------|
|
||||
| `auto` | AI 自動執行 | `authorized_by: "system"` |
|
||||
| `web` | 前端 Dashboard | `authorized_by: "{user_id}"` |
|
||||
| `telegram` | Telegram Bot | `authorized_by: "{telegram_user_id}"` |
|
||||
|
||||
### 6. 前端揭露
|
||||
|
||||
在 Dashboard 新增「AI 自動修復報告」區塊:
|
||||
|
||||
- 過去 24 小時自動修復統計
|
||||
- 最近自動修復列表
|
||||
- 修復成功/失敗比例
|
||||
- 需人工介入的項目
|
||||
|
||||
### 7. API 端點
|
||||
|
||||
```
|
||||
GET /api/v1/repairs # 修復日誌列表
|
||||
GET /api/v1/repairs/{id} # 修復詳情
|
||||
POST /api/v1/repairs/{id}/execute # 人工觸發修復
|
||||
GET /api/v1/repairs/stats # 統計 (自動/人工比例)
|
||||
```
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
1. **AI 真正主動** - 不再等人操作,自動偵測並修復
|
||||
2. **透明揭露** - 用戶清楚知道 AI 做了什麼
|
||||
3. **授權可追溯** - 記錄每次授權的來源和時間
|
||||
4. **降低 MTTR** - 低風險問題秒級自動修復
|
||||
|
||||
### Negative
|
||||
|
||||
1. **複雜度增加** - 需要新增 Worker、模型、API
|
||||
2. **風險** - 自動修復可能造成更大問題 (透過 cooldown 緩解)
|
||||
3. **成本** - 每次分析需要 OpenClaw API 呼叫
|
||||
|
||||
### Risks
|
||||
|
||||
| 風險 | 機率 | 影響 | 緩解措施 |
|
||||
|------|------|------|---------|
|
||||
| 自動修復失敗 | 中 | 中 | 失敗自動升級為人工審批 |
|
||||
| 修復風暴 | 低 | 高 | Cooldown: 同資源 5 分鐘 3 次上限 |
|
||||
| AI 誤判風險 | 中 | 中 | 保守分類,有疑問升級為 MEDIUM |
|
||||
|
||||
## Integration Feasibility (首席架構師評估 2026-03-26)
|
||||
|
||||
### 現有架構相容性: ✅ 95% 相容
|
||||
|
||||
調研結論:系統已具備所有必要基礎設施,可無縫整合。
|
||||
|
||||
| 組件 | 可復用程度 | 說明 |
|
||||
|------|----------|------|
|
||||
| Redis Stream (XREADGROUP) | ✅ 100% | SignalWorker 模式直接複製 |
|
||||
| Worker 消費循環 | ✅ 100% | 代碼結構完全相同 |
|
||||
| AuditLog 持久化 | ✅ 90% | 只需新增 3 欄位 |
|
||||
| Trace Context | ✅ 100% | restore_trace_context() 可用 |
|
||||
| OpenClaw AI | ✅ 70% | 需新增 analyze_failure() |
|
||||
| Telegram 推送 | ✅ 80% | 改為推送修復卡片 |
|
||||
|
||||
### 衝突點與緩解
|
||||
|
||||
| 風險 | 緩解方案 |
|
||||
|------|---------|
|
||||
| 重試無限迴圈 | `max_retry_count = 3` |
|
||||
| OpenClaw 過載 | backpressure queue (max 50) |
|
||||
| Telegram 風暴 | 10 秒批量聚合 |
|
||||
| 決策二重性 | DecisionManager 優先 |
|
||||
|
||||
### 模組化驗證
|
||||
|
||||
```
|
||||
✅ leWOOOgo 積木化原則檢查:
|
||||
├── Protocol 先行: IFailureWatcher, IRepairAnalyzer
|
||||
├── Router 層乾淨: /api/v1/repairs/* 只做 HTTP 轉發
|
||||
├── Service 注入: get_failure_watcher() Singleton
|
||||
├── Repository 分離: AuditLogRepository.list_failures()
|
||||
└── Worker 獨立: failure-watcher-worker Deployment
|
||||
```
|
||||
|
||||
## Implementation Plan (修訂版)
|
||||
|
||||
| Phase | 內容 | 預估 | 優先級 |
|
||||
|-------|------|------|--------|
|
||||
| 18.1 | AuditLog 表擴展 + Migration | 2h | P0 |
|
||||
| 18.2 | FailureWatcher Service | 6h | P0 |
|
||||
| 18.3 | FailureWatcherWorker (K8s) | 4h | P0 |
|
||||
| 18.4 | OpenClaw 失敗分析方法 | 8h | P1 |
|
||||
| 18.5 | Telegram 修復卡片 | 3h | P1 |
|
||||
| 18.6 | E2E 測試 + 部署驗證 | 6h | P0 |
|
||||
|
||||
**總計: 29h (~3.6 天)**
|
||||
|
||||
### 工作依賴順序
|
||||
|
||||
```
|
||||
18.1 (DB) ─┬─→ 18.2 (Service) ─┬─→ 18.3 (Worker) ─→ 18.6 (E2E)
|
||||
│ │
|
||||
│ └─→ 18.5 (Telegram)
|
||||
│
|
||||
└─→ 18.4 (OpenClaw) ──────────────────→ 整合到 18.2
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [Memory: Phase 18 Failure Loop](~/.claude/projects/-Users-ogt-awoooi/memory/project_phase18_failure_loop.md)
|
||||
- [AWOOOI Agentic Workspace Roadmap](../AWOOOI_AGENTIC_WORKSPACE_ROADMAP.md)
|
||||
- [ADR-009: OpenClaw Agent Teams](./ADR-009-openclaw-agent-teams.md)
|
||||
@@ -1,4 +1,4 @@
|
||||
# ADR-025: CI/CD AI 整合架構 (Phase 13.1)
|
||||
# ADR-029: CI/CD AI 整合架構 (Phase 13.1)
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
Reference in New Issue
Block a user