Przejdź do głównej zawartości

Deterministyczna detekcja anomalii oznacza, że o złym stanie produkcji rozstrzyga wersjonowana reguła alertu z testami jednostkowymi, a agent AI startuje dopiero po jej zadziałaniu. Agent czyta zamrożony pakiet dowodów z tożsamością read-only i szkicuje diagnozę ze źródłami. Nie decyduje, czy anomalia wystąpiła, a poziom ważności (severity) nigdy nie daje mu uprawnień do zapisu.

W zeszły wtorek odsetek błędów checkoutu rósł przez 40 minut i nikt nie dostał powiadomienia, bo statyczny alert „błędy powyżej 5%” reaguje tylko na awarie. Tydzień wcześniej ten sam alert dwa razy obudził dyżurnego o 3:00 dla usługi, która obsługuje cztery żądania na minutę. Ktoś proponuje, żeby dashboardy obserwował agent. Ta strona jest dla dewelopera, który jest właścicielem tego alertu, i dla tech leada, który odpowiada w imieniu zespołu na pytanie Q22 ze scorecardu. Pokazuje, jak najpierw uczynić detekcję testowalną i gdzie dopiero potem agent wnosi wartość.

Pytanie scorecardu (Q22): Jak monitorujesz stan produkcji i wykrywasz anomalie wymagające działania?

Odpowiedź za maksimum punktów: Wersjonowana polityka monitoringu z testowanymi progami, diagnozą read-only, zachowaniem dowodów i routingiem do właściwej bramki

  • Regułę alertu Prometheusa opartą na tempie spalania budżetu błędów SLO (burn rate), z progiem wolumenu i alertem o brakującej telemetrii, gotową do przeniesienia na własną usługę.
  • Plik testów promtool, który odtwarza cztery okna (normalne, skok, rzadki ruch, brak danych) i świeci na czerwono, gdy ktoś osłabi próg.
  • Uruchomienie diagnozy w Claude Code, Codeksie i Cursorze, które czyta wyłącznie wyeksportowany pakiet dowodów i zapisuje zgłoszenie wstępne (intake) do akceptacji przez człowieka.
  • Trzy prompty do skopiowania: szkic reguł i testów, diagnoza alertu oraz przegląd zmiany w regule.
  • Listę typowych awarii i checklistę, która dowodzi działania kontroli bez ponownego czytania reguł.

Szerszy stos monitoringu (metryki, tracing, dashboardy) opisuje strona monitoring i obserwowalność. Obsługę incydentu na żywo, w tym konfigurację Grafana MCP w trybie read-only, znajdziesz w ograniczonym triażu incydentów z AI. Ta strona obejmuje krok pomiędzy: regułę, która się odpala, i pierwszą diagnozę.

Detektor musi dać tę samą odpowiedź po odtworzeniu tych samych danych. Dzięki tej właściwości możesz go testować jednostkowo, recenzować jego zmiany i wyjaśnić po fakcie, dlaczego zadziałał albo nie. Model patrzący na dashboard daje wiarygodnie brzmiącą odpowiedź, która zmienia się między uruchomieniami, więc nie udowodnisz, że złapałby wtorkowy incydent. Podziel pracę według tego, w czym każda część jest dobra:

WarstwaKto decydujeWynikJak to testujesz
DetekcjaWersjonowana reguła oceniana przez system monitoringuOdpala albo nieTesty z odtworzeniem w CI; to samo wejście, ta sama decyzja
RoutingEtykiety reguły (severity, risk_class) i router alertówKogo powiadomić, czy startuje diagnozaTesty konfiguracji routera, próbne powiadomienia
DiagnozaAgent read-only nad zamrożonym pakietem dowodówObserwacje, hipotezy, brakujące dowodyKażde twierdzenie wskazuje źródło, które drugi przebieg może otworzyć
DziałanieWskazany człowiek, przez system deployu, flag lub rollbackuOgraniczenie skutków, rollback albo nowa intencjaLog audytowy i bramka zatwierdzeń tego systemu

Narracja modelu może się różnić między dwoma przebiegami dla tego samego alertu. To dopuszczalne, bo narracja jest analizą. Decyzja o odpaleniu alertu różnić się nie może.

Użyj systemu monitoringu, który już masz. Przykład poniżej to plik reguł Prometheusa, bo reguły Prometheusa mają oficjalny runner testów jednostkowych; Grafana Mimir i Thanos oceniają ten sam format reguł. Jeśli używasz Datadoga, alertingu Grafana Cloud albo CloudWatcha, obowiązują te same trzy zasady: trzymaj regułę w repozytorium, dołącz do niej etykiety routingu i przed merge’em odtwórz na niej historię.

Reguła dotyczy SLO: 99,9% żądań checkoutu kończy się sukcesem w oknie 30 dni, więc budżet błędów wynosi 0,1%. Wykorzystuje wzorzec wielu okien i wielu progów tempa spalania (multiwindow, multi-burn-rate) z rozdziału „Alerting on SLOs” książki Google SRE Workbook. Tempo spalania 14,4 utrzymane przez godzinę zużywa 2% trzydziestodniowego budżetu (14,4 × 1 h ÷ 720 h). Okno godzinowe nie pozwala dwuminutowemu skokowi obudzić dyżurnego; okno pięciominutowe nie pozwala alertowi wisieć długo po powrocie do normy.

monitoring/rules/checkout-slo.rules.yml
groups:
- name: checkout-slo
rules:
- record: checkout:error_ratio:rate5m
expr: sum(rate(http_requests_total{service="checkout",code=~"5.."}[5m])) / sum(rate(http_requests_total{service="checkout"}[5m]))
- record: checkout:error_ratio:rate1h
expr: sum(rate(http_requests_total{service="checkout",code=~"5.."}[1h])) / sum(rate(http_requests_total{service="checkout"}[1h]))
- record: checkout:requests:rate1h
expr: sum(rate(http_requests_total{service="checkout"}[1h]))
# SLO: 99.9% of checkout requests succeed over 30 days (error budget 0.1%).
# Page when the budget burns 14.4x too fast over 1h AND is still burning over 5m.
- alert: CheckoutErrorBudgetFastBurn
expr: |
checkout:error_ratio:rate1h > (14.4 * 0.001)
and checkout:error_ratio:rate5m > (14.4 * 0.001)
and checkout:requests:rate1h > 1
labels:
severity: page
risk_class: low
diagnosis: read-only
annotations:
summary: "Checkout is burning its 30-day error budget 14.4x too fast"
runbook: "docs/runbooks/checkout-errors.md"
# Silence is not health: page if the checkout series disappears.
- alert: CheckoutTelemetryMissing
expr: absent(http_requests_total{service="checkout"})
for: 10m
labels:
severity: page
risk_class: low
diagnosis: read-only
annotations:
summary: "No checkout request metrics for 10 minutes"
runbook: "docs/runbooks/telemetry-gap.md"

Trzy szczegóły w tym pliku robią to, czego nie potrafi statyczny próg:

  • Próg wolumenu (checkout:requests:rate1h > 1, jedno żądanie na sekundę) nie pozwala usłudze z czterema żądaniami na minutę budzić dyżurnego z powodu dwóch błędów.
  • Alert absent() łapie awarię, której stosunek błędów nie widzi: gdy exporter padnie, stosunek nie ma danych, a alert burn rate milczy.
  • Etykiety niosą routing, nie uprawnienia. risk_class używa klas ryzyka niska, średnia, wysoka i krytyczna z zarządzania i autonomii; diagnosis: read-only mówi routerowi, żeby uruchomił diagnozę. Żadna etykieta nie wydaje poświadczeń.

Dobierz typ reguły do kształtu sygnału, zamiast kopiować wszędzie ten sam zestaw progów:

Kształt sygnałuPasująca regułaDlaczego nie zwykły próg σ
Skuteczność żądań względem SLOBurn rate w wielu oknachAlarmuje o zużytym budżecie, czyli o tym, co czują użytkownicy
Silny cykl dobowy lub tygodniowyPorównanie z tą samą godziną w poprzednich tygodniach (offset 1w)Globalna średnia oznaczy każdy poniedziałkowy poranek
Rzadkie lub skokowe liczniki (płatności na minutę, rejestracje)Minimalna liczba zdarzeń plus próg bezwzględnyOdchylenie standardowe serii bliskiej zera to szum
LatencjaPróg percentyla z klauzulą trwałości for:Latencja jest skośna; średnia i σ ukrywają ogon
Heartbeat, cron lub exporterabsent() albo absent_over_time()Brak danych nie daje żadnego stosunku

Reguła, której nie odtworzyłeś na danych, jest zgadywaniem. promtool test rules ocenia reguły na syntetycznych seriach i porównuje alerty, które się odpaliły, z oczekiwanymi. Plik poniżej obejmuje cztery okna, o które pyta scorecard: normalne, dryf lub skok, rzadki ruch i brak danych.

monitoring/rules/checkout-slo.test.yml
rule_files:
- checkout-slo.rules.yml
evaluation_interval: 1m
tests:
# Normal day: 0.05% errors at 100 req/s. Nothing fires.
- interval: 1m
input_series:
- series: 'http_requests_total{service="checkout",code="200"}'
values: '0+5997x120'
- series: 'http_requests_total{service="checkout",code="500"}'
values: '0+3x120'
alert_rule_test:
- eval_time: 90m
alertname: CheckoutErrorBudgetFastBurn
exp_alerts: []
# Spike: errors jump to 5% at minute 30. Fires once the 1h window catches up.
- interval: 1m
input_series:
- series: 'http_requests_total{service="checkout",code="200"}'
values: '0+5997x30 179910+5700x90'
- series: 'http_requests_total{service="checkout",code="500"}'
values: '0+3x30 90+300x90'
alert_rule_test:
- eval_time: 32m
alertname: CheckoutErrorBudgetFastBurn
exp_alerts: []
- eval_time: 60m
alertname: CheckoutErrorBudgetFastBurn
exp_alerts:
- exp_labels:
severity: page
risk_class: low
diagnosis: read-only
exp_annotations:
summary: "Checkout is burning its 30-day error budget 14.4x too fast"
runbook: "docs/runbooks/checkout-errors.md"
# Sparse traffic: 1 of 2 requests per minute fails. Below the volume floor, no page.
- interval: 1m
input_series:
- series: 'http_requests_total{service="checkout",code="200"}'
values: '0+1x120'
- series: 'http_requests_total{service="checkout",code="500"}'
values: '0+1x120'
alert_rule_test:
- eval_time: 90m
alertname: CheckoutErrorBudgetFastBurn
exp_alerts: []
# Missing data: the series never arrives. The gap alert fires after 10 minutes.
- interval: 1m
input_series: []
alert_rule_test:
- eval_time: 12m
alertname: CheckoutTelemetryMissing
exp_alerts:
- exp_labels:
service: checkout
severity: page
risk_class: low
diagnosis: read-only
exp_annotations:
summary: "No checkout request metrics for 10 minutes"
runbook: "docs/runbooks/telemetry-gap.md"

Uruchamiaj obie kontrole w CI przy każdej zmianie w monitoring/ (terminal lub job CI, promtool 3.15.0):

Okno terminala
promtool check rules monitoring/rules/*.rules.yml
cd monitoring/rules && promtool test rules --junit=promtool-junit.xml *.test.yml

Oba pliki przechodzą na promtool 3.15.0. Żeby potwierdzić, że testy potrafią się wywrócić, zmień w regule 14.4 na 144 i uruchom je ponownie: test skoku robi się czerwony. Łatwo przeoczyć dwa szczegóły. absent() kopiuje do alertu dopasowania równościowe ze swojego selektora, więc alert o brakujących danych niesie service: checkout i test musi się go spodziewać. Skok nie odpala alertu w 32. minucie, bo dwie minuty błędów prawie nie ruszają stosunku godzinowego. To opóźnienie jest ceną za brak alarmów o chwilowe skoki; zdecyduj o nim świadomie.

Niech agent szkicuje reguły i testy, a nie o nich decyduje

Dział zatytułowany „Niech agent szkicuje reguły i testy, a nie o nich decyduje”

Ręczne pisanie arytmetyki burn rate i syntetycznych serii to miejsce, w którym agent realnie oszczędza czas. Przepływ jest taki sam w Claude Code, Codeksie i Cursorze: otwórz repozytorium, wklej prompt i pozwól agentowi uruchamiać promtool, aż testy przejdą. Recenzja człowieka czyta potem przypadki testowe i progi, a nie PromQL linijka po linijce.

Traktuj wynik jak każdy inny pull request agenta: dowodem są testy, a recenzent sprawdza, czy kodują zachowanie, którego chce zespół. Jak prowadzić taką recenzję, opisuje strona code review PR-a agenta bez czytania każdej linii.

Gdy odpala się CheckoutErrorBudgetFastBurn, router powiadamia człowieka i, dzięki etykiecie diagnosis: read-only, równolegle uruchamia diagnozę. Przebieg nigdy sam nie odpytuje produkcji. Najpierw mały skrypt eksportuje zamrożony pakiet dowodów, więc agent pracuje na tych samych danych, które człowiek później zaudytuje.

  1. Wyślij alert do odbiornika webhooka w routerze alertów (w Prometheusie: trasa Alertmanagera dopasowująca diagnosis="read-only"). Odbiornik zapisuje payload jako alert.json w nowym katalogu nazwanym od fingerprintu alertu.

  2. Wyeksportuj dowody poświadczeniami read-only, które trzyma runner, a nie agent. Na przykład 60 minut przed i 30 minut po starcie alertu:

    Okno terminala
    promtool query --http.config.file=/srv/diagnosis/prom-readonly.yml \
    range --start="$START" --end="$END" --step=1m \
    "$PROM_URL" 'checkout:error_ratio:rate5m' > "$EVIDENCE_DIR/error_ratio_5m.txt"

    prom-readonly.yml to konfiguracja klienta HTTP promtoola, która trzyma token bearer tylko do odczytu (blok authorization z credentials_file), więc token nie pojawia się ani w wierszu poleceń, ani w katalogu dowodów.

    Dodaj zdarzenia deployu z tego samego okna z systemu deployu oraz logi na poziomie error, z sekretami i danymi osobowymi zamaskowanymi u źródła.

  3. Uruchom agenta nad tym katalogiem bez możliwości zapisu: Claude Code dostaje tylko Read, Grep i Glob; Codex dostaje powłokę w sandboksie read-only; Cursor dostaje maszynę wirtualną, w której jest tylko pakiet dowodów. Każde uruchomienie pokazują zakładki poniżej. Wynikiem jest jeden plik zgłoszenia, intake.md.

  4. Opublikuj zgłoszenie na kanale incydentu przez istniejącego bota. Człowiek go akceptuje, odrzuca albo eskaluje; każdy rollback, zmiana flagi czy poprawka kodu przechodzi przez własną bramkę.

  5. Przechowuj alert.json, pliki dowodów, plik zgłoszenia i log przebiegu razem z rekordem incydentu przez okres określony w polityce incydentów.

Uruchom z katalogu dowodów (terminal lub runner CI; sprawdzone na Claude Code 2.1.283 (kanał latest) i 2.1.274 (kanał stable)):

Okno terminala
cd "$EVIDENCE_DIR"
claude -p "$(cat /srv/diagnosis/diagnose-prompt.md)" \
--bare --restricted --setting-sources "" --strict-mcp-config \
--tools "Read,Grep,Glob" \
--allowedTools "Read,Grep,Glob" \
--permission-mode dontAsk \
--output-format json \
--max-budget-usd 2 > "$OUT_DIR/run.json" \
&& jq -r .result "$OUT_DIR/run.json" > "$OUT_DIR/intake.md"

--tools "Read,Grep,Glob" zostawia tylko te trzy wbudowane narzędzia, więc nie ma Bash, Edit ani Write, a --allowedTools jawnie je zatwierdza. --restricted ogranicza Read, Grep i Glob do katalogu roboczego, więc agent czyta katalog dowodów i nic więcej na runnerze: ani uwierzytelnienia Codeksa, ani poświadczeń chmury w $HOME. Mimo to uruchamiaj runnera jako użytkownika, który nie może czytać kluczy usług, bo prompt injection w logach może poprosić o każdy osiągalny plik, a krok 4 publikuje zgłoszenie na kanale. --bare pomija hooki, pluginy i wykrywanie CLAUDE.md oraz uwierzytelnia się przez ANTHROPIC_API_KEY (albo apiKeyHelper przekazany przez --settings), nigdy przez OAuth ani pęk kluczy: daj runnerowi klucz należący do usługi incydentowej. --setting-sources "" nie wczytuje plików ustawień użytkownika, projektu ani lokalnych, a --strict-mcp-config bez --mcp-config nie uruchamia żadnego serwera MCP, więc nic w katalogu dowodów ani na runnerze nie doda narzędzi ani uprawnień. dontAsk odrzuca wszystko spoza dozwolonego zestawu, zamiast czekać na zgodę, której nikt nie udzieli. run.json to koperta JSON (wynik, koszt, identyfikator sesji), która służy jako log przebiegu przechowywany w kroku 5; jq wyciąga z niej zgłoszenie w Markdownie do intake.md.

Zapisz ten prompt jako /srv/diagnosis/diagnose-prompt.md. Działa bez zmian we wszystkich trzech narzędziach.

Jeśli agent ma w trakcie incydentu odpytywać na żywo Grafanę, Sentry albo Datadoga przez MCP, użyj konfiguracji MCP read-only z ograniczonego triażu incydentów z AI i serwerów z listy serwerów MCP do obserwowalności.

Reguły dryfują. Ktoś podnosi próg, żeby uciszyć hałaśliwy alert, a sześć tygodni później prawdziwa regresja przechodzi niezauważona. Uruchamiaj ten prompt przy każdym pull requeście, który dotyka monitoring/, i wymagaj też zgody zespołu będącego właścicielem.

Poziom ważności zmienia to, kogo powiadamiasz. Nigdy nie zmienia tego, czego może dotknąć tożsamość diagnostyczna.

KrokRola agentaKto decydujeGdzie zapisane
Reguła się odpalaŻadnaWersjonowana regułaSystem monitoringu, historia alertów
Powiadomienie i start diagnozyŻadnaRouter alertów, na podstawie etykiet regułyLog routera
DiagnozaSzkicuje zgłoszenie—Plik zgłoszenia plus pakiet dowodów
Akceptacja, odrzucenie lub eskalacja zgłoszeniaŻadnaDyżurny inżynier albo zadeklarowana polityka, tylko dla niskiej klasy ryzykaNarzędzie incydentowe
Rollback, zmiana flagi, wdrożenie poprawkiWskazuje runbookWskazany człowiek przez bramkę danego systemuLog audytowy deployu lub flag
Przekształcenie w nowe zadanieSzkicuje intent.mdWłaściciel triażuBacklog albo repozytorium

Bramki z dwóch ostatnich wierszy opisują strony zatwierdzanie produkcji jako granica systemu i przećwiczony rollback z ludzką władzą nad produkcją.

Alerty nadal są hałaśliwe po przepisaniu. Podsumowanie agenta nie naprawi złego detektora. Pobierz alerty z ostatnich 30 dni, odtwórz okno każdego z nich jako nowy przypadek testowy i dostrajaj próg wolumenu lub okno, aż niechciane alerty przestaną się odpalać w teście, zanim zmienisz produkcję.

Prawdziwy incydent nikogo nie powiadomił. Dodaj okno tego incydentu do pliku testów jako przypadek, który musi się odpalić, zobacz, jak test pada, i dopiero wtedy zmień regułę. Ten przypadek chroni cię przed kolejną osobą, która podniesie próg.

Metryka zniknęła, a wszystko wyglądało na zielone. Każdy alert oparty na stosunku potrzebuje towarzyszącego absent(). Jeśli exporter obsługuje kilka usług, alarmuj o serii każdej usługi, a nie o exporterze jako całości.

Logi niosą prompt injection. Linia logu albo treść ticketu każe agentowi „wyciszyć ten alert”. Tożsamość diagnostyczna nie ma narzędzia, które by to umożliwiło, a prompt każe agentowi takie teksty cytować. Dodaj podrzuconą instrukcję do testowego pakietu dowodów i sprawdź, czy zgłoszenie ją cytuje i niczego nie zmienia.

Poziom ważności podłączono do uprawnień zapisu. Usuń to sprzężenie: etykieta severity: critical może powiadomić więcej osób, ale nigdy nie może uruchomić przebiegu z poświadczeniami do deployu czy bazy danych.

Agent wskazuje przyczynę na podstawie korelacji. Deploy dwie minuty przed skokiem to hipoteza, nie przyczyna. Odrzucaj zgłoszenia bez sekcji kontrdowodów i brakujących dowodów, a przy incydentach wysokiego ryzyka używaj promptu audytowego z ograniczonego triażu incydentów z AI.

  • Każda reguła alertu jest w repozytorium i zmienia się tylko przez zrecenzowany pull request.
  • promtool test rules (albo odpowiednik twojej platformy) działa w CI z przypadkami normalnym, skoku, rzadkiego ruchu i braku danych dla każdej reguły.
  • Celowa mutacja progu wywraca co najmniej jeden test.
  • Odtworzenie okna historycznego incydentu daje tę samą decyzję „odpala / nie odpala”, bez udziału modelu.
  • Przebieg diagnozy nie może zapisywać niczego poza swoim plikiem wynikowym, może czytać tylko pakiet dowodów i nie ma poświadczeń do deployu ani produkcji, a jego tożsamość jest osobno widoczna w logach audytowych.
  • Payload alertu, pakiet dowodów, zgłoszenie i log przebiegu są przechowywane z incydentem.
  • Próbny przebieg z podrzuconą instrukcją w logach nie zmienia niczego poza plikiem zgłoszenia.
  • Zaakceptowane zgłoszenia wracają do cyklu życia przez triaż, a nie jako bezpośrednie commity.

Kieruj zaakceptowane zgłoszenia do etapu Maintain, a wykrywanie i przywracanie działania mierz metrykami cyklu życia. Obserwowanie samych agentów (wywołania narzędzi, koszt, ślady audytowe) opisuje strona obserwowalność agentów.

Najczęstsze pytania

Jaka jest rola agenta AI w deterministycznej detekcji anomalii?

O nieprawidłowym stanie produkcji rozstrzyga wersjonowana reguła alertu z testami jednostkowymi, a agent AI uruchamia się dopiero po jej zadziałaniu, by z tożsamością read-only przeanalizować zamrożony pakiet dowodów i naszkicować diagnozę ze źródłami.

Czy wysoki poziom ważności (`severity`) daje agentowi diagnozującemu prawo zapisu na produkcji?

Nie, agent nigdy sam nie rozstrzyga o wystąpieniu anomalii, a poziom ważności alertu nigdy nie nadaje mu uprawnień do zapisu ani wykonywania zmian na produkcji.