Dify 本番運用ガイド:SLO/SLA 設定とアラート設計のベストプラクティス
Dify で構築した AI アプリケーションを本番環境で運用する際、安定性と信頼性を担保するためには適切なモニタリング体制が欠かせません。本記事では、SLO(Service Level Objective)と SLA(Service Level Agreement)の設定方法、そしてアラート設計のベストプラクティスを具体的に解説します。
これから紹介する内容を実践することで、ビジネス要件に合わせた信頼性の高い運用体制を構築できるでしょう。
背景
Dify における本番運用の重要性
Dify は AI アプリケーション開発を効率化する優れたプラットフォームですが、本番環境で安定稼働させるためには、従来の Web アプリケーションとは異なる観点での運用管理が求められます。
LLM(大規模言語モデル)を活用したアプリケーションでは、以下のような特有の課題があります。
- API 呼び出しのレイテンシが不安定
- トークン消費によるコスト変動
- モデルの応答品質のばらつき
- 外部 API への依存による障害リスク
これらの課題に対処するため、適切な SLO/SLA 設定とアラート体制の構築が必要になります。
SLA、SLO、SLI の関係性
本番運用を設計する前に、サービスレベルに関する 3 つの重要な概念を整理しましょう。
以下の図は、これら 3 つの指標がどのように関連しているかを示しています。
mermaidflowchart TB
sla["SLA<br/>(Service Level Agreement)<br/>顧客との契約"]
slo["SLO<br/>(Service Level Objective)<br/>内部目標値"]
sli["SLI<br/>(Service Level Indicator)<br/>測定可能な指標"]
monitor["モニタリングシステム"]
alert["アラート発火"]
sla -->|"より厳しい目標"| slo
slo -->|"達成度を測定"| sli
sli -->|"データ収集"| monitor
monitor -->|"閾値超過"| alert
style sla fill:#ff9999
style slo fill:#ffcc99
style sli fill:#99ccff
図で理解できる要点:
- SLA は顧客との約束であり、違反するとペナルティが発生する可能性があります
- SLO は SLA よりも厳しい内部目標として設定し、バッファを確保します
- SLI は実際に計測可能な具体的な指標で、SLO の達成度を評価します
| # | 用語 | 説明 | 例 |
|---|---|---|---|
| 1 | SLA | サービス提供者と利用者の間で結ぶ契約。違反時の補償も含まれる | 「月間稼働率 99.9% を保証」 |
| 2 | SLO | SLA 達成のために設定する内部目標。SLA より厳しく設定 | 「月間稼働率 99.95% を目標」 |
| 3 | SLI | SLO の達成を判断するために使用される測定可能な指標 | 「API レスポンス時間」「エラー率」 |
SLO を SLA よりも厳しく設定することで、実際に SLA 違反が発生する前にアラートを受け取り、対応する時間的余裕を確保できます。
Dify のアーキテクチャと監視ポイント
Dify は複数のコンポーネントで構成されており、それぞれが異なる役割を担っています。
mermaidflowchart LR
user["エンドユーザー"]
web["Web<br/>フロントエンド"]
api["API サーバー<br/>(Flask)"]
worker["Worker<br/>非同期処理"]
sandbox["Sandbox<br/>コード実行環境"]
redis[("Redis<br/>キャッシュ・キュー")]
postgres[("PostgreSQL<br/>メインDB")]
vector[("Qdrant/Weaviate<br/>ベクトルDB")]
llm["LLM API<br/>(OpenAI等)"]
user -->|"HTTPS"| web
web -->|"REST API"| api
api -->|"タスク送信"| worker
api -->|"安全実行"| sandbox
api -.->|"セッション"| redis
worker -.->|"ジョブキュー"| redis
api -.->|"永続化"| postgres
api -.->|"ベクトル検索"| vector
api -->|"プロンプト送信"| llm
worker -->|"バッチ処理"| llm
style api fill:#99ccff
style worker fill:#99ccff
style llm fill:#ffcc99
図で理解できる要点:
- API サーバーと Worker はスケーリング可能なステートレスコンポーネントです
- Redis、PostgreSQL、ベクトル DB は状態を保持する重要なデータストアです
- 外部 LLM API への依存があるため、その可用性も考慮する必要があります
各コンポーネントで監視すべきポイントは以下の通りです。
| # | コンポーネント | 監視項目 | 重要度 |
|---|---|---|---|
| 1 | API サーバー | レスポンスタイム、エラー率、CPU/メモリ使用率 | ★★★ |
| 2 | Worker | ジョブ処理時間、キュー滞留数、失敗率 | ★★★ |
| 3 | Redis | メモリ使用率、接続数、レイテンシ | ★★☆ |
| 4 | PostgreSQL | クエリ実行時間、接続数、ディスク使用率 | ★★★ |
| 5 | ベクトル DB | 検索レイテンシ、インデックスサイズ | ★★☆ |
| 6 | LLM API | API レスポンスタイム、トークン消費量、エラー率 | ★★★ |
課題
Dify 標準機能の限界
Dify には標準でモニタリング機能が搭載されていますが、本格的な本番運用には以下のような限界があります。
標準モニタリング機能で確認できる指標:
| # | 指標 | 内容 | 制約 |
|---|---|---|---|
| 1 | 質問回数 | 1 日ごとのチャットボットとの対話回数 | 時間単位での詳細分析は不可 |
| 2 | ユーザー満足度 | 1000 メッセージごとの「いいね」数 | リアルタイム性に欠ける |
| 3 | トークン消費量 | 1 日ごとの LLM へのトークン消費量 | コスト最適化には粒度が粗い |
| 4 | 実行ログ | アプリケーションの実行履歴 | アラート機能がない |
Dify の標準機能では、以下のような重要な運用要件を満たせません。
- リアルタイムアラート通知
- 複数サービスの統合監視
- 詳細なパフォーマンス分析
- カスタマイズ可能な SLI 設定
- 障害時の自動エスカレーション
SLO/SLA 設計における課題
AI アプリケーション特有の特性により、従来の Web アプリケーションと同じ SLO/SLA 設計は適用できません。
mermaidflowchart TB
subgraph traditional["従来の Web アプリ"]
web_req["リクエスト"]
web_db[("DB クエリ")]
web_res["レスポンス"]
web_req --> web_db
web_db --> web_res
web_note["予測可能な<br/>レスポンスタイム<br/>(10-100ms)"]
end
subgraph ai_app["AI アプリ (Dify)"]
ai_req["リクエスト"]
ai_vector[("ベクトル検索")]
ai_llm["LLM API<br/>呼び出し"]
ai_res["レスポンス"]
ai_req --> ai_vector
ai_vector --> ai_llm
ai_llm --> ai_res
ai_note["不安定な<br/>レスポンスタイム<br/>(1-10s+)"]
end
style traditional fill:#e6f3ff
style ai_app fill:#fff3e6
AI アプリケーション特有の課題:
-
レイテンシの変動が大きい
- LLM の応答時間は入力長やモデルの負荷状況に依存します
- P50、P95、P99 で大きな差が生じるため、単純な平均値では評価できません
-
品質指標の定量化が難しい
- 「正しい回答」の基準が曖昧です
- ユーザー満足度は主観的で、即座に測定できません
-
外部依存による制御不可能性
- OpenAI や Anthropic などの外部 API に依存します
- 外部サービスの障害やレート制限の影響を直接受けます
-
コストと品質のトレードオフ
- 高速化のためのキャッシュ戦略が品質に影響します
- より高性能なモデルを使うとコストが増加します
これらの課題を考慮した SLO/SLA 設計が必要になります。
アラート設計の難しさ
適切なアラート設計がなければ、以下のような問題が発生します。
| # | 問題 | 影響 | 発生頻度 |
|---|---|---|---|
| 1 | アラート疲れ | 重要な通知を見逃す | 高 |
| 2 | 検知遅延 | 障害対応が後手に回る | 中 |
| 3 | 誤検知 | 無駄な対応コスト | 高 |
| 4 | エスカレーション不備 | 適切な担当者に届かない | 中 |
Dify の標準機能にはアラート機能が組み込まれていないため、外部ツールとの統合が必須となります。
解決策
SLI の定義と選定
まず、Dify アプリケーションで測定すべき具体的な SLI を定義しましょう。
システム境界での SLI 設定
モダンなシステムでは、個々のコンポーネントではなくシステム境界で SLI を設定することが推奨されています。
mermaidflowchart LR
subgraph boundary["システム境界"]
direction TB
endpoint["API エンドポイント"]
subgraph internal["内部コンポーネント<br/>(監視対象外)"]
api_comp["API"]
worker_comp["Worker"]
db_comp["DB"]
end
endpoint --> internal
end
user_app["クライアント<br/>アプリケーション"]
user_app -->|"SLI 測定ポイント"| endpoint
style boundary fill:#e6f3ff
style endpoint fill:#99ccff
システム境界でのみ SLI を測定することで、以下のメリットがあります。
- 顧客視点での品質を直接測定できます
- 監視対象が絞られ、運用負荷が軽減されます
- 内部実装の変更に影響されません
Dify 向け推奨 SLI 一覧
Dify アプリケーションで設定すべき主要な SLI を以下にまとめました。
可用性(Availability)関連:
| # | SLI 名 | 測定方法 | 計算式 |
|---|---|---|---|
| 1 | リクエスト成功率 | HTTP ステータスコードで判定 | (成功リクエスト数 / 総リクエスト数) × 100 |
| 2 | エンドポイント稼働率 | ヘルスチェックの成功率 | (成功チェック数 / 総チェック数) × 100 |
レイテンシ(Latency)関連:
| # | SLI 名 | 測定方法 | 目標値の考え方 |
|---|---|---|---|
| 1 | API レスポンスタイム P95 | リクエスト送信から完了までの時間 | ユーザー体験を損なわない範囲 |
| 2 | LLM 応答時間 P99 | LLM API 呼び出しの所要時間 | プロバイダの SLA を考慮 |
| 3 | ベクトル検索時間 P95 | ベクトル DB への検索クエリ時間 | 全体レイテンシの 10% 以内 |
品質(Quality)関連:
| # | SLI 名 | 測定方法 | 評価タイミング |
|---|---|---|---|
| 1 | ユーザー満足度スコア | いいね/よくない の比率 | 週次集計 |
| 2 | エラー応答率 | LLM からのエラー応答の割合 | リアルタイム |
| 3 | タイムアウト率 | 設定時間内に応答できなかった割合 | リアルタイム |
コスト効率(Cost Efficiency)関連:
| # | SLI 名 | 測定方法 | 監視目的 |
|---|---|---|---|
| 1 | 1 リクエストあたりのトークン消費量 | 総トークン数 / リクエスト数 | コスト最適化 |
| 2 | キャッシュヒット率 | キャッシュヒット数 / 総検索数 | パフォーマンス向上 |
これらの SLI を組み合わせて、ビジネス要件に合った SLO を設定していきます。
SLO の設定戦略
SLI が定義できたら、次は具体的な目標値(SLO)を設定しましょう。
SLO 設定の基本原則
SLO を設定する際は、以下の原則に従ってください。
-
理想値ではなく許容可能な最低ライン
- 100% の可用性を目指すとコストが膨大になります
- ビジネスに必要な最低限の品質レベルを設定します
-
SLA よりも厳しく設定
- SLA が 99.9% なら、SLO は 99.95% に設定します
- バッファを持つことで、SLA 違反前に対処できます
-
測定可能で自動化可能
- 手動で確認する必要がある SLO は避けます
- モニタリングツールで自動計測できる指標にします
-
段階的に厳しくする
- 最初は達成可能な目標から始めます
- 安定稼働できたら徐々に目標を引き上げます
具体的な SLO 設定例
以下は、一般的な Dify アプリケーションでの SLO 設定例です。
可用性の SLO:
| # | SLO 項目 | 目標値 | 測定期間 | 許容ダウンタイム |
|---|---|---|---|---|
| 1 | API エンドポイント稼働率 | 99.9% | 月次 | 43.2 分/月 |
| 2 | リクエスト成功率 | 99.5% | 日次 | 7.2 分/日 |
パフォーマンスの SLO:
| # | SLO 項目 | 目標値 | 測定期間 | 備考 |
|---|---|---|---|---|
| 1 | API レスポンスタイム P95 | < 3 秒 | 時間単位 | チャットボット用途 |
| 2 | API レスポンスタイム P99 | < 5 秒 | 時間単位 | タイムアウト前に完了 |
| 3 | LLM 応答時間 P95 | < 2 秒 | 時間単位 | 外部 API の SLA 考慮 |
品質の SLO:
| # | SLO 項目 | 目標値 | 測定期間 | 評価方法 |
|---|---|---|---|---|
| 1 | ユーザー満足度 | > 80% | 週次 | いいね率で評価 |
| 2 | LLM エラー応答率 | < 1% | 日次 | エラーレスポンス数で測定 |
コスト効率の SLO:
| # | SLO 項目 | 目標値 | 測定期間 | 目的 |
|---|---|---|---|---|
| 1 | 平均トークン消費量 | < 500 トークン/リクエスト | 日次 | コスト管理 |
| 2 | ベクトル検索キャッシュヒット率 | > 60% | 日次 | パフォーマンス向上 |
これらの SLO は、あくまで参考値です。実際のビジネス要件やユーザー体験に基づいて、適切な値を設定してください。
エラーバジェットの活用
SLO を設定したら、エラーバジェット(許容されるエラーの量)を計算し、活用しましょう。
mermaidflowchart TB
slo_target["SLO 目標: 99.9%"]
error_budget["エラーバジェット: 0.1%"]
subgraph usage["バジェット使用状況"]
remaining["残り 50%"]
consumed["消費済み 50%"]
end
decision{"バジェット<br/>残量は?"}
action_safe["新機能リリース OK"]
action_warn["慎重なリリース"]
action_freeze["リリース凍結<br/>安定化に注力"]
slo_target --> error_budget
error_budget --> usage
usage --> decision
decision -->|"> 70%"| action_safe
decision -->|"30-70%"| action_warn
decision -->|"< 30%"| action_freeze
style action_safe fill:#99ff99
style action_warn fill:#ffff99
style action_freeze fill:#ff9999
エラーバジェットの計算例:
SLO が 99.9%(月次)の場合、許容されるダウンタイムは以下の通りです。
- 1 ヶ月(30 日)= 43,200 分
- エラーバジェット = 43,200 × 0.1% = 43.2 分/月
このバジェットを使い切った場合は、新機能開発を停止し、安定性向上に集中します。
外部モニタリングツールの統合
Dify の標準機能だけでは本格的な運用は困難なため、外部のモニタリングツールと統合しましょう。
推奨ツールスタック
以下は、Dify の本番運用で推奨されるモニタリングツールの組み合わせです。
mermaidflowchart TB
subgraph dify_app["Dify アプリケーション"]
api["API サーバー"]
worker["Worker"]
end
subgraph llm_observability["LLM Observability"]
langfuse["Langfuse"]
langsmith["LangSmith"]
end
subgraph infra_monitoring["インフラ監視"]
prometheus["Prometheus"]
grafana["Grafana"]
end
subgraph alerting["アラート管理"]
alertmanager["Alertmanager"]
pagerduty["PagerDuty"]
end
dify_app -->|"トレース・メトリクス"| langfuse
dify_app -->|"トレース・メトリクス"| langsmith
dify_app -->|"システムメトリクス"| prometheus
langfuse -.->|"可視化"| grafana
prometheus -->|"メトリクス"| grafana
prometheus -->|"アラート"| alertmanager
alertmanager -->|"通知"| pagerduty
style llm_observability fill:#fff3e6
style infra_monitoring fill:#e6f3ff
style alerting fill:#ffe6e6
各ツールの役割:
| # | ツール | 役割 | 監視対象 | 統合方法 |
|---|---|---|---|---|
| 1 | Langfuse | LLM トレーシング | プロンプト、応答、レイテンシ、コスト | Dify 標準統合(ワンクリック) |
| 2 | LangSmith | LLM モニタリング | 同上 + 詳細なデバッグ情報 | Dify 標準統合(ワンクリック) |
| 3 | Prometheus | メトリクス収集 | CPU、メモリ、API レート | /metrics エンドポイント公開 |
| 4 | Grafana | ダッシュボード | 全体の可視化 | Prometheus データソース |
| 5 | Alertmanager | アラート管理 | 閾値超過時の通知 | Prometheus ルール定義 |
| 6 | PagerDuty | インシデント管理 | オンコール通知 | Alertmanager Webhook |
Langfuse 統合の実装
Langfuse は Dify と公式に統合されており、ワンクリックで設定できます。
統合手順:
- Langfuse アカウントを作成します(https://langfuse.com)
- プロジェクトを作成し、API キーを取得します
- Dify の管理画面で「モニタリング」タブを開きます
- Langfuse を選択し、API キーを入力します
- 保存すると、自動的にトレースデータが送信されます
Langfuse で確認できる指標:
typescript// Langfuse が自動収集する主要メトリクス
interface LangfuseMetrics {
// レイテンシ分析
latency: {
total: number; // 全体の処理時間
llm: number; // LLM API 呼び出し時間
retrieval: number; // ベクトル検索時間
};
// コスト分析
cost: {
inputTokens: number; // 入力トークン数
outputTokens: number; // 出力トークン数
totalCost: number; // 推定コスト(USD)
};
// 品質分析
quality: {
userFeedback: 'positive' | 'negative'; // ユーザー評価
errorRate: number; // エラー率
};
// トレース情報
trace: {
traceId: string; // 一意のトレース ID
spans: Span[]; // 処理ステップの詳細
metadata: object; // カスタムメタデータ
};
}
Langfuse のダッシュボードでは、以下のような分析が可能です。
- リクエストごとの詳細トレース
- コストのトレンド分析
- レイテンシの P50/P95/P99 分布
- ユーザーフィードバックの集計
Prometheus + Grafana によるインフラ監視
LLM 特有の指標は Langfuse で監視し、インフラレベルの指標は Prometheus + Grafana で監視します。
Prometheus メトリクスのエクスポート:
Dify の API サーバーでメトリクスエンドポイントを公開します。
python# Dify API サーバーにメトリクスエンドポイントを追加
# api/app.py
from prometheus_client import Counter, Histogram, Gauge, generate_latest
from flask import Response
# メトリクスの定義
request_count = Counter(
'dify_api_requests_total',
'Total API requests',
['method', 'endpoint', 'status']
)
python# レスポンスタイムのヒストグラム
request_duration = Histogram(
'dify_api_request_duration_seconds',
'API request duration',
['method', 'endpoint']
)
python# アクティブな接続数
active_connections = Gauge(
'dify_api_active_connections',
'Number of active connections'
)
python# メトリクスエンドポイントの公開
@app.route('/metrics')
def metrics():
"""Prometheus メトリクスを返す"""
return Response(
generate_latest(),
mimetype='text/plain'
)
上記のコードでは、Prometheus が収集できる形式でメトリクスを公開しています。
Prometheus 設定ファイル:
yaml# prometheus.yml
# Prometheus の設定ファイル
global:
scrape_interval: 15s # 15 秒ごとにメトリクスを収集
evaluation_interval: 15s
yaml# スクレイプ対象の設定
scrape_configs:
# Dify API サーバーのメトリクス収集
- job_name: 'dify-api'
static_configs:
- targets: ['dify-api:5001']
labels:
service: 'api'
yaml # Dify Worker のメトリクス収集
- job_name: 'dify-worker'
static_configs:
- targets: ['dify-worker:5002']
labels:
service: 'worker'
yaml # Redis のメトリクス収集(redis_exporter 使用)
- job_name: 'redis'
static_configs:
- targets: ['redis-exporter:9121']
yaml # PostgreSQL のメトリクス収集(postgres_exporter 使用)
- job_name: 'postgres'
static_configs:
- targets: ['postgres-exporter:9187']
この設定により、Dify の各コンポーネントとデータストアのメトリクスを一元管理できます。
Grafana ダッシュボードの作成:
Grafana で SLO ダッシュボードを作成し、リアルタイムで達成状況を可視化します。
json{
"dashboard": {
"title": "Dify SLO Dashboard",
"panels": [
{
"title": "API Availability (SLO: 99.9%)",
"targets": [
{
"expr": "sum(rate(dify_api_requests_total{status=~\"2..\"}[5m])) / sum(rate(dify_api_requests_total[5m])) * 100"
}
]
}
]
}
}
上記は、API の成功率を計算する PromQL クエリの例です。
アラート設計のベストプラクティス
SLO を設定したら、その達成状況を監視し、違反時にアラートを発火する仕組みを構築しましょう。
アラートの優先度設定
すべてのアラートを同じ扱いにすると、重要な通知が埋もれてしまいます。以下のように優先度を設定しましょう。
mermaidflowchart TB
alert["アラート発生"]
decision_slo{"SLO への<br/>影響は?"}
decision_user{"ユーザーへの<br/>影響は?"}
decision_auto{"自動復旧<br/>可能?"}
p0["P0: Critical<br/>即座に対応"]
p1["P1: High<br/>1時間以内に対応"]
p2["P2: Medium<br/>営業時間内に対応"]
p3["P3: Low<br/>週次で確認"]
alert --> decision_slo
decision_slo -->|"SLO 違反"| p0
decision_slo -->|"SLO に近い"| decision_user
decision_user -->|"影響あり"| p1
decision_user -->|"影響なし"| decision_auto
decision_auto -->|"不可"| p2
decision_auto -->|"可能"| p3
style p0 fill:#ff0000,color:#fff
style p1 fill:#ff9900
style p2 fill:#ffff00
style p3 fill:#99ff99
優先度別の対応方針:
| # | 優先度 | 条件 | 通知先 | 対応時間 | 例 |
|---|---|---|---|---|---|
| 1 | P0 (Critical) | SLO 違反、全ユーザー影響 | 電話 + SMS | 即座 | API 全体ダウン |
| 2 | P1 (High) | SLO に近い、一部ユーザー影響 | PagerDuty | 1 時間以内 | エラー率 5% |
| 3 | P2 (Medium) | SLO 余裕あり、影響限定的 | Slack | 営業時間内 | レイテンシ増加 |
| 4 | P3 (Low) | 情報提供、自動復旧可能 | メール | 週次確認 | キャッシュミス増加 |
Prometheus アラートルールの設定
Prometheus で SLO ベースのアラートルールを定義します。
yaml# prometheus-rules.yml
# Prometheus アラートルールの定義
groups:
# API 可用性のアラート
- name: dify_slo_availability
interval: 1m
rules:
# P0: API 成功率が 99% を下回る(SLO 99.9% 違反)
- alert: DifyAPIAvailabilityCritical
expr: |
(
sum(rate(dify_api_requests_total{status=~"2.."}[5m]))
/
sum(rate(dify_api_requests_total[5m]))
) < 0.99
yaml for: 2m # 2 分間継続したら発火
labels:
severity: critical
priority: P0
annotations:
summary: "Dify API の可用性が SLO を下回っています"
description: "成功率: {{ $value | humanizePercentage }}"
yaml # P1: API 成功率が 99.5% を下回る(SLO に近い)
- alert: DifyAPIAvailabilityWarning
expr: |
(
sum(rate(dify_api_requests_total{status=~"2.."}[5m]))
/
sum(rate(dify_api_requests_total[5m]))
) < 0.995
for: 5m
labels:
severity: warning
priority: P1
annotations:
summary: "Dify API の可用性が低下しています"
description: "成功率: {{ $value | humanizePercentage }}"
上記のルールでは、SLO に対する余裕度に応じて異なる優先度のアラートを発火します。
yaml # API レイテンシのアラート
- name: dify_slo_latency
interval: 1m
rules:
# P0: P95 レイテンシが 5 秒を超える(SLO 3 秒違反)
- alert: DifyAPILatencyCritical
expr: |
histogram_quantile(0.95,
rate(dify_api_request_duration_seconds_bucket[5m])
) > 5
yaml for: 3m
labels:
severity: critical
priority: P0
annotations:
summary: "Dify API のレイテンシが SLO を大幅に超過"
description: "P95 レイテンシ: {{ $value }}s"
yaml # P1: P95 レイテンシが 3.5 秒を超える(SLO に近い)
- alert: DifyAPILatencyWarning
expr: |
histogram_quantile(0.95,
rate(dify_api_request_duration_seconds_bucket[5m])
) > 3.5
for: 5m
labels:
severity: warning
priority: P1
annotations:
summary: "Dify API のレイテンシが上昇しています"
description: "P95 レイテンシ: {{ $value }}s"
レイテンシのアラートでは、パーセンタイル値を使うことで、一時的なスパイクを無視し、持続的な劣化を検知します。
yaml # LLM エラー率のアラート
- name: dify_slo_quality
interval: 1m
rules:
# P1: LLM エラー率が 1% を超える
- alert: DifyLLMErrorRateHigh
expr: |
(
sum(rate(dify_llm_requests_total{status="error"}[10m]))
/
sum(rate(dify_llm_requests_total[10m]))
) > 0.01
for: 5m
labels:
severity: warning
priority: P1
annotations:
summary: "LLM エラー率が上昇しています"
description: "エラー率: {{ $value | humanizePercentage }}"
LLM の一時的な障害は外部要因の可能性があるため、10 分間の平均で評価しています。
Alertmanager による通知ルーティング
Alertmanager で、アラートの優先度に応じた通知先を設定します。
yaml# alertmanager.yml
# Alertmanager の設定ファイル
global:
resolve_timeout: 5m
yaml# 通知先の定義
route:
# デフォルトの設定
group_by: ['alertname', 'service']
group_wait: 10s
group_interval: 10s
repeat_interval: 12h
receiver: 'default'
yaml # 優先度別のルーティング
routes:
# P0: Critical - 即座に電話とページャー
- match:
priority: P0
receiver: 'pagerduty-critical'
group_wait: 0s
repeat_interval: 5m
yaml # P1: High - PagerDuty に通知
- match:
priority: P1
receiver: 'pagerduty-high'
group_wait: 30s
repeat_interval: 1h
yaml # P2: Medium - Slack に通知
- match:
priority: P2
receiver: 'slack-medium'
group_wait: 5m
repeat_interval: 3h
yaml # P3: Low - メールで通知
- match:
priority: P3
receiver: 'email-low'
repeat_interval: 24h
優先度に応じて、通知のタイミングと頻度を調整しています。
yaml# 受信者の設定
receivers:
# デフォルト(全通知)
- name: 'default'
slack_configs:
- api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
channel: '#dify-alerts'
yaml # P0: PagerDuty(Critical)
- name: 'pagerduty-critical'
pagerduty_configs:
- service_key: 'YOUR_PAGERDUTY_SERVICE_KEY'
severity: critical
description: '{{ .CommonAnnotations.summary }}'
yaml # P1: PagerDuty(High)
- name: 'pagerduty-high'
pagerduty_configs:
- service_key: 'YOUR_PAGERDUTY_SERVICE_KEY'
severity: error
yaml # P2: Slack(Medium)
- name: 'slack-medium'
slack_configs:
- api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
channel: '#dify-monitoring'
title: '⚠️ {{ .CommonLabels.alertname }}'
yaml # P3: Email(Low)
- name: 'email-low'
email_configs:
- to: 'ops-team@example.com'
from: 'alertmanager@example.com'
smarthost: 'smtp.example.com:587'
このように、アラートの重要度に応じて適切な通知手段を選択します。
アラート疲れを防ぐ工夫
アラートが多すぎると重要な通知を見逃してしまいます。以下の工夫で、ノイズを減らしましょう。
1. 適切な閾値設定
| # | 指標 | 不適切な閾値 | 適切な閾値 | 理由 |
|---|---|---|---|---|
| 1 | エラー率 | > 0% | > 1% | ゼロエラーは現実的でない |
| 2 | レイテンシ | 平均値 > 1s | P95 > 3s | 平均値は外れ値に影響されやすい |
| 3 | CPU 使用率 | > 50% | > 80% | 50% は正常範囲内 |
2. 時間ベースのフィルタリング
一時的なスパイクを無視するため、for 句で持続時間を指定します。
yaml# 3 分間継続した場合のみアラート
- alert: HighErrorRate
expr: error_rate > 0.01
for: 3m # 3 分間継続した場合のみ
3. メンテナンスウィンドウの設定
計画的なメンテナンス中はアラートを抑制します。
yaml# メンテナンス中はアラートを抑制
inhibit_rules:
- source_match:
alertname: 'MaintenanceMode'
target_match_re:
severity: '.*'
equal: ['service']
4. 関連アラートのグループ化
同じ原因で複数のアラートが発生する場合、グループ化して 1 つの通知にまとめます。
yaml# 同じサービスのアラートをグループ化
route:
group_by: ['service', 'alertname']
group_wait: 10s # 最初のアラートから 10 秒待つ
group_interval: 10s # 追加のアラートを 10 秒間隔で集約
これらの工夫により、運用チームは本当に重要なアラートに集中できます。
具体例
ケーススタディ:カスタマーサポートチャットボット
ここでは、実際の Dify アプリケーションでの SLO/SLA 設定とアラート設計の具体例を見ていきましょう。
ビジネス要件の定義
あるEC サイトが、カスタマーサポートの効率化のため Dify でチャットボットを構築したとします。
ビジネス要件:
| # | 要件 | 理由 | 影響 |
|---|---|---|---|
| 1 | 営業時間中(9-21 時)は常時利用可能 | ユーザーサポートの代替手段 | 利用不可時は有人対応が増加 |
| 2 | レスポンスは 3 秒以内 | ユーザー体験の維持 | 遅延するとユーザー離脱 |
| 3 | 正確な回答率 80% 以上 | 顧客満足度の維持 | 低いと信頼性が低下 |
| 4 | 月間コストを 10 万円以内に抑制 | 費用対効果の確保 | 超過すると採算が悪化 |
これらの要件を、測定可能な SLI/SLO に変換していきます。
SLI/SLO の具体的な設定
ビジネス要件から、以下のような SLI/SLO を設定します。
mermaidflowchart LR
subgraph business["ビジネス要件"]
b1["常時利用可能"]
b2["3秒以内"]
b3["正確な回答 80%"]
b4["コスト 10万円/月"]
end
subgraph slo["SLO(内部目標)"]
s1["稼働率 99.9%"]
s2["P95 < 2.5s"]
s3["満足度 85%"]
s4["8.5万円/月"]
end
subgraph sli["SLI(測定指標)"]
i1["HTTP 2xx 率"]
i2["API レスポンスタイム"]
i3["いいね率"]
i4["トークン消費量"]
end
b1 --> s1 --> i1
b2 --> s2 --> i2
b3 --> s3 --> i3
b4 --> s4 --> i4
style business fill:#ffe6e6
style slo fill:#fff3e6
style sli fill:#e6f3ff
具体的な SLO 設定表:
| # | カテゴリ | SLI | SLO 目標値 | SLA(顧客約束) | 測定方法 |
|---|---|---|---|---|---|
| 1 | 可用性 | API 成功率 | 99.9%(営業時間) | 99.5% | Prometheus: success_rate |
| 2 | レイテンシ | API P95 レスポンス | < 2.5 秒 | < 3 秒 | Prometheus: http_request_duration_seconds |
| 3 | レイテンシ | API P99 レスポンス | < 4 秒 | < 5 秒 | 同上 |
| 4 | 品質 | ユーザー満足度 | > 85% | > 80% | Langfuse: positive_feedback_rate |
| 5 | 品質 | エラー応答率 | < 0.5% | < 1% | Langfuse: error_rate |
| 6 | コスト | 月間トークン消費 | < 17M トークン | < 20M トークン | Langfuse: total_tokens |
| 7 | コスト | 1 リクエスト平均 | < 450 トークン | < 500 トークン | 同上 |
SLO を SLA より 15-20% 厳しく設定することで、バッファを確保しています。
アラートルールの実装
上記の SLO に基づいて、具体的なアラートルールを実装します。
可用性のアラート:
yaml# 営業時間中の API 可用性監視
- alert: ChatbotAvailabilityCritical
expr: |
# 営業時間(9-21時)のみ評価
(
sum(rate(dify_api_requests_total{
service="chatbot",
status=~"2.."
}[5m]))
/
sum(rate(dify_api_requests_total{
service="chatbot"
}[5m]))
) < 0.995
and
hour() >= 9 and hour() < 21
yaml for: 2m
labels:
severity: critical
priority: P0
team: platform
annotations:
summary: "チャットボットの可用性が SLO を下回っています"
description: |
現在の成功率: {{ $value | humanizePercentage }}
SLO 目標: 99.9%
影響: 営業時間中のユーザーサポートに影響
runbook_url: "https://wiki.example.com/runbooks/chatbot-availability"
営業時間外は SLO の対象外とするため、hour() 関数で時間帯を限定しています。
レイテンシのアラート:
yaml# P95 レスポンスタイムの監視
- alert: ChatbotLatencyHigh
expr: |
histogram_quantile(0.95,
sum(rate(dify_api_request_duration_seconds_bucket{
service="chatbot"
}[5m])) by (le)
) > 2.5
for: 3m
labels:
severity: warning
priority: P1
team: platform
annotations:
summary: "チャットボットのレスポンスが遅延しています"
description: |
現在の P95 レスポンス: {{ $value }}s
SLO 目標: < 2.5s
ユーザー体験への影響が懸念されます
yaml# P99 レスポンスタイムの監視(タイムアウト直前)
- alert: ChatbotLatencyCritical
expr: |
histogram_quantile(0.99,
sum(rate(dify_api_request_duration_seconds_bucket{
service="chatbot"
}[5m])) by (le)
) > 4.5
for: 2m
labels:
severity: critical
priority: P0
team: platform
annotations:
summary: "チャットボットのレスポンスがタイムアウト間近です"
description: |
現在の P99 レスポンス: {{ $value }}s
タイムアウト設定: 5s
一部ユーザーでタイムアウトが発生している可能性があります
P95 と P99 で異なる閾値を設定することで、段階的なアラートが可能になります。
コスト超過のアラート:
yaml# 日次トークン消費量の監視(月間予算の 1/30)
- alert: ChatbotCostOverBudget
expr: |
sum(increase(dify_llm_tokens_total{
service="chatbot"
}[24h])) > 566666 # 17M / 30 日
labels:
severity: warning
priority: P2
team: product
annotations:
summary: "チャットボットのトークン消費が予算を超過しています"
description: |
本日の消費量: {{ $value }} トークン
目標値: 566,666 トークン/日
このペースでは月間予算を超過します
yaml# 1 リクエストあたりの平均トークン数の監視
- alert: ChatbotTokenPerRequestHigh
expr: |
(
sum(rate(dify_llm_tokens_total{
service="chatbot"
}[1h]))
/
sum(rate(dify_api_requests_total{
service="chatbot"
}[1h]))
) > 450
for: 30m
labels:
severity: info
priority: P3
team: product
annotations:
summary: "1 リクエストあたりのトークン消費が増加しています"
description: |
現在の平均: {{ $value }} トークン/リクエスト
目標値: < 450 トークン/リクエスト
プロンプト最適化を検討してください
コストアラートは即座の対応は不要なため、P2/P3 に設定しています。
ダッシュボードの構成
Grafana で、SLO の達成状況を一目で確認できるダッシュボードを作成します。
ダッシュボードのパネル構成:
| # | パネル名 | 表示内容 | 目的 |
|---|---|---|---|
| 1 | SLO サマリー | 各 SLO の達成率 | 全体状況の把握 |
| 2 | エラーバジェット残量 | 残りの許容エラー量 | リスク評価 |
| 3 | API 可用性(時系列) | 成功率の推移 | トレンド分析 |
| 4 | レスポンスタイム(パーセンタイル) | P50/P95/P99 の推移 | パフォーマンス分析 |
| 5 | トークン消費量 | 日次・月次の消費トレンド | コスト管理 |
| 6 | ユーザー満足度 | いいね率の推移 | 品質評価 |
Grafana パネルの PromQL 例:
promql# SLO 達成率の計算(可用性)
(
sum(rate(dify_api_requests_total{status=~"2.."}[30d]))
/
sum(rate(dify_api_requests_total[30d]))
) * 100
promql# エラーバジェット残量(月次 99.9% SLO の場合)
# 残りの許容エラー数を計算
(
0.001 * sum(increase(dify_api_requests_total[30d]))
-
sum(increase(dify_api_requests_total{status!~"2.."}[30d]))
) /
0.001 * sum(increase(dify_api_requests_total[30d])) * 100
promql# レスポンスタイムのパーセンタイル(P95)
histogram_quantile(0.95,
sum(rate(dify_api_request_duration_seconds_bucket[5m])) by (le)
)
これらのクエリで、SLO の達成状況をリアルタイムで可視化できます。
インシデント対応フローの整備
アラートが発火した際の対応フローを事前に定義しておきます。
mermaidflowchart TB
alert_fire["アラート発火"]
check_severity{"優先度は?"}
p0_action["P0: 即座に対応<br/>1. オンコール担当者に架電<br/>2. インシデント作成<br/>3. 顧客への通知準備"]
p1_action["P1: 1時間以内に対応<br/>1. PagerDuty で通知<br/>2. 状況確認<br/>3. 必要に応じエスカレーション"]
p2_action["P2: 営業時間内に対応<br/>1. Slack で共有<br/>2. 原因調査<br/>3. 対応策の検討"]
investigate["原因調査<br/>・ログ確認<br/>・メトリクス分析<br/>・トレース追跡"]
resolve{"解決<br/>できた?"}
escalate["エスカレーション<br/>・上位管理者へ報告<br/>・開発チーム招集<br/>・ベンダーへ問い合わせ"]
monitor["継続監視<br/>・再発防止<br/>・ポストモーテム"]
alert_fire --> check_severity
check_severity -->|"P0"| p0_action
check_severity -->|"P1"| p1_action
check_severity -->|"P2/P3"| p2_action
p0_action --> investigate
p1_action --> investigate
p2_action --> investigate
investigate --> resolve
resolve -->|"Yes"| monitor
resolve -->|"No"| escalate
escalate --> investigate
style p0_action fill:#ff0000,color:#fff
style p1_action fill:#ff9900
style p2_action fill:#ffff00
style monitor fill:#99ff99
対応手順の詳細化(例:P0 可用性アラート):
| # | ステップ | 担当者 | 目安時間 | 実施内容 |
|---|---|---|---|---|
| 1 | 初動確認 | オンコール | 5 分 | アラート内容確認、影響範囲の特定 |
| 2 | 暫定対応 | オンコール | 10 分 | 再起動、ロールバック等の即効性のある対応 |
| 3 | 顧客通知 | サポート | 15 分 | ステータスページの更新、重要顧客への連絡 |
| 4 | 根本対応 | 開発チーム | 1 時間 | 原因特定と恒久対策の実施 |
| 5 | 事後対応 | 全員 | 24 時間以内 | ポストモーテムの作成、再発防止策の策定 |
このように、優先度ごとに明確な対応フローを定義することで、混乱を防げます。
高可用性構成での SLO 達成
単一インスタンスでは 99.9% の可用性を達成するのは困難です。以下のような高可用性構成を検討しましょう。
Kubernetes による冗長化
Alibaba Cloud ACK や AWS EKS などの Kubernetes プラットフォームを活用し、自動復旧とスケーリングを実現します。
yaml# dify-deployment.yaml
# Dify API サーバーのデプロイメント設定
apiVersion: apps/v1
kind: Deployment
metadata:
name: dify-api
labels:
app: dify
component: api
yamlspec:
# 最低 2 つのレプリカで冗長化
replicas: 2
# ローリングアップデート戦略
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0 # ダウンタイムゼロ
maxSurge: 1 # 1 つずつ更新
yaml selector:
matchLabels:
app: dify
component: api
template:
metadata:
labels:
app: dify
component: api
yaml spec:
# Pod アンチアフィニティ設定
# 同じノードに複数の Pod を配置しない
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: component
operator: In
values:
- api
topologyKey: kubernetes.io/hostname
yaml containers:
- name: api
image: dify/api:latest
# リソース制限
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
yaml # ヘルスチェック設定
livenessProbe:
httpGet:
path: /health
port: 5001
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
yaml readinessProbe:
httpGet:
path: /ready
port: 5001
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
この設定により、以下を実現できます。
- 最低 2 つの Pod が常に稼働(単一障害点の排除)
- 異なるノードに配置(ノード障害時の影響を最小化)
- 自動ヘルスチェックと再起動
- ゼロダウンタイムデプロイ
HPA によるオートスケーリング
負荷に応じて自動的にスケールする設定を追加します。
yaml# dify-hpa.yaml
# Horizontal Pod Autoscaler の設定
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: dify-api-hpa
yamlspec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: dify-api
# スケール範囲
minReplicas: 2 # 最小 2 つ(冗長性確保)
maxReplicas: 10 # 最大 10 つ(コスト上限)
yaml # スケール条件
metrics:
# CPU 使用率ベース
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
yaml # メモリ使用率ベース
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
yaml # スケール動作の調整
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100 # 最大で現在の 2 倍まで増やす
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300 # 5 分間の猶予
policies:
- type: Pods
value: 1 # 1 つずつ減らす
periodSeconds: 60
急激な負荷増加にも対応しつつ、無駄なスケールダウンを防ぐ設定になっています。
マネージドサービスの活用
データストア層は、マネージドサービスを活用することで SLA を向上させられます。
| # | コンポーネント | オープンソース | マネージドサービス | SLA 向上 |
|---|---|---|---|---|
| 1 | PostgreSQL | セルフホスト PostgreSQL | AWS RDS / Cloud SQL | 99.5% → 99.95% |
| 2 | Redis | セルフホスト Redis | AWS ElastiCache / Upstash | 99% → 99.9% |
| 3 | ベクトル DB | セルフホスト Qdrant | Pinecone / Weaviate Cloud | 99% → 99.9% |
マネージドサービスを使うことで、以下のメリットがあります。
- 自動バックアップと復旧
- 高可用性構成(マルチ AZ 配置)
- パッチ適用の自動化
- 24/7 のサポート
コストは増加しますが、SLO 達成のためには有効な選択肢です。
まとめ
Dify で構築した AI アプリケーションを本番環境で安定運用するためには、適切な SLO/SLA 設定とアラート設計が不可欠です。
本記事で紹介した内容を以下にまとめます。
SLO/SLA 設定のポイント:
- SLI の選定:システム境界で測定可能な指標を選び、顧客視点での品質を評価します
- SLO の設定:理想値ではなく許容可能な最低ラインを設定し、SLA よりも厳しい目標にします
- エラーバジェット:許容されるエラーの量を明確化し、開発速度と安定性のバランスを取ります
アラート設計のポイント:
- 優先度の設定:P0 から P3 まで明確に分類し、対応時間と通知先を定義します
- 適切な閾値:一時的なスパイクを無視し、持続的な劣化を検知する設定にします
- アラート疲れ対策:グループ化、時間フィルタ、メンテナンスウィンドウで不要な通知を削減します
ツールスタックの選定:
- Langfuse/LangSmith:LLM 特有の指標(トークン消費、プロンプト品質)を監視します
- Prometheus + Grafana:インフラレベルの指標を収集・可視化します
- Alertmanager + PagerDuty:優先度別にアラートをルーティングし、適切な通知を実現します
高可用性の実現:
- Kubernetes:Pod の冗長化、自動復旧、ゼロダウンタイムデプロイを実現します
- HPA:負荷に応じた自動スケーリングで、突発的なトラフィックにも対応します
- マネージドサービス:データストア層は SLA の高いマネージドサービスを活用します
これらの実践により、ビジネス要件を満たす信頼性の高い AI アプリケーション運用が可能になります。
最初は小さく始めて、段階的に SLO を厳しくしていくアプローチがおすすめです。まずは最も重要な指標(可用性とレイテンシ)から監視を開始し、運用が安定してきたら品質やコスト効率の指標を追加していきましょう。
関連リンク
articleDify 本番運用ガイド:SLO/SLA 設定とアラート設計のベストプラクティス
articleDify 中心のドメイン駆動設計:ユースケースとフローの境界づけ
articleDify プロンプト設計チートシート:役割宣言・制約・出力フォーマットの定石
articleDify を macOS でローカル検証:Docker Compose で最短起動する手順
articleDify と LangGraph/LangChain を比較:表現力・保守性・学習コストのリアル
articleDify でジョブが止まる/再実行される問題の原因切り分けガイド
articleESLint 運用ダッシュボード:SARIF/Code Scanning で違反推移を可視化
articleSolidJS 本番運用チェックリスト:CSP・SRI・Preload・エラーレポートの総点検
articleRedis 使い方:Next.js で Cache-Tag と再検証を実装(Edge/Node 両対応)
articleDify 本番運用ガイド:SLO/SLA 設定とアラート設計のベストプラクティス
articleCursor の KPI 設計:リードタイム・欠陥率・レビュー時間を定量で追う
articlePython 本番運用 SLO 設計:p95 レイテンシ・エラー率・スループットの指標化
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来