第95回 実務で回すAIのSLO設計とインシデント対応ワークフロー — Pythonで作る指標・アラート・オンコール・事後対応の手順

はじめに — つまずきに寄り添って

AI機能を業務に組み込むとき、「モデルの挙動が安定しない」「どの指標を見れば良いか分からない」「アラートが頻繁で対応が追いつかない」といった悩みをよく聞きます。本記事は、実務で使えるSLO(Service Level Objective)設計からアラート、オンコール、事後対応までを、現場でそのまま使える手順とPython例で示します。第94回のCI/CD・テスト運用の検証を運用に繋げる流れを意識しています。

なぜAIにSLOが必要か

AIは従来のサービスと違い、モデルの更新や外部APIの変化で振る舞いが変わります。SLOを定める目的は主に次の3点です。

  • ビジネス影響との紐付け:ユーザー体験や売上に直結する指標に焦点を当てる。
  • ユーザー体験低下の早期検出:モデル劣化や外部障害を早めに察知する。
  • 運用コスト削減:重要でないノイズなアラートを減らし、対応工数を節約する。

第94回で作ったテストやCIを、SLOによる運用ループに組み込むことで、デプロイ前後のリスク管理が容易になります。

SLI選定とSLOの決め方(実務フロー)

まずSLI(Service Level Indicator)を選定し、SLO(目標)を現場ルールで決めます。以下は代表的なSLIと定義方法の例です。

SLI 具体的な定義 計測方法
レイテンシ API応答時間のp95 < 500ms リクエストごとに応答時間をHistogramで記録
成功率 正常応答率(HTTP 200かつエラーフラグなし) > 99% ステータスコード+内部APIエラー判定をカウント
事実性(ファクトチェク率) 情報源に基づく出典応答率 > 90% 応答に出典が付与されている割合をログから抽出
ビジネスKPI 転換率の低下が1%未満 イベントトラッキングとSLOアラートの紐付け

目標設定のルール(実務例)

  • SLO期間:30日(短期)/90日(中期)の両方を監視する。
  • 許容バースト:短時間のスパイクを許容するため、burn rateを導入する(例:1時間でのburn rate > 4でCritical)。
  • 運用しやすさ重視:まずは重要SLIを2〜3個に絞る。

メトリクス収集と実装例(Python)

実務では、リクエストにトレースしやすいIDを付与し、Prometheusなどで集計するのが定石です。以下は簡易サンプルです。

from prometheus_client import Counter, Histogram, start_http_server
import time, uuid

REQUEST_LATENCY = Histogram('ai_request_latency_seconds', 'AI API latency')
REQUEST_COUNTER = Counter('ai_requests_total', 'Total AI requests', ['status'])

def handle_request(request):
    req_id = str(uuid.uuid4())
    start = time.time()
    try:
        # ここでAI呼び出し
        result = call_ai_api(request, request_id=req_id)
        REQUEST_COUNTER.labels(status='ok').inc()
    except Exception:
        REQUEST_COUNTER.labels(status='error').inc()
        raise
    finally:
        REQUEST_LATENCY.observe(time.time() - start)
    return result

if __name__ == '__main__':
    start_http_server(8000)  # Prometheusに公開

事実性メトリクスはログやベクトルDBの照合で得ます。例:応答テキストの出典がベクトルDBの最上位レコードと類似度閾値を満たす割合をカウントします。

# 疑似コード: 事実性チェック(ベクトルDBからの類似度確認)
def check_factuality(response_text, query_embedding):
    docs = vector_db.search(query_embedding, top_k=3)
    # 出典の有無と平均類似度で閾値判定
    return any(similarity > 0.8 for _, similarity in docs)

SLOの計算は定期バッチで行うことが多いです。簡易スクリプト例:

def calculate_slo(success_count, total_count):
    return success_count / total_count if total_count > 0 else 1.0

# 30日窓での例
slo = calculate_slo(ok_count_30d, total_count_30d)

アラート設計としきい値運用

アラートはWarning/Criticalの2段階がおすすめです。運用中に閾値はチューニングが必要です。

レベル 条件(例) 対応
Warning 30日SLO達成率 < 99.5% または burn rate > 2(1時間) Slack通知+当番への軽い確認
Critical 30日SLO達成率 < 99% または burn rate > 4(1時間) PagerDuty通知+オンコール起動+自動スナップショット収集

ノイズを減らす工夫:

  • エラー率だけでなくビジネス影響(転換率低下や注文キャンセルの増加)との組合せで条件化する。
  • 短時間のスパイクは移動平均やburn rateで評価する。
  • しきい値決定チェックリスト:データ量・業務時間・影響コストを基に決める。

インシデント対応ランブック(Runbook)とトリアージ

代表的な初動手順のテンプレートを示します。簡潔で実行しやすいことが重要です。

初動チェックリスト

  • アラート確認:どのSLIがトリガーかを特定する。
  • 影響範囲の特定:ユーザー数・地域・APIキー別など。
  • 最近のデプロイ確認:CI/CDでの直近の変更有無。
  • フェイルオーバー可否:フォールバックモデルや機能制限が可能か。

トリアージ用の調査クエリ例

# ログストレージ例(疑似クエリ)
SELECT count(*) AS errors, status_code
FROM logs
WHERE time > now() - interval '1 hour'
GROUP BY status_code
ORDER BY errors DESC;

暫定対応(テンプレート)

  • 軽微な劣化:警告を出して継続監視。
  • モデル劣化疑い:直近モデルにロールバック、または安定モデルへ切替。
  • 外部API障害:リトライ制御を強め、必要なら機能制限(例:重たい推論を一時停止)。

オンコール運用とローテーション設計

小さなチームで回す実務ルールの例:

  • 1週間単位の当番制(週替わり)で負荷を平準化。
  • 夜間は簡易対応ルール:自動復旧試行→重大な場合のみフル起動。
  • 引継ぎメモのフォーマットを用意:現状、未解決タスク、観測中の指標。
項目 フォーマット例
当番 2026-07-01 ~ 2026-07-07: 山田(#oncall)
引継ぎ 未解決:事実性低下の調査中(ログ:link)

インシデント自動化(Python例)

アラート発生時の処理を自動化すると負担が減ります。以下はPagerDuty/Slackへ自動で通知し、データスナップショットを保存する例です。

import requests, datetime, json

# Slack通知
def notify_slack(webhook_url, text):
    requests.post(webhook_url, json={'text': text})

# PagerDutyイベント(簡易)
def trigger_pagerduty(integration_key, summary):
    url = 'https://events.pagerduty.com/v2/enqueue'
    payload = {
        'routing_key': integration_key,
        'event_action': 'trigger',
        'payload': {'summary': summary, 'severity': 'critical'}
    }
    requests.post(url, json=payload)

# スナップショット収集
def collect_snapshot(request_ids):
    # DBやログストレージから該当リクエストを抽出してS3等に保存する
    filename = f'snapshot_{datetime.datetime.utcnow().isoformat()}.json'
    with open(filename, 'w') as f:
        json.dump({'requests': request_ids}, f)
    return filename

CIでランブックの自動テストを組み込み、想定手順を定期的に検証すると夜間の対応が安定します。

事後対応(Postmortem / RCA)と改善ループ

事後対応は形式に従って事実ベースで短くまとめ、改善につなげることが重要です。以下はテンプレートです。

項目 記入内容
事実 いつ、何が起きたか(タイムライン)
影響範囲 影響を受けたユーザー数、売上、機能
根本原因 原因を深掘り。単なる事象ではなくシステムや運用の欠陥を特定
対策(短期/中期/長期) 具体的な担当者と期限を設定

改善策はCI/CD・監視・SLOに結びつけ、実装後に自動で回帰テストを走らせることが理想です。

運用で見るべき効果指標とレビュー頻度

定期レビューは効果的な運用の要です。代表的な指標と推奨頻度を示します。

指標 説明 レビュー頻度
MTTD 障害検知までの平均時間 月次
MTTR 障害復旧までの平均時間 月次
インシデント数 期間内のインシデント発生回数 月次 / 四半期
SLO達成率 SLOの達成状況 週次(要監視) / 月次(レビュー)

現場での注意点・よくある失敗パターン

  • 過度に細かいSLO設定:初期は絞って運用し、データが揃ったら拡張する。
  • アラート過多(アラート疲れ):重要指標に絞り、階層化する。
  • 事後対応の形骸化:実行可能な対策と期限、担当者を必ず書く。

付録:テンプレート(そのまま貼れるHTML)

SLO定義シート(例)

項目 定義
SLI名 事実性(出典応答率)
SLO 90日で >= 90%
計測方法 応答に出典が付いている割合をログから集計
オーナー プロダクト責任者(氏名)

ランブックテンプレート(抜粋)

ステップ 内容
1 アラート内容と発生時刻の記録
2 影響範囲の特定(ユーザー数/機能)
3 暫定対応(ロールバック/フォールバック)
4 再発防止策の仮決定とチケット作成

RCAテンプレート(抜粋)

項目 記述欄
概要
タイムライン
根本原因
対策(短/中/長期)

簡易Pythonスクリプト断片(そのまま貼れる)

from prometheus_client import Summary
import requests

REQUEST_TIME = Summary('request_processing_seconds', 'Time spent processing request')

@REQUEST_TIME.time()
def call_ai_api(payload, request_id=None):
    headers = {'X-Request-ID': request_id} if request_id else {}
    r = requests.post('https://api.example.com/ai', json=payload, headers=headers, timeout=10)
    r.raise_for_status()
    return r.json()

まとめ

本記事では、AI機能に対するSLO設計からメトリクス収集、アラート設計、オンコール運用、インシデント自動化、事後対応までを実務寄りにまとめました。ポイントは「小さく始める」「重要指標に集中する」「自動化で負担を下げる」ことです。まずは2〜3のSLIを定め、簡易なメトリクス収集とWarning/Criticalのアラートを設定して運用を回し、得られたデータでSLOと閾値を改善していくことをおすすめします。

次回以降は、今回のSLO運用と第94回で扱ったCI/CDの連携事例をより具体的に示します。Manage AIシリーズ「AIとPythonの実務」を続けてご覧ください。