Przejdź do treści

Przewodniki

Eksperymenty online (testy A/B)

Twoje porównanie offline powiedziało, że nowa wersja jest lepsza. Test A/B na produkcji zadaje to samo pytanie prawdziwym użytkownikom. Twój własny router losowo przydziela jednostki (użytkowników lub sesje) do dwóch ramion; oloproof experiment czyta jego logi i odpowiada tymi samymi czterema stanami co każda inna reguła. Metoda jest dopuszczona przez niezależny audyt na określonych warunkach: observed_until to Twoja deklaracja, kiedy wyodrębniono dziennik wyników, jednostki losowano niezależnie, wynik żadnej jednostki nie zależy od ramienia innej, wyniki nie dryfowały, gdy zmieniał się podział, a każde spojrzenie czyta cały dziennik. Poza nimi odpowiedź nie jest objęta gwarancją.

Logi i deklaracja

Dwa pliki, CSV lub JSONL: log przydziału z jednym wierszem na jednostkę (zadeklarowana przez ciebie kolumna jednostki oraz arm) i log wyników z jednostką i jej value.

experiment:
  name: checkout-v2
  unit: user
  allocation: {control: 0.5, treatment: 0.5}
  control: control
  treatment: treatment
  assignments: logs/assignments.csv
  outcomes: logs/outcomes.csv
  kind: rate
  rules:
    - {id: lift, kind: superiority}
    - {id: no-harm, kind: non_inferiority, margin: 0.01}
oloproof experiment experiment.yaml --policy release.yaml --json

kind: mean przyjmuje zadeklarowany range: [low, high]; direction: max traktuje niższą wartość jako lepszą. Przydzielona jednostka bez wiersza wyniku jest brakująca i ograniczana swoją najgorszą wartością po każdej stronie, chyba że missing_outcome: zero mówi, że brak wiersza oznacza zero. Zapisuj wiersz dla każdej jednostki, łącznie z zerami: dziennik konwersji zawierający tylko konwertujących odczytuje każdą inną jednostkę jako brakującą, a odpowiedź pozostaje INSUFFICIENT_EVIDENCE. Uzupełnianie zerami zakłada, że okno wyniku każdej liczonej jednostki się zamknęło; jednostka przydzielona godzinę temu jeszcze nie skonwertowała, a liczenie jej jako zera faworyzuje ramię, które konwertuje szybciej. Zadeklaruj outcome_window_hours, as_of i observed_until (kiedy wyodrębniono dziennik wyników), z kolumną assigned_at w dzienniku przydziału, a liczone są tylko jednostki, których okno zamknęło się do as_of; missing_outcome: zero jest bez nich odrzucane, niezależnie od monitorowania. Zapisuj każdy czas z przesunięciem lub Z (2026-10-11T00:00:00Z); czas bez nich jest odrzucany. as_of nie może być późniejsze niż observed_until i żadne z nich nie może leżeć w przyszłości: wyniku po wyodrębnieniu nie ma w dzienniku. Okno wybiera pytanie: okno 48-godzinne odpowiada na „skonwertował w ciągu 48 godzin”, więc musi obejmować opóźnienie wyniku, o który chodzi. Identyfikatory jednostek porównuje się jako tekst po usunięciu spacji, a 42.0 czyta się jako 42. Kod wyjścia to kod najgorszej reguły: 0 PASS, 1 FAIL, 3 INSUFFICIENT_EVIDENCE, 4 MANUAL_REVIEW.

Co sprawdza najpierw

  • Proporcja próby. Liczności jednostek w ramionach są testowane względem zadeklarowanego przydziału (dokładny test dwumianowy dla dwóch ramion, chi-kwadrat dla większej liczby, próg 0,001). Niezgodność zmienia każdą regułę w MANUAL_REVIEW: zepsuty podział oznacza, że ramiona nie są już porównywalne, a więcej danych tego samego rodzaju tego nie naprawi. Znajdź przyczynę (przekierowanie gubiące użytkowników, filtr botów działający na jednym ramieniu), zanim odczytasz jakąkolwiek różnicę.
  • Jednostka w dwóch ramionach. Przydział przeciekł; każda reguła brzmi MANUAL_REVIEW.
  • Kilka wierszy wyniku dla jednej jednostki. Odrzucone, bo zdarzenia jednego użytkownika nie są niezależne. Zadeklaruj aggregate: unit_mean, aby wynikiem każdej jednostki była jej własna średnia: odpowiedź dotyczy wtedy przeciętnego użytkownika, a nie przeciętnego zdarzenia.
  • Puste ramię. INSUFFICIENT_EVIDENCE, dopóki nie ma wyników.
  • Wiersze wyników, które nie pasują do żadnej przydzielonej jednostki, przy missing_outcome: zero. Zera opierają się na złączeniu, więc zepsute złączenie odczytałoby prawdziwe jednostki jako zera; każda reguła daje MANUAL_REVIEW, dopóki identyfikatory się nie zgadzają. Domyślnie są liczone i pomijane.

Jak decyduje

Średnia każdego ramienia dostaje przedział, którego Oloproof już używa dla jednego przebiegu (dokładny Clopper-Pearson dla odsetka, w przeciwnym razie ograniczona średnia oparta na zakładach), każdy z połową budżetu błędu, a różnica jest ograniczona przeciwległymi końcami obu. Obowiązuje przy każdej wielkości próby i jest szerszy niż podręcznikowy przedział normalny. Reguła wyższości przechodzi, gdy cały przedział leży powyżej zera; reguła nie-gorszości przechodzi, gdy jej dolny koniec jest równy lub wyższy niż minus margines.

monitoring: anytime używa przedziału opartego na zakładach dla obu ramion, który obowiązuje niezależnie od tego, jak często patrzysz i kiedy przestajesz. Obowiązuje to pod warunkiem, że każde spojrzenie przekazuje cały dziennik do tej chwili: nigdy nie odrzucaj ani nie filtruj wierszy według okresu po ich odczytaniu. Domyślny fixed odczytuje się raz, przy zaplanowanej wielkości próby.

Kilka wariantów

Zadeklaruj treatments: [b, c] zamiast treatment: i podaj każdej regule wariant, który porównuje (treatment: b). Przedział każdego ramienia jest brany na poziomie 1 - alpha/m dla m ramion, więc każdy wariant minus kontrola jest pokryty jednocześnie przez nierówność Boole'a: jedna reguła na wariant, jedno twierdzenie na każdą, a rodzina trzyma się razem. Każdy przedział jest szerszy niż przy dwóch ramionach, bo każde ramię płaci za pozostałe. Przy kilku wariantach raport wskazuje najlepszy spośród tych, które przechodzą każdą wskazującą je regułę, oraz czy jest oddzielony od każdego innego przechodzącego wariantu: każda różnica, ograniczona tymi samymi przedziałami jednoczesnymi, wyklucza zero. Remisy zachowują zadeklarowaną kolejność i nigdy nie są rozdzielane. Kontrola proporcji próby już czyta każde ramię. Łączna gwarancja obejmuje ramiona jednego pliku eksperymentu: rozdzielenie wariantów na kilka plików ją traci.

Metryki ilorazowe

Współczynnik klikalności to kliknięcia przez sesje, a użytkownik z wieloma sesjami nie jest wieloma niezależnymi użytkownikami. Zadeklaruj iloraz na jednym wierszu na jednostkę, z zakresami, w których leżą wartości każdej jednostki:

  ratio: {numerator: clicks, denominator: sessions, numerator_range: [0, 50], denominator_range: [1, 50]}
  aggregate: unit_sum   # only if a unit has several rows: they are added

Estymandą jest średni licznik każdego ramienia przez jego średni mianownik. Obie średnie są ograniczone dopuszczonym przedziałem, każda swoją częścią budżetu błędu, a iloraz przez podzielenie ich końców, więc obowiązuje przy każdej wielkości próby bez przybliżenia normalnego. Mianownik, którego przedział sięga zera, nie daje przedziału. Wartość spoza zakresu jest błędem konfiguracji wskazującym jednostkę i nigdy nie jest przycinana. Przedział metody delta, zwykle węższy, jest pokazywany obok i nigdy nie decyduje.

Zmienna towarzysząca sprzed testu

Wynik, który podąża za czymś zmierzonym przed testem (wydatki z zeszłego miesiąca, sesje z zeszłego tygodnia), zmienia się mniej, gdy się to usunie. Podaj wartość każdej jednostki sprzed testu i współczynnik ustalony, zanim odczytano wyniki tego testu:

  covariate: {values: logs/pre_period.csv, range: [0, 500], theta_from: logs/history.csv}

Decydowanym wynikiem jest Y - theta (X - c). theta jest zadeklarowane (theta:, z opcjonalnym center:, domyślnie środkiem zakresu) albo dopasowane na pliku historii z okresu przed testem (kolumny covariate i outcome), nigdy na własnych wynikach tego testu. Ponieważ X zmierzono przed przydziałem, a to, które jednostki mają X, też ustalono przed przydziałem, skorygowana różnica ma tę samą estymandę. Jednostka bez wartości w pliku nie jest korygowana. Poprawna korekta wciąż może być szersza niż jej brak, bo zakres skorygowanego wyniku jest szerszy, więc raport pokazuje oba przedziały i mówi, który jest węższy; nie twierdzi, że coś oszczędza.

Nowość i interferencja, pokazane

novelty: {exposure_column: exposed_at, time_column: at, days: 7} odczytuje pierwszą ekspozycję każdej jednostki z logu przydziału i czas każdego wiersza wyniku, i pokazuje różnicę w pierwszych days dniach ekspozycji i później. Rozstrzygnięta wczesna różnica przy nierozstrzygniętej lub przeciwnej późniejszej jest nazywana „możliwy efekt nowości”. Podział nigdy nie decyduje o regule: jednostki bez wierszy w danym przedziale są z niego pomijane, a nie ograniczane w najgorszym wariancie. Przyjmuje jeden wynik na wiersz, nie iloraz ani zmienną towarzyszącą.

cluster_column: team liczy zespoły, które mają jednostki z kilku ramion, i pyta, czy wynik jednej jednostki może zależeć od ramienia innej. Jeśli może, losuj według zespołu i zadeklaruj go jako jednostkę.

Kilka wariantów, ilorazy i zmienne towarzyszące zostały dopuszczone przez niezależny audyt i jego potwierdzenie 3 listopada 2026 r., na tych samych warunkach co dwa ramiona.

Offline i online

Wskaż porównanie offline i jego metrykę (offline_comparison: <id>, offline_metric: pass_rate), a odpowiedź poda, czy dwa rozstrzygnięte kierunki są zgodne. Jest to raportowane i nigdy niczego nie rozstrzyga: niezgodność to powód, by przyjrzeć się zestawowi, a nie werdykt o wydaniu.

Pułapki

  • Podglądanie. Codzienne odczytywanie testu o stałym horyzoncie i zatrzymanie go w dobrym dniu zawyża fałszywe wygrane. Zaplanuj wielkość próby albo zadeklaruj monitoring: anytime.
  • Nowość i uczenie się. Użytkownicy reagują na wszystko, co nowe, a potem się uspokajają. Zysk z pierwszego tygodnia może zniknąć; prowadź test wystarczająco długo, by objąć cykle twoich użytkowników, i zadeklaruj novelty:, aby zobaczyć podział.
  • Interferencja. Przedział zakłada, że wynik jednej jednostki nie zależy od ramienia innej. Wspólne zapasy, marketplace'y, funkcje społecznościowe lub pamięć podręczna rozgrzana przez jedno ramię to łamią; wtedy losuj według większej jednostki (regionu, zespołu), i zadeklaruj cluster_column:, aby zobaczyć, jak wymieszane są klastry.
  • Dryf przy zmieniającym się podziale. Przedział zakłada, że przydział pozostał stały w trakcie testu albo że wyniki nie dryfowały, gdy się zmieniał. Zwiększanie z 10% do 50% albo 90/10, a potem 10/90 w dzień roboczy i w weekend, waży okresy inaczej w każdym ramieniu i miesza efekt czasu z różnicą; sprawdzenie proporcji próby czyta łączne liczności i tego nie widzi. Utrzymuj stały podział albo decyduj tylko na podstawie okresu po zwiększeniu.
  • Zmiana jednostki. Losuj i analizuj według tej samej jednostki. Losowanie użytkowników i liczenie sesji jako niezależnych fałszywie zwęża przedział.

Czego to nie powie

  • Czy wynik obowiązuje dla użytkowników spoza okna czasowego, regionu lub ruchu testu.
  • Niczego o metryce, której nie zadeklarowano przed testem; metryka wybrana po fakcie jest opisem.
  • Czy twój router naprawdę losował: kontrola proporcji próby wyłapuje duże błędy, nie subtelne.
  • Który wariant jest najlepszy spośród tych, które nie przeszły: szeregowane są tylko warianty, które przechodzą. Przydział warstwowy i projekty typu switchback nie są zbudowane.