> ## Documentation Index
> Fetch the complete documentation index at: https://docs.befailproof.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# アラート

> AgentEye アラートのドキュメント。

アラートは、スケジュールに従ってルールを評価し、何かがしきい値を超えたときに通知します。アラートによって AgentEye は、エラー率のスパイク、レイテンシの低下、評価スコアの落ち込み、または ClickHouse クエリで表現できる任意のカスタムイベントなど、重要な事象を通知するページングサーフェスへと変わります。

このガイドでは、アラートの概要、5 種類のトリガータイプ、4 種類の通知チャンネル、インシデントのライフサイクル、および運用上の調整項目について説明します。

<img src="https://mintcdn.com/exosphere/kH8rXaL6tCSRWEFy/agenteye/images/alerts.png?fit=max&auto=format&n=kH8rXaL6tCSRWEFy&q=85&s=ed466c15352d370f38181eee48f622fd" alt="アラートページ：アラートルールカードのグリッド。各カードにはトリガータイプ、評価ウィンドウ、チャンネル、情報/警告/重大の重要度バッジが表示されています" width="3200" height="2000" data-path="agenteye/images/alerts.png" />

***

## 概念

* **アラート** — ルールそのものです。*何を*チェックするか（トリガー）、*どのくらいの頻度で*（評価間隔）、*いつ問題とみなすか*（複合ロジック）、*緊急度*（重要度）、*誰に/どこへ*通知するか（チャンネル）を定義します。
* **インシデント** — アラートが発火したときに発生するものです。1 つのアラートに対して、同時に開いているインシデントは最大 1 つです。繰り返し違反が発生した場合は、同じインシデントのエビデンスが更新されます。インシデントはオペレーターが解決します。ルールが違反しなくなったときの自動解決は計画中ですが、現時点では有効になっていません。
* **チャンネル** — 通知の送信先です：メール、Slack、汎用 Webhook、またはダッシュボード内。各アラートには任意の組み合わせを設定できます。

アラートとインシデントは組織に属し、その組織のオペレーター間で共有されます（シングルテナントデプロイメントでは、組み込みの `default` 組織がそれに当たります）。インシデントはトリアージのために個々のオペレーターに割り当てることができます。

***

## トリガータイプ

それぞれ独自の JSON 仕様を持つ 5 種類があります。「問題あり」をどのように表現したいかに合ったものを選んでください。ダッシュボードの**新規アラート**フォームは、選択したトリガータイプに合わせて条件エディターを切り替えながら、同じ仕様を構築します。

<img src="https://mintcdn.com/exosphere/kH8rXaL6tCSRWEFy/agenteye/images/alert-new.png?fit=max&auto=format&n=kH8rXaL6tCSRWEFy&q=85&s=b3c4ccec22e50e4af05be61fa14f6d26" alt="新規アラートフォーム：基本情報（名前、説明、有効/無効）と、メトリクスしきい値、カスタム SQL、評価スコア、評価失敗、イベント単位のオプションを表示するトリガーピッカー" width="3200" height="2000" data-path="agenteye/images/alert-new.png" />

### 1. `metric_threshold`

最もシンプルなタイプです。定義済みのリストからメトリクス、演算子、しきい値、時間ウィンドウを選択します。

| メトリクス            | カウント対象                                                      |
| ---------------- | ----------------------------------------------------------- |
| `event_count`    | ウィンドウ内のイベント総数                                               |
| `error_count`    | `event_type = 'error'` または `error_type IS NOT NULL` のイベント   |
| `error_rate`     | `error_count / event_count`（0〜1）                            |
| `p95_latency_ms` | `duration_ms` を持つすべてのイベントに対する `quantile(0.95)(duration_ms)` |
| `p99_latency_ms` | `quantile(0.99)(duration_ms)`                               |
| `token_sum`      | `SUM(input_tokens + output_tokens)`                         |

演算子：`>`、`>=`、`<`、`<=`、`==`（`gt`、`gte`、`lt`、`lte`、`eq` も使用可）。

オプションフィルター：`environment`、`event_type`。

仕様の例：

```json theme={null}
{
  "metric": "p95_latency_ms",
  "filter": { "environment": "production" },
  "window_secs": 900,
  "op": ">",
  "value": 5000
}
```

### 2. `custom_sql`

プリセットのメトリクスでカバーできないあらゆる用途に使用します。オペレーターが記述した SQL は、ディスパッチャーが実行する前に、`/queries/run` と同じガード（SELECT/WITH のみ、単一ステートメント、10,000 行上限）を通過します。2 つのモードがあります。

* **rows モード**（`op`/`value` なし）：クエリが少なくとも 1 行を返した時点でアラートが発火します。
* **value モード**：クエリは 1 つのカラムを `metric_value` としてエイリアスする必要があり、ディスパッチャーは最初の行の `metric_value` を `op` を使って `value` と比較します。

```json theme={null}
{
  "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR",
  "op": ">",
  "value": 100
}
```

### 3. `evaluation_score`

`agenteye.evaluations` を読み取り、ウィンドウ内の指定されたスコアの平均値を比較します。

```json theme={null}
{
  "score_key": "hallucination",
  "op": ">",
  "value": 0.6,
  "window_secs": 3600,
  "min_count": 5,
  "environment": "production"
}
```

`min_count` は単一サンプルの外れ値からの保護です。ウィンドウ内に少なくとも N 件の評価が存在するまで、ディスパッチャーは発火しません。

### 4. `eval_compound`

*複数の*評価スコアにまたがって初めて現れる品質低下を検出します。`evaluation_score` が単一の名前付きスコアを監視するのに対し、`eval_compound` は複数の評価スコア条件を 1 つのアラートに組み合わせ、選択したロジックで結果を結合します。これにより、「ヘルプフルネスが低下**または**ハルシネーションが増加した場合に発火」「ヘルプフルネス**かつ**ツール効率の両方が低下した場合のみ発火」「3 つのチェックのうち**少なくとも 2 つ**が違反した場合に発火」といったルールを 1 つで表現できます。

各条件は、共有ウィンドウにわたって `agenteye.evaluations` から 1 つの名前付きスコアの平均値を読み取り、独自の演算子としきい値でテストします。ブール値の結果は `combinator` によって結合されます。

| コンビネーター             | ロジック   | 発火条件            |
| ------------------- | ------ | --------------- |
| `"any"`             | OR     | 少なくとも 1 つの条件が違反 |
| `"all"`             | AND    | すべての条件が違反       |
| `{ "at_least": N }` | M of N | 少なくとも N 個の条件が違反 |

```json theme={null}
{
  "combinator": { "at_least": 2 },
  "conditions": [
    { "score_key": "hallucination", "op": ">", "value": 0.8 },
    { "score_key": "helpfulness",   "op": "<", "value": 0.6 },
    { "score_key": "tone",          "op": "<", "value": 0.5 }
  ],
  "window_secs": 3600,
  "min_count": 5,
  "environment": "production"
}
```

* `combinator`：`"any"`、`"all"`、または `{ "at_least": N }`。
* `conditions[]`：各要素は `{ score_key, op, value }` で、他のトリガーと同じ演算子（`>`、`>=`、`<`、`<=`、`==`）を使用します。
* `window_secs`：すべての条件に適用される共通のルックバック期間（デフォルト `3600`）。
* `min_count`：条件が違反と判定される前に必要な評価の最小件数（条件ごと）。ウィンドウ内のサンプルが少なすぎる条件は「違反なし」としてカウントされます（デフォルト `1`）。
* `environment`：省略可能。すべての条件を 1 つの環境に限定します。

通知のエビデンスには、各条件の観測された平均値、テストしたしきい値、評価の件数、違反したかどうかが記録されます。これにより、どのチェックがトリガーされたかを正確に確認できます。

### 5. `per_event`

「X に一致するイベントが発生した」というアラートに使用します。集計は行わず、ディスパッチャーはルックバックウィンドウ内に一致するものを見つけた時点で発火します。

```json theme={null}
{
  "event_type": "error",
  "lookback_secs": 60,
  "environment": "production",
  "tool_name": "bash",
  "agent_id": "caa",
  "error_type": "TimeoutError",
  "message_contains": "vertex-ai timed out"
}
```

すべてのフィルターは AND で結合されます。省略したフィールドは制約なしになります。

| フィールド              | 用途                                                                                                                                                        |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agent_id`         | 特定のエージェント（`/errors` 行に表示されるもの）からのエラーに限定します。                                                                                                               |
| `error_type`       | すべてのエラーではなく、特定のエラークラス（例：`TimeoutError`）に限定します。                                                                                                            |
| `message_contains` | `payload.message` に対する大文字・小文字を区別しない部分文字列マッチ。同じエージェントのすべてのエラーをアラートの対象にせず、特定の障害モード（例：`prompt is too long`）だけを捕捉するのに便利です。200 文字上限で、パターンではなくリテラル文字列としてマッチします。 |

ヒント：同じイベントへの二重通知を防ぐために、`lookback_secs` をアラートの `eval_interval_secs` とおおよそ一致させるように設定してください。

**`/errors` からのショートカット：** エラービューの各エラーグループの代表行（およびエラーイベントのセッションイベント詳細パネル）には **+ アラート** ボタンがあります。このボタンをクリックすると、その行の `event_type` と環境に紐づいた `per_event` トリガーが事前に入力された状態で `/alerts/new` が開きます。ペイロードに `error_type` が存在する場合は、それから生成された名前も入力されます。チャンネルの選択とルックバックの確認は引き続き必要ですが、マッチャーは自動的に入力されます。このボタンを表示するにはオペレーターに `alerts:write` 権限が必要です。

***

## 複合ロジック（M of N）

すべてのアラートには、トリガーに加えて 2 つの整数設定があります。

* `eval_window`：参照する直近の評価数（デフォルト 1）
* `min_breaches`：アラートを発火させるために必要な違反数（デフォルト 1）

`1 of 1`（デフォルト）は「最初の違反で発火」を意味します。`3 of 5` は「直近 5 回の評価のうち 3 回違反した場合に発火」を意味し、単一の悪い測定値がノイズになりやすい不安定なシグナルに便利です。ディスパッチャーはアラートごとにリングバッファを管理するため、状態を自分で管理する必要はありません。

***

## 評価間隔

`eval_interval_secs` は、ディスパッチャーがルールを実行する頻度を制御します。`[30, 86400]` の範囲に制限されます。ダッシュボードのプリセット：1 分 / 5 分 / 15 分 / 1 時間。基となるシグナルの変化速度に合わせた間隔を選んでください。5 分間のエラー率アラートを 15 秒ごとに評価するのは CPU の無駄遣いです。また、イベント単位のアラートはルックバックを短くしないと、評価のタイミング間でイベントが検出されずに失われる可能性があります。

***

## チャンネル

各アラートには以下の 4 種類の任意の組み合わせを設定できます。チャンネルごとの認証情報（Slack の Webhook URL、汎用 Webhook の URL と署名シークレット、デフォルトのメール受信者）は **`/settings`** で一度設定し、各アラートからキーで参照します。これにより、1 つの Slack チャンネルを多くのアラートで共有でき、各アラートが Webhook URL のコピーを保持する必要がありません。

3 つの外部チャンネル種別（メール、Slack、Webhook）は、組織全体のキルスイッチ `alerts.enabled_channels` によっても制御されます。発火したアラートに設定されているチャンネル種別がこのセットに含まれていない場合、ディスパッチャーはそのチャンネルをスキップし、ステータスを `skipped_disabled`、ターゲットを `<channel_disabled>` とした `alert_notifications` 行を記録します（これにより、すべてのルールを編集することなく、例えば Slack への配信をグローバルに一時停止できます）。ダッシュボード内チャンネルは常に許可されています。詳細は[設定](#configuration)を参照してください。

### メール

OTP ログインメールを送信するのと同じ SMTP トランスポートを再利用します。受信者は以下の順序で解決されます。

1. チャンネルごとの `recipients[]` オーバーライド（空でない場合）。
2. `alerts.email_default_recipients` 設定（メールアドレスの配列）。

SMTP が設定されていない場合、このチャンネルは何もしません。ただし、ディスパッチャーは引き続き `alert_notifications` 行をターゲット `<smtp_unconfigured>` で記録するため、監査証跡で設定ミスを確認できます。

### Slack

[受信 Webhook URL](https://api.slack.com/messaging/webhooks) に Block Kit メッセージを送信します。

* デフォルト URL：`alerts.slack_default_webhook`（`/settings` で設定）。
* アラートごとのオーバーライド：チャンネルの `webhook_setting_key` を他の URL 型設定キー（例：`alerts.slack_oncall`、`alerts.slack_costs`）に設定します。

ヘッダーには重要度の絵文字（`:rotating_light:` / `:warning:` / `:bell:`）が含まれ、メッセージにはインシデントページへのディープリンクボタンが付いています。

### 汎用 Webhook

PagerDuty、Opsgenie、または独自の取り込みエンドポイントへの JSON POST インテグレーションです。ボディの形式：

```json theme={null}
{
  "schema_version": 1,
  "event": "alert.firing",
  "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" },
  "alert":    { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" },
  "breach":   { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } }
}
```

`alerts.webhook_signing_secret` が設定されている場合、リクエストにはシークレットを使ったボディの HMAC-SHA256 である `X-AgentEye-Signature: sha256=<hex>` ヘッダーが含まれます。ペイロードを信頼する前に、受信側で検証してください。

`X-AgentEye-Event` ヘッダーには `alert.firing` / `alert.test` が入ります（`alert.resolved` は計画中の自動解決機能用に予約されており、現時点では送信されません）。

### ダッシュボード内

外部への配信はなく、アラートはダッシュボードのインシデントページに表示される `alert_notifications` 行を書き込むだけです。ルールを調整中で外部システムへの通知を送りたくない場合や、通常のトリアージ中にオペレーターが確認する緊急度の低いアラートに便利です。

***

## インシデントのライフサイクル

```
firing  ──ack──▶  acknowledged
   │                    │
   └────────────────────┴───── operator resolve ───▶  resolved
```

* **firing** — ディスパッチャーがインシデントを新規作成したか、別の違反を検出しました。発火通知は（インシデントの `notified_firing_at` タイムスタンプによるゲート制御で）正確に 1 回だけファンアウトされます。
* **acknowledged** — オペレーターが `/incidents/:id` で *ack* を押しました。インシデントはまだオープンとみなされます。その後の違反はエビデンスを更新しますが、再通知はされません。
* **resolved** — オペレーターが *resolve* を押しました。ルールの違反が止まったときの自動解決は計画中ですが、現時点では有効になっていないため、オープンなインシデントはオペレーターが解決するまでオープンのままです。

以前のインシデントが解決された後、同じアラートで新しいインシデントがいつでも再オープンできます。

**アクティビティタイムライン。** インシデントのすべてのアクション（オープン、承認、解決）は追記専用のアクティビティログに記録され、インシデントの*アクティビティ*タイムラインに表示されます。各エントリは、アクションを実行したオペレーター（メールアドレス）または、ディスパッチャーが自律的に実行したアクション（違反時の自動オープン）については**automated** に帰属します。承認は共有されます。複数のオペレーターが同じインシデントを承認でき、それぞれが個別の帰属エントリとして表示されます。

**インシデント**受信箱では、オープンなインシデントを状態ごとにグループ化し、重要度や担当者でフィルタリングできます。

<img src="https://mintcdn.com/exosphere/kH8rXaL6tCSRWEFy/agenteye/images/incidents.png?fit=max&auto=format&n=kH8rXaL6tCSRWEFy&q=85&s=942a2b470c771834941ffbc51f07b9f7" alt="重要度バッジと担当者が表示された、アラートに紐づくインシデントとアドホックインシデントカードを示すインシデント受信箱" width="3200" height="2000" data-path="agenteye/images/incidents.png" />

インシデントを開くと、違反のエビデンス、担当者とサブスクライバー、帰属アクティビティタイムライン、コメントスレッドが表示されます。

<img src="https://mintcdn.com/exosphere/kH8rXaL6tCSRWEFy/agenteye/images/incident-detail.png?fit=max&auto=format&n=kH8rXaL6tCSRWEFy&q=85&s=62cdf625211a6425d3203302d1a84c1b" alt="インシデント詳細ビュー：親アラート、違反サマリー、担当者、サブスクライバー、帰属アクティビティログ、会話" width="3200" height="2000" data-path="agenteye/images/incident-detail.png" />

***

## 必要な権限

アラート*ルール*の作成と*インシデント*のトリアージは別々の関心事であり、それぞれ個別の権限が必要です。これにより、オンコールローテーションにルールの書き換え権限を与えることなく、インシデントへのアクセス権を付与できます。

* `alerts:read`：アラートルールの表示。
* `alerts:write`：アラートルールの作成、編集、削除、テスト通知のトリガー。
* `incidents:read`：インシデントの表示。
* `incidents:write`：アラートに紐づかない手動（アドホック）インシデントのオープン。
* `incidents:ack`：インシデントの承認、割り当て、コメント、解決。

> **レガシー `alerts:ack`。** 旧 `alerts:ack` トークンが付与されたキーとオペレーターは引き続き機能します。`incidents:ack` として受け入れられ（`incidents:read` も含む）、既存のオンコール担当者は資格情報を再発行することなくアクセスを維持できます。新しい権限付与には `incidents:*` ファミリーを使用してください。

API キー（`POST /keys`）とオペレーター（`PUT /users/:id`）に付与します。ダッシュボードの `PermGate` は権限がない場合に関連ボタンをロックし、アクションの横に `// 403` が表示されます。

> **メール受信者ピッカー。** アラートエディターの受信者ピッカーは、組織のメンバーを一覧表示し、名前で選択できます。`alerts:read` または `alerts:write` を持つオペレーターであれば読み込まれます。この用途でチームのディレクトリを表示するために `users:read` は**不要**で、ピッカーはメンバーのメールアドレスのみを返し、完全なユーザーレコードは返しません。

***

## 設定

ディスパッチャーが使用する環境変数：

| 変数                         | デフォルト                        | 用途                                                   |
| -------------------------- | ---------------------------- | ---------------------------------------------------- |
| `ALERT_WORKERS`            | `1`                          | サーバーインスタンスごとのワーカータスク数。ほとんどのデプロイメントでは 1 で十分です。        |
| `ALERT_CLAIM_BATCH`        | `16`                         | 1 回のワーカーティックで処理するアラートの最大数。                           |
| `ALERT_POLL_IDLE_SECS`     | `5`                          | キューが空のときのワーカーのスリープ時間。                                |
| `ALERT_REQUEST_TIMEOUT_MS` | `15000`                      | トリガーごとの評価タイムアウト。                                     |
| `DASHBOARD_URL`            | `https://app.befailproof.ai` | 通知内のインシデントマジックリンクの生成に使用されるオリジン。ダッシュボードのホストに設定してください。 |

一時的な評価の失敗（ClickHouse が到達不可能、クエリのタイムアウト）が発生した後、ディスパッチャーは指数バックオフでルールを再試行します。ルールが一時的な失敗を **5** 回連続で蓄積すると、バックオフを継続する代わりに通常のサイクルで再スケジュールされるため、永続的に失敗しているルールでも引き続き再評価されます。この上限は固定であり、オペレーターが調整することはできません。

チャンネル設定（環境変数ではなく `/settings` から管理）：

* `alerts.email_default_recipients`（`email_list`）：メールアドレスの JSON 配列。メールチャンネルのデフォルト受信者。
* `alerts.slack_default_webhook`（`url`）：デフォルトの Slack 受信 Webhook URL。
* `alerts.webhook_default_url`（`url`）：デフォルトの汎用 Webhook URL。
* `alerts.webhook_signing_secret`（`secret`）：HMAC-SHA256 キー。GET レスポンスでは常に `""` として返されます。ローテーションするには新しい値を入力してください。
* `alerts.enabled_channels`（`channel_set`）：アラート発火時にディスパッチされる外部チャンネル種別の組織全体のセット。デフォルトはすべての 3 種別（`email`、`slack`、`webhook`）。ここから種別を削除すると、各ルールを編集することなく、そのチャンネルをすべてのアラートでグローバルに抑制します。ダッシュボード内チャンネルは常に配信され、この設定の影響を受けません。

***

## 新しいアラートの検証

新しいアラートを本番利用する前に：

1. 少なくとも 1 つの通知チャンネルを設定して有効な状態で保存します。
2. アラート詳細ページで**テスト**を選択し、設定した各送信先がテスト通知を受信することを確認します。
3. 最初の実際の違反が発生したら、**インシデント**ページにインシデントが表示されること、および測定値が対応するダッシュボードクエリと一致することを確認します。

条件がクリアされてもインシデントは自動解決されません。オペレーターがインシデント詳細ページから解決する必要があります。

***

## トラブルシューティング

| 症状                          | 考えられる原因                                                                                                                                                                                                                                                           |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| アラートが発火しない                  | `enabled = false`、チャンネルが設定されていない、または基となる CH クエリが 0 行を返している。*テスト*でチャンネルを確認し、`/queries/run` でメトリクスを確認してください。                                                                                                                                                        |
| Slack 通知が届かない               | `alerts.slack_default_webhook`（またはアラートごとのオーバーライドキー）が未設定：`alert_notifications.target` で `<unset:…>` 行を確認してください。または `slack` 種別が `alerts.enabled_channels` でグローバルに無効化されている：ステータスが `skipped_disabled`、ターゲットが `<channel_disabled>` の `alert_notifications` 行を確認してください。 |
| 汎用 Webhook で 401 が返る        | 受信側が署名を要求しているが `alerts.webhook_signing_secret` が未設定です。受信側で HMAC が `hmac_sha256(secret, body)` と一致することを確認してください。                                                                                                                                                   |
| メールで「from all sends failed」 | SMTP 認証情報が誤っているか、`from` アドレスがリレーで拒否されています。OTP メールを送信するのと同じ基盤であるため、それが機能していれば SMTP トランスポートは正常です。                                                                                                                                                                   |
| インシデントが繰り返し再オープンされる         | 複合設定が積極的すぎます。一時的なスパイクによって解決済みのインシデントが再オープンされないよう、`min_breaches` または `eval_window` を大きくしてみてください。                                                                                                                                                                   |
