はじめに — つまずきに寄り添って
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の実務」を続けてご覧ください。