多步 Agent 的延迟预算:为什么 P50 会说谎,而 P99 才是用户的真实感受
仪表盘显示智能体很快。P50 停留在 1.2 秒,团队开会庆祝,然后放弃率却在持续攀升。没有人关注用户真正体验到的那个图表。
这是生产环境中多步智能体可靠的失效模式:中位数是你能够达到的指标,而尾部延迟才是你用户感受到的指标。随着你在流水线上不断增加子调用,这两者之间的差距会呈非线性增长。一个包含四个步骤的智能体,即使每一步在“中位数表现”上都很快,其 P99 通常也会比任何单步操作糟糕 6 到 8 倍。用户体验到的不是中位数,而是他们那次特定请求中最慢的一步。
如果你的团队优化了错误的分位线,你交付的系统将拥有出色的基准测试表现和精美的演示效果,但在你从未监测的长尾场 景中,用户正不断流失。
数学逻辑:为什么组合会惩罚中位数
以一个包含五个步骤的智能体为例:意图分类、文档检索、重排序、生成、验证。每一步的中位数(P50)为 200 毫秒,P99 为 2 秒 —— 也就是中位数与尾部之间有 10 倍的差距,对于基于 LLM 的步骤来说,这还是保守估计。直观的错觉会认为端到端的 P50 是 1 秒,端到端的 P99 是 10 秒,事情就结束了。
这种直觉在两个方向上都是错误的,而且错得最离谱的那个方向正是最伤人的。
对于独立延迟的加和,均值相加,方差也相加。标准差随步骤数量的平方根增长,因此平均而言,随着步骤的增加,系统看起来会更可预测 —— 这正是陷阱所在。平均化只在均值处起作用。总和的尾部是由任何一个组件的尾部主导的。具体来说:你的流水线中某一步落入其自身 1% 尾部的概率是 1 - 0.99^N。对于 N=5,这大约是 5%,这意味着用户可见的 P95 被拉低到了接近单步 P99 的水平。对于 N=10,用户可见的 P90 就会被拉低到单步 P99 的水平。
翻译一下:随着步骤的增加,“出现一个慢步骤”的分位线会向左移动,吞噬掉分布中越来越大的比例。Jeff Dean 和 Luiz Barroso 的《Tail at Scale》为扇出(fan-out)系统阐述了这种数学逻辑的经典版本 —— 一个平均延迟 10 毫秒、P99 为 1 秒的服务器,如果每次请求查询 100 次,产生的分布中 63% 的用户请求将超过 1 秒。同样的逻辑也适用于串行组合,只是坡 度稍缓,而且它永远不会向着有利于你的方向弯曲。
这就是为什么在生产环境中观察中位数延迟的团队会被系统性地误导。他们的仪表盘测量的是最可靠的用户体验。而最不可靠的用户体验 —— 那些导致用户流失的体验 —— 在他们选择的分位线上是不可见的。
为什么 LLM 的尾部延迟比数据库更糟糕
经典分布式系统中的尾部放大源于排队、垃圾回收、网络波动和“嘈杂邻居”。这些尾部是真实存在的,但也是有界的 —— P99/P50 比例通常在 5-10 倍。而在 2026 年,基于 LLM 的步骤常规性地显示出 20-50 倍的比例,且原因更为复杂:
- 输出长度的波动。 一个在中位数情况下生成 50 个 token 的模型,当它决定“详尽”一点时,可能会生成 2000 个 token。逐 token 生成的延迟与输出长度呈线性复合关系,而输出长度是输入的属性,你无法仅凭输入就预测它。同一类 prompt 可能在 800 毫秒内返回,也可能耗时 28 秒,这取决于模型的决定。
- 提供商端的排队。 托管推理是多租户的。当提供商的 GPU 池饱和时,你会陷入一个你看不见的队列。状态页显示绿色并不代表尾部延迟也是健康的。
- 工具冷启动。 如果某一步调用了沙盒代码执行环境、无服务器函数或刚刚缩容的向量数据库,冷启动路径的耗时是热启动路径的 5-30 倍。
- SDK 内部的重试风暴。 许多提 供商的 SDK 会在遇到 429 和 500 错误时使用指数退避算法透明地进行重试。除非你接入了正确的钩子,否则第一次失败的尝试及其退避过程在你的追踪(trace)中是不可见的,但在用户的等待中却非常明显。
- 流式 TTFT 与完整生成。 首字生成时间(TTFT)可能很合理,但完整生成时间可能非常糟糕。如果下游步骤阻塞并等待完整输出,你继承的是完整生成的延迟,而不是 TTFT。
实际意义在于:你无法通过阅读模型卡片或供应商的基准测试来估算端到端延迟。你必须针对你真实的 prompt 分布,测量每一步从端到端的尾部延迟。
“延迟预算”到底意味着什么
预算是系统与用户之间的一种契约。它表明:在 99% 的情况下,我们将在 X 秒内做出响应,并在剩下的 1% 情况下优雅降级。预算不是愿景。它是每一步都必须满足的约束。没有预算,“让它更快”就是无边界且无法确定优先级的口号。
一个有效的预算包含三个部分:
- 端到端的目标分位线和数值。 选择用户真实感受到的指标。对于交互式 UX,这通常是 P95,有时是 P99。选择一个产品层面可以承诺的数值(“95% 的回答在 4 秒内完成”),而不是团队目前能达到的数值。
- 分摊到每一步且总和等于目标的配额。 如果目标是 P95 下 4 秒,且智能体有四个步骤,那么每一步大约有 1 秒的 P95 预算,减去编排开销的余量。分配不应是均等的 —— 给生成步骤 的配额要多于验证步骤。
- 硬性截止时间和回退方案(Fallback)。 当某一步超过其预算时,系统会执行某些操作:提供降级的回答、使用缓存的回退方案、发送“正在处理中”的消息,或者使用更小的模型进行重试。如果没有截止时间,超出的预算会以用户可见的卡死形式传播。
大多数团队都有第一部分,但跳过了第二和第三部分。他们在规划文档中写下一个目标,从未将其分解,也从未在运行时强制执行。然后他们发现,在负载下,第三步消耗了 80% 的预算,而且他们没有回退方案,因为架构假设每一步都能在预期时间内成功。
设计杠杆:从成本最低到最高
在你上线对冲(hedging)或投机执行(speculative execution)之前,先从那些低成本的杠杆入手。
消除步骤。 最快的步骤就是不运行的步骤。审计你的编排流水线,看看哪些步骤纯粹是因为有人添加了它而存在,而不是因为用户能感受到差异。大多数智能体(agent)都会演化出一个“重排序”(rerank)步骤,而此时检索质量其实已经足够好了;或者增加一个“验证”步骤,去捕捉那些在生产环境提示词分布中根本不会出现的失败模式;亦或是增加一个“格式化”步骤,而这本可以用一个简单的正则表达式搞定。你裁掉的每一个步骤,都会从你的延迟分布中移除它的长尾效应。
并行化独立调用。 当两个子调用互不依赖时,并发运行它们,将 sum(latencies)(延迟总和)转变为 max(latencies)(延迟最大值)。在均值和长尾表现上,两个独立调用的最大值明显优于它们的总和。这里的关键在于真正找到独立性——许多智能体代码是顺序执行的,仅仅是因为开发者习惯这么写,而不是因为数据依赖的要求。
流式输出并尽早启动下游消费者。 如果步骤一还在输出 token 时,步骤二就可以开始解析,那么步骤一的长尾延迟就会被步骤二的计算所掩盖。结构化流式传输(JSON schema、部分解析)能保证这一过程的安全性。大多数智能体框架默认采用“等待完全完成后再开始下一步”,而大多数智能体如果不对其进行优化,速度会慢很多。
在流水线前端使用更小的模型。 路由或分类步骤不需要最强的前沿模型。一个中位延迟 80 ms 的 3B 参数模型,表现远优于一个中位延迟 800 ms 的 80B 模型,且小模型的长尾延迟也相应更紧凑。请把大模型留给那些真正需要其能力的步骤。
在语义边界进行激进缓存。 嵌入(embeddings)、检索结果和中间分解步骤往往在不同请求间重复。缓存命中意味着一个零长尾的步骤。在优秀的语义缓存上进行投入,不仅能节省成本,在 P99 延迟上的回报也同样丰厚。
对冲慢步骤。 这是《Tail at Scale》论文中的做法,而且非常有效。在等待时间达到预期第 95 百分位延迟后,向两个副本发出相同的请求。重复请求会增加约 5% 的额外负载,但能极大地削减长尾。对于 LLM 调用,这意味着在超时后向第二个供应商或第二个区域发送相同的提示词。大多数团队因成本原因抵触这种做法;成本是真实的,用户体验的提升也是真实的,这种权衡应该是深思熟虑后的决策,而非默认放弃。
为每个步骤设置截止时间并及时退出。 当某个步骤超过预算时,中止它并运行备选方案(fallback)。备选方案可以是一个缓存的答案、一个更小的模型,或者是一条“我们无法获得完美答案,这是部分结果”的路径。一个在第 4 秒优雅退出的系统,每一次都能击败一个挂起直到第 12 秒的系统,尽管从技术上讲,退出的系统有“更多失败”。
你真正需要的仪表盘
如果你的追踪设置只显示每步的 P50 和端到端的平均值,那么你就是在盲目飞行。对于一个多步骤智能体,最小可用仪表盘应显示:
- 用户可见请求的 端到端 P50、P95、P99 和 P99.9,并按路由和提示词类别拆分。P99.9 线能捕捉到那些导致用户流失的离群值,而 P99 往往会把它们平均掉。
- 每步的 P95 和 P99,并显示每步对端到端延迟的百分比贡献。这是你找到消耗预算的步骤的方法。
- 分布形状,而不仅仅是百分位数。 端到端延迟的直方图或累积分布函数(CDF)能揭示双峰分布(如缓存命中与未命中、小输出与大输出),而百分位数会抹平这些特征。
- 长尾相关性。 当端到端变慢时,是哪一步变慢了?将此信息显性化,让值班工程师不必从原始追踪数据(spans)中去推导。
OpenTelemetry 加上一个追踪后端可以帮你实现大部分功能。工具无法替代的是 在正确的节奏下查看正确的百分位数 的纪律。智能体系统中的中位延迟仪表盘比没有仪表盘更糟糕,因为它们会产生虚假的安全感。
预算先行,优化在后
开发可靠智能体的团队不会从优化开始。他们从预算开始——一个用户能感知到的百分位数的明确数字——然后设计流水线以适应这个数字。每个步骤都有分配额度,每个额度都有截止时间,每个截止时间都有备选方案。
这个顺序与大多数团队的做法截然相反。默认做法通常是先构建流水线,最后测量延迟,然后在长尾延迟已经让人痛苦时进行恐慌式优化。到那时,架构已经假设每个步骤都会成功,备选方案并不存在,团队只能沦落到不断更换模型并祈祷。提前制定预算能让延迟从“你发现的东西”变成“你设计的东西”。
对于具有复合结构的系统来说,中位数是一个虚荣指标。长尾才是系统的本质。为长尾而构建,测量它,并为它设定截止时间——否则就只能让你的用户替你去发现它。
- https://research.google/pubs/the-tail-at-scale/
- https://www.barroso.org/publications/TheTailAtScale.pdf
- https://redis.io/blog/p99-latency/
- https://aerospike.com/blog/what-is-p99-latency/
- https://oneuptime.com/blog/post/2025-09-15-p50-vs-p95-vs-p99-latency-percentiles/view
- https://www.langchain.com/langsmith/observability
- https://inference.net/content/llm-observability-monitoring-production-deployments/
- https://latitude.so/blog/real-time-observability-llm-workflows
- https://www.mirantis.com/blog/inference-latency/
