feat(Phase 6): AI SLO REST API — GET /api/v1/ai/slo 收官
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
ADR-087 Phase 6 自我治理閉環最後一塊拼圖: 1. api/v1/ai_slo.py — GET /api/v1/ai/slo - Service 層快取優先(TTL 5min,AiSloCalculator.get_cached_report) - force_refresh=true 強制重算(AiSloCalculator.run) - Router 層零 Redis 直接存取(leWOOOgo 積木化鐵律) 2. main.py — 路由掛載 ai_slo_v1.router(prefix=/api/v1) 3. MASTER §8 Living Changelog 追加: - P0 告警靜默 3 根因 RCA 完整紀錄 - P2 飛輪斷鏈修復摘要 - Phase 6 全元件完成清單 Phase 6 退出條件 5/6 已達(生產驗證待 image 上線) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
58
apps/api/src/api/v1/ai_slo.py
Normal file
58
apps/api/src/api/v1/ai_slo.py
Normal file
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
AI SLO REST API
|
||||
===============
|
||||
ADR-087 Phase 6 自我治理閉環 — AI 決策品質 SLO 查詢端點
|
||||
|
||||
Endpoints:
|
||||
GET /api/v1/ai/slo — 取得最新 SLO 計算結果(含 Redis 快取)
|
||||
|
||||
設計原則:
|
||||
- 優先讀 Service 層快取(TTL 5min),快取失效才重算
|
||||
- 計算失敗 → 保守回傳 any_violated=True(由 AiSloCalculator 處理)
|
||||
- 強制重算:?force_refresh=true
|
||||
- Router 層不直接存取 Redis(leWOOOgo 積木化鐵律)
|
||||
|
||||
2026-04-15 ogt + Claude Sonnet 4.6(亞太): Phase 6 初始建立
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import structlog
|
||||
from fastapi import APIRouter, Query
|
||||
|
||||
from src.services.ai_slo_calculator import AiSloCalculator
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/ai/slo")
|
||||
async def get_ai_slo(
|
||||
force_refresh: bool = Query(False, description="忽略快取,強制重算"),
|
||||
) -> dict:
|
||||
"""
|
||||
取得 AI 決策品質 SLO 最新結果。
|
||||
|
||||
優先讀 Redis 快取(TTL 5min);force_refresh=true 則強制重算並更新快取。
|
||||
|
||||
Response:
|
||||
calculated_at ISO 時間戳
|
||||
window_days 計算視窗(天)
|
||||
any_violated 是否有任何 SLO 違反
|
||||
cache_hit 是否命中快取
|
||||
metrics[] 三大 SLO 指標明細
|
||||
"""
|
||||
calc = AiSloCalculator()
|
||||
|
||||
if not force_refresh:
|
||||
cached = await calc.get_cached_report()
|
||||
if cached:
|
||||
data = cached.to_dict()
|
||||
data["cache_hit"] = True
|
||||
return data
|
||||
|
||||
report = await calc.run()
|
||||
data = report.to_dict()
|
||||
data["cache_hit"] = False
|
||||
return data
|
||||
@@ -34,6 +34,7 @@ from sentry_sdk.integrations.starlette import StarletteIntegration
|
||||
|
||||
from src.api.v1 import agents as agents_v1 # Phase 9.5: Agent Teams API
|
||||
from src.api.v1 import ai as ai_v1
|
||||
from src.api.v1 import ai_slo as ai_slo_v1 # Phase 6 ADR-087: AI SLO 自我治理
|
||||
from src.api.v1 import approvals as approvals_v1
|
||||
from src.api.v1 import alert_operation_logs as alert_operation_logs_v1
|
||||
from src.api.v1 import audit_logs as audit_logs_v1
|
||||
@@ -514,6 +515,7 @@ app.include_router(csrf_v1.router, prefix="/api/v1", tags=["Security"]) # Phase
|
||||
app.include_router(dashboard_v1.router, prefix="/api/v1", tags=["Dashboard"])
|
||||
app.include_router(approvals_v1.router, prefix="/api/v1", tags=["HITL Approvals"])
|
||||
app.include_router(ai_v1.router, prefix="/api/v1", tags=["AI Decision"])
|
||||
app.include_router(ai_slo_v1.router, prefix="/api/v1", tags=["AI SLO"]) # Phase 6 ADR-087
|
||||
app.include_router(webhooks_v1.router, prefix="/api/v1", tags=["Webhooks"])
|
||||
app.include_router(timeline_v1.router, prefix="/api/v1", tags=["Timeline"])
|
||||
app.include_router(audit_logs_v1.router, prefix="/api/v1", tags=["Audit Logs"])
|
||||
|
||||
Reference in New Issue
Block a user