Testing whether LLMs can sample from probability distributions or just pick the most likely option. 5.6M API calls across 4 OpenAI models. Spoiler: they can't.
When you tell an LLM "pick a state with 20% probability," does it actually produce that state ~20% of the time across many calls? Or does it just pick the most likely option every time?
This matters for any application using LLMs for decision-making, game AI, simulation, or agentic workflows where stochastic behavior is expected. We tested this with two experiments across four OpenAI models, making 5.6 million API calls total.
Each model is given a probability distribution over 10 states and asked to "pick one" per call. No code execution, no random library — just the model's own sense of probability. 1,000,000 independent calls per model, temperature=1.0.
graph LR
subgraph dist [Each call: pick one state according to these probabilities]
S1["S1\n3%"]
S2["S2\n5%"]
S3["S3\n8.5%"]
S4["S4\n11.5%"]
S5["S5\n15%"]
S6["S6\n20%"]
S7["S7\n15%"]
S8["S8\n10%"]
S9["S9\n7%"]
S10["S10\n5%"]
end
The percentage shows how often each model picked State 6 (the 20% mode) out of 1,000,000 calls:
| State | Expected | GPT-5.4-mini | GPT-5.4 | GPT-5-mini | GPT-4.1 |
|---|
random.choices() deviates by <0.07% across all runs. The baseline is trustworthy.Can the models follow conditional probability distributions across a 3-layer hierarchical state machine? Each iteration traces a path from root to leaf. Two modes: Chained (3 API calls, one per layer) and Single-shot (1 call, full tree shown). 100,000 paths per model per mode.
graph TD
Root((" "))
Root -->|"15%"| S1["S1 Input"]
Root -->|"30%"| S2["S2 Compute"]
Root -->|"25%"| S3["S3 Validate"]
Root -->|"20%"| S4["S4 Optimize"]
Root -->|"10%"| S5["S5 Output"]
S1 -->|"40%"| S11["S1.1 Tokenize"]
S1 -->|"35%"| S12["S1.2 Parse"]
S1 -->|"25%"| S13["S1.3 Normalize"]
S2 -->|"20%"| S21["S2.1 Arithmetic"]
S2 -->|"30%"| S22["S2.2 Logic"]
S2 -->|"35%"| S23["S2.3 Pattern Match"]
S2 -->|"15%"| S24["S2.4 Heuristic"]
S3 -->|"45%"| S31["S3.1 Type Check"]
S3 -->|"30%"| S32["S3.2 Bounds Check"]
S3 -->|"25%"| S33["S3.3 Constraints"]
S4 -->|"45%"| S41["S4.1 Cache"]
S4 -->|"25%"| S42["S4.2 Recompute"]
S4 -->|"18%"| S43["S4.3 Prune"]
S4 -->|"12%"| S44["S4.4 Parallelize"]
S5 -->|"55%"| S51["S5.1 Format"]
S5 -->|"45%"| S52["S5.2 Serialize"]
S11 -->|"..."| L3a["Layer 3\n2-4 leaves each"]
S23 -->|"..."| L3b["Layer 3\n2-4 leaves each"]
S41 -->|"..."| L3c["Layer 3\n2-4 leaves each"]
| Model | Expected Argmax | Chained Favorite | Chained % | Single Favorite | Single % |
|---|
Based on 5.6M API calls across both experiments:
| Model | Behavior | Description |
|---|---|---|
| GPT-5.4 | Approximate distributer | Distributes across all states with heavy mode bias. Best probabilistic intuition of any model tested. Chi-squared 4.5x lower than others. |
| GPT-5.4-mini | Non-argmax collapser | Collapses to a single state, but NOT always the highest-probability one. Bias is label and prompt-structure dependent. |
| GPT-4.1 | Strict argmax | Reliably picks the highest-probability option. 100% deterministic in flat distributions. Predictable but useless as a sampler. |
| GPT-5-mini | Strict argmax / variable | Argmax in chained mode, but single-shot shows unexpected variety. Reasoning tokens may give more deliberation. |