跳到主要内容

下午 3 点和凌晨 3 点的同一个 Prompt 并不是同一个 Prompt:LLM 评估中的昼夜漂移

· 阅读需 13 分钟
Tian Pan
Software Engineer

评估套件在凌晨 2 点运行。流量很低。缓存是冷的,但队列是空的。供应商的连续批处理程序有空闲插槽,并将以接近其 TTFT(首 Token 延迟)底线的水平处理每个请求。延迟分布很紧凑,评测模型分数稳定,仪表盘显示一片绿色。团队发布上线。

六个小时后,太平洋时间上午 8 点,同样的 Prompt 在美国早高峰期间进入生产环境。p95 延迟是评估报告的 2.4 倍。相当一部分请求从一个供应商那里收到了 529 错误,并回退到另一个供应商的较小路由层级。流式传输的节奏更加断断续续。评测模型(当天晚上对生产环境追踪样本进行重新运行)给出的中位数得分比凌晨 2 点给出的相同 Prompt 的得分低了半分。代码库没有变化。Prompt 没有变化。只是挂钟时间变了。

必须意识到的架构真相是:LLM 调用不是其输入 Token 的纯函数。它是一个随机分布式系统调用,其输入包括挂钟时间、供应商集群的负载、Prompt 缓存的状态、当前解码批次的大小,以及供应商负载均衡器在你的请求到达的那一毫秒所做出的路由决策。在凌晨 2 点运行评估的团队,是在一种用户永远无法体验到的条件下校准仪器。

为什么挂钟时间是一个输入

枚举这些机制是有帮助的,因为一旦它们被命名,昼夜效应就不再显得神秘。至少有四个机制。

连续批处理改变了负载下的计算逻辑。 现代推理服务器不会一次只运行一个请求。它们使用连续批处理(continuous batching),将来自多个请求的 Token 插入到同一个前向传播中,并在每个请求完成时在 Token 级别将其移除。Anyscale 对该技术的研究表明,与静态批处理相比,吞吐量有数量级的差异,但这种吞吐量的提升带来了一个评估套件很少建模的属性:处理你的 Token 的前向传播批次大小取决于当时正在处理的其他 Token。在凌晨 2 点,批次很小;在上午 10 点,批次很大。矩阵乘法更大,内核选择可能不同,在某些硬件上,浮点累加顺序会发生变化——这意味着你在独立请求中计算出的相同 Logit 可能会产生足够大的差异,从而在边界附近改变 top-k 的决策。

浮点运算不符合结合律。 Thinking Machines 对 LLM 推理非确定性的分析使这一点变得具体:即使在 temperature 为 0 时,相同的输入也可能产生不同的输出,因为在不同负载条件下运行的内核以不同的顺序减少浮点总和,而在 IEEE-754 标准中,(a + b) + c 并不总是等于 a + (b + c)。大多数时候,这种差异是不可见的。但在边界 Token 上——即在 Softmax 中两个候选 Token 差之毫厘的情况下——这种差异就会显现。边界 Token 翻转的速率与批次大小相关,批次大小与负载相关,而负载又与一天中的时间相关。

Prompt 缓存具有“温度”。 供应商缓存长共享前缀(系统提示词、检索到的上下文、少样本示例),这样他们就不必为每个请求重新计算。在前缀是“热”的情况下到达的请求支付一种延迟成本;在前缀被逐出时到达的请求支付另一种成本。逐出是由总缓存压力驱动的,而总缓存压力由邻近流量驱动,而这——再次强调——是具有昼夜规律的。在凌晨 2 点,你的评估套件是唯一使用该前缀的租户;由于重复使用,缓存保持为“热”。在高峰时段,你正在与其他人竞争缓存容量,你的前缀被冷启动重新计算的频率比你的评估所建议的要高。

供应商在负载下会悄悄地重新路由。 供应商不会公布具体发生的时间,但过载错误模式已有详尽记录:在 2026 年,OpenAI 和 Anthropic 都有明显的峰值时段容量压力,且 429 / 529 曲线具有强烈的昼夜特征。不太明显、且对评估来说更危险的是在过载错误之前发生的路由回退:原本会命中主集群的请求被转移到了具有不同硬件、可能具有不同量化、可能具有不同投机解码配置的备份池中。输出仍然符合发票上模型名称的规格,但不一定与主集群产生的输出完全一致。而在凌晨 2 点在主集群上进行评估的团队,并没有可追溯的记录来证明其生产环境请求中的一部分正由微妙不同的系统处理。

为什么凌晨 2 点评估是行业默认标准

没有人主动选择这样做。这是逐渐形成的。

CI 在夜间运行,是因为在过去的世界里,CI 一直是在那个时间运行的,当时衡量的指标是单元测试的通过/失败,而成本相关的维度是“我们是否在早会前腾出了构建服务器集群”。对于确定性系统来说,这是一个合理的计划。但对于一个行为随他人硬件负载而变化的随机分布式系统来说,这是一个错误的计划。

供应商方面的激励措施加剧了这种情况。非高峰时段的批处理 API 提供了大幅折扣——Anthropic 的批处理层级优惠 50%,OpenAI 的也类似,而且窗口期明确设定在低负载时段。一个试图完成季度成本目标的团队会将评估移至折扣窗口,而不会仔细思考这对代表性意味着什么,因为预算中的细目写着“评估”,而捕获后果的细目写着“生产质量回退”,它们存在于由不同人负责的不同仪表盘上。

还有人为因素:评估工程师希望在早上看到结果。凌晨 2 点运行意味着稳定的条件、没有高峰时段频率限制带来的波动,以及早会上整洁的仪表盘。每一个个体动机都指向了错误的时间。

必须落地的纪律

有五项实践,共同作用下可以弥合这一差距。每一项单独来看都不难。难点在于团队必须承认差距的存在。

在整个昼夜曲线中进行评估采样,而不是只选一个方便的时间点。 正确的评估节奏不是“凌晨 2 点”。它应该是覆盖完整流量分布的分层采样:工作日高峰(用户主要地区的上午 9–11 点和下午 2–4 点)、周末低谷、欧洲上午、亚太傍晚,以及那些对成本敏感的用户仍在使用的非高峰时段。这在资金上更昂贵,在操作上也更嘈杂,但它产生的评估结果对于生产环境实际运行的条件才有意义。如果你只能负担得起一个时间段,请在高峰期运行,而不是非高峰期——团队应该针对用户实际生活的环境进行优化,而不是针对最容易测量的环境。

将按小时统计的延迟作为一类 SLO 进行跟踪。 24 小时窗口内平均的单一 p95 数据就是一个谎言。真正有意义的仪表盘是一个热力图:一轴是每周的小时,另一轴是 p50/p95/p99 延迟,并叠加请求量,这样你就能看到批处理压力存在于何处。Anthropic 和 OpenAI 的状态页面已经发布了按小时细分的 API 响应时间跟踪器;一个针对你的流量和 Prompt 范围的内部版本仪表盘,就是让团队能够观察到昼夜漂移(diurnal drift)的工具。

区分冷缓存和热缓存预算。 不区分这两个状态的延迟 SLO 会掩盖 3–10 倍的差距。如果一个 Prompt 预期的热缓存 p95 为 800ms,冷缓存 p95 为 3200ms,那么这两项预算都应在合同中指明,且告警系统应知道特定请求适用哪项预算。最简单的监测方法是对系统提示词前缀(system-prompt prefix)进行哈希处理,并为每个请求打上标签,标注供应商是否返回了缓存命中;如果你的供应商提供了该信号(Anthropic 的 API 提供,OpenAI 的自动缓存通过响应元数据体现),请务必使用它。

运行一个能够重现高峰条件的合成负载评估。 这是更难的一步。目的不是对你自己的基础设施进行压力测试(那是负载测试的工作)。目的是在真实的邻居压力下运行 你的评估套件。像 LLMPerf、GuideLLM 和 Gatling 这样的工具可以模拟生产环境下的并发流量形状——多样的 Prompt 长度、真实的输入输出 Token 分布、爬坡和预热阶段——同时由一个独立的辅助线程触发评估 Prompt。在这种条件下得到的延迟、错误率和评测得分,才是你决定是否发布产品时应该依靠的数据,而不是在评估 Prompt 是你账号发送的唯一请求时得到的数据。

让你的供应商明确说明在负载变动时哪些因素是稳定的。 某些路由行为是稳定的:发票上的模型名称不会静默切换到另一个系列。但有些则不然:具体是哪个集群、回退(fallback)时使用哪个量化层级、哪种投机采样(speculative-decoding)配置、哪种内核实现。询问供应商的企业团队,列出哪些维度保证在负载条件下保持稳定,哪些维度是团队在每次重大流量变化后必须重新测量的。答案通常比你希望的要更不乐观,而对话本身就是产出物——它强制明确了那些一直隐含且未被监控的合同的所有权。

这能捕获的两种失败模式

一旦团队做对了昼夜评估,两种特定的事故模式就会消失。

第一种是发布时显示为绿色但随后静默退化的场景。某个功能在凌晨 2 点测得的评估分数下发布。生产环境用户在高峰期使用它。质量始终低于发布时的承诺,但从未差到足以触发针对凌晨 2 点基准校准的回归告警。团队花了一个季度思考为什么定性的用户反馈比仪表盘显示的要差。有了昼夜评估,这种差异在发布检查清单阶段就会显现出来,而不会等到用户发现。

第二种是评估通过但破坏了生产环境的 Prompt 更改。工程师为了清晰起见重写了系统提示词。在凌晨 2 点、热缓存、小批量的情况下,评估显示评分标准提高了一分。Prompt 发布了。高峰期的生产环境在冷缓存和大批量下运行新 Prompt,冷缓存前向传递的形状与新 Prompt 的结构相互作用,触发了一个路由决策,而热缓存评估从未覆盖到这一点。用户看到了回归。团队归咎于模型。实际的根本原因是评估是在无法推广到生产环境的条件下进行的,而 Prompt 的更改恰好落在了评估未探测到的边界附近。

生产环境一致性真正的含义

在离线与在线评估的讨论中,“生产环境一致性”(production parity)这个词经常被用到。它通常意味着“评估 Prompt 看起来像真实的用户 Prompt”——相同的长度分布、相同的标签组合、相同的采样温度设置、相同的模型名称。这固然必要,但还不够。两个字节完全相同的 Prompt 可能会因为墙上时钟的不同而看到不同的模型行为。生产环境一致性必须包含调用的 运行条件,而不仅仅是输入字节:可能适用的批处理大小、可能适用的缓存状态、可能适用的路由层级,以及推理运行的时间点。

那些以低成本学会这一点的团队,从第一天起就将其构建到评估框架中:每个评估结果都打上墙上时钟小时、缓存命中信号和观察到的端到端延迟的标签,并基于这些共同维度(而不只是 Prompt 内容)与生产环境分布进行对比。而那些以昂贵代价学会这一点的团队,则是那些在评估为绿色时发布功能,却经历了长达一个季度才追踪到评估定时任务执行时间的静默退化。

架构框架

更深层的认知框架是,LLM 推理是大多数产品团队将要运行的第一项基础设施,它既是一个模型产物(受权重和行为变化的影响),又是一个共享计算服务(受邻里效应和负载影响),但目前还缺乏这两个领域各自带来的运营规范。机器学习团队习惯于对权重进行版本管理,但不习惯考虑多租户问题。分布式系统团队习惯于考虑多租户,但不习惯考虑在提示词-缓存轴上发生偏移的行为。AI 工程化作为一个学科,正是这两个领域的词汇必须同时落地的地方。

“挂钟时间作为输入”这一观察是切入点。一旦团队接受了一天中的具体时间也是输入分布的一部分,那么其余的规范——分层评估调度、冷启动与热启动预算、合成负载评估、供应商稳定性合约——都会遵循一个单一原则:在你实际运行的条件下进行测量,而不是在最容易测量的条件下进行。在这一原则被内化之前,团队构建的每一个仪表盘都是在用户从未体验过的条件下校准仪器,而每一个发布决策都是针对一个在早上 6 点负载回归时就会消失的“现实版本”做出的。

References:Let's stay in touch and Follow me for more thoughts and updates