跳到主要内容

48 篇博文 含有标签「latency」

查看所有标签

你的 Agent 链路中无人分配的延迟预算

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的 Agent 有一个延迟 SLO。有人把它写在了文档里:“响应时间低于 8 秒,p95”。但没人决定这 8 秒该如何分配。检索调用没有细分预算,规划步骤没有细分预算,模型因为感到不确定而决定调用的第三个工具也没有细分预算。预算在边界处只是一个数字,而在内部则完全不存在。因此,当一个五跳链路冲破 8 秒时,值班工程师盯着追踪链路(trace),却无法回答那个唯一重要的问题:到底是哪一跳超时了?

这就是拥有“延迟预算”的服务与拥有“延迟愿望”的服务之间的区别。预算是分配给每个组件并强制执行的;而愿望是在出口处测量并祈祷达标的。大多数 Agent 系统发布时都带着愿望,因为跳数结构是动态的——模型决定调用多少次工具——而且为无法控制的事情制定预算感觉是不可能的。事实并非如此。正因为你无法控制它,你才更需要为它制定预算。

P99 是产品决策,而非基建决策

· 阅读需 10 分钟
Tian Pan
Software Engineer

在几乎每一个发布 AI 功能的团队中,都会上演这样一种“仪式”:有人运行负载测试,看着 p99 延迟攀升并超过 2 秒,然后提交了一个工单:“让它快一点。”这个工单落到了基建(infra)团队手中。他们调整批处理大小(batch sizes),增加 GPU,争论调度器(scheduler),最终费尽心思将这个数字降到了 1.4 秒。每个人都点头认可。p99 被“解决”了。

整个过程都建立在一个错误的前提之上。这个前提认为延迟目标是系统的一个既定事实——是基建团队发现并为之优化的一个物理常数。事实并非如此。目标是一个选择,而且是一个产品层面的选择。什么才算“足够快”,完全取决于用户等待时界面的表现,而界面并不在基建团队的设计范围内。

护栏税:当安全分类器让你的延迟和账单翻倍时

· 阅读需 11 分钟
Tian Pan
Software Engineer

在安全评审中,有人问道:“如何防止用户通过越狱来泄露系统提示词(system prompt)?”于是你添加了一个输入分类器。接着又有人问:“如果模型生成了有害内容怎么办?”于是你又增加了一个输出分类器。然后法务部门要求对个人可识别信息(PII)进行脱敏,RAG 团队想要进行可靠性(groundedness)检查。现在,原本只需要一次模型调用的用户消息,变成了需要四次。你的 p95 延迟翻了一倍,推理费用上涨了 40%,而那个原本感觉是秒开的演示 Demo,现在在屏幕显示内容之前有了明显的停顿。

这就是“护栏税”(guardrail tax),而且几乎没有人为此做预算。出于本能去“添加护栏”感觉是免费的,因为每一个单独的检查都很便宜,而且显然是有益的。但护栏的组合并不是免费的——它们堆叠在关键路径(critical path)上,每一个都是增加延迟、消耗 Token 的串行环节,并且成为了一个新的依赖项,可能宕机、触发限流,或者干脆判错。

诚实的讨论应该从承认这一点开始:护栏不是一个功能开关(feature flag)。它是强行加在第一个推理系统之上的第二个推理系统,它有自己的失效模式和自己的账单。以下是如何思考护栏的实际成本,以及如何在不支付高昂代价的情况下获得保护的方法。

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

· 阅读需 12 分钟
Tian Pan
Software Engineer

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

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

当往返时延成为 Bug :你一直在忽略的端侧推理必要性

· 阅读需 11 分钟
Tian Pan
Software Engineer

这是一个你应该比现在更关注的数字:在模型生成第一个 token 之前,云端 LLM 端点的中位网络往返延迟在 48 到 800 毫秒之间。这不包括推理时间,也不包括排队时间。这是“走出大楼”的代价——DNS 解析、TLS 握手、往返最近数据中心的传输。对于单次聊天补全,你从未注意到它。但对于一个需要进行九次连续工具调用来回答一个问题的智能体,你刚刚交付了 5 秒钟的纯传输延迟,而你的用户能真切感受到其中的每一点。

大多数团队将往返延迟视为业务的固定成本,认为可以通过流式传输和加载动画来优化。但对于越来越多类型的工作负载来说,往返延迟本身就是 Bug。你需要的模型足够小,完全可以在数据所在地运行;任务足够重复,导致边际云端成本累积成一笔巨款;数据足够敏感,将其发送给第三方是你一直在默默承受的风险。端侧和边缘推理是大多数工程团队会反射性拒绝的选项——“本地模型不够好”——而这种拒绝正变得越来越站不住脚。

GPU 调度是一个排队问题,而不是资源配置问题

· 阅读需 11 分钟
Tian Pan
Software Engineer

当一个团队的推理端点开始无法达到延迟目标时,他们做的第一件事通常是购买更多的 GPU。一个月后,他们会发现第二件事:p99 延迟几乎没变,而账单却翻了一倍。显卡利用率徘徊在 40%,而尾部延迟依然很难看。有人添加了自动扩缩容(autoscaler)。自动扩缩容频繁震荡。现在有了更多的显卡,更高的成本,以及来自同一批用户的同样抱怨。

错误在于将推理缓慢视为容量不足。事实几乎从未如此。你面临的是一个披着容量问题外衣的排队问题。LLM 端点的尾部延迟取决于大小迥异的请求如何随时间共享固定的计算池——这是典型的调度问题,而非资源配置问题。在你理解服务栈实际运行的排队规则(queue discipline)之前,你添加的每一块 GPU 都只是更昂贵的变慢方式。

你的 AI 功能无法使用 CDN 边缘缓存,因为响应因用户而异

· 阅读需 10 分钟
Tian Pan
Software Engineer

产品团队将新 AI 摘要器的 SLO 设置为 200ms TTFB,因为这是产品其他部分在 p50 下的表现。会议上没人问这 200ms 是怎么来的。它源于十年来通过 CDN 边缘缓存提供的静态资源和 JSON 响应,其缓存命中率为 85%,大多数请求从未到达源站,即便到达了,数据量也很小。而这个摘要器是针对每个用户的,每次调用都是重新生成的,且每次请求都要经过“边缘 → 源站 → 模型提供商”的路径。从第一天起,这个 SLO 在结构上就是无法实现的。团队在第六周才发现这一点,而此时仪表盘已经红了整整六周。

这是 AI 功能发布中反复出现的一种模式。组织在某种物理规律基础上建立的延迟标准,被一个遵循完全不同物理规律的功能所继承。于是,继承目标与可实现底线之间的差距,变成了一个长达数月的缓解项目,而不是第 0 天的设计约束。数字并不关心你是否出于诚意与客户协商了该 SLO。

微调冷启动:云供应商如何将延迟计入你的闲置成本

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的微调变体在平稳的工作日每分钟处理几百个请求,p99 延迟仪表盘基本保持平稳。然后,在周二当地时间 03:14,某个请求的 p99 延迟从 800 毫秒飙升至 4.6 秒,随后恢复正常。第二天晚上,同样的情况再次发生,模式基本一致,时间也大致相同。你向供应商提交了一个工单询问这次飙升。得到的回复准确但毫无用处:他们的仪表盘显示其侧没有任何异常,没有速率限制,没有故障,在飙升时刻你的 token 使用量也很寻常。4.6 秒确实发生了。但账单上没有体现。

这种差距——用户明显感受到的延迟事件与未记录任何异常的账单之间——就是“微调冷启动税”的体现。这并不是你代码中的 bug,也不是供应商侧的性能回退。它是两种计费模式交汇的缝隙:供应商向你收取适配器上的活跃推理时间费用,而将适配器“加载”到服务槽位的成本隐藏在了供应商的基础设施层,在那里,它表现为你的延迟,却是他们的成本。如果你的流量模式低于供应商的预热阈值,那么每次流量回升时,你都要为 p99 延迟中的这段往返时间买单。

你增加的 Reranker:对召回率的拖累超过了对精准度的提升

· 阅读需 12 分钟
Tian Pan
Software Engineer

离线评估的结果非常明确。在向量搜索的前 50 个结果之上叠加一个交叉编码器(cross-encoder)后,nDCG@5 提升了 4 个点。团队在周二上线了该功能。到了周四,p99 检索延迟已超过 SLO(服务水平目标)700 毫秒,客户成功团队也开始转发空结果页面的截图,而这些页面在旧的流水线下本应是有内容的。真正关键的指标——用户感知的回答质量——下降了。重排序器(reranker)实际上是一个被团队冠以“改进”之名的性能退化,而评估标准则是将这种退化隐藏在众目睽睽之下的幕后黑手。

这是生产环境检索中最常见的失效模式之一,且很少被准确描述为:一个评估缺陷(evaluation bug)。重排序器完成了它的宣传任务:以更细的粒度对前 50 个结果进行了重新排序。问题在于,用于证明其合理性的指标——在无限预算下针对完整重排序列表计算的离线 nDCG——描述的是一个生产系统并不存在的理想世界。在生产环境中,最终输出的答案并非评分最高的重排序列表,而是系统在请求截止时间前所能返回的任何内容。一旦你以此方式重新定义指标,重排序器的贡献就不再是 4 个点的提升,而是一条曲线。

语音代理 SLO 定义为首个音频时间,而你的服务商则以首个 Token 时间衡量

· 阅读需 11 分钟
Tian Pan
Software Engineer

产品规格说明书规定用户在说完话后的 600 毫秒内听到回复。LLM 供应商的仪表盘显示首个 Token 时间(TTFT)为 280 毫秒。你查看的每一张图表都在 SLO 范围内。但用户仍然抱怨智能体有延迟,当你亲自拨打电话时,确实能感觉到明显的停顿——每次都在 600 毫秒以上。仪表盘没有撒谎。它测量的是一个不包含 TTS 流水线、音频传输或接收端抖动缓冲(jitter buffer)的数值。流式传输的最后一个 Token 与第一帧音频之间存在的 350 毫秒差距是真实存在的,只是它没有出现在 LLM 团队的图表上。

Bug 不在模型中。Bug 出在 SLO 上。它被定义在了错误的堆栈层级。供应商的出站(egress)并不是用户的耳朵,任何忽视这一点的延迟契约都会在生产环境中显得数据健康,而产品体验却是一团糟。

你定义‘首个 Token’的位置决定了你的延迟 SLO 是否真实

· 阅读需 11 分钟
Tian Pan
Software Engineer

我上季度合作的一个团队在周二发布了推理层升级,周三就开始收到支持工单。用户反映助手感觉“坏了”、“冻结了”或“卡住了”。值班工程师查看了延迟仪表盘,没发现任何异常。p99 首字延迟(first-token latency)为 612 毫秒——远低于团队花了一个季度建立的 800 毫秒 SLO。仪表盘是一片绿色。电话却响个不停。

问题的根源在于 14 个月前做出的一个埋点决策,当时生产环境中还没有推理模型。标记为 “first token” 的指标测量的是供应商发出的第一个数据块(chunk)的时间戳。升级后,第一个 chunk 变成了推理 token——这对用户不可见,也从未渲染,但在 SLO 中却被计为“首个”。模型在流式传输第一个用户可见字符之前,会先发出 4 到 7 秒的内部思考过程。每个图表依然是绿色的。每个用户却在黑暗中等待。

这不是一个关于指标好坏的故事。指标对于它最初设计的模型来说是正确的。这是一个关于当你的埋点边界不再是用户的感知边界时会发生什么的故事——以及在不知不觉中发布这种偏差是多么容易且危险。

Agent 循环从搜索框偷走的延迟预算

· 阅读需 13 分钟
Tian Pan
Software Engineer

发布指标看起来很干净。回答质量提升了,引用率上升了,评估套件全绿。那个用基于 Agent 的检索器替换旧关键词搜索的团队发布了产品,赢得了胜利,然后转向了下一个项目。六周后,有人注意到该界面的周活跃用户数下降了 12%,但没人能找到性能回归。其实并没有回归。Agent 运行正常。用户离开是因为以前在 200 毫秒内就能给出答案的搜索框,现在需要 4 秒钟,而发布回顾中没有任何内容涉及到这方面的预算。

这就是延迟预算转移问题,而且几乎没有人会画出能捕捉到这一问题的组织架构图。搜索框不仅仅是一个函数调用。它是与用户神经系统签订的一份为期三十年的契约:输入、查看结果、扫视、点击。200 毫秒的响应并不是某个仪表盘上的性能指标——它是当结果送达时,用户的注意力仍然留在屏幕上的原因。当搜索框背后的团队用 Agent 循环替换关键词索引时,函数调用表面看起来是一样的,但新调用的 SLA 处于一个完全不同的范畴。延迟预算从拥有索引的团队转移到了拥有 Agent 的团队,又从拥有 Agent 的团队转移到了用户身上,而唯一参加会议的只有用户。