跳到主要内容

思维的 p99:当模型决定你的请求耗时多久

· 阅读需 12 分钟
Tian Pan
Software Engineer

你拥有的每一份延迟优化手册(latency playbook)都是为那些单次请求工作量大致恒定的系统编写的。数据库查询耗时相对固定。图像缩放随像素数变化,而这是预先可知的。甚至经典的 LLM 补全也有可预测的成本范畴:输入多少 token,输出有限的 token。推理模型悄无声息地打破了这一假设。当模型在运行时自行决定思考多久——且它是基于问题难度来决定时——响应时间便不再是基础设施的属性,而变成了问题本身的属性。

后果首先体现在你的分位数指标上。在生产环境中运行推理模型的团队报告称,p99 延迟会激增到 p50 的三到五倍,这不是因为主机变慢或缓存失效,而是因为百分之一的请求恰好真的很难。你的自动扩缩容策略、超时策略和 SLO 仪表板都是针对一个“这种差异意味着系统出现故障”的世界而调整的。而现在,这却意味着系统正按设计运行——你用来管理尾部延迟的所有工具都指向了错误的原因。

延迟曾是基础设施的属性,现在则是模型的决策

在固定成本推理的时代,尾部延迟(tail latency)有基础设施层面的解释:排队、资源竞争、垃圾回收或坏的副本。Google SRE 的经典准则——最著名的莫过于《规模化下的尾部延迟》(Tail at Scale)系列研究——正是建立在这一前提之上的。请求本身是“无辜”的,是环境让它变慢了。因此,补救措施也是环境层面的:重试到另一个副本、隔离慢主机、优化调度器。

推理模型增加了第二个、也是更大的变量来源,它存在于请求内部。思维链(Chain-of-thought)的长度取决于输入,并且是增量决定的:模型不断输出思考 token,直到其内部的置信感提示停止。充满自我反思和不确定性标记的路径会持续进行;而简单的问题则会提早结束。关于高效推理的研究一致发现,这种动态退出行为会在单次请求的计算中产生沉重的右尾(heavy right tails)——极小部分的输入消耗了不成比例的 token 和墙钟时间(wall-clock time)。

令人不安的是,在运行请求之前,难度是不可观测的。你可以估算它——路由和难度分类器正是为此而存在的——但真相只有在模型思考时才会揭晓。这意味着你的延迟分布在任何实用意义上都不再是静态的。它会随着你的流量组合而漂移:一次吸引了更难问题的产品发布,一群粘贴了更长文档的新用户,或者一个开始触及边缘情况的 Agent 工作流。你的基础设施没有任何改变,但 p99 却翻了一倍。

还有一个值得一提的叠加效应:过度思考(overthinking)。高效推理的相关文献表明,模型经常在推理路径的早期就得出了正确答案,但随后仍继续生成验证步骤。因此,长尾不仅仅是“难题耗时更长”。其中一部分是模型在已经解决的问题上空耗 token——产生了纯粹的延迟和成本,却没有任何质量回报。你的 p99 既包含合理的难度,也包含病态的沉思,从外部看,它们完全一样。

“调高超时时间”会将延迟 SLO 转化为成本事故

当推理请求开始触发你设置的 30 秒超时限制时,本能的修复方案是调高超时时间。这看起来很安全,实则不然,原因在于计费模式。

当推理模型思考时,你正在为它产生的每一个 token 付费——思考 token 的计费方式与输出 token 相同,而在顶尖推理模型上,输出定价通常是输入定价的数倍。因此,超时不仅仅是延迟的边界,它还是单次请求唯一的硬性成本上限。将超时从 30 秒提高到 180 秒,每个失控请求在系统放弃之前,现在可能会多消耗六倍的成本。再叠加重试策略,将同一个硬核提示(hard prompt)再次发给同一个模型——由于问题难度并未改变,第二次思考的时间依然会同样长——你实际上构建了一个机器,它通过反复付费来响应难题。

这就是延迟 SLO 如何悄然演变成成本事故的。过程几乎总是一样的:

  • 尾部请求开始超过超时限制,用户看到错误。
  • 调高超时时间,错误消失。
  • 增加重试和对冲(hedges)以保护剩余的尾部。
  • 账单寄到,财务询问为什么在流量增长 20% 的情况下,token 支出翻了三倍。

自动扩缩容(Autoscaling)也有同样的盲点。大多数扩缩容策略以请求速率或 GPU 利用率为核心指标,这两者都假设请求是大致等同的工作单元。当单次请求的计算量相差一个数量级时,请求速率就无法再预测负载了。十个困难请求就能使足以轻松服务一百个简单请求的容量达到饱和。更新的推理服务层研究通过基于工作量的信号来解决这个问题——基于 token 速率(流经 prefill 和 decode 阶段的 token 速率)而非请求数量进行扩缩容。但如果你的扩缩容策略早于推理模型出现,它几乎肯定是在测量错误的指标,并且在队列已经积压之后才做出反应。

对冲(Hedging)有效——前提是对冲到不同的模型,而不是副本

经典的尾部延迟(tail-at-scale)解决方案是“对冲请求”(hedged request):如果主请求在 p95 预期延迟内没有响应,则向另一个副本发送一个备份请求,并采用最先完成的结果。在 Google 著名的 BigTable 基准测试中,这种方法以约 2% 的额外负载将 p99.9 从 1,800 毫秒降低到了 74 毫秒。它之所以奏效,是因为变慢的原因在于环境——另一个副本通常不会遇到同样的环境问题。

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates