
Konzepte
- Alert — die Regel. Sie legt fest, was geprüft wird (der Trigger), wie oft (das Auswertungsintervall), wann ein Verstoß vorliegt (Verbundlogik), wie dringend (Schweregrad) und wer/wohin benachrichtigt wird (Kanäle).
- Incident — das Ereignis, das ausgelöst wird, wenn ein Alert feuert. Ein Alert hat maximal einen offenen Incident gleichzeitig. Wiederholte Verstöße aktualisieren die Belege desselben Incidents. Incidents werden von einem Operator aufgelöst; eine automatische Auflösung, wenn die Regel nicht mehr feuert, ist geplant, aber derzeit nicht aktiviert.
- Channel — wohin eine Benachrichtigung gesendet wird: E-Mail, Slack, generischer Webhook oder im Dashboard. Jeder Alert kann eine beliebige Kombination davon verwenden.
default-Org). Incidents können zur Triage einem einzelnen Operator zugewiesen werden.
Trigger-Typen
Fünf Arten, jede mit eigenem JSON-Spec. Wählen Sie diejenige, die am besten beschreibt, was bei Ihnen als „defekt” gilt. Das Neuer Alert-Formular im Dashboard erstellt dieselbe Spezifikation für Sie und passt den Bedingungseditor an den gewählten Trigger-Typ an:
1. metric_threshold
Die einfachste Option. Wählen Sie eine Metrik aus einer festen Liste, einen Operator, einen Schwellenwert und ein Zeitfenster.
| Metrik | Was gezählt wird |
|---|---|
event_count | Gesamte Ereignisse im Fenster |
error_count | event_type = 'error' ODER ein Ereignis mit error_type IS NOT NULL |
error_rate | error_count / event_count (0..1) |
p95_latency_ms | quantile(0.95)(duration_ms) über alle Ereignisse mit einem duration_ms |
p99_latency_ms | quantile(0.99)(duration_ms) |
token_sum | SUM(input_tokens + output_tokens) |
>, >=, <, <=, == (auch akzeptiert als gt, gte, lt, lte, eq).
Optionale Filter: environment, event_type.
Beispiel-Spec:
2. custom_sql
Für alles, was die vordefinierten Metriken nicht abdecken. Das vom Operator angegebene SQL durchläuft denselben /queries/run-Guard (nur SELECT/WITH, einzelne Anweisung, maximal 10.000 Zeilen), bevor der Dispatcher es ausführt. Zwei Modi:
- Zeilenmodus (kein
op/value): Der Alert feuert, sobald die Abfrage mindestens eine Zeile zurückgibt. - Wertmodus: Die Abfrage muss eine Spalte als
metric_valuealiasieren; der Dispatcher vergleicht denmetric_valueder ersten Zeile mitvalueunter Verwendung vonop.
3. evaluation_score
Liest agenteye.evaluations und vergleicht den Durchschnitt eines benannten Scores über ein Zeitfenster.
min_count schützt vor Einzelstichproben-Ausreißern; der Dispatcher feuert erst, wenn mindestens N Evaluierungen im Fenster vorliegen.
4. eval_compound
Erkennt eine Qualitätsregression, die nur über mehrere Evaluator-Scores gleichzeitig sichtbar wird. Während evaluation_score einen einzelnen benannten Score überwacht, kombiniert eval_compound mehrere Evaluierungs-Score-Bedingungen in einem Alert und verknüpft deren Ergebnisse mit einer gewählten Logik. So kann eine Regel ausdrücken: „Feuern, wenn Hilfsbereitschaft sinkt oder Halluzination steigt”, „Feuern nur, wenn Hilfsbereitschaft und Tool-Effizienz beide sinken” oder „Feuern, wenn mindestens 2 von diesen drei Prüfungen verletzt sind”.
Jede Bedingung liest den Durchschnitt eines benannten Scores aus agenteye.evaluations über das gemeinsame Fenster und prüft ihn mit eigenem Operator und Schwellenwert. Die booleschen Ergebnisse werden dann durch den combinator kombiniert:
| Kombinator | Logik | Feuert, wenn |
|---|---|---|
"any" | OR | mindestens eine Bedingung verletzt ist |
"all" | AND | jede Bedingung verletzt ist |
{ "at_least": N } | M von N | mindestens N Bedingungen verletzt sind |
combinator:"any","all"oder{ "at_least": N }.conditions[]: jeweils{ score_key, op, value }, mit denselben Operatoren wie die anderen Trigger (>,>=,<,<=,==).window_secs: der gemeinsame Rückblickzeitraum, der auf jede Bedingung angewandt wird (Standard:3600).min_count: Mindestanzahl von Evaluierungen pro Bedingung, bevor diese Bedingung als verletzt gelten kann; eine Bedingung mit zu wenigen Stichproben im Fenster gilt als „nicht verletzt” (Standard:1).environment: optional; schränkt jede Bedingung auf eine Umgebung ein.
5. per_event
Für Alerts à la „ein Ereignis, das X entspricht, ist eingegangen”. Keine Aggregation; der Dispatcher feuert, sobald er im Rückblickfenster eine Übereinstimmung findet.
| Feld | Zweck |
|---|---|
agent_id | Auf Fehler eines bestimmten Agenten beschränken (der auf der /errors-Zeile angezeigt wird). |
error_type | Auf eine bestimmte Fehlerklasse beschränken (z. B. TimeoutError), anstatt jeden Fehler zu erfassen. |
message_contains | Groß-/Kleinschreibung-unabhängige Teilstring-Suche in payload.message. Nützlich, um einen bestimmten Fehlermodus zu erfassen (z. B. prompt is too long), ohne bei jedem Fehler desselben Agenten zu alarmieren. Auf 200 Zeichen begrenzt; als literaler String abgeglichen, nicht als Muster. |
lookback_secs ungefähr auf den Wert von eval_interval_secs des Alerts, damit dasselbe Ereignis nicht doppelt gemeldet wird.
Schnellzugriff über /errors: Die repräsentative Zeile jeder Fehlergruppe in der Fehleransicht (und das Session-Ereignisdetail-Panel für ein Fehlerereignis) enthält eine + Alert-Schaltfläche, die /alerts/new mit einem per_event-Trigger öffnet, der auf event_type + Umgebung dieser Zeile vorausgefüllt ist, einschließlich eines aus dem error_type des Payloads abgeleiteten Namens, falls vorhanden. Sie wählen noch die Kanäle aus und bestätigen den Rückblickzeitraum, aber der Matcher ist bereits ausgefüllt. Operatoren benötigen alerts:write, damit die Schaltfläche angezeigt wird.
Verbundlogik (M von N)
Jeder Alert hat zusätzlich zum Trigger zwei ganzzahlige Parameter:eval_window: wie viele der letzten Auswertungen betrachtet werden (Standard: 1)min_breaches: wie viele davon verletzt sein müssen, bevor der Alert feuert (Standard: 1)
1 von 1 (der Standard) bedeutet „beim ersten Verstoß feuern”. 3 von 5 bedeutet „feuern, wenn die Regel bei 3 der letzten 5 Auswertungen verletzt war” — nützlich für unruhige Signale, bei denen ein einzelner schlechter Messwert Rauschen ist. Der Dispatcher verwaltet einen Ringpuffer pro Alert; Sie müssen keinen Zustand selbst pflegen.
Auswertungsintervall
eval_interval_secs steuert, wie oft der Dispatcher Ihre Regel ausführt. Eingegrenzt auf [30, 86400]. Voreinstellungen im Dashboard: 1m / 5m / 15m / 1h. Wählen Sie ein Intervall, das zur Dynamik des zugrundeliegenden Signals passt: Ein 5-minütiger Fehlerrate-Alert, der alle 15 Sekunden ausgewertet wird, verschwendet CPU; ein Per-Event-Alert benötigt einen kurzen Rückblickzeitraum, sonst fallen Ereignisse zwischen den Ticks lautlos weg.
Kanäle
Jeder Alert kann eine beliebige Kombination dieser vier Kanäle verwenden. Kanalspezifische Zugangsdaten (Slack-Webhook-URL, generische Webhook-URL + Signierungsgeheimnis, Standard-E-Mail-Empfänger) werden einmalig in/settings konfiguriert und von jedem Alert per Schlüssel referenziert. So kann ein Slack-Kanal viele Alerts bedienen, ohne dass jeder seine eigene Kopie der Webhook-URL speichert.
Die drei externen Kanalarten (E-Mail, Slack, Webhook) werden außerdem durch einen organisationsweiten Kill-Switch, alerts.enabled_channels, gesteuert. Wenn ein gefeuerter Alert eine Kanalart angibt, die nicht in diesem Set enthalten ist, überspringt der Dispatcher sie und erstellt einen alert_notifications-Eintrag mit Status skipped_disabled und Ziel <channel_disabled> (so können Sie z. B. alle Slack-Benachrichtigungen global pausieren, ohne jede Regel bearbeiten zu müssen). Der In-Dashboard-Kanal ist immer aktiv. Siehe Konfiguration.
- Per-Kanal-Überschreibung
recipients[](wenn nicht leer). - Die Einstellung
alerts.email_default_recipients(ein Array von E-Mail-Strings).
alert_notifications-Eintrag mit Ziel <smtp_unconfigured>, damit der Audit-Trail die Fehlkonfiguration sichtbar macht.
Slack
Sendet eine Block Kit-Nachricht an eine Incoming-Webhook-URL.- Standard-URL:
alerts.slack_default_webhook(in/settingsgesetzt). - Per-Alert-Überschreibung: Setzen Sie
webhook_setting_keydes Kanals auf einen anderen URL-typisierten Einstellungsschlüssel, z. B.alerts.slack_oncall,alerts.slack_costs.
:rotating_light: / :warning: / :bell:), und die Nachricht enthält eine Schaltfläche, die direkt zur Incident-Seite verlinkt.
Generischer Webhook
Eine JSON-POST-Integration für PagerDuty, Opsgenie oder Ihren eigenen Endpunkt. Body-Struktur:alerts.webhook_signing_secret gesetzt ist, enthält die Anfrage einen X-AgentEye-Signature: sha256=<hex>-Header — den HMAC-SHA256 des Body unter Verwendung des Geheimnisses. Verifizieren Sie ihn auf der Empfängerseite, bevor Sie dem Payload vertrauen.
Der Header X-AgentEye-Event enthält alert.firing / alert.test. (alert.resolved ist für die geplante Auto-Auflösungsfunktion reserviert und wird derzeit nicht gesendet.)
Im Dashboard
Keine externe Zustellung: Der Alert schreibt lediglich einenalert_notifications-Eintrag, den die Incidents-Seite im Dashboard anzeigt. Nützlich, solange Sie eine Regel verfeinern und kein externes System mit Benachrichtigungen fluten möchten, oder für Alerts mit geringer Dringlichkeit, die Operatoren bei der normalen Triage prüfen.
Incident-Lebenszyklus
- firing — der Dispatcher hat gerade den Incident eröffnet oder einen weiteren Verstoß erkannt. Die Firing-Benachrichtigung wird genau einmal ausgesendet (gesteuert durch den
notified_firing_at-Zeitstempel am Incident). - acknowledged — ein Operator hat Ack auf
/incidents/:idgedrückt. Der Incident gilt noch als offen; nachfolgende Verstöße aktualisieren seine Belege, ohne erneut zu benachrichtigen. - resolved — ein Operator hat Auflösen gedrückt. Die automatische Auflösung, wenn die Regel nicht mehr verletzt wird, ist geplant, aber derzeit nicht aktiviert; ein offener Incident bleibt offen, bis ein Operator ihn auflöst.


Erforderliche Berechtigungen
Das Erstellen von Alert-Regeln und die Triage von Incidents sind getrennte Zuständigkeiten mit separaten Berechtigungen, sodass Sie einem Bereitschaftsdienst Incident-Zugriff geben können, ohne ihm auch die Möglichkeit zu geben, Regeln zu ändern.alerts:read: Alert-Regeln anzeigen.alerts:write: Alert-Regeln erstellen, bearbeiten, löschen und eine Test-Benachrichtigung auslösen.incidents:read: Incidents anzeigen.incidents:write: Manuelle (Ad-hoc-)Incidents öffnen, die nicht an einen Alert gebunden sind.incidents:ack: Incidents bestätigen, zuweisen, kommentieren und auflösen.
LegacyGewähren auf API-Schlüsseln (alerts:ack. Schlüssel und Operatoren, denen das älterealerts:ack-Token gewährt wurde, funktionieren weiterhin: Es wird alsincidents:ackanerkannt (und impliziertincidents:read), sodass bestehende Bereitschaftsdienst-Mitglieder ihren Zugriff behalten, ohne Zugangsdaten neu auszustellen. Neue Berechtigungen sollten mit derincidents:*-Familie erteilt werden.
POST /keys) und Operatoren (PUT /users/:id). Das PermGate des Dashboards sperrt die entsprechenden Schaltflächen, wenn eine Berechtigung fehlt; neben der Aktion erscheint dann // 403.
E-Mail-Empfänger-Auswahl. Die Empfängerauswahl im Alert-Editor listet die Mitglieder Ihrer Organisation auf, sodass Sie sie nach Namen auswählen können. Sie lädt für jeden Operator mitalerts:readoderalerts:write; die Anzeige des Team-Verzeichnisses zu diesem Zweck erfordert nichtusers:read, und die Auswahl gibt nur E-Mail-Adressen der Mitglieder zurück, niemals vollständige Benutzerdatensätze.
Konfiguration
Vom Dispatcher verwendete Umgebungsvariablen:| Variable | Standard | Zweck |
|---|---|---|
ALERT_WORKERS | 1 | Worker-Tasks pro Serverinstanz. Die meisten Deployments benötigen nur einen. |
ALERT_CLAIM_BATCH | 16 | Maximale Anzahl von Alerts, die ein einzelner Worker-Tick verarbeitet. |
ALERT_POLL_IDLE_SECS | 5 | Worker-Schlafzeit, wenn die Warteschlange leer ist. |
ALERT_REQUEST_TIMEOUT_MS | 15000 | Timeout pro Trigger-Auswertung. |
DASHBOARD_URL | https://app.befailproof.ai | Origin für den Incident-Magic-Link in Benachrichtigungen. Auf Ihren Dashboard-Host setzen. |
/settings, nicht per Umgebungsvariable):
alerts.email_default_recipients(email_list): JSON-Array von E-Mail-Strings — die Standard-Empfänger für E-Mail-Kanäle.alerts.slack_default_webhook(url): Standard-Slack-Incoming-Webhook-URL.alerts.webhook_default_url(url): Standard-URL für generische Webhooks.alerts.webhook_signing_secret(secret): HMAC-SHA256-Schlüssel. Wird in der GET-Antwort immer als""zurückgegeben; geben Sie einen neuen Wert ein, um ihn zu rotieren.alerts.enabled_channels(channel_set): Die organisationsweite Menge externer Kanalarten, die beim Feuern eines Alerts ausgelöst werden; standardmäßig alle drei (email,slack,webhook). Wird eine Art hier entfernt, wird dieser Kanal für jeden Alert global unterdrückt, ohne dass jede Regel bearbeitet werden muss. Der In-Dashboard-Kanal wird immer zugestellt und ist von dieser Einstellung nicht betroffen.
Neuen Alert verifizieren
Bevor Sie sich auf einen neuen Alert verlassen:- Speichern Sie ihn als aktiviert mit mindestens einem Benachrichtigungskanal.
- Wählen Sie Test auf der Alert-Detailseite und bestätigen Sie, dass jedes konfigurierte Ziel die synthetische Benachrichtigung erhält.
- Bestätigen Sie nach dem ersten echten Verstoß, dass der Incident unter Incidents erscheint und der gemessene Wert mit der entsprechenden Dashboard-Abfrage übereinstimmt.
Fehlerbehebung
| Symptom | Wahrscheinliche Ursache |
|---|---|
| Alert feuert nie | enabled = false, keine Kanäle angehängt, oder die zugrundeliegende CH-Abfrage gibt 0 Zeilen zurück. Verwenden Sie Test, um Kanäle zu bestätigen; verwenden Sie /queries/run, um die Metrik zu prüfen. |
| Slack-Benachrichtigung fehlt | alerts.slack_default_webhook (oder der per-Alert-Überschreibungsschlüssel) ist nicht gesetzt: Prüfen Sie alert_notifications.target auf <unset:…>-Einträge; oder die slack-Art ist in alerts.enabled_channels global deaktiviert: Prüfen Sie auf alert_notifications-Einträge mit Status skipped_disabled und Ziel <channel_disabled>. |
| Generischer Webhook 401 | Der Empfänger erwartet eine Signatur, aber alerts.webhook_signing_secret ist nicht gesetzt. Überprüfen Sie auf der Empfängerseite, ob der HMAC hmac_sha256(secret, body) entspricht. |
| E-Mail “from all sends failed” | SMTP-Zugangsdaten falsch oder die from-Adresse wird von Ihrem Relay abgelehnt. Dieselbe Konfiguration wie für OTP-E-Mails: Wenn diese funktionieren, ist der SMTP-Transport in Ordnung. |
| Incident öffnet sich wiederholt | Die Verbundparameter sind zu aggressiv: Versuchen Sie, min_breaches oder eval_window zu erhöhen, damit vorübergehende Spitzen keine Incidents erneut öffnen, die Sie bereits aufgelöst haben. |

