服务、网关与算力
只有端点返回文本,不等于模型已经得到可靠服务。真正的服务意味着,已声明的一类请求能够在质量、延迟、可用性、成本和策略边界内得到合格结果。因此,真正需要运营的是一份版本化的服务契约:模型制品、运行时、适配器、请求语义、路由策略和算力放置共同产生结果。这把 第 81 章 中版本化线上系统的原则延伸到了生产环境。
运行时背后的原理见 第 31 章 和 第 32 章。本章把原理落实为运营方法:先固定契约,再用代表性负载测量完整路径,最后才选择引擎、加入 网关(gateway),也就是模型调用的路由与策略层,或采购容量。这些组件都是手段,不是架构起点。
固定服务契约
HTTP 请求格式只是连接组件的手段,不是行为标准。不同供应商在消息角色、工具和 JSON Schema 方言、分词方式、流式事件、停止条件、用量字段、错误、安全行为、数据处理方式和模型默认值上都可能不同。官方文档直接反映了这种差异:Anthropic 会列出哪些字段经过转换、被忽略或不受支持;Google 则建议尚未绑定通用客户端的应用使用其原生 API (Anthropic n.d.; Google n.d.)。应把 OpenAI 形式的 API 或其他共享封装视为共同支持的传输子集。供应商特有行为放在适配器后面;这个子集无法表达所需能力时,仍要允许应用调用原生接口。
内部请求契约至少要固定以下内容。
| 方面 | 契约必须固定的内容 |
|---|---|
| 身份 | 租户、调用方、请求类别、追踪 ID;可能产生副作用时还要有幂等键 |
| 模型输入 | 消息角色、提示词模板、工具模式、媒体格式、上下文策略和词元上限 |
| 生成 | 采样与推理设置、结构化输出方言、停止行为和允许的工具选择 |
| 生命周期 | 截止时间与取消、流式传输与错误行为、背压和过载响应 |
| 策略 | 数据分类与区域、保留期限、供应商白名单、安全策略和预算 |
| 副作用 | 只读或副作用类别、授权主体、能否重试,以及如何处理重复副作用 |
| 证据 | 所选部署、适配器版本、用量、结束原因、质量检查和关联追踪 |
每个供应商适配器都应运行同一套适配器一致性测试集。测试要覆盖普通消息、应用实际使用的每项工具和模式特性、部分流和已取消的流、上下文长度错误、用量核算,以及超时、速率限制、拒绝和格式错误的响应。字段一旦发生转换、模拟或丢弃,就必须拒绝该请求或明确报告,不能静默忽略。测试结果应形成翻译损失报告。同一套测试必须覆盖每条候选路由,也必须在每次适配器升级时重新运行。
部署身份必须包含所有会改变行为的层。下面是一种实用的系统指纹:
其中, 是供应商适配器及其版本; 是引擎镜像与配置; 是模型、分词器和制品摘要; 是提示词模板、工具解析器和结构化输出设置; 是数值精度和并行放置; 是注意力与 KV 缓存策略; 是解码、批处理和准入策略; 是加速器与网络拓扑; 是路由、重试和回退策略。每个符号都代表一份版本化记录,而不是产品名称。任意一项变化都会产生新的候选系统,必须重新通过相关评测。
图 82.2 展示了这条边界。中介服务是可选层,自主管理也只是部署方式之一;契约和证据则贯穿每条路径。
测量用户实际等待的时间
引擎先在预填充阶段处理提示词,再通过自回归解码生成后续词元。预填充通常有较多并行计算,容易受算力限制;解码的算术强度往往较低,容易受内存流量限制。这些只是常见情形,不是定律。提示词长度、批次形态、模型架构、内核、缓存状态和硬件,都可能让两个阶段遇到不同瓶颈。应测量准确的系统指纹 ,不能根据阶段名称预设瓶颈。
对于产生 个输出词元的简单请求,可以把关键路径写成
其中, 是准入和调度等待时间; 包括产生首个词元所需的工作; 是第 个输出词元的生成间隔; 是关键路径上串行工具调用或外部服务所花的时间。遇到并行分支时,应取最长分支的耗时,而不是相加。网络和客户端缓冲在影响显著时应单独记录。
首词元时间(time to first token,TTFT)从请求被接收到用户看到第一个词元为止。对于 ,常见的每输出词元时间(time per output token,TPOT)是首个可见词元到最后一个可见词元之间的时间除以 。端到端延迟仍然重要,漂亮的 TTFT 可能掩盖缓慢的解码、工具调用或重试。应按请求类别报告 p50、p95 和 p99,同时给出拒绝和超时的比例。否则,系统可以通过拒绝最难处理的流量,制造看似良好的延迟。
引擎机制是有条件的调节手段
现代服务运行时会组合多种机制。它们的发展历史说明了每种机制解决的具体问题。Orca 引入迭代级调度,让活跃批次可以在每轮解码之间变化,不必等待静态批次全部结束 (Yu et al. 2022)。vLLM 的 PagedAttention 把分块分配用于持续增长的 KV 缓存,减少了限制常驻序列数量的预留浪费和碎片 (Kwon et al. 2023)。后续系统又研究了分块预填充,以及把预填充和解码放到不同资源上 (Agrawal et al. 2024; Zhong et al. 2024)。这些结果都不能证明存在通用的生产默认配置。
| 机制 | 可能的收益 | 前提与代价 |
|---|---|---|
| 迭代级调度或连续批处理 | 请求进入和完成时重建活跃集合,增加调度机会 | 准入和批处理策略会改变 TTFT、词元节奏、公平性和内存压力 |
| 分页式 KV 分配 | 不再要求为最大缓存预留一块连续空间,减少容量浪费 | 仍有分块元数据、尾部浪费、缓存淘汰和内核支持问题 |
| 精确前缀复用 | 对精确相同的分词前缀跳过重复预填充 | 模型修订版、模板、适配器状态、位置、缓存格式、多模态状态和隔离策略必须一致;文档顺序或时间戳变化都会导致未命中 |
| 量化 | 减少权重、激活或 KV 内存中的一项或多项,也可能启用更快的内核 | 必须说明量化对象;校准、缩放因子、内核可用性和任务质量都要验证 |
| 投机解码 | 通过提议器与目标接受规则,减少目标模型的串行步骤 | 收益取决于接受率、提议器成本、内存、批次形态和保持分布的假设;见 第 33 章 |
| 语法约束输出 | 把完整输出限制在受支持的语法内 | 只能保证语法,不能保证语义正确、已获授权、工具选择安全,也不能保证流完整且未被拒绝 (Dong et al. 2025) |
| 分块预填充 | 把有限长度的提示词块与正在进行的解码交错执行,减少长提示词对生成的阻塞 | 增加新的调度选择,也可能改变 TTFT、吞吐和缓存行为 |
| 预填充与解码分离 | 隔离两个阶段的相互干扰,并允许分别放置和定容 | 增加 KV 传输、网络排队、重复容量、路由状态和新的故障边界 |
前缀复用不是语义缓存,语义相近并不代表 KV 状态可以复用。它也只节省预填充工作。当解码占主导或前缀很少重复时,保留缓存状态反而可能浪费容量。同理,如果运行时缺少高效内核,需要反复转换,低比特制品可能更慢。必须在准确的硬件上验证准确的制品,再重新运行 第 87 章 中的任务质量门。
结构化解码也需要同样谨慎。生成结束后,应检查结束原因、解析与模式验证结果、业务领域不变量、调用方授权,以及副作用对应的前置条件。转账请求在语法上有效,仍然需要授权。服务层由此接入 第 56 章。
对完整系统指纹做基准测试
有意义的比较,应固定一条符合生产形态的开环到达轨迹。轨迹保留真实的请求类别比例、输入和输出长度分布、前缀复用分布、工具和模式组合、取消和突发流量。所谓开环,是指请求到达时间遵循已经记录的计划,而不是等待前一个响应完成。否则,慢系统会降低自己的输入负载,从而显得格外稳定。
对每个候选系统依次执行:
- 固定完整指纹 ,验证适配器一致性和任务质量。
- 同时运行冷缓存和代表性的热缓存条件。
- 保持轨迹不变,让输入负载从空闲一直扫描到饱和。
- 记录准入和拒绝的请求、TTFT、TPOT、端到端尾延迟、输出速率、内存、可获得的功耗数据,以及每项合格任务的成本。
- 一次只改变一种机制。单因素消融便于查明收益究竟来自哪里。
- 重复足够多次以暴露方差,再测试工作进程丢失、网络延迟、取消和恢复。
不能一边比较两个引擎名称,一边更换模型修订版、模板、精度、硬件或请求组合,然后把差异归因于引擎。如果这些变化是有意为之,就应把它们作为两个完整线上服务系统的候选方案来比较。
只有同时通过所有硬约束和联合服务目标,配置才具备准入资格。对于请求类别 ,三个门应一起定义:
覆盖许可证、区域、接口和容量等所有硬约束; 是实测质量,门槛为 ;、 和 分别是 TTFT、TPOT 和端到端限制; 是要求的联合达标率。未知的硬约束证据不能通过。成本或吞吐优化只能在这个可行集合内进行,而且准入率必须与条件延迟一起公布。
只有边界有价值时才引入中介层
网关或中介服务是一种设计选择,不是必选层。当许多调用方或供应商会重复实现身份、凭据引用、配额、路由、预算和遥测时,中介层可以集中这些职责。只有一个应用和一个供应商时,经过充分测试的直接适配器可能更简单。真正要问的是:集中管理是否形成了团队真正能够执行和运营的边界?
中介边界只有明确维持以下不变量时才有价值:
- 先验证调用方和租户身份,再授权所请求的模型、工具、数据类别和副作用。持有代理密钥还不够。
- 只在允许的候选集合内路由;集合中的所有系统都必须通过同一份契约和策略兼容的回退评测。
- 分派之前原子地检查并预留预算,之后根据实测用量核对预留。
- 传递原请求剩余的截止时间和取消信号。重试不能获得一份新的超时时间。
- 只有故障类别和操作允许重试、幂等键或只读保证能够确保重复安全,而且预算与截止时间仍有余量时,才可以重试。结果不明不能证明没有发生任何工作。
- 把每次尝试、所选部署、策略决定和结果关联到同一条追踪中。W3C Trace Context 为此定义了可互操作的传播字段 (Kanzhelev et al. 2021)。
- 缺少身份、授权、路由资格或预算证据时,一律拒绝请求。可观测性故障不能悄悄关闭策略检查。
路由、策略和凭据发生变化的管理控制平面,应与读取这些记录的请求数据平面分开。两者都要受到保护并接受审计。与长期有效的持有者密钥相比,工作负载身份或短期、受众受限的凭据更合适。供应商密钥应通过凭据引用解析,不要复制进路由配置。
HTTP 区分幂等方法,但推理通常通过 POST 调用,生成结果还可能触发外部动作。因此,传输重试安全不能单独证明应用副作用安全 (Fielding et al. 2022)。如果工具可能已经执行后才发生超时,应按幂等键查询副作用账本;无法确认时,则把结果不明状态交给后续核对。不能盲目把同一动作交给另一个模型。
系统只能有唯一的重试负责人,并且要限制总尝试次数。客户端、中介层和供应商 SDK 中的嵌套重试会相乘,而不是相加。还要区分同一部署上的传输重试、切换到另一个合格部署的供应商故障切换,以及切换到另一个线上系统的模型回退。只有在第一个字节尚未到达调用方,而且替代方案仍符合相同契约时,才可以回退。流式传输开始后,应返回可见的部分流失败。身份验证、授权、无效输入,或无法重建的有状态会话,都不能通过尝试另一家供应商来解决。
下面的策略对象仅用于说明。它是一份内部设计记录,并不声称任何特定网关接受这份模式。
route_contract: support-summary-v3
request_class: read_only_summary
candidates:
- deployment_ref: hosted-eu@sha256:...
adapter_ref: adapter-a@sha256:...
data_classes: [internal]
regions: [eu]
- deployment_ref: managed-eu@sha256:...
adapter_ref: adapter-b@sha256:...
data_classes: [internal]
regions: [eu]
credential_ref: workload-identity://inference/support
deadline_ms: 2500
budget_reservation: required
retry:
attempts: 1
eligible_failures: [connect_before_send, rate_limited]
requires: read_only_or_idempotency_key
fallback:
requires_same_contract: true
telemetry:
record_content: false
propagate_trace_context: true
这条路由之所以有两个候选系统,是因为两者都已经通过一致性、质量、区域和负载门。同一个别名背后的不同模型不会自动成为合格回退。它可能改变工具行为、安全策略、上下文限制、数据处理、延迟和价格。
默认只记录低基数的运营事实:请求类别、逻辑路由、部署版本、词元数量、结束原因、延迟、尝试次数、策略结果和成本账引用。OpenTelemetry 正在完善生成式 AI 的语义约定,但输入与输出内容可能含有个人身份信息和其他敏感数据 (OpenTelemetry n.d.)。除非专门的保留、访问和脱敏策略明确授权,否则提示词、模型输出、工具参数和检索文档都不应进入普通遥测。
另行维护一份未采样的逻辑请求账本,不要用抽样诊断追踪代替。账本把每次尝试与路由修订版、实际供应商和部署、上游请求 ID、翻译损失、用量、价格版本、预估费用、策略决定和流终止状态关联起来。还要用供应商发票核对账本。本地估算不等于发票核对,也不能证明硬性预算上限。
根据测量结果采购容量
部署与采购是两个不同的决定。团队可以使用第一方 API、由供应商运营并承载指定制品的托管端点,也可以在租用或自有加速器上运行自主管理的引擎。比较三者时,必须使用相同的硬约束、质量门、工作负载和核算期。
| 方面 | 需要记录的问题 |
|---|---|
| 计费 | 按词元、请求、加速器秒,还是预留时段计费?计费粒度和最低承诺是什么? |
| 容量 | 有容量保证、配额或预留,还是仅尽力而为?突发流量和准入如何处理? |
| 启动 | 冷启动和扩容延迟是多少?空闲时需要付费维持多少热容量? |
| 故障 | 是否使用可中断容量?支持怎样的通知、检查点、重试和恢复? |
| 位置 | 涉及哪些区域、数据路径、存储层和出口费用? |
| 硬件 | 实际分配了哪种加速器、内存容量、互连、主机带宽和拓扑? |
| 运营 | 谁负责补丁、发布、监控、事故响应和容量预测? |
| 退出路径 | 制品、日志、适配器和评测证据能否迁移,并且不改变服务契约? |
不存在通用的利用率百分比,可以判定哪种模式更便宜。容量按台阶购买,需求具有突发性,热副本和冗余也要付费,而便宜的路由可能产出更少合格结果。应建立低、中、高需求情景,把容量台阶、承诺用量、中断、出口费用、运维人力和事故成本都纳入。随后比较 第 81 章 和 第 76 章 中定义的每项合格任务的端到端成本。
先估算规划下界,再做负载测试
设 为已声明的峰值到达率, 为在生产请求组合下实测的每请求加速器服务秒数, 为选定的规划利用率上限。加速器数量的粗略下界为
这是一项规划近似,不是自动伸缩公式。动态批处理会让服务需求呈非线性;提示词和输出长度的尾部都很重要;张量或流水线放置可能要求多块加速器作为不可拆分的整体;启动延迟也不允许立即扩容。对于放置规模 下实测的服务率 ,队列稳定至少要求
其中 是输入负载, 是该放置规模的实测服务率。这个必要条件不能保证 p95 或 p99 延迟。应通过开环扫描验证 ,再为故障、发布、维护和预测误差显式增加余量和冗余。最终采购的容量等于可行放置规模加上这些储备,并向上取整到供应商的分配单位。
每种需求情景都要报告合格任务、拒绝任务、质量通过率、SLO 达标率、计费空闲时间和总成本。完整成本账应除以合格任务,不能除以原始请求数或生成词元数。这样,便宜但不可靠或质量不足的路径才不会显得经济。
按工作负载语义选择编排方式
团队一旦控制资源池,就需要管理放置和生命周期。不能因为某个控制平面在业界流行就直接采用,应先写清楚工作负载。
- 长期运行的服务需要健康与就绪检查、滚动发布、受控中断、稳定寻址、流量排空、自动伸缩和快速回滚。
- 有限的分布式作业可能需要成组调度、拓扑感知放置、检查点与重启、抢占、优先级和跨团队公平配额。
- 两类负载都需要加速器身份、健康状态、隔离和核算。多节点作业还需要网络拓扑约束和全有或全无的准入。
- Python 或其他应用执行框架可以管理任务和执行单元,但不能替代集群准入、设备分配或服务生命周期控制。
Slurm 是集群工作负载管理器,负责资源分配、排队和作业步骤执行 (SchedMD n.d.)。Kubernetes 提供服务控制器和 Pod 放置,Kueue 等扩展可以增加配额和工作负载准入,但不会取代调度器或作业控制器 (Kubernetes SIG Scheduling n.d.)。两者都可以扩展,有些组织也会组合使用。持久的区别在于所需的生命周期和调度语义,而不是“训练用 Slurm,推理用 Kubernetes”之类的口号。
自动伸缩受到物理条件限制。如果一个副本需要几分钟才能分配硬件、加载权重、编译内核并预热缓存,几秒前的队列信号就不能挽救当前的请求突发。此时只能保持热容量或减少准入流量,根据已知峰值提前预测,并测试完整扩容路径。设备插件和动态分配同样不能证明模型能够装入设备、所需拓扑确实存在,或降级硬件仍可安全服务。
服务经济性可以影响训练选择,但必须测量这条因果链。当模型整个生命周期的服务需求让较低的单请求成本具有价值时,较小的模型可能值得投入更多训练算力,相关讨论见 第 5 章。这个判断取决于合格结果的质量、预期规模、硬件和核算期,不能只从参数量小推导出来。
把决策落实为运营流程
图 82.3 展示的端到端流程,把架构与证据放在同一个闭环中。
- **固定契约与工作负载。**声明请求类别、到达轨迹、质量门、SLO、准入策略、数据规则和成本核算期。
- **固定一套基线。**记录完整指纹。加入缓存复用、投机执行或阶段分离之前,先建立简单的共置配置。
- **验证行为。**运行适配器一致性、任务评测、安全检查和结构化输出不变量。未知的硬约束证据直接淘汰。
- **负载测试与定容。**在冷态和热态下,把输入负载扫描到饱和。定容时加入余量和冗余,再分别计算低、中、高需求情景。
- **故障注入。**测试连接故障、供应商返回的
429和5xx、慢速流、取消、工作进程丢失、扩容延迟、损坏输出、预算耗尽,以及结果不明的工具动作。验证截止时间、重试、授权和核算不变量仍然成立。 - **可逆发布。**策略允许时先运行影子流量,再按请求类别和租户进行金丝雀发布。适配器、路由、引擎、模型和调度器配置都要有经过测试的回滚路径。
- **保留证据记录。**为制品或适配器变化、供应商行为漂移、工作负载变化、SLO 退化、价格或配额变化、策略变化和定期到期定义重新评测触发条件。
预填充与解码分离、学习型路由、语义缓存和多云故障切换,都应作为假设进入这套流程。只有当更简单的基线无法达到已声明目标,而且新设计在同一轨迹下计入传输、重复容量、策略和故障成本后仍然胜出,才值得加入。
团队可以合理地选择不同运营边界。直接连接供应商的适配器可以减少需要运营的组件;中介层可以为许多调用方集中策略和证据。第一方 API 能减少运维,托管端点提供更多制品控制,自主管理引擎则暴露完整的运行时和容量问题。高级调度器可能改善一个实测瓶颈,同时增加另一条队列或新的故障域。不存在持久有效的产品默认选项。应保留版本化契约,并针对同一工作负载比较完整候选系统。
第 88 章 中的完整技术栈,是这些边界的一种实现。本章的方法就是它的验收测试:只有当完整线上服务系统在不违反契约的前提下产生更多合格结果时,端点、网关或 GPU 资源池才值得保留。
延伸阅读
- Yu et al., “Orca: A Distributed Serving System for Transformer-Based Generative Models” (用于自回归模型服务的迭代级调度), 2022. usenix.orgOrca 引入迭代级调度,让生成模型服务器在每个解码步骤后重组批次,而不必等待静态批次全部结束。
- Kwon et al., “Efficient Memory Management for Large Language Model Serving with PagedAttention” (vLLM 中基于分块的 KV 缓存分配), 2023. arXiv:2309.06180vLLM 通过分块分配与共享 KV 缓存来减少碎片,并提高服务系统可同时驻留的序列数量。
- Zheng et al., “SGLang: Efficient Execution of Structured Language Model Programs” (用基数树管理可复用的词元前缀), 2024. proceedings.neurips.ccSGLang 使用压缩有限状态机与跳跃式前向处理,减少结构化输出中确定性片段的顺序解码工作。
- Agrawal et al., “Taming Throughput-Latency Tradeoff in LLM Inference with Sarathi-Serve” (分块预填充与面向停顿的批处理), 2024. usenix.orgSarathi-Serve 将长预填充拆成多个块并与解码共同调度,以限制生成停顿并保留批处理机会。
- Zhong et al., “DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving” (在联合延迟目标下分离部署预填充与解码), 2024. usenix.orgDistServe 将预填充与解码放到独立 GPU 池,并用在指定 TTFT 与 TPOT 达标率下可持续的到达率定义 goodput。
- Dong et al., “XGrammar: Flexible and Efficient Structured Generation Engine for Large Language Models” (用于结构化语法的文法约束解码), 2025. proceedings.mlsys.orgXGrammar 通过预检查词元、持久化解析栈,以及文法工作与加速器执行重叠来加速上下文无关文法。
- Anthropic, “OpenAI SDK Compatibility” (记录兼容层中的字段转换、忽略项与原生功能缺口), n.d.. platform.claude.comAnthropic 将其 OpenAI SDK 兼容层定位为测试便利工具,并列出语义差异以及不受支持或被忽略的请求字段。
- Google, “OpenAI Compatibility” (提供商对 OpenAI 形状适配层及其限制的说明), n.d.. ai.google.devGoogle 记录 OpenAI 库调用如何映射到 Gemini,并建议在应用需要提供商特有功能时使用原生 Gemini 集成。
- Fielding et al., “HTTP Semantics” (定义安全与幂等的 HTTP 方法及重试约束), 2022. rfc-editor.orgRFC 9110 根据所请求的服务器效果定义幂等性,并限制客户端无法判断非幂等请求是否已执行时的自动重试。
- Kanzhelev et al., “Trace Context” (跨服务边界传播可互操作的请求标识), 2021. w3.orgTrace Context 标准化 traceparent 与 tracestate HTTP 字段,使同一分布式请求能跨服务和追踪厂商保持关联。
- OpenTelemetry, “OpenTelemetry Generative AI Semantic Conventions” (通用遥测属性以及模型敏感内容警告), n.d.. opentelemetry.ioOpenTelemetry 注册表定义生成式 AI 遥测属性,并警告模型输入与输出很可能包含敏感信息或个人身份信息。
- MLCommons, “MLPerf Inference Benchmark Rules” (推理测量中的被测系统、质量、负载生成与延迟规则), n.d.. github.comMLPerf Inference 规定完整被测系统、最低质量、开放环服务器到达过程与延迟约束,说明吞吐量必须结合工作负载和服务条件解释。
- SchedMD, “Slurm Workload Manager: Overview” (资源分配、作业排队与作业步骤执行), n.d.. slurm.schedmd.comSlurm 概览区分集群资源分配、排队作业调度以及在已分配节点上执行作业步骤。
- Kubernetes SIG Scheduling, “Kueue Overview” (Kubernetes 原生工作负载准入、配额与公平共享), n.d.. kueue.sigs.k8s.ioKueue 管理消耗配额的工作负载何时准入、等待或抢占,同时将 Pod 放置、自动扩缩容和作业生命周期交给相应的 Kubernetes 组件。
- Kubernetes, “Dynamic Resource Allocation” (面向专用资源的结构化申请与设备选择), n.d.. kubernetes.ioKubernetes 动态资源分配让工作负载通过结构化申请请求设备,并让驱动参与设备选择与准备。
评论
登录后评论