把决策压进50ms:棋牌AI推理优化的工程实录
决策P95<50ms是棋牌AI进生产池的硬门槛,但它不是模型问题,而是预算分配问题:把50ms拆成网络、排队、特征、推理、后处理五段,每段有数字上限,超预算就动对应的技术杠杆。本文实录量化、批处理、缓存、特征预计算四板斧的取舍,并解释表演延迟think_ms为什么必须与计算延迟分离。
决策P95<50ms是棋牌AI进生产池的硬门槛,但它不是模型问题,而是预算分配问题:把50ms拆成网络、排队、特征、推理、后处理五段,每段有数字上限,超预算就动对应的技术杠杆。本文实录量化、批处理、缓存、特征预计算四板斧的取舍,并解释表演延迟think_ms为什么必须与计算延迟分离。
推理优化的第一步不是换模型,而是把端到端延迟拆成有数字的预算表:哪一段占多少毫秒、目标是多少、超了动哪根杠杆。没有这张表的团队,优化动作全凭直觉,最常见的结局是把模型量化折腾了三天,最后发现网络和排队占了六成延迟。
// 决策延迟预算表:每段有上限,超标即告警
{
"total_budget_ms": 50,
"network_rtt": 8, // 客户端到接入层
"auth_and_queue": 4, // 鉴权与排队
"feature_lookup": 6, // 特征读取(预计算后)
"model_infer": 22, // 模型推理
"postprocess": 5, // 合法性校验与行为层包装
"reserve": 5 // 长尾缓冲
}量化是性价比最高的第一刀:把FP32模型压到INT8,推理耗时普遍降到一半以下,而牌力损失在棋牌场景可测且可控——棋牌决策对数值精度的敏感度远低于视觉任务,灰度对局里的胜率波动通常在一两个百分点内。顺序应该是先量化再看别的:它便宜、见效快、风险可灰度。
批处理提升吞吐但不必然降低延迟,关键在凑批窗口:把等待凑批的时间上限设在5ms以内,配合按玩法的请求粘性,万级房间并发的吞吐可以翻倍而P95几乎不动。窗口一旦放宽,省下的GPU时间会以玩家可感的延迟还回去——批处理是把双刃剑,窗口就是刀刃。
缓存的对象是“不变的答案”:同一局面加同一画像状态的特征向量、牌型合法性判定、常见残局的打法模板,命中直接返回。局面缓存的命中率在麻将类玩法可达六成以上,因为大量决策面对的是低信息量的平凡局面——这类局面真人也是不过脑子的。
特征预计算把延迟从决策时转移到事件时:对手画像、已出牌统计、危险牌热度这些特征,在每次出牌事件落库时增量更新,决策时只做一次内存读取。预计算之后特征读取段从几十毫秒级压到个位数毫秒,是四板斧里单笔收益最大、也最容易被忽略的一项——因为它改的是数据流,不是模型。
超过2秒不出牌,玩家就会开始怀疑对面不是人:行业普遍实测口径下,真人跟牌多在1秒内完成,2秒以上的停顿已经是明确的长考,频繁出现的长考构成“机器人在转圈”的直觉证据。这也是决策必须压进50ms的产品理由——计算快,才配得上表演慢。
工程上的正确姿势是把计算延迟与表演延迟分离:模型在50ms内给出决策,think_ms字段按拟人化节奏模型下发表演时长,客户端按think_ms做思考动画。我们API的决策返回里latency_ms与think_ms并排出现,就是这对分离的接口化——快是底层的事,慢是表现层的设计。
延迟优化的验收口径只有P95:平均值永远漂亮,长尾才是玩家可感的地方。按玩法、按时段、按房间规模分别拉P95,任何一段预算连续超标就告警到人。延迟是会回胖的——每次模型迭代、每次特征加列都可能把某一段悄悄推过线,预算表必须跟着发布流程一起跑,而不是躺在文档里。
30 天全功能免费试用,5 分钟接入首个AI牌局。开通试用请添加商务微信 kxlin0101 或发送邮件至 skyin.lewis@gmail.com。