libincao
← ARTICLES
2026.09.22 · 8 MIN · 中文 · AI

用 Jev 打德州扑克

Jev 一个字都不生成。不能聊天,不能写代码,只返回带类型的判断和一个校准过的概率。我把一个真实牌局的翻牌圈喂给它,只问一个决策点:第一遍它建议跟注,自己只有 32% 的把握;我往局面描述里补了一句话,它翻转成弃牌,把握涨到 63%,而弃牌才是数学上正确的答案。那句话是「我手里没有方块」。这篇讲的是它为什么推不出来,以及为什么这比结论更值得记。

一个没有嘴的人物侧影,嘴的位置是一只只有指针的仪表盘,面前的桌上立着三张背面朝上的牌

Jev 是什么

2026 年 9 月 15 日,一家叫 TypeSafe AI 的公司放出了第一个模型 Jev。创始人 Diogo Almeida 是前 OpenAI 研究员,RLHF 的共同发明人之一,也就是 ChatGPT 背后那套方法的作者之一。

他们给 Jev 的定位叫 System One Model,对应卡尼曼那套「系统一是快速直觉判断,系统二是慢速推理」。

它和你熟悉的所有大模型有一个根本区别:

它完全不生成文字。

不能聊天,不能写代码,一个字都吐不出来。你给它一段材料和一组带类型的问题,它返回带类型的答案:一个选择、一个分数、一个概率,每个都附带置信度。

和大模型的四个差别

一、架构上不解码。 大模型是逐个 token 往外吐,结构化输出是把吐出来的字符串再解析成 JSON。Jev 没有语言模型头,直接用决策头输出概率分布,中间没有「先写一段话再转结构」这一步。

二、答案空间由你定义。 你给它三个选项,它只能在这三个里选。「输出了一个不存在的分类」在架构层面就不可能发生,这不是靠提示词约束,是靠结构。

三、概率是校准过的。 这是最值钱的一条,也是它整个训练方法的目标。TypeSafe 管这套训练叫 RLCD(Reinforcement Learning for Calibrated Decisions):不用人类偏好打分,而是用可验证的真实答案配上严格评分规则来算奖励。目标不是「让人觉得好」,而是「说 70% 的时候,真的就该有 70% 会中」。

四、便宜和快。 输入 $0.042 / 百万 token,输出免费,因为它根本不产出 token。延迟在几十到几百毫秒量级。

为什么「校准」是重点

我在本地做过一个对照。用 Ollama 跑本地模型,把候选映射成字母,直接读 token 的 logprob 再归一化,这样拿到的是模型真实的输出分布,不是问它「你有多确信」。

然后问它一个原理上不可知的问题:

一枚硬币已经抛出但尚未揭晓,是正面吗?

本地模型给的是 99.9%。温度调到 0、1、2 都一样,因为那是未经温度缩放的原始分布。

同样的问题给 Jev:51%。

差别不在于谁更聪明。本地那个模型当然知道硬币是五五开,你在聊天里问它,它会告诉你 50%。缺的不是知识,是那个数字没承载知识。 被迫选一个 token 的时候,它就是会给 99.9%。

RLCD 教的不是「硬币是公平的」,是让那个数字有意义。

注册

好消息:TypeSafe 在 9 月 21 日取消了等待名单,现在 console.typesafe.ai 直接注册就能用,新账号送 $5 额度,按 $0.042 / 百万 token 算大约一亿两千万 token。玩起来基本等于无限。

注意是 console 子域名,主站 typesafe.ai 是产品页。API Key、Playground、用量面板都在 console 里。

Playground 长这样:左边上方填 State,左边下方写 Questions(JSON),右边出结果。

把一手牌翻译成 State 和 Questions

拿来做实验的是一场直播现金局里的一手牌。说清楚范围:我没有让它打完一局,只截取了翻牌圈上的一个决策点,问它此刻该弃该跟还是该加。

牌局画面:公共牌 Q♦ 10♣ J♦,底池 44K,PAMPAGE 大盲位 A♣7♣ 过牌,HANDZ 枪口位 QQ 过牌,PAV 按钮位 K8 下注 15K
翻牌 Q♦ 10♣ J♦。我要站在 PAMPAGE 的位置上做决策

翻牌 Q♦ 10♣ J♦,底池 29,000。三个人:PAMPAGE 在大盲位拿 A♣7♣,HANDZ 在枪口位拿 QQ,PAV 在按钮位拿 K8。

我要做的是:站在 PAMPAGE 的位置上,让 Jev 给一个决策。

第一个设计决定:不能给它上帝视角

直播画面是上帝视角:三家的底牌全亮着,HANDZ 的 QQ、PAV 的 K8 都一目了然。这些绝对不能进 State。

因为 PAMPAGE 坐在桌上时看不见对手的牌。放进去会得到一个「正确但毫无用处」的建议,它在用上帝视角做决策,而真实场景里你没有那份信息。

这是设计这类系统最容易犯的错:State 里只能有决策者当下真的能观察到的东西。

第二个设计决定:能算的别问

跟注赔率是确定的算术:

下注前底池 29,000 + 按钮下注 15,000 + 我跟注 15,000 = 59,000
15,000 ÷ 59,000 = 25.4%

意思是我至少要有 25.4% 的胜率,这一跟才不亏。这个数我用计算器算好写进 State,不问模型。 模型该做的是判断,不是计算。

最终的 State

Six-handed cash game. Blinds are 500/1000 with a 2000 ante from every player.

I am in the big blind holding A♣ 7♣ (the ace and seven of clubs).
The flop is Q♦ 10♣ J♦ (queen of diamonds, ten of clubs, jack of diamonds).

Preflop: the UTG player raised to 5,500, the button called, I called from the
big blind, and the small blind folded. Three players saw the flop and the pot
was 29,000.

Flop action so far: I checked, the UTG player checked, and the button bet
15,000.

It is now my turn. Calling costs 15,000. If I call, the pot will be 59,000,
so I am getting 25.4% pot odds.

The UTG player still acts after me, so calling does not close the action and
I could still face a raise.

Stacks: me 1,100,000, the UTG player 843,000, the button 940,000.

I have no diamonds in my hand, so I have no flush draw. My only draw is a
gutshot to Broadway, needing a king.

最后那两句是这次实验的关键,后面说。

Questions:三种类型,分四层

Jev 有三种问题类型:

类型答案空间返回
Noul固定:真 / 假一个概率
Choice你定义的选项每个选项一个概率 + 总置信度
Score你定义的等级一个数值(可小数)+ 置信度

criteria 就是你定义答案空间的地方。Choice 用对象,键是选项;Score 用数组,下标就是分数。Noul 没有 criteria,因为答案空间天然固定,没什么可定的。

我把六个问题拆成四层:

我的牌力 currently_best_hand made_hand_strength draw_quality 答案我已知 用来验证 对手 opponent_range_is_strong 位置风险 utg_likely_to_raise 决策 action Fold / Call / Raise 拆开之后,模型在哪一环出错是看得见的
六个问题分四层,最后一层才是要的那个答案
{
  "currently_best_hand": {
    "type": "noul",
    "instructions": "Right now on this flop, is my hand most likely the best hand among the players still in the pot?"
  },
  "made_hand_strength": {
    "type": "score",
    "instructions": "How strong is my made hand right now, ignoring any drawing potential?",
    "criteria": [
      "No pair and no showdown value at all",
      "High card only, or bottom pair",
      "Middle pair, or a weak top pair",
      "Strong top pair",
      "Two pair or better"
    ]
  },
  "draw_quality": {
    "type": "score",
    "instructions": "How good is my potential to improve to a winning hand on the turn or river?",
    "criteria": [
      "No draw at all",
      "Gutshot straight draw only, roughly four outs",
      "Open-ended straight draw, or a flush draw",
      "Strong combination draw with many outs",
      "Drawing to the effective nuts with a very large number of outs"
    ]
  },
  "opponent_range_is_strong": {
    "type": "noul",
    "instructions": "Given the preflop action and this flop, does the betting player's range look strong here?"
  },
  "utg_likely_to_raise": {
    "type": "noul",
    "instructions": "If I call the 15,000, is the UTG player behind me likely to raise?"
  },
  "action": {
    "type": "choice",
    "instructions": "Facing a 15,000 bet with one player still to act behind me, what should I do?",
    "criteria": { "Fold": null, "Call 15,000": null, "Raise": null }
  }
}

为什么不直接问一句「我该怎么打」?

因为那样你只得到一个答案和一个置信度,模型在哪一步出的错你完全不知道。拆开之后,每一环都能单独验证,而这正是后面救了我的东西。

前两条尤其重要:它们的正确答案我已经知道,所以可以用来检验模型到底读懂牌面没有。先用已知答案的问题做验证,再去信那些你不知道答案的问题。

Jev 的回答

Jev Playground 界面:左侧是 State 和 Questions,右侧六条回答,分别是 17%、1.04/4、1.08/4、65%、30%,以及 Fold 75% / Call 22% / Raise 3%
六个判断一起返回,State 编码 79 毫秒,推理 385 毫秒
问题回答置信度
我现在是最大的吗17% 为真—
成牌强度1.04 / 469%
听牌质量1.08 / 493%
对手范围强吗65% 为真—
身后会被加注吗30% 为真—
我该怎么打弃牌 75% / 跟注 22% / 加注 3%63%

逐条解读

我现在是最大的吗 → 17%。只有 A 高牌,没成对。牌面 Q-J-10,对手手里只要有 Q、J、10 中任意一张就成对了。要赢必须两家同时落空、高牌还都比我小。17% 甚至偏乐观。

成牌强度 → 1.04 / 4。落在第 1 档「只有高牌」。没落到第 0 档(毫无摊牌价值),是因为 A 高终究还能赢下对方的 K 高、Q 高。返回 1.04 而不是整数,是因为它给的是整个分布的期望值。

听牌质量 → 1.08 / 4,置信度 93%。落在第 1 档「只有卡顺,约四张出牌」,完全正确。我的 A 配上牌面的 Q-J-10,只差一张 K 就成 A-K-Q-J-10,全副牌四张 K。牌面那两张方块在公共牌上不在我手里,所以没有同花听牌。93% 是全屏最高的置信度。这一条是整篇文章的转折点。

对手范围强吗 → 65%。按钮位在两家都过牌之后才下注。要么真有牌,要么看两家示弱来偷池。65% 偏向「真有牌」,留三成多给诈唬,分配合理。

身后会被加注吗 → 30%。UTG 翻牌前加注、翻牌后却过牌了,过牌这个动作通常削弱范围。但过牌加注是真实存在的打法,所以不能给 0。

这里有个值得玩味的地方:实际上 HANDZ 手里是 QQ,在这个牌面上是三条,他大概率真的会加注。 但 Jev 不该知道,PAMPAGE 在桌上看不见。从那个座位上能拿到的信息看,30% 就是诚实的答案。这正是一开始坚持不泄露底牌的意义。

我该怎么打 → 弃牌 75% / 跟注 22% / 加注 3%,置信度 63%。弃牌为什么对:

需要的胜率        25.4%
卡顺,下一张牌     4 ÷ 47 = 8.5%
就算能看两张牌     ≈ 16.5%

而且 UTG 在我后面,这 15,000 买不断两张牌,连 16.5% 都拿不到。

跟注那 22% 不是噪声,它对应隐含赔率:万一真来了 K,对手会付我一个大底池。Jev 认可这个理由存在,只是判断它不够补上缺口。

加注 3%:对着一个 65% 偏强的范围诈唬,身后还有人可能反加,几乎永远是错的。约等于零,判断准确。

一个结构上的细节

你会注意到 Noul 那三条没有单独的置信度,而 Choice 和 Score 有。

因为对判断题来说,概率本身就是答案,「17% 为真」已经把不确定性说完了。而 Choice 和 Score 的答案是「选了哪个」「落在哪档」,这个选择本身有多可靠是另一个问题,所以需要额外一个数。

真正的发现

前面跳过的那件事:第一次跑的时候,State 里没有最后那两句。

STATE 少一句 STATE 补上「我手里没有方块」 听牌质量 2.38 / 4 置信度 39% 全屏最低 被当成有同花听牌 听牌质量 1.08 / 4 置信度 93% 全屏最高 只有卡顺,正确 最终建议 跟注 54% 置信度 32% 最终建议 弃牌 75% 置信度 63% 上游一句话,下游整个翻转 置信度最低的那一环,正是坏掉的那一环
State 里补一句话,下游整条链跟着翻转

它把牌面上的两张方块当成了我的同花听牌。

这个推理对人来说是零成本的:我拿 A♣7♣,牌面 Q♦J♦,一眼就知道我没方块。但它做不了这个减法。补上一句「我手里没有方块」,听牌评估立刻落到正确档位,置信度从全屏最低变成全屏最高,最终建议也跟着翻转了。

于是这次实验真正回答的不是「这手牌该怎么打」,而是:模型能不能自己推出归属关系。

答案是不能。所以:

凡是「X 属于 A 不属于 B」这类归属关系,必须显式写进 State,不要指望模型自己推。

三条可复用的东西

一、错误传播链是可见的。 它之前建议跟注,唯一原因就是高估了听牌。上游一修正,下游立刻反转。如果我只问一句「我该怎么打」,我看不到这条链,只会觉得模型反复无常。

二、置信度精确地指向了 bug 的位置。 第一次跑的时候 39% 是全屏最低,那正是坏掉的那一环。按置信度升序排,修最低的那个,重跑。 这是一套可以直接拿去用的排查流程,不需要懂扑克。

三、置信度是诚实的。 它错的时候说自己没把握,对的时候说自己有把握,两次都说对了。这就是校准的全部意义,也是本地那个玩具永远做不到的事,它在两种情况下都会给你 100%。

最后

Jev 不是扑克求解器,别指望它替代 solver。GTO solver 给的是数学上可证的最优解,Jev 给的是判断,这是两件事。

它也不是「最终答案」,而是一个部件。这个局面真正的结论来自三样东西的汇合:确定的算术(需要 25.4%,实际 8.5%)、模型的判断(弃牌 75%)、位置的事实(跟注不能封顶)。三条指向同一个方向,才是该行动的时候。

反过来说:如果模型说跟注而算术说亏,听算术的。算术是确定的,模型是判断,这个优先级不能反。

还有一句和牌桌无关的:我们不知道这手牌实际怎么走的,截图只到翻牌。但即使跟注之后真的来了一张 K、赢下一个大池,弃牌仍然是当时正确的决策。8.5% 的事情会发生,发生了也不代表当初该跟。

结果好,不等于决策对。