Tutorial · Build a GTO trainer教程 · 构建 GTO 陪练

Part 1: Your first strategy call第一篇:你的第一次策略调用

We'll build the core of a GTO poker trainer — the same kind that powers Counterplay. This part: make a real preflop strategy call, read mixed frequencies, and grade a decision.我们来搭一个 GTO 扑克陪练的核心——和驱动 过招 的是同一套。本篇:发一次真实的翻前策略调用、读混合频率、给决策评级。

1 · First call首次调用 2 · The range grid范围网格 3 · Postflop tree翻后决策树 4 · Turn/river solving转/河牌求解

What you'll need准备什么

A free API key (grab one here) and curl or Python 3. Set your key as an env var:一个免费 API Key(在这里拿)以及 curl 或 Python 3。把 Key 设成环境变量:

export POKERAI_API_KEY="gto_your_key_here"

Step 1 · Your first call第一次调用

Ask for the GTO strategy when Hero holds A♥K♥ in MP and UTG has raised:问一下:Hero 在 MP 持 A♥K♥、UTG 已加注时的 GTO 策略:

curl https://pokerai.bet/v1/gto/preflop \
  -H "authorization: Bearer $POKERAI_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "hole_cards": "AhKh",
    "positions": { "hero": "MP" },
    "preflop_actions": [
      { "position": "SB", "action": "small blind", "amount": 0.5 },
      { "position": "BB", "action": "big blind", "amount": 1 },
      { "position": "UTG", "action": "raise", "amount": 3 }
    ]
  }'

Response:返回:

{
  "hole_cards": "AhKh",
  "situation": "Raise",
  "strategy": [
    { "action": "raise", "frequency": 1, "amount_bb": 9, "sizing_pot": 0.8 }
  ]
}

AKs facing a UTG open is a pure 3-bet: raise 100% of the time, to 9bb. situation is derived from the actions you sent (here, facing one raise = "Raise").AKs 面对 UTG 开局是纯 3bet:100% 加注,到 9bb。situation 由你发的动作推导(这里面对一个加注 = "Raise")。

Step 2 · Read the frequencies读懂频率

The key idea: the API returns a mixed strategy — the GTO frequency of each action — not a single "recommended" move. Most hands are pure (one action at 100%), but many are mixed. For example, UTG opening A2s:核心思想:API 返回的是混合策略——每个动作的 GTO frequency——不是单一「推荐动作」。多数手牌是纯策略(某动作 100%),但很多是混合。比如 UTG 开局 A2s:

{ "action": "raise", "frequency": 0.296 }   # raise 29.6% of the time
{ "action": "fold",  "frequency": 0.704 }   # fold 70.4% of the time
Both raising and folding A2s here are GTO-correct. A player who always folds it, or always raises it, isn't "wrong" on any single hand — but over many hands they deviate from the equilibrium mix. That's exactly what a trainer measures.这里加注和弃牌 A2s 都是 GTO 正确的。总是弃、或总是加,单手不算「错」——但长期偏离了均衡混合。陪练要衡量的正是这个。

Step 3 · In code写进代码

A tiny typed client — the same shape Counterplay uses (app/gto/client.py):一个极小的类型化客户端——和过招用的同构(app/gto/client.py):

import os, httpx

class Pokerai:
    def __init__(self):
        self.h = {"Authorization": f"Bearer {os.environ['POKERAI_API_KEY']}"}
        self.c = httpx.Client(base_url="https://pokerai.bet", timeout=15)

    def preflop(self, hole_cards, hero, actions):
        r = self.c.post("/v1/gto/preflop", headers=self.h, json={
            "hole_cards": hole_cards,
            "positions": {"hero": hero},
            "preflop_actions": actions,
        })
        r.raise_for_status()
        return {s["action"]: s["frequency"] for s in r.json()["strategy"]}

gto = Pokerai()
strat = gto.preflop("AhKh", "MP", [{"position":"UTG","action":"raise","amount":3}])
print(strat)   # {'raise': 1.0}

Step 4 · Grade a decision给决策评级

This is the trainer's heart. Grade Hero's action by the GTO frequency of the action they chose — not by how far it is from the most-frequent action. A 14%-frequency raise is a fine mixed play, not a mistake:这是陪练的核心。按「Hero 所选动作的 GTO 频率」给他评级——不是按离最高频动作有多远。14% 频率的加注是合理的混合打法,不是错误:

def grade(chosen_action, strategy):
        freq = strategy.get(chosen_action, 0.0)
        if freq >= 0.10: return "ok"        # a real part of the GTO mix
        if freq >= 0.005: return "minor"    # rare, but not a blunder
        return "major"                       # ~never played → a real leak

grade("raise", {"raise": 0.296, "fold": 0.704})   # "ok"  (A2s raise)
grade("raise", {"fold": 1.0})                     # "major" (raising 32o UTG)
This is exactly how Counterplay grades — severity comes from the chosen action's own frequency, so low-frequency mixed actions aren't punished. (See the case study.)这正是过招的评级方式——严重度来自所选动作自身的频率,低频混合动作不被误判。(见案例研究。)

What you built你搭好了什么

A working strategy layer: fetch GTO frequencies for any preflop spot, and grade a player's decision against the equilibrium. That loop — spot → strategy → grade — is the whole trainer, one street at a time.一个能用的策略层:对任意翻前局面取 GTO 频率,并对照均衡给玩家决策评级。这个循环——局面 → 策略 → 评级——就是整个陪练,一街一街来。

Next — Part 2: the 13×13 range grid下一篇 · 第二篇:13×13 范围网格

Fetch a whole range in one call and render it, like the range pages. Coming soon.一次调用取整段范围并渲染,像范围页那样。即将上线。