跳到主要内容

39 篇博文 含有标签「inference」

查看所有标签

Token 预留容量:被人们忽略的、尚未从云时代迁移过来的预留实例决策

· 阅读需 13 分钟
Tian Pan
Software Engineer

大多数团队购买推理资源的方式,就像他们的前辈在 2010 年购买 EC2 时一样:全部按需(on-demand),按 token 计费,且在两个维度上同时让人措手不及。账单是一个意外。速率限制(rate limit)是另一个——在发布的中途出现的 429 错误,就在你从未预留的按需资源池被其他同样选择支付零售价的人争抢时。然后有人打开定价页面,发现供应商一直都在悄悄销售预留容量:预置吞吐量(provisioned throughput)、承诺使用折扣(committed-use discounts)、按单位小时计费而不是按百万 token 计费。云计算行业花了十年时间才内化的预留实例决策,现在就摆在 token 面前,但几乎没有人移植这一套玩法。

这种现象的原因并非无知。而是你为计算资源学习的预留实例数学模型无法直接迁移,而它失效的方式恰恰是在惩罚那种天真的承诺。预留一个 EC2 实例是在赌你一年后仍然需要那种实例类型。预留一块 token 吞吐量则是在赌你一年后仍然需要 那个模型——而模型的生命周期是以月计算的,而不是以十年计算。承诺的结构很熟悉,但你所承诺的对象却并非如此。

Prompt 缓存悬崖:一次系统提示词修改如何重置你的整个集群成本

· 阅读需 11 分钟
Tian Pan
Software Engineer

一切都没坏。这正是让人困惑的地方。没有部署失败,没有延迟报警,错误率也没有上升。有人合并了一个只有一行的 PR,在系统提示词(system prompt)末尾添加了一句话——一个新工具的描述、一条政策提醒,或者是“今天的日期是”的页眉——结果第二天早上,推理账单就高出了三到五倍。流量平稳,模型没变,代码也完全按照预期运行。

改变的是那一行代码放错了位置,导致你集群中所有的缓存前缀(cached prefix)瞬间失效。你的缓存命中率在一个请求周期内从 90% 降到了零,原本几乎免费的每个 token 开始按全价计费。这就是 Prompt 缓存悬崖(prompt-cache cliff),它是生产环境下 LLM 系统中最昂贵的故障模式,而且没人会对它进行威胁建模,因为它看起来根本不像故障。

Best-of-N 是一种架构,而不仅仅是打榜技巧

· 阅读需 14 分钟
Tian Pan
Software Engineer

每个前沿实验室的发布公告现在都附带同样的脚注:“包含并行测试时计算 (parallel test-time compute)”。Sonnet 的 SWE-bench 分数因此提升了约 5 分。GPT-5 级别的模型利用它将错误率降低了两位数。Gemini 的 Deep Think 依靠它几乎将其 ARC-AGI-2 分数翻了一番。大多数工程团队将该脚注视为基准测试的“调味剂”——一种虚标排行榜数字的手段,且认为没有实际系统会为此买单——然后继续围绕他们能负担得起的最强模型,进行单次尝试 (one attempt) 的产品架构设计。

这种直觉大概落后了两年。实验室在专业版 (pro tiers) 中加入并行采样并非为了营销装饰;他们加入它是由于在单个答案背后运行 N 次尝试通常是获得高质量的最廉价方式,有时甚至是唯一方式。当一个廉价模型的三次尝试加上一个像样的选择器 (selector) 能够击败每个 token 成本高出十倍的模型的一次尝试时,Best-of-N 就不再是一个基准测试把戏,而变成了一个架构决策——它拥有自己的成本模型、延迟特征以及标志性的失败模式。以此方式对待它的团队,正悄无声息地以比那些仍在旗舰模型上进行单次推理 (one-shot inference) 的团队更低的成本,交付更好的答案。

当硬件说谎时:静默数据损坏遇上随机性软件

· 阅读需 13 分钟
Tian Pan
Software Engineer

在你的推理集群中的某个地方,可能有一块芯片正在计算错误答案。不是崩溃 —— 而是错误答案。它通过了制造测试,通过了健康检查,但在指令序列、数据值、电压和温度的特定组合下,它会返回一个完全错误的数字。超大规模云服务商已经在大规模范围内记录了这一现象:大约每千台设备中就有一台会发生静默数据损坏(Silent Data Corruption),这一比率比我们过去担心的宇宙射线导致的比特翻转(bit flip)要高出几个数量级。

五十年来,软件拥有一种针对此情况的免疫系统:确定性(Determinism)。相同的输入,相同的输出 —— 因此你可以进行校验和(checksum)、回放,并与基准结果(golden results)进行对比,撒谎的硬件最终会被抓获。LLM 推理是第一个失去这种免疫系统的主要工作负载。当模型给出一个略差的答案时,是因为采样器的随机性,还是因为退化的 GPU 在你的 KV 缓存中翻转了比特?没人能通过检查来判断。一个不稳定的加速器可以在所有仪表盘显示正常的情况下,静默地拉低你的质量指标数周之久。

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

· 阅读需 12 分钟
Tian Pan
Software Engineer

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

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

零温度并非确定性:复现那些你无法重新运行的事故

· 阅读需 11 分钟
Tian Pan
Software Engineer

模型给了客户一个错误的、代价高昂的回答。你打开复盘报告(post-mortem),将完全相同的提示词(prompt)粘贴回完全相同的端点,并将 temperature=0,结果你得到了一个不同的答案。不是更坏,也不是更好——只是不同。你本该找出根本原因(root-cause)的 bug 无法按需复现,而那个每个人都告诉你保证能复现的开关刚才却当面撒了谎。

就在这一刻,大多数团队发现“将 temperature 设置为 0”只是民间传说,而非工程控制手段。零 temperature 改变了模型的“采样”(sampling)方式——它强制进行贪婪解码(greedy decoding),始终选择概率最高的 token。它并不能保证两次计算得出的概率本身是完全一致的。而在生产环境的服务栈中,它们通常并不一致。

你发出的流式中止信号,供应商照样收了费:账单中隐藏的 14% 差额

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的财务团队发起了一项申诉并失败了。该账单项是“输出 token”,它比你交付 token 总数的统计指标高出了 14%。供应商的支持工程师以“流式传输取消下的预期行为”为由关闭了工单,并附上了一份文档链接,上面写着“取消操作将在最后一个交付的 token 处停止计费”。这两句话都是事实,而它们之间的差距,正是你尚未编写的那行代码。

你阅读的合同是一回事,推理调度器的实际操作是另一回事。这种不匹配既不是 bug,也不是计费错误,更不是恶意欺诈——它是一个分层系统,取消信号必须穿越三个边界(浏览器、边缘节点、GPU),而计费表位于第三个边界,但你的“停止生成”按钮却位于第一个边界。缩小这一差距是一个由财务负责人发起的工程项目。

在解码中途缩减至零的自动伸缩器:当推理被视作无状态网络流量时

· 阅读需 13 分钟
Tian Pan
Software Engineer

集群完全按照我们的指令行事。流量在 45 秒内降至零,队列深度指标也归于平寂,KEDA 将副本数从 1 改为 0,90 秒后,节点自动扩缩容工具回收了 H100 Pod。图表看起来很干净。Slack 频道一片寂静。成本看板上的数字跳低了半美分。

一小时十二分钟后,一封客户支持工单送达:一个长时间运行的文档分析任务——一个预算为 28 分钟解码时间的 180k-token 推理任务——消失了。客户端 SDK 没报错。应用程序日志没异常。只有网关访问日志中埋着的一行 499,时间戳大致就在调度器判定 Pod 空闲并将其回收的时候。

你的评估套件设置了确定性种子,但供应商却悄悄忽略了它

· 阅读需 13 分钟
Tian Pan
Software Engineer

你设置了 seed=42。你设置了 temperature=0。你记录了运行情况,发布了仪表板,并在模型更换上签了字。第二天早上,重新运行相同的提示词却返回了不同的数字,你给出的解释——“肯定是采样噪声”——错得离谱:根本没有采样,而且噪声是结构性的。Seed 离开了你的客户端,网关将其丢弃,内核将你的请求与 17 个不相关的请求打包在一起,浮点归约(floating-point reduction)顺序在你眼皮底下发生了变化。你所谓的“可复现”基准测试,距离变成另一个基准测试其实只差一个批次(batch)。

这种失败模式是悄无声息的,因为技术栈中的每一层在技术上都是正确的。SDK 接受了 seed。供应商记录了 seed。模型返回了 system_fingerprint。评估工具记录了这三者。没有 5xx 错误,没有警告,没有抗议。仪表板上的数字只是发生了偏移,而团队将这种偏移合理化为一直存在的某种抖动——因为他们没有工具能告诉他们,他们看到的究竟是随机解码(stochastic decoding),还是导致三周的对比实验全部失效的后端轮换(backend rotation)。

确定性种子:为什么供应商将其视为“提示”而非“契约”

· 阅读需 12 分钟
Tian Pan
Software Engineer

CI 测试只有一个断言:相同的模型、相同的温度、相同的提示词、相同的种子(seed)、相同的输出字符串。它在每个开发者的笔记本电脑上都通过了,在前一百次 CI 运行中也通过了,但在三周内每五十次运行就会出现一次随机失败(flake),直到最后有人承认这种模式是真实存在的。第一个假设是显而易见的——测试工具中某处存在非确定性依赖——三天的调查却一无所获。实际原因隐藏在供应商 API 参考文档的一个脚注中:“seed 提供尽力而为的确定性。”团队读到了参数名称,并将其视为一种契约。而供应商记录的只是一个提示。

这是托管推理的一种特定失败模式,它困扰着那些围绕单一心智模型设计测试基础设施的团队:模型是其输入的纯函数,而 seed 是使函数具有可重现性的关键。在生产环境中,这个模型的这两个部分都是错误的。API 表面与底层物理原理之间的差距如此之大,以至于团队在供应商明确否认的假设之上,构建了整个评估和回归测试栈。

批处理负载挤占了你的实时路径:GPU 预留的惨痛教训

· 阅读需 10 分钟
Tian Pan
Software Engineer

每晚的微调任务在 UTC 时间 02:00 开始。它进入共享 GPU 池,占用它能找到的每一个槽位并持续持有。到 09:30,当工作日的首波推理流量到达时,自动扩缩器(autoscaler)试图声明已被连续占用七个半小时的容量。早晨的前 90 分钟,系统运行在约为基准 p99 延迟四倍的水平上。仪表盘报告了一个“喧闹的早晨尾部(noisy morning tail)”,推理团队将其归因于用户行为,因为实际的资源争用发生在一个推理团队并不拥有的任务队列中。

这是你在容量评审的成本归因幻灯片中无法捕捉到的 GPU 共享失败模式。共享被宣传为利用率的胜利——晚上训练,白天服务,填补低谷。实际交付的却是直到池按延迟类别(而非按团队或按时间)进行分区之前,你都无法摆脱的延迟长尾。

不属于你的那次变慢:对话中途的 KV 缓存逐出

· 阅读需 11 分钟
Tian Pan
Software Engineer

一段对话在同一个 Claude 会话里跑了四十分钟。十一轮回合,每轮平均首字延迟(TTFT)800ms,每轮都很便宜——因为那段 28,000 token 的前缀命中了提示词缓存。第十二轮到来,TTFT 飙到 3.4 秒。对话的形态没变,模型没切换,网络也正常。缓存输入 token 从 27,800 掉到 0。下一轮的 prefill 账单从第一个 token 起就全额计费。

你去追踪里找原因,没有任何一条日志写着"另一个租户的突发流量把你逐出了缓存"。对这次毛刺最诚实的解读是:在同一片 GPU 池的某处,另一个客户的 prompt 让调度器认为,丢掉你这段温热的前缀是代价最小的选择。你无法重放这一轮,无法证明那次逐出。那一刻的缓存状态是陌生人流量的函数,而那些流量不在你的追踪里,因为它们本来就不属于你。