跳到主要内容

内部容量市场:在团队间分配稀缺的推理资源

· 阅读需 14 分钟
Tian Pan
Software Engineer

周五下午 4:50,数据团队的某人启动了一次评估扫描(eval sweep):针对公司的共享模型部署运行四万个提示词,计划在周末完成。下午 5:10,面向客户的聊天助手开始超时。值班工程师盯着仪表盘看了两个小时,显示服务商返回了 429 错误,直到有人想起问一句还有谁在使用该账号。没有任何东西损坏。系统正完全按照配置运行,也就是说什么也没做,因为没人配置它去做任何事。

这是一种新型故障的雏形,它具有一个比普通停机更棘手的特性:没有需要修复的 Bug。评估扫描是正当的工作。聊天助手的流量也是正当的工作。失败之处在于,两个具有不同紧急程度的团队从一个无差别的推理算力池中提取资源,而该池子对谁更重要没有任何判断。当你的公司有多个团队同时使用同一个服务商账号时,容量分配就不再仅仅是基础设施的细节——它变成了一个政治问题,而传呼机(pager)继承了这一麻烦。

本能的反应是将其视为频率限制(rate-limiting)问题,购买更大的配额,然后继续。但配额的增长只是推迟了冲突。随着智能体(agent)工作负载的倍增——现在每个团队都有批量回填、每晚的评估套件、调用模型的 CI 任务,以及至少一个偶尔会陷入重试循环的智能体——需求增长的速度超过了任何配额谈判周期。持久的解决方案不是更多的容量,而是一种在资源不足时提前在代码中决定谁的 Token 优先得到服务的机制。换句话说:一个内部容量市场。

一个池子,多方博弈

大多数公司的默认架构是单一的服务商账号,或单一的预配置吞吐量部署,前面挂一个共享的 API 密钥或薄薄的网关。这是一个自然的起点——只需谈一个合同,付一张账单,构建一个集成。但这也是一个没有围栏的公地。

从该公地提取资源的工作负载是极其异构的:

  • 交互式、面向用户的流量——聊天助手、产品内 Copilot。对延迟敏感,与收入挂钩,随用户行为剧烈波动。
  • 批量和回填任务——Embedding 重新生成、文档分类扫描、数据增强。Token 量巨大,但完全不紧急。没人关心它们是在凌晨 2 点还是 6 点完成。
  • 评估(Evals)和 CI——天生具有爆发性。评估套件旨在一次性触发数千个请求,且每当有人合并代码时就会运行。
  • 开发与实验——原型、Notebook 以及构建中的智能体,包括偶尔出现的会几分钟内耗尽一整天预算的失控循环。

这些任务对延迟的容忍度、每个 Token 的业务价值以及失败模式都截然不同。当它们共享一个无差别的池子时,竞争下的行为是由偶然决定的——通常取决于谁发送请求最快。共享密钥无法告诉平台团队哪个消费者该为消耗负责;它只显示一个不断上升的数字。多租户基础设施中的“噪声邻居”(noisy-neighbor)问题再次出现,只不过被争夺的资源不是 CPU 或磁盘 IOPS,而是每分钟 Token 数(TPM),而租户则是你自己的同事。

使这个问题更具政治毒性而不仅仅是技术问题的原因在于,每一个解决路径都要经过组织架构图。当评估扫描导致聊天产品瘫痪时,修复方案不是更改代码,而是两名总监之间关于谁的工作更重要的谈判,这种谈判以事故复盘的节奏进行,而值班工程师则成了被迫的调解人。构建分配机制的全部意义在于,在设计文档中进行一次这样的谈判,而不是在每个周五晚上。

大型机早已解决了这个问题

这一切并不新鲜。这几乎完全是 1960 年代分时系统所解决的问题。大型机是稀缺、昂贵、集中拥有的计算资源,每个部门都想分一杯羹。答案不是给每个部门配一台大型机——没人负担得起——而是构建一个操作系统,在用户之间对机器进行多路复用,以 CPU 秒和内存千字节秒为单位计量消耗,并按使用量向每个部门收费。

计量改变了行为:当部门为 CPU 时间付费时,程序员会优化他们的代码。市场做到了备忘录做不到的事情。

这一脉络直接延续到了现代集群调度器。谷歌的 Borg——塑造了 Kubernetes 的系统——将每个任务组织成互不重叠的优先级带:监控、生产、批量、尽力而为(best-effort)。当集群资源紧张时,生产任务可以抢占批量任务。配额是在需求发生前协商好的,是在特定优先级下、一段时间内的资源量向量。

Borg 中有一条规则可以直接借鉴到推理分配中:生产任务不抢占其他生产任务,因为允许这样做会产生抢占级联——一种每个移除都会触发另一个移除的连锁反应。

这两个时代的教训是相同的。稀缺的共享计算资源需要三样东西:优先级类别(规定谁的工作向谁让路)、在冲突发生前而非冲突期间协商好的配额,以及让消耗可见并可追溯的计量。每个现在让多个 AI 团队针对一个推理池运行的公司都在重新发现这一点,通常是一次一个事故。你可以通过借鉴这些设计来少走弯路。

Token 的优先级层级与抢占机制

推理场景下的具体实现包含两个层面:供应商提供的基础原语,以及网关执行的策略。

供应商已经将优先级频谱产品化了,因为他们在内部也面临着同样的多路复用(multiplexing)问题。OpenAI 对延迟敏感的流量按 Token 收取溢价提供优先级处理,中间层是标准按需付费(pay-as-you-go),对于能容忍响应慢或偶尔不可用的工作负载,则以约半价提供灵活和批处理(flex and batch)。Anthropic 提供具有承诺容量(committed capacity)的优先级层级,当你超过容量时会回退到标准模式。Azure 的预置吞吐量(provisioned-throughput)部署支持溢出(spillover),即那些会让你的预留容量触发 429 报错的请求会被重定向到按需付费模式,而不是直接失败。价格本身就是一种信号:紧迫性的市场溢价通常在“立即处理”和“有空再处理”之间存在 2 到 4 倍的差距。

大多数平台团队犯的错误是购买了这些原语,但仍然通过默认层级路由所有内容,因为内部没有机制来决定哪些工作负载值得使用哪个层级。而这个决定正是工作的核心所在。一个可行的初始策略(参考 Borg 的分段)如下:

  • 核心业务(交互式、面向用户):预留容量 —— 为每分钟 Token 数(TPM)设定一个其他类别无法触及的保障底线,大小按生产流量峰值设定。这是你的预置吞吐量或承诺优先级层级。
  • 生产批处理:在共享池中以较高优先级运行,允许在预留容量闲置时进行突发使用(burst),当核心业务需要空间时,这类流量最先被舍弃。
  • 评估与 CI:限制并发,默认路由到灵活或批处理层级。无论同时有多少个 merge 提交,评估套件绝不应消耗超过固定比例的共享容量。
  • 开发与实验:尽力而为(best-effort),设置严格的单 Key 预算,最先被限流。这一类中由于 Agent 逻辑卡死导致的死循环,应该在其他人察觉之前就触达其自身的上限。

实现这一点的网关模式是“预留加突发”(reserved plus burstable):每个类别获得一个保障份额,而共享突发池则在其他类别空闲时吸收流量峰值。预留份额保护了公平性;突发池则保持了高利用率 —— 因为简单的静态分区存在双重失效模式:既要为闲置的预留容量付费,又要让另一个团队排队等待。

推理的抢占机制与集群作业不同 —— 你不会杀掉一个正在进行的请求,而是停止接纳新请求。压力下的降级意味着批处理流量会溢出到供应商廉价且缓慢的层级,评估并发量下降,开发 Key 被限流,而核心业务类别则保留其底线。Borg 的级联规则在这里同样适用:两个生产核心类别永远不应互相抢占。如果你的聊天助手和反欺诈 Agent 都是核心业务,且它们的合计峰值超过了底线,那么解决方案是购买更大的底线,而不是让他们竞争 —— 两个核心服务之间的竞争本质上就是人为制造的故障。

费用分摊(Chargeback):让团队感受自己的负载

优先级层级控制任务何时运行。它们并不控制团队产生了多少工作量 —— 如果没有反馈闭环,每个类别的需求都会不断增长直到触及上限。大型机的解决办法是计费,这在今天依然奏效,但 LLM 消耗有一个打破标准云服务模式的特性:没有可供打标签的资源。一次 API 调用是一次交易(transaction),而不是一项资产。成本归属必须在应用层、在调用时,作为每个请求的元数据进行捕获。

在实践中,这意味着网关会为每次调用打上一组小而固定的维度标签 —— 团队、项目、环境、模型、成本中心,这几乎涵盖了你会被问到的所有分配问题 —— 并以此计量 Token。从第一天起就这样做;为六个月后的匿名共享 Key 流量回溯归属信息无异于考古。

然后按照 GPU 平台团队总结出的经验来安排上线顺序:

  1. 先进行 Showback(账单公示)。在真正涉及资金流动前,先公示一两个月各团队的消耗情况 —— Token 数量、成本、竞争时段的容量占比。Showback 能发现归属信息的缺失,并改变对话方式:配额谈判不再是基于感性的拉扯,而是基于双方都能看到的仪表盘。
  2. 在覆盖范围可信后再进行 Chargeback(费用分摊)。当团队的实际预算吸收了他们实际的 Token 支出时,激励机制就会自我修复。在优先级层级运行 40,000 个 Prompt 评估套件的团队会在他们自己的损益表(P&L)上发现,批处理层级的成本只有一半。不需要任何人发备忘录提醒。
  3. 对不同层级进行差异定价。内部定价应反映供应商的定价:优先级 Token 的成本高于标准,标准高于批处理。如果紧迫性是免费的,每个人都会声称自己紧迫 —— 在看到账单之前,每个工作负载都是核心业务。

要避免的失效模式是另一个极端:过于激进的费用分摊,导致团队开始囤积配额,为未来需求过度预留,或者在个人信用卡上建立影子账户以逃避内部市场。根据实测的 P99 使用量而非团队的申请量来确定预留大小,可以保持囤积行为的诚实。如果内部市场比绕过它更痛苦,人们就会选择绕过它,你就会把“嘈杂邻居”(noisy-neighbor)问题变成一个无法计量的影子 IT 问题。

专属容量还是共享池优先级?

最后一个反复出现的决策是:团队何时从共享池优先级“毕业”,转向拥有自己的专属容量——即独立的预置部署、独立的供应商账号、独立的协商合同。专属容量是用组织架构手段解决调度问题,正如大多数组织架构方案一样,它有时是正确的。

在以下情况下,请给团队提供专属容量:

  • 他们的流量是导致其他人收到告警(Page)的原因。 如果某个工作负载的峰值经常迫使其他所有级别的请求被舍弃,那么隔离的成本比维持秩序的成本更低。
  • 他们的利用率足以维持预留资源的热度。 预置容量无论是否使用都按小时计费;如果一个团队的持续利用率低于约 50%,他们就是在为某种隔离支付高额溢价,而这种隔离本可以通过优先级下限(Priority Floor)来实现。
  • 他们的需求确实存在差异——不同的模型、合规边界、共享网关无法满足的延迟 SLO,或者是出于爆炸半径(Blast-radius)的考量,需要将他们的故障与其他人的隔离开来。

当他们的需求只是普通紧急程度时,请让他们留在共享池优先级中,因为共享池具有任何专属孤岛集合都无法企及的结构性优势:统计复用(Statistical Multiplexing)。十个需求有波动的团队共享一个资源池所需的总容量,远小于十个独立预置峰值的总和;在碎片化的架构中,闲置的预留资源无法借给任何正在爆发流量的团队——即便 A 团队正在休眠,其孤岛中被困住的容量对 B 团队的流量峰值也毫无价值。每一次专属划分都会缩小资源池,并削弱对剩下所有人的平滑缓冲作用。碎片化是整个组织为某个团队的自主权所支付的税收;请让他们用利用率数据来证明其合理性,而不是靠资历。

资源池即产品

一个令人不安的总结是:如果你公司运行的 AI 工作负载超过了几个,无论你是否设计过,你实际上都在运营一个容量市场。未经设计的版本通过请求提交的速度进行分配,并通过事故复盘来解决争端。经过设计的版本则通过预先商定的优先级类别进行分配,按团队计量消耗,对紧急程度进行诚实定价,并将政治博弈留给真正的新问题。

从比你认为需要的更小的规模开始:将流量分为三个级别(关键、批处理、尽力而为),为关键级别提供预留底线,限制开发密钥,并开启费用展示(Showback)。这只需要几周的网关配置时间,就能将下个周五傍晚的评测扫描(Eval Sweep)从一次停机故障转化为一个无人察觉的调度事件。大型机时代的人们在计费 CPU 秒的年代学会了这一点;集群时代的人们将其编码为优先级带和配额向量。推理时代则继承了这两套方案——唯一的问题是,你是在自己周五下午 4:50 的事故发生之前还是之后采用它们。

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