Skip to content
[OPEN_POKER]

Fortgeschrittene Poker-Bot-Architektur: Equity und Tests

JJoão Carvalho||10 min read

Ein fortgeschrittener Poker-Bot macht aus einer zuverlässigen Ereignisschleife ein messbares Entscheidungssystem. Der nächste Schritt heißt nicht einfach „KI hinzufügen“. Er besteht aus unveränderlichen Entscheidungs-Snapshots, expliziten Pokermerkmalen, Range-basierter Equity, wiederholbaren Händen und einem Experimentzyklus, der eine Policy-Änderung nachweisen kann. Behalte den Schutz für gültige Aktionen aus dem grundlegenden Bot bei. Alles Intelligentere liegt dahinter.

Serie zur Poker-Bot-Architektur: Teil 2 von 3. Beginne mit Grundlegende Poker-Bot-Architektur, falls deine Laufzeitumgebung noch Aktionen ablehnt. Lies danach Professionelle Poker-Bot-Architektur. Vergleiche Betriebsoptionen in Kosten eines Poker-Bots 2026.

Was ändert sich bei einer fortgeschrittenen Poker-Bot-Architektur?

Ein fortgeschrittener Poker-Bot trennt Fakten, Schätzungen, Policy und Ausführung. Fakten stammen aus dem neuesten Zug des Servers: Pot, Board, Stacks, gültige Aktionen, Hand-ID und Token. Zu den Schätzungen gehören Equity und gegnerische Range. Die Policy verwendet beides, um eine Absicht zurückzugeben. Die Ausführung prüft diese Absicht ein letztes Mal gegen die Fakten.

Diese Unterscheidung ist wichtig, weil Schätzungen falsch sein dürfen. Ein Gegnermodell kann eine zu enge Range annehmen. Ein Monte-Carlo-Lauf kann Stichprobenfehler enthalten. Keiner dieser Fehler darf einen ungültigen Raise oder eine Antwort auf einen abgelaufenen Zug erzeugen. Die äußere Hülle bleibt deterministisch, auch wenn die innere Policy probabilistisch wird.

DatenklasseBeispielVerlässlichkeitZuständig
Serverfaktpot = 180, Raise-Maximum 1,640MaßgeblichProtokolladapter
Abgeleiteter FaktPot Odds, effektiver Stack, PositionExakt, wenn die Eingaben stimmenFeature-Schicht
Schätzung43 % Showdown-EquityAus Stichprobe oder ModellEquity-Service
AnnahmeGegner eröffnet am Button 31 %UnsicherGegnermodell
AbsichtCall, weil Equity den Preis übertrifftAusgabe der PolicyStrategie

Fasse diese Daten niemals in einem untypisierten Dictionary zusammen. Sobald Verlässlichkeit und Zuständigkeit verschwinden, wirkt eine geschätzte Range genauso vertrauenswürdig wie die Raise-Grenze des Servers.

Wie sollten unveränderliche Entscheidungs-Snapshots funktionieren?

Ein unveränderlicher Entscheidungs-Snapshot ist eine vollständige, schreibgeschützte Eingabe, die aus einem einzelnen your_turn erfasst wird. Er verhindert, dass verspätete Netzwerkereignisse Daten verändern, während Equity- oder Modellberechnungen laufen. Außerdem wird er zur Einheit, die du in Tests wiederholst.

from dataclasses import dataclass
from typing import Literal
 
Action = Literal["fold", "check", "call", "raise", "all_in"]
 
 
@dataclass(frozen=True)
class DecisionSnapshot:
    hand_id: str
    turn_token: str
    street: str
    hole: tuple[str, str]
    board: tuple[str, ...]
    pot: float
    stack: float
    to_call: float
    opponents: int
    position: str
    legal: tuple[Action, ...]
    min_raise: float | None
    max_raise: float | None
 
    @property
    def pot_odds(self) -> float:
        return self.to_call / (self.pot + self.to_call) if self.to_call else 0.0
 
    @property
    def stack_to_pot(self) -> float:
        return self.stack / self.pot if self.pot else float("inf")

Erzeuge den Snapshot synchron, sobald der Zug eintrifft. Übergib ihn anschließend an einen asynchronen Entscheidungstask. Vergleiche vor dem Senden des Ergebnisses seine hand_id und sein turn_token erneut mit dem aktiven Zug. Open-Poker-Tokens werden nach einer Aktion verbraucht, und jedes neue your_turn macht das vorige ungültig. Veraltete Arbeit muss daher verworfen und darf nicht erneut versucht werden.

Die Referenz der Nachrichtentypen dokumentiert die Felder auf der Leitung. Dein Normalisierer sollte nach einem Reconnect auch table_state akzeptieren, weil dessen spielerspezifischer Abschnitt hero Hole Cards und aktuell gültige Aktionen enthält.

Wie werden Equity und Pot Odds zu einer Entscheidung?

Equity beschreibt, wie häufig eine Hand gegen eine angenommene Range beim Showdown den Pot erhält. Pot Odds beschreiben den Mindestanteil, ab dem sich ein Call rechnet. Ein Call hat positiven Chip-Erwartungswert, wenn die geschätzte Equity größer als call / (pot + call) ist, bevor zukünftige Einsätze, Range-Fehler und Turnierziele berücksichtigt werden.

Wenn der Pot 180 beträgt und ein Call 60 kostet, ergeben sich Pot Odds von 60 / 240 = 25%. Eine Equity-Schätzung von 38 % liegt 13 Prozentpunkte über dieser rohen Schwelle. Calle nicht jede Situation mit einem Vorteil von einem Prozentpunkt. Monte-Carlo-Varianz, eine ungenaue gegnerische Range und zukünftige Aktionen können einen knappen Vorteil auslöschen. Wir verwenden eine ausdrückliche Sicherheitsmarge und protokollieren sie.

from dataclasses import dataclass
 
 
@dataclass(frozen=True)
class EquityResult:
    equity: float
    trials: int
    range_name: str
 
 
def call_has_margin(snapshot: DecisionSnapshot, result: EquityResult,
                    margin: float = 0.03) -> bool:
    return (
        "call" in snapshot.legal
        and result.equity >= snapshot.pot_odds + margin
    )

Der Monte-Carlo-Equity-Rechner zeigt eine Python-Implementierung. Für gepflegte Auswertungsbausteine ist die Evaluator-Dokumentation von PokerKit ein besserer Ausgangspunkt, als während eines Strategieprojekts selbst einen Hand-Ranker zu schreiben.

Wie sollte ein Gegnermodell Unsicherheit abbilden?

Ein Gegnermodell sollte Zählwerte und geglättete Raten speichern, keine Etiketten wie „aggressiv“ oder „Fish“. Nützliche frühe Merkmale sind freiwillige Preflop-Beteiligung, Preflop-Raise-Rate, Three-Bet-Gelegenheiten und -Aktionen, Postflop-Aggression, Fold-to-Bet-Gelegenheiten und beobachtete Showdown-Hände. Jede Rate braucht ihren Nenner.

Ein Spieler, der in vier Gelegenheiten zweimal geraist hat, besitzt eine beobachtete Rate von 50 %, aber fast keine statistische Sicherheit. Bayessche Glättung verhindert, dass winzige Stichproben die Policy stark ausschlagen lassen. Mit einer Beta-Prior lässt sich eine Rate als (successes + alpha) / (opportunities + alpha + beta) schätzen. Eine neutrale Beta(2, 2)-Prior macht aus zwei Raises bei vier Gelegenheiten 4 / 8 = 50%, während null Raises bei einer Gelegenheit zu 2 / 5 = 40% werden und nicht zu einer vermeintlich sicheren Null.

Segmentiere Statistiken nach Situationen, die die Strategie verändern. Position und Street sind relevant. Eine tischweite „Aggressivität“ vermischt einen Open-Raise under the gun mit einem Check-Raise am River. Beginne mit wenigen Buckets, die sich mit Daten füllen lassen, nicht mit fünfzig dünn besetzten Zellen. Unser Leitfaden zur Gegnermodellierung behandelt Gewichtungsverfall, Showdown-Evidenz und Grenzen für Exploits ausführlicher.

Behalte eine Baseline-Policy, die Gegnermerkmale ignoriert. Ohne sie kannst du nicht feststellen, ob die Anpassung hilft oder der ganze Bot lediglich eine gute Woche hatte.

Was sollte die Schnittstelle der fortgeschrittenen Policy zurückgeben?

Die fortgeschrittene Policy sollte Aktionsabsicht, beabsichtigten Betrag, Begründungscodes, Feature-Werte und Modellmetadaten zurückgeben. Ein einfacher String wie "call" ist für Analysen zu klein. Ein frei formulierter Aufsatz ist für Code zu unstrukturiert. Verwende einen typisierten Datensatz.

from dataclasses import dataclass, field
 
 
@dataclass(frozen=True)
class DecisionIntent:
    action: Action
    amount: float | None
    reason_code: str
    confidence: float
    features: dict[str, float] = field(default_factory=dict)
    policy_version: str = "range-equity-v3"
 
 
def decide(snapshot: DecisionSnapshot, eq: EquityResult) -> DecisionIntent:
    features = {
        "equity": eq.equity,
        "pot_odds": snapshot.pot_odds,
        "spr": snapshot.stack_to_pot,
    }
    if snapshot.to_call == 0 and "check" in snapshot.legal:
        return DecisionIntent("check", None, "free_action", 1.0, features)
    if call_has_margin(snapshot, eq):
        confidence = min(1.0, (eq.equity - snapshot.pot_odds) * 4)
        return DecisionIntent("call", None, "equity_clears_price", confidence, features)
    return DecisionIntent("fold", None, "equity_below_price", 0.8, features)

Der Ausführungsschutz ist weiterhin für Begrenzung und Fallback zuständig. Wenn diese Policy einen Call vorschlägt, nachdem sich der aktive Zug geändert hat, verwirf ihn. Wenn sie einen Raise vorschlägt, der nicht in der Liste gültiger Aktionen steht, ersetze ihn durch Check oder Fold und erhöhe eine Metrik für Policy-Verstöße. Eine stille Korrektur verbirgt Fehler. Korrektur plus Telemetrie hält den Tisch sicher und macht den Fehler sichtbar.

Wie testen Hand-Replays den gesamten Entscheidungsweg?

Hand-Replays führen aufgezeichnete Serverereignisse durch denselben Normalisierer und dieselbe Policy wie im Live-Betrieb, ohne einen Socket zu öffnen. Sie finden Fehler, die isolierte Unit-Tests übersehen: Zustand, der zwischen Händen weiterlebt, eine aus einem leeren Sitz abgeleitete Position, ein doppeltes Ereignis oder ein null-Betrag, der in einer Berechnung landet.

Speichere eine JSON-Nachricht pro Zeile und erhalte die Reihenfolge des Eintreffens. Ein Replay-Runner kann die Datei laden und die echten Handler aufrufen. Ersetze Zufall durch einen festen Seed und externe Dienste durch aufgezeichnete Antworten. Die Ausgabe sollte eine Folge von Entscheidungsdatensätzen sein, die ein Test mit freigegebenem Verhalten vergleichen kann.

import json
import random
from pathlib import Path
 
 
def replay(path: str, engine) -> list[dict]:
    random.seed(20260812)
    decisions = []
    for line in Path(path).read_text(encoding="utf-8").splitlines():
        event = json.loads(line)
        result = engine.apply(event)
        if result is not None:
            decisions.append(result)
    return decisions
 
 
def test_replay_never_emits_illegal_action(engine):
    for item in replay("fixtures/three_hands.jsonl", engine):
        assert item["action"] in item["legal"]

Property-based Tests sind für Aktionsschutzmechanismen nützlich. Erzeuge zufällige Mengen gültiger Aktionen und Raise-Grenzen und stelle dann sicher, dass die Ausgabe immer angeboten wird und innerhalb der Grenzen liegt. Hypothesis wurde für diese Testform entwickelt. Du brauchst nicht für jede Pokermeinung Property-Tests, doch Protokollinvarianten verdienen sie.

Wie solltest du eine Strategieänderung bewerten?

Bewerte eine Strategieänderung mit gepaarten Policies, festen Versionsbezeichnungen, Betriebsmetriken und genügend Händen, um Unsicherheit sichtbar zu machen. Spiele nicht einfach eine neue Range aus und vergleiche die nächsten 200 Hände mit dem Ergebnis vom vergangenen Dienstag. Gegnerzusammensetzung, Positionen und Kartenvarianz haben sich verändert.

Erfasse mindestens diese Metriken:

MetrikWarum sie wichtig ist
Ungültige Aktionen pro 1.000 ZügeHartes Korrektheitskriterium
Entscheidungslatenz p50, p95, p99Erkennt Ausreißer, die Durchschnittswerte verbergen
Fallback-RateZeigt Instabilität der Policy oder ihrer Abhängigkeiten
bb/100 mit KonfidenzintervallNach Blinds normalisiertes Strategieergebnis
All-in-bereinigte SchätzungVerringert einen Teil der Showdown-Varianz
VPIP, PFR, Three-Bet-RateErklärt, wie sich das Verhalten geändert hat
Fold-Rate nach StreetFindet offensichtliche strategische Leaks

Verwende in einem Simulator nach Möglichkeit gemeinsame Zufallszahlen: Lasse Policy A und B gegen dieselben Kartenverteilungen und Gegneraktionen antreten. Live-Spiel kann die Umgebung nicht vollständig kontrollieren, daher solltest du die Tischzusammensetzung aufzeichnen und längere Zeitfenster vergleichen. Das OpenSpiel-Paper von Google DeepMind beschreibt ein Evaluations- und Forschungsframework für Spiele, darunter solche mit unvollständiger Information. Es ist lokal nützlich, während die Live-Arena von Open Poker Protokoll und Gegnervielfalt testet.

Eine Änderung wird nicht allein deshalb freigegeben, weil bb/100 positiv ist. Sie muss die Korrektheitsmetriken bei null halten, im Latenzbudget bleiben und ein vorab festgelegtes Ziel verbessern, ohne an anderer Stelle einen untragbaren Rückschritt zu verursachen.

Wo passt ein LLM auf der fortgeschrittenen Stufe hinein?

Ein LLM passt hinter dieselbe Policy-Schnittstelle wie ein selektiver Berater, nicht an die Stelle des Netzwerkclients oder der Gültigkeitsinstanz. Gib ihm einen kompakten Snapshot, exakte gültige Aktionen, berechnete Pot Odds, eine geschätzte Range und ein striktes JSON-Schema. Validiere seine Antwort und halte einen deterministischen Fallback bereit.

Leite offensichtliche Entscheidungen am Modell vorbei. Ein kostenloser Check, ein erzwungener Fold aus einer strikten Preflop-Tabelle oder eine bereits durch eine deterministische Value-Regel bestimmte Raise-Größe benötigt keinen Remote-Aufruf. Selektives Routing senkt Kosten und erleichtert die Latenzkontrolle. Der Leitfaden zu LLM-Poker-Bots zeigt das grundlegende Verbindungsmuster. Eine fortgeschrittene Laufzeitumgebung sollte zusätzlich Schemavalidierung, versionierte Prompts, Abbruch bei Fristüberschreitung und Replay-Fixtures bieten.

Wir betrachten natürlichsprachliche Begründungen skeptisch, wenn sie als Evaluationsevidenz dienen sollen. Ein Modell kann eine überzeugende Erklärung für eine schlechte Aktion liefern. Bewerte die Aktion anhand von Ergebnissen, kontrafaktischen Tests und stabilen Metriken. Behalte den Text zum Debuggen, vertraue aber den strukturierten Merkmalen und dem Experimentdatensatz.

FAQ

Was macht einen Poker-Bot fortgeschritten?

Ein fortgeschrittener Bot verwendet unveränderliche Zug-Snapshots, explizite abgeleitete Merkmale, Range-basierte Equity, Gegnerstatistiken, Replay-Tests und versionierte Experimente. Mehr Strategiecode allein macht die Architektur nicht fortgeschritten.

Wie viele Monte-Carlo-Versuche sollte ein Poker-Bot durchführen?

Beginne mit 2.000 bis 5.000 Versuchen pro Entscheidung und führe Benchmarks auf deiner Hardware durch. Verwende nur dann mehr, wenn die Schätzung Entscheidungen oft genug verändert, um die zusätzliche Latenz zu rechtfertigen. Protokolliere sowohl die Anzahl der Versuche als auch die Laufzeit.

Wie viele Daten brauche ich für die Gegnermodellierung?

Verwende Glättung ab der ersten Beobachtung, halte die Anpassung aber klein, bis jede Statistik einen aussagekräftigen Nenner besitzt. Es gibt keine magische Handzahl, weil Three-Bet-Gelegenheiten deutlich seltener auftreten als Gelegenheiten zur Preflop-Beteiligung.

Sollte ich für Winrate oder Chipgewinn optimieren?

Verwende Big Blinds pro 100 Hände für vergleichbare Strategieberichte und zusätzlich rohe Chips für die Auswirkung auf die Saison. Veröffentliche immer Unsicherheit und Betriebsmetriken. Eine Punktschätzung ohne Handzahl und Intervall vermittelt falsche Sicherheit.

Können Replay-Tests beweisen, dass eine Pokerstrategie gewinnt?

Nein. Replays beweisen deterministisches Verhalten und finden Regressionen in bekannten Situationen. Simulationen und Live-Experimente testen die Leistung gegen Verteilungen von Händen und Gegnern.

Wenn Policy-Versionen, Hand-Replays und Metriken jede Änderung nachvollziehbar machen, ist der Betrieb der nächste Engpass. Professionelle Poker-Bot-Architektur behandelt Resynchronisierung, Fristbudgets, Fehlerisolierung, Shadow-Evaluation und sichere Releases für einen Bot, der unbeaufsichtigt läuft.

Weiterlesen