Anleitungen
Online-Experimente (A/B-Tests)
Ihr Offline-Vergleich sagte, die neue Version sei besser. Ein A/B-Test in Produktion stellt echten Nutzern dieselbe Frage. Ihr eigener Router teilt Einheiten (Nutzer oder Sitzungen) zufällig auf zwei Arme auf; oloproof experiment liest seine Logs und antwortet mit denselben vier Zuständen wie jede andere Regel. Die Methode ist durch ein unabhängiges Audit zu genannten Bedingungen zugelassen: observed_until ist Ihre Angabe, wann das Ergebnislog extrahiert wurde, Einheiten wurden unabhängig randomisiert, das Ergebnis keiner Einheit hängt vom Arm einer anderen ab, Ergebnisse drifteten nicht, während sich die Aufteilung änderte, und jeder Blick liest das ganze Log. Außerhalb dieser Bedingungen ist die Antwort nicht abgedeckt.
Die Logs und die Deklaration
Zwei Dateien, CSV oder JSONL: ein Zuweisungslog mit einer Zeile pro Einheit (die von Ihnen deklarierte Einheitenspalte und arm) und ein Ergebnislog mit der Einheit und ihrem 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 --jsonkind: mean nimmt einen deklarierten range: [low, high]; direction: max wertet niedriger als besser. Eine zugewiesene Einheit ohne Ergebniszeile fehlt und wird auf jeder Seite mit ihrem schlechtesten Wert begrenzt, es sei denn, missing_outcome: zero sagt, dass keine Zeile null bedeutet. Protokollieren Sie eine Zeile für jede Einheit, Nullen eingeschlossen: Ein Konversionsprotokoll, das nur Konvertierende enthält, liest jede andere Einheit als fehlend, und die Antwort bleibt INSUFFICIENT_EVIDENCE. Das Auffüllen mit Null setzt voraus, dass das Ergebnisfenster jeder gezählten Einheit geschlossen ist; eine vor einer Stunde zugewiesene Einheit hat noch nicht konvertiert, und sie als Null zu zählen begünstigt den Arm, der schneller konvertiert. Deklarieren Sie outcome_window_hours, as_of und observed_until (wann das Ergebnisprotokoll extrahiert wurde), mit einer Spalte assigned_at im Zuweisungsprotokoll, und nur Einheiten, deren Fenster bis as_of geschlossen ist, werden gezählt; missing_outcome: zero wird ohne sie abgelehnt, unabhängig vom Monitoring. Schreiben Sie jede Zeit mit Offset oder Z (2026-10-11T00:00:00Z); eine Zeit ohne beides wird abgelehnt. as_of darf nicht später als observed_until liegen, und keines von beiden darf in der Zukunft liegen: Ein Ergebnis nach der Extraktion steht nicht im Protokoll. Das Fenster wählt die Frage: Ein 48-Stunden-Fenster beantwortet „innerhalb von 48 Stunden konvertiert“, also muss es die Verzögerung des gemeinten Ergebnisses abdecken. Einheiten-IDs werden nach dem Entfernen von Leerzeichen als Text verglichen, wobei 42.0 als 42 gelesen wird. Der Exit-Code ist der der schlechtesten Regel: 0 PASS, 1 FAIL, 3 INSUFFICIENT_EVIDENCE, 4 MANUAL_REVIEW.
Was zuerst geprüft wird
- Stichprobenverhältnis. Die Einheitenzahlen der Arme werden gegen die deklarierte Aufteilung getestet (exakter Binomialtest bei zwei Armen, Chi-Quadrat bei mehr, Schwelle 0,001). Eine Abweichung macht jede Regel zu MANUAL_REVIEW: Eine kaputte Aufteilung bedeutet, dass die Arme nicht mehr vergleichbar sind, und mehr Daten derselben Art reparieren das nicht. Finden Sie die Ursache (eine Weiterleitung, die Nutzer verliert, ein Bot-Filter nur auf einem Arm), bevor Sie eine Differenz lesen.
- Eine Einheit in zwei Armen. Die Zuweisung ist durchgesickert; jede Regel lautet MANUAL_REVIEW.
- Mehrere Ergebniszeilen für eine Einheit. Abgelehnt, weil Ereignisse eines Nutzers nicht unabhängig sind. Deklarieren Sie aggregate: unit_mean, damit der eigene Mittelwert jeder Einheit ihr Ergebnis ist: Die Antwort betrifft dann den durchschnittlichen Nutzer, nicht das durchschnittliche Ereignis.
- Ein leerer Arm. INSUFFICIENT_EVIDENCE, bis er Ergebnisse hat.
- Ergebniszeilen, die zu keiner zugewiesenen Einheit passen, unter missing_outcome: zero. Die Nullen beruhen auf der Verknüpfung, eine kaputte Verknüpfung würde also echte Einheiten als Nullen lesen; jede Regel liest MANUAL_REVIEW, bis die IDs übereinstimmen. In der Voreinstellung werden sie gezählt und ausgelassen.
Wie entschieden wird
Der Mittelwert jedes Arms erhält das Intervall, das Oloproof bereits für einen Lauf verwendet (exaktes Clopper-Pearson für eine Rate, sonst der beschränkte Mittelwert per Wette), jeweils mit der Hälfte des Fehlerbudgets, und die Differenz wird durch die entgegengesetzten Enden beider begrenzt. Sie gilt bei jeder Stichprobengröße und ist breiter als ein Normalintervall aus dem Lehrbuch. Eine Überlegenheitsregel besteht, wenn das ganze Intervall über null liegt; eine Nicht-Unterlegenheitsregel besteht, wenn ihr unteres Ende bei oder über minus der Marge liegt.
monitoring: anytime verwendet das Wett-Intervall für beide Arme, das gilt, wie oft Sie auch hinsehen und wann immer Sie aufhören. Das gilt, solange jeder Blick das ganze Protokoll bis zu diesem Moment übergibt: Lassen Sie nach dem Lesen nie Zeilen nach Zeitraum weg und filtern Sie sie nie. Die Voreinstellung, fixed, wird einmal bei der geplanten Stichprobengröße gelesen.
Mehrere Behandlungen
Deklarieren Sie treatments: [b, c] statt treatment: und geben Sie jeder Regel die Behandlung, die sie vergleicht (treatment: b). Das Intervall jedes Arms wird bei 1 - alpha/m für die m Arme genommen, sodass jede Behandlung minus die Kontrolle durch die Union-Schranke zugleich abgedeckt ist: eine Regel pro Behandlung, je eine Aussage, und die Familie hält zusammen. Jedes Intervall ist breiter als bei zwei Armen, weil jeder Arm für die anderen bezahlt. Bei mehreren Behandlungen nennt der Bericht die beste unter denen, die jede sie nennende Regel bestehen, und ob sie von jeder anderen bestehenden Behandlung getrennt ist: Jede Differenz, beschränkt durch dieselben simultanen Intervalle, schließt null aus. Gleichstände behalten die deklarierte Reihenfolge und werden nie getrennt. Die Prüfung des Stichprobenverhältnisses liest bereits jeden Arm. Die gemeinsame Garantie deckt die Arme einer Experimentdatei ab: Wer die Behandlungen auf mehrere Dateien verteilt, gibt sie auf.
Verhältnismetriken
Eine Klickrate ist Klicks geteilt durch Sitzungen, und ein Nutzer mit vielen Sitzungen ist nicht viele unabhängige Nutzer. Deklarieren Sie das Verhältnis über eine Zeile pro Einheit, mit Bereichen, in denen die Werte jeder Einheit liegen:
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 addedDer Schätzgegenstand ist der mittlere Zähler jedes Arms geteilt durch seinen mittleren Nenner. Beide Mittelwerte werden durch das zugelassene Intervall beschränkt, jeder mit seinem Anteil am Fehlerbudget, und das Verhältnis durch Division ihrer Enden, sodass es bei jeder Stichprobengröße ohne Normalapproximation gilt. Ein Nenner, dessen Intervall null erreicht, ergibt kein Intervall. Ein Wert außerhalb seines Bereichs ist ein Konfigurationsfehler, der die Einheit nennt, und wird nie abgeschnitten. Das Intervall der Delta-Methode, meist enger, wird daneben gezeigt und entscheidet nie.
Eine Kovariate von vor dem Test
Ein Ergebnis, das etwas vor dem Test Gemessenem folgt (die Ausgaben des letzten Monats, die Sitzungen der letzten Woche), schwankt weniger, wenn man das herausnimmt. Bringen Sie den Wert jeder Einheit von vor dem Test und einen Koeffizienten mit, der festgelegt wurde, bevor die Ergebnisse dieses Tests gelesen werden:
covariate: {values: logs/pre_period.csv, range: [0, 500], theta_from: logs/history.csv}Das entschiedene Ergebnis ist Y - theta (X - c). theta wird deklariert (theta:, mit einem optionalen center:, standardmäßig die Mitte des Bereichs) oder auf einer Verlaufsdatei aus einem Zeitraum vor dem Test angepasst (Spalten covariate und outcome), nie auf den eigenen Ergebnissen dieses Tests. Weil X vor der Zuteilung gemessen wurde und auch vor der Zuteilung feststand, welche Einheiten ein X haben, hat die bereinigte Differenz denselben Schätzgegenstand. Eine Einheit ohne Wert in der Datei wird nicht bereinigt. Eine gültige Bereinigung kann trotzdem breiter sein als keine, weil der Bereich des bereinigten Ergebnisses breiter ist; der Bericht zeigt daher beide Intervalle und sagt, welches enger ist; er beansprucht keine Ersparnis.
Neuheit und Interferenz, gezeigt
novelty: {exposure_column: exposed_at, time_column: at, days: 7} liest die erste Exposition jeder Einheit aus dem Zuteilungsprotokoll und die Zeit jeder Ergebniszeile und zeigt die Differenz in den ersten days der Exposition und danach. Eine entschiedene frühe Differenz mit einer unentschiedenen oder entgegengesetzten späteren wird als "möglicherweise ein Neuheitseffekt" benannt. Die Aufteilung entscheidet nie eine Regel: Einheiten ohne Zeilen in einem Band werden darin weggelassen, nicht im ungünstigsten Fall beschränkt. Sie nimmt ein Ergebnis pro Zeile, kein Verhältnis und keine Kovariate.
cluster_column: team zählt die Teams, die Einheiten mehrerer Arme enthalten, und fragt, ob das Ergebnis einer Einheit vom Arm einer anderen abhängen kann. Wenn ja, randomisieren Sie nach dem Team und deklarieren Sie es als Einheit.
Mehrere Behandlungen, Verhältnisse und Kovariaten wurden am 3. November 2026 durch ein unabhängiges Audit und seine Bestätigung zugelassen, zu denselben Bedingungen wie zwei Arme.
Offline und online
Nennen Sie den Offline-Vergleich und seine Metrik (offline_comparison: <id>, offline_metric: pass_rate), und die Antwort meldet, ob die beiden entschiedenen Richtungen übereinstimmen. Das wird berichtet und entscheidet nie etwas: Eine Abweichung ist ein Grund, sich die Suite anzusehen, kein Urteil über das Release.
Fallstricke
- Zwischendurch nachsehen. Einen Test mit festem Horizont täglich zu lesen und an einem guten Tag aufzuhören, bläht falsche Gewinne auf. Planen Sie die Stichprobengröße oder deklarieren Sie monitoring: anytime.
- Neuheit und Lernen. Nutzer reagieren auf alles Neue und beruhigen sich dann. Ein Gewinn in der ersten Woche kann verblassen; lassen Sie lange genug laufen, um die Zyklen Ihrer Nutzer abzudecken, und deklarieren Sie novelty:, um die Aufteilung zu sehen.
- Interferenz. Das Intervall setzt voraus, dass das Ergebnis einer Einheit nicht vom Arm einer anderen abhängt. Gemeinsamer Bestand, Marktplätze, soziale Funktionen oder ein von einem Arm aufgewärmter Cache brechen das; randomisieren Sie dann nach einer größeren Einheit (einer Region, einem Team), und deklarieren Sie cluster_column:, um zu sehen, wie gemischt die Cluster sind.
- Drift bei wechselnder Aufteilung. Das Intervall setzt voraus, dass die Aufteilung während des Tests konstant blieb oder dass die Ergebnisse nicht drifteten, während sie sich änderte. Ein Hochfahren von 10 % auf 50 %, oder 90/10 und dann 10/90 über einen Werktag und ein Wochenende, gewichtet die Zeiträume in jedem Arm anders und mischt einen Zeiteffekt in die Differenz; die Prüfung des Stichprobenverhältnisses liest zusammengefasste Zahlen und sieht das nicht. Halten Sie die Aufteilung fest, oder entscheiden Sie nur über den Zeitraum nach dem Hochfahren.
- Die Einheit wechseln. Randomisieren und analysieren Sie nach derselben Einheit. Nutzer zu randomisieren und Sitzungen als unabhängig zu zählen, verengt das Intervall fälschlich.
Was Ihnen das nicht sagen kann
- Ob das Ergebnis für Nutzer außerhalb des Zeitfensters, der Region oder des Traffics des Tests gilt.
- Irgendetwas über eine Metrik, die Sie nicht vor dem Test deklariert haben; eine nachträglich gewählte Metrik ist eine Beschreibung.
- Ob Ihr Router wirklich randomisiert hat: Die Prüfung des Stichprobenverhältnisses fängt große Fehler, keine subtilen.
- Welche Behandlung unter denen, die nicht bestanden haben, die beste ist: Nur bestehende Behandlungen werden geordnet. Geschichtete Zuteilung und Switchback-Designs sind nicht gebaut.