Skip to main content

07 - Token 速率与 QoS:优质客户凭什么更快

前置01 - 网关是什么 里的 TPM / RPM;04 - 多租户与配额 里的配额机制。

本篇回答:VIP 客户要求"稳定的高速 token 输出",这件事到底靠什么实现?网关在其中能做什么、不能做什么?

会用到的词

  • TTFT(Time To First Token):从发出请求到收到第一个 token 的时间
  • TPOT / ITL(Time Per Output Token / Inter-Token Latency):吐出后续每个 token 之间的间隔
  • SLO / SLA:前者是你给自己定的服务目标,后者是写进合同、违约要赔钱的承诺

一、速率由两个指标构成

用户说"这个模型好慢",可能在说两件完全不同的事:

同一次流式响应,用户能感知到的两段时间时间发出请求TTFT · 等待期,屏幕上一片空白第 1 个 token第 2 个结束TPOT · 每两个 token 之间的间隔,决定「吐字」快不快总耗时 = TTFT + TPOT × 输出长度。只记一个总耗时,输出长度不同的两次请求根本没法比较,也分不出用户抱怨的「慢」到底是等太久,还是吐字太慢 —— 这两件事的成因和解法完全不同。
把这两段分开记,是回答「客户为什么说慢」的唯一依据。OpenTelemetry 的 GenAI 语义约定里也专门给了两个独立指标:time_to_first_chunk 和 time_per_output_chunk。

总耗时 ≈ TTFT + TPOT × 输出 token 数

这两个数的体感完全不同:

TTFT 差TPOT 差
用户感受"点了没反应,是不是卡了""字一个一个往外蹦,急死人"
典型场景长文档输入、冷启动后端过载、批次里请求太多
主要影响因素输入长度、prefill 排队、缓存命中后端的并发批次大小

而"优质客户要稳定的速率",说的几乎总是 TPOT,而且是 P99 的 TPOT。

这一点很重要:平均 TPOT 30ms 听起来不错,但如果 P99 是 400ms,用户每分钟都会遇到几次明显的卡顿 —— 体验上他会认为这个服务"不稳定",而不是"平均还行"。

💡 定 SLO 时不要用平均值。 平均值会被大量快速请求掩盖掉少量灾难请求,而用户记住的恰恰是后者。

二、网关不能创造吞吐

网关不能创造吞吐,只能分配吞吐。

token 是 GPU 算出来的。网关不管做什么优化,都不可能让一张 H100 每秒多吐几个 token。它能做的只有三件事:

  1. 让某些请求排在前面(优先级)
  2. 让某些请求走独占的通道(隔离)
  3. 让某些请求根本不用算(缓存,见 06 篇

所以"给优质客户保速"的本质不是优化,是隔离。你要么从 provider 那里买到隔离,要么在自建集群里造出隔离。

理解了这一点,下面三条路的逻辑就都通了。

三、路线一:购买 provider 的优先级

3.1 OpenAI:service_tier 与 Fast mode

OpenAI 把服务等级做成了请求参数。注意一个命名变更:Priority processing 于 2026 年 7 月 30 日更名为 Fast mode

resp = client.chat.completions.create(
model="gpt-5.6-sol",
messages=[...],
service_tier="fast", # 旧值 "priority" 仍向后兼容
)

也可以在项目级别配置(Settings → General → Project Service Tier),不必逐个请求传。

官方对 Fast mode 的效果描述是:对 gpt-5.6-sol 提供最高 2.5 倍的速度和更一致的延迟。注意"more consistent latency"这半句 —— 呼应第一节,卖的不只是快,是

四个等级的定位:

service_tier定位关键特征
flex省钱约便宜 50%,可以慢
默认(standard)常规
fast(原 priority保速按 token 加价;SLA 与 Scale Tier 同等对待
Scale Tier包量99.9% 可用性 SLA,优先计算资源

2026 年 7 月起 Scale Tier 的流量会自动溢出到 Fast mode,并按两者 SLA 中较高的那个给予补偿。

3.2 三个限制条件

1. Ramp rate(爬坡速率)限制 —— 这条最容易翻车。

官方规则:如果你超过 100 万 TPM,并且在 15 分钟内把 TPM 提升了 50% 以上,请求可能被降级回标准速度。

翻译成人话:Fast mode 不保护突发流量。 你花钱买了保速,结果搞了一次促销活动流量翻倍,恰恰在最需要它的时刻被降级。

对策:如果你能预知流量高峰(大促、发版、定时批处理),要提前分段爬坡把 TPM 抬上去,而不是到点直接冲。这件事必须由网关来做 —— 只有网关看得见全局的 TPM 曲线。

2. 账单和额度是分开的。 Fast mode 的请求单独计费,不消耗你已购买的 Scale Tier TPM 包。但两者共享同一个模型的基础速率限制。

3. 不是所有模型都支持。 官方明确:Fast mode 不支持微调模型和 embedding,且不保证覆盖每个模型。

这一条直接影响网关设计:你不能无条件地给 VIP 请求加上 service_tier="fast",得先判断目标模型支不支持,否则请求直接报错。这个判断逻辑放在网关最合适 —— 业务代码不该知道哪个模型支持哪个等级。

3.3 Anthropic:按账户层级而非请求参数

Anthropic 的路子不同,它把限额绑在账户层级上(Start / Build / Scale / Custom),而且输入和输出分别限流

层级Claude Sonnet 5 的限额
Start1,000 RPM / 2M ITPM / 400K OTPM
Scale10,000 RPM / 10M ITPM / 2M OTPM

📖 ITPM / OTPM:Input / Output Tokens Per Minute。输出 token 的限额通常比输入小一个量级(这里是 5 倍差距),因为输出是逐 token 解码出来的,比批量 prefill 昂贵得多。

这对网关限流的直接影响04 篇里那套按"tokens"单一维度计数的限流,在 Anthropic 上是不够用的 —— 输入和输出必须分开计数,否则你会在输出侧被限流而毫无察觉。

四、路线二:购买独占容量

比"优先级"更硬的保障是预留专属算力。这条路上两家云的模型不一样:

Azure OpenAI PTUAWS Bedrock Provisioned Throughput
单位Provisioned Throughput Unit,模型无关的配额单位,可分配给不同 deployment按模型预留的吞吐单位
灵活性高:同一批 PTU 可在模型间调配低:绑定具体模型
延迟表现专属预留容量,性能更稳定、延迟更低、吞吐可预测美国区域峰值负载下首字时间可低于 200ms(第三方评测)

这两者和 Fast mode 的本质区别:Fast mode 是"在共享池子里排到前面",预留容量是"这块 GPU 只服务你"。前者在极端拥塞时仍可能受影响,后者不会。代价是预留容量按时间计费 —— 不管你用不用,钱都在烧

💰 一条通用规律:按量付费买的是可用性,预留容量买的是延迟确定性

混合部署才是常见形态:基础负载走预留容量保住 P99,突发溢出部分走按量付费。而"什么时候溢出、溢出到哪里"—— 这正好是 03 篇讲的路由策略要解决的问题。

五、路线三:自建集群内做隔离

如果后端是自己的 vLLM 集群(★89,407,Apache-2.0),你就得自己实现优先级。这里有一个必须知道的现状限制

vLLM 支持优先级调度,但能力是不完整的。官方 issue #40004(2026-04-16 提出,至今 open)把问题说得很清楚:

The current priority scheduling only supports evicting low-priority requests from the running queue when resources are insufficient. However, when scheduling the waiting queue, if pending requests cannot be scheduled (for example, when the number of requests in the running queue has reached max_num_seqs), even high-priority requests cannot preempt requests in the running queue.

翻译:当运行队列已经站满 max_num_seqs 个请求时,高优先级的新请求只能排队等,抢不进去。

对生产的影响很直接:一批低优先级的长文本请求把运行队列占满,此时 VIP 请求进来 —— 它得等到某个长请求跑完才有位置。你为 VIP 配置的优先级在这个场景下形同虚设。

还有一层更微妙的矛盾(来自公开研究):vLLM 的调度偏向 prefill,会积极执行每个请求的 prefill 阶段来压低 TTFT,但这会导致 decode 阶段被冷落,进而广泛地违反 TPOT 目标

回到第一节 —— 优质客户在意的恰恰是 TPOT。所以默认调度策略优化的方向,和你的 SLO 目标是拧着的。

5.1 自建环境下的保障手段

在 vLLM 补齐抢占能力之前,可靠的做法只有一个:物理分池。

在引擎补齐抢占能力之前,可靠的做法只有物理分池网关按客户等级路由到不同的池VIP普通批处理VIP 实例池max-num-seqs 调小 —— 一批里同时解码的请求少,每个 token 来得更准时,TPOT 稳共享实例池max-num-seqs 调大 —— 一批塞更多请求,单卡吞吐高,代价是每个请求的 TPOT 抖低优先级池可被抢占 —— 前两个池资源紧张时,这里的任务先让路,反正没人在屏幕前等着
为什么必须靠物理隔离:同一个引擎实例里,批次大小是全局参数,没法给单个请求单独设。要让 VIP 的 TPOT 稳,就得让它待在一个批次本来就小的池子里。

关键参数是 --max-num-seqs(单实例最大并发序列数):

  • 调小 → 每个批次里的请求少 → 每个请求分到的解码时间多 → TPOT 更快更稳,但整体吞吐低
  • 调大 → 吞吐高,但批次里请求一多,每个请求的 TPOT 都会被拉长

VIP 池要的是低 max-num-seqs。你是在用整体吞吐换个体的速率稳定性 —— 这也正是"VIP 更贵"的成本来源。

网关在这个架构里的职责就非常清楚了:根据请求携带的客户等级,把它送进对应的池子。03 篇的标签路由就能实现。

六、网关承担的五项职责

把三条路线合起来,网关的职责清单是:

#职责具体做什么
分级路由按客户等级选择 deployment 池或 provider 等级
参数注入自动加 service_tier="fast",并先判断该模型是否支持
爬坡管理监控全局 TPM 曲线,避免触发 ramp rate 降级
降级策略VIP 池打满时,是排队等、还是降级到共享池、还是直接拒绝
SLO 可观测分别记录 TTFT 和 TPOT 的 P50/P95/P99,按客户等级分开统计

第 ⑤ 项最容易被做错。大部分网关的可观测只记"请求耗时"这一个数 —— 而它等于 TTFT + TPOT × 输出长度输出长度不同的请求根本没法比较

必须把 TTFT 和 TPOT 拆开记。 03 篇里我们看到 LiteLLM 的 lowest_latency 策略已经在这么做了:

use_ttft = (
request_kwargs is not None
and request_kwargs.get("stream", None) is not None
and request_kwargs["stream"] is True
and len(item_ttft_latency) > 0
)

流式请求用 TTFT 而不是总耗时来做路由决策 —— 同一套数据,既能用来路由,也能用来算 SLO。

七、限流是保障速率的手段

很多人把限流理解成"给用户添堵",和"保证速度"是对立的。实际上恰恰相反。

回到第二节:网关不能创造吞吐。那么当请求量超过后端能力时,只有两种结局:

做法结果
不限流,全部放进去所有人的 TPOT 一起劣化,没有一个人达标
限流,超出的直接拒绝放进去的那些全部达标,被拒的收到明确的 429

后者是唯一能让 SLO 成立的做法。 一个明确的 429 让客户端可以重试或降级,而一个慢到 P99 十秒的响应,客户端什么都做不了。

所以 04 篇那 4,789 行限流代码,真正的价值不是"省钱",是保住已接纳请求的服务质量

这也解释了为什么 VIP 的配额通常不是"更宽松",而是"更硬":VIP 池的限额要卡得比容量更保守,宁可拒绝,也不能让已经放进来的请求变慢。

八、分级设计表

如果你要从零设计一套分级服务,可以照这个填:

白金黄金标准离线批处理
TPOT SLO(P99)< 50 ms< 100 ms尽力而为
TTFT SLO(P99)< 500 ms< 1.5 s尽力而为
后端预留容量 / 专属 vLLM 池Fast mode按量付费Flex / 空闲时段
max-num-seqs最大
超限行为排队 + 告警降级到标准429延后执行
语义缓存关(要新鲜结果)视链路

最后一行是和 06 篇的交叉点,也是个容易搞反的地方:缓存命中能让 TTFT 直接归零,看起来对 VIP 最有价值。但 VIP 客户往往也是对结果新鲜度和准确性要求最高的那一批 —— 给他们返回一个"意思差不多"的缓存答案,是拿 SLA 换延迟。 这笔账通常不划算。

下一篇08 - 云厂商怎么做:国内四朵云在这些能力上各自给了什么。

← 回到 专题索引  ·  Agent Infra 板块总览