有些事平时看起来不起眼,真到了线上翻车才觉得肉疼。比如给 LLM 推理服务升级模型版本,或者换个 GPU 实例类型,流程里最怕的就是“切过去 5 分钟,用户特效没了”。以前想稳妥一点,就得自己搭影子流量、双跑比对,再拿脚本对比延迟和错误率,一套下来不比写业务代码省心。最近我看到某个提供 Serverless GPU 的平台推出了“端点候选(Endpoint Candidates)”能力,看下来思路挺直接的:给同一个推理端点挂多个候选配置,按比例放一点流量过去,观察一段时间,表现稳定就把候选晋升成正式端点。这种“先并存、再评估、后晋升”的做法,其实就是把灰度发布的核心逻辑搬到了推理端点上。这篇文章我想从实际使用者的角度把这个功能拆开聊,讲讲它解决什么问题、具体怎么用、有哪些坑,以及适合谁去用。
整个功能并不复杂,但背后涉及到的模型部署、流量切换、成本评估这些模块,值得好好梳理一遍。如果你也在做 LLM 推理服务、API 网关层,或者负责给模型平台做基础设施,我建议往下看,后面有一些参数和判断维度是文档里不会写太细的。
1. 内容整体设计与思路拆解
1.1 从固定端点到可候选的演进
过去大多数推理平台对“端点”的管理都是固定配置:你指定一个模型版本、一类 GPU 实例、一种副本数量,平台帮你创建出一个可访问的 URL,之后流量就都在这个固定集合上跑。这种模式有个隐藏假设——你当前的配置是“最优”的。可现实里模型迭代、实例类型更换、推理框架优化,这些都是常态。每次改动都要重新建一个端点,或者直接原地升级。原地升级最尴尬的地方是,出了问题只能硬着头皮回滚,回滚本身又是一个新变更。
Endpoint Candidates 在做的事情,是把“端点”和“候选配置”解耦。你可以把端点想象成公司对外的一个服务入口,候选则是背后可以接班的几套班子:A 班子是当前生产配置,B 班子是新换的模型版本加新 GPU,C 班子可能是另一个区域的实例。所有班子都先挂着,流量想怎么切就怎么切。核心逻辑从“替换”变成了“并存、分流、观察、晋升”。
这个思路其实在传统后端服务里很成熟,比如金丝雀发布。但放到 AI 推理端点上意义更特殊,因为模型推理服务不像普通 API 一样只关注响应码和耗时,它还有 Token 级延迟、显存占用、冷启动、并发限流这一类额外指标。这些指标的好坏直接决定切换后用户体验和账单数字,必须放在真实流量里去看才有参考价值。
1.2 为什么要灰度评估推理端点
先说一个最直观的例子。模型从 v1.0 升级到 v2.0,离线评测指标可能都很好,中文能力、代码能力都变强了,但一上线发现首字延迟从 150ms 涨到 500ms。为什么?因为 v2.0 的上下文处理逻辑更重,或者量化方式变了,导致小 batch 请求时 GPU 利用率反而不如以前。这些情况在离线压测里很难完全暴露,因为压测流量是均匀的,而真实用户请求有长短文本、命中缓存、并发突发等多种形态。
再说换 GPU 型号这件事。云厂商给的同系列 GPU 价格可以差很多,实际算力也差很多。你只听产品经理说“新实例性能提升 40%”,但切换到真实生场景后,可能因为驱动版本、共享占用、内存带宽差异,延迟表现并没有那么理想。在固定端点模式下,要验证只能拆一个临时端点,自己写网关脚本把部分请求引过去,然后反复拉指标、出报告,试错成本非常重。
灰度评估机制的意义在于,把“小流量验证”变成平台原生能力。你不需要自己造路由规则和评估管道,只需要声明几个候选端点,设置好权重,平台会按比例把真实流量分发过去,并通过同一套监控收集指标。这个机制对风险敏感型应用尤其重要,比如智能客服、实时翻译、代码生成工具这类一旦延迟劣化立刻被用户感知的产品。
1.3 相比自建方案的优势
自己做灰度评估也不是不行,团队如果有专门的网关层,可以在负载均衡器上配置不同 upstream 组,再通过自定义 header 或百分比路由做分流。但这项工作有几个不太舒服的难点:
- 需要自己维护两套甚至多套完整端点的生命周期,冷启动、扩容、缩容都要分别处理。
- 监控指标分散在多个系统里,延迟数据看 APM,Token 相关指标看推理框架的暴露面板,GPU 利用率又要去实例监控里查,整合报告的人会被逼疯。
- 回滚逻辑要自己写。晋升之后如果发现异常,是直接切回旧端点,还是保留旧端点继续收一小部分流量?很多自建方案根本没有这种能力,只能停机切换。
平台化的优势在于这些基础能力是内置的,操作路径短、一致性强。对中小团队来说,尤其是没有专职 SRE 的团队,这会省下不少时间。当然,大团队也可以把它作为一个快速验证工具,后续再决定是否沉淀成自己的发布系统。本质上这属于把成熟方法论工程化了,没必要因为听起来“简单”就看轻它。
2. 核心细节解析与实操要点
2.1 候选端点到底怎么定义
我理解里,“候选端点”不是简单地在原端点后面加一个新副本,而是一份完整的部署配置快照。一个候选应该包含:
- 模型镜像的版本标识,可以具体到 commit 或 tag。
- 实例类型,比如某系列的 L4、A10、A100,以及对应的显存和 CPU 配置。
- 缩放策略,包括最小/最大副本数、并发阈值、是否允许缩到零。
- 推理参数,比如 max tokens、temperature 的默认值,或者量化格式。
- 环境变量、启动命令、挂载的数据卷这些细节。
定义得越完整,灰度对比越有意义。如果你只换模型版本,但实例类型和缩放策略跟生产不一致,最后得出的延迟差异很难归因。反过来,如果你想比较新实例和自己现在的实例,那就应该保持模型镜像完全一致,只改实例类型。这样才能保证变量隔离。
这里有个小建议:候选配置不要随意起名,建议命名里带上版本号和目的。我见过有人把候选叫“test1”“final2”,两周之后根本看不出哪个是新的,晋升操作时还得猜。比起这种妖名,用“v2-l4-150ms”这种带信息的命名,后面排查问题时效率会高非常多。
2.2 灰度评估的关键判断维度
评估一个推理端点能不能晋升,不只是看“没报错”。以下指标我建议在灰度期间持续观察,并做成一张简单表格/看板:
| 指标 | 怎么看 | 决定问题 |
|---|---|---|
| 首次 Token 延迟(TTFT) | 分位数 p50/p95/p99 | 用户体验首位,过长会感觉“卡住” |
| Token 间延迟(ITL) | p50/p95 | 生成速度,影响打字机效果 |
| 错误率 | 5xx / 4xx 比例 | 直接影响可用性 |
| 限流次数 | 429 数量 | 判断并发配置是否合理 |
| 冷启动耗时 | 从请求到实例 Ready | 如果允许缩零,这个指标非常关键 |
| 每分钟成本 | 平台账单或用量 | 算性价比 |
上表里的初判阈值并不一定适合所有业务,但有个通用原则:候选端点如果有一条核心指标比当前生产差 10% 以上,就不太建议盲目晋升,除非你能接受其他方面的收益(比如成本明显下降 30%)。所有指标至少要覆盖一个完整的业务波动周期,我习惯跑 24 到 72 小时,避免只看中午高峰或者凌晨低谷。
2.3 晋升机制的设计要点
晋升不是“点个按钮就完事”,背后需要一套条件判断和回滚预案。我建议团队把晋升动作拆成几个阶段:
- 人工确认候选的指标和日志无误。
- 把流量权重从“大部分在生产”切到“候选占主导”,观察有没有报错。
- 将候选设置为新的生产端点,同时保留旧端点作为回滚目标。
- 再观察一段时间,确认稳定后才清理旧资源。
有些平台会提供一键晋升,但我个人建议在初期不要全自动。全自动晋升需要非常完善的分析逻辑,但这个逻辑不容易写好。比如,错误率如果因为外部依赖临时抖动而上探,你马上自动晋升,反而把没问题的候选否了。手动晋升只是多花几分钟人工确认,但安全边际高很多。
还有一个细节:晋升之后,原本的“候选”身份会消失,变成默认的生产端点。这时候旧的端点配置建议保留至少一周,万一需要回滚,你可以快速切回去。真有团队把旧端点删得飞快,结果用户抱怨响应慢,想回滚就只能重新重建,等于把灰度省下的时间全赔进去了。
3. 实操过程与核心环节实现
3.1 创建候选的通用步骤
虽然不同平台的控制台和 API 写法不一样,但流程大同小异,我按常见实践整理一个可参考的过程:
- 先明确对比目标。是换模型版本,还是换实例类型,还是调整缩放策略。不要混合多个变量。
- 基于现有生产端点复制出候选 A(保持当前配置)和候选 B(目标配置)。候选 A 的目的是作为对照,避免因为时间因素导致指标漂移。
- 创建一个新的逻辑端点,或者选择已有端点,把候选 A 和 B 挂载进去。
- 设置流量权重。建议把目标配置的权重从 1% 到 5% 开始,观察一段时间没有明显异常后再慢慢放大。
- 拉取评估指标,如果候选 B 在各项指标上和候选 A 相当或更优,则执行晋升。
- 晋升后继续观察 24 小时,然后根据情况清理旧候选。
这个流程看起来简单,但现实里每一步都可能踩坑。比如流量权重设置了 5%,不等于平台会精确地把每 100 个请求分 5 个给候选 B,它可能是按连接粒度或者会话粒度去分配的。如果你测试的请求量很小,实际分到候选 B 的样本可能特别少,看着权重到了但数据量不够。
3.2 一个可参考的双候选示例
假设当前生产端点是一个 Llama 系列模型的 7B 版本,跑在某型号 L4 实例上,模型量化方式是 4bit。你想评估新出的 v2 版本,以及 A100 实例是否能带来更低的延迟。这时候可以建两个候选:
- 候选 prod:镜像 tag
llama7b-v1-4bit,实例类型gpu-l4-24g,min replica 1,max replica 4,max batch size 16。 - 候选 canary:镜像 tag
llama7b-v2-4bit,实例类型gpu-a100-40g,min replica 1,max replica 4,max batch size 32。
这里把实例类型和镜像版本同时换了,对验证最终性能是合理的,但如果中途指标变差,你得能判断变量来源。如果你有精力,建议拆成两组实验:第一组只换模型版本,第二组只换实例类型。虽然多花两轮时间,但归因会更清楚。
流量权重初始可以设成prod 95% / canary 5%。跑 30 分钟左右,看看 canary 的错误率和 p50/p99 TTFT。稳定后改成prod 80% / canary 20%,再过几个小时,如果指标继续优秀,直接切到prod 0% / canary 100%,然后执行晋升。
这个过程中的日志需要带端到端追踪 ID。很多平台会为每个请求生成 request id,但你要确认日志中是否带上了“候选标识”,否则后面分析慢调用会分不清到底走了哪个候选。如果没有标识,建议在业务代码里通过环境变量区分,或者记录响应头和 URL 里的端点信息。
3.3 操作中必须避开的坑
- 不要在业务高峰期间做首次灰度流量切换。虽然灰度比例小,但新候选的冷启动和缓存预热可能会在高峰放大故障,建议先低峰跑通一轮再说。
- 别只盯着平均值。平均值会被少数快请求拉平,p95/p99 才能暴露长尾问题。在推理场景里,偶尔一次 3 秒首 token 就足以劝退用户。
- 注意“候选”和“生产”之间的共享资源。如果两个候选部署在同一个物理 GPU 上,可能出现资源争抢,指标会互相干扰。虽然平台通常隔离,但同区域的大实例也有可能有邻居效应。
- 量化类型不一致时,尽量测试输入输出一致的效果。有些量化格式对长上下文不友好,短压测看不出来,调成长文档测试就会露馅。
- 关闭不必要的重试。网关层如果对超时请求自动重试,灰度期间会把部分请求重试到另一个候选,指标会被污染,严重时会出现“流量放大”。
灰度评估要有一点耐心。我见过最快 15 分钟就晋升的,但那种情况只适用于模型版本打了一个纯 bugfix,改动很小,风险可控。加推理参数、换底层框架这类变更,我建议无论如何都要观察满一个业务日周期,包括爬坡时段和低谷时段。
4. 常见问题与排查技巧实录
4.1 问题速查表
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| 灰度流量完全没到新候选 | 权重设置未生效,或客户端复用连接,DNS/连接池没刷新 | 先检查权重配置,再尝试断开客户端连接或换新请求验证 |
| 新候选错误率突增 | 模型镜像与实例驱动不兼容;显存不足 | 查看平台日志中是否包含 OOM、CUDA 版本错误;回落权重并提升实例规格 |
| 候选 TTFT 比生产高很多 | 冷启动;批处理 queue 过长;权重太低导致样本少 | 设置最小副本数常驻;观察冷启动指标;提高权重到 10% 以上重测 |
| 晋升后部分用户闪断 | 连接池重建、DNS 缓存未失效;旧的实例被回收 | 保留旧端点,设置连接保持时间;必要时在网关层做连接 draining |
| 成本看似变化不大 | 候选没有真正接收流量;或者最小副本数导致空置 | 核对请求日志里的候选标识;调整 min replica 避免空跑 |
这个表是我在实际运维里比较常遇到的类型,不是官方 checklist,但通用性还可以。遇到问题时,第一步永远是确认“流量到底走了哪个候选”,如果这一步没确认,后面所有排查都是猜。
4.2 我的评估方法与个人心得
灰度评估听起来简单,但真正落地时,最大的敌人是“归因混乱”。有一次我把模型版本和实例类型一起换了,结果延迟下降很漂亮,团队很高兴。后来为了追一个坑,拆回去单独换实例,发现原来延迟改善大部分是因为实例换了,模型版本本身还变慢了。所以我现在做变更时严格执行“一次只改一个变量”,哪怕多花时间。
第二个心得是建立“基准线”。每次灰度开始前,把当前生产端点的 p50/p99 延迟、错误率、限流次数、平均实例数先记录成一份基准。对比的时候不要只拿“先有候选 vs 后选候选”的差异,而是把候选的指标跟基准线比,更不容易被环境抖动误导。
还有一个技巧:灰度期间,我会把候选的告警阈值调得更严一点。比如生产的错误率告警是 5%,候选就设成 2%;生产的 p99 TTFT 告警是 2 秒,候选就设成 1.5 秒。这样即使候选只接了 5% 流量,出问题也能更早发现。平台如果支持候选级告警最好,不支持的话,就通过日志和指标工具单独拉出来配一条。
4.3 从经验中沉淀的评估模板
到了后面,可以给团队做一个标准检查清单,每个候选晋升前过一遍:
- 候选运行时长是否超过 24 小时,覆盖至少一个高峰和一个低谷?
- 采样请求数量是否足够?建议至少 500 个有效请求,太少没有统计意义。
- 是否对比了 TTFT、ITL、错误率、限流次数、成本这些指标?
- 有没有抓几条人工评测请求,实际看响应质量和返回速度?
- 回滚方案是否明确?旧端点是否保活?
- 相关监控是否已经迁移到新端点?如果新端点没有接告警,晋升等于裸奔。
这套清单不复杂,但对稳定性很管用。它本质上是把“灰度经验”沉淀成团队规范,而不是每次靠某个人拍脑袋。
5. 这个能力背后的应用场景扩展
5.1 从模型版本升级到更广的场景
Endpoint Candidates 不止能用来做模型 A/B。我在前面的变量隔离里反复强调“一次只改一个变量”,但在实际业务里,它的用途可以更宽:
- 比较不同推理框架的收益。比如显存占用和延迟优化版本和原版对比,直接验证收益值不值得换。
- 跨区域部署迁移。新区域实例的成本可能更低,但延迟是否达标?可以通过小流量切一部分过去评估。
- 新版本模型上线前的“灰度陪审团”。让部分真实用户先体验,收集反馈,避免“我们觉得好,用户不买账”。
- 评估竞价实例或可抢占实例的稳定性。如果你的平台支持更便宜的实例类型,用它作为候选跑一段时间,看看回收频率对可用性影响大不大。
这些场景有一个共同点:它们都不适合用“全量替换”的方式去验证,只有灰度通道才能在不影响整体质量的前提下收集真实的运行数据。
5.2 适用于什么类型的团队
如果你是个人开发者,跑本地模型,或者只是少量调用推理 API,这个能力未必用得上,自己开两个容器测试就够了。但要是有以下情况之一,就很值得研究:
- 团队有多条业务线共用同一个推理平台,每次升级都怕被投诉。
- 有明确的成本控制目标,需要通过灰度对比确定不同实例的性价比。
- 模型更新频率高,每周都可能发一个小版本,需要一套稳健的发布流程。
- 平台侧已经有完善的日志和监控,只缺一个分流能力来做实验闭环。
反过来,如果团队没有监控体系,或者日志找不到请求追踪,那就算有灰度能力也没法做有效评估。工具只能帮你分流,但判断还得依靠数据。真想用好它,首要任务是把可观测性补上。
5.3 未来可能的演化方向
按这个思路继续走下去,后面平台大概率会把“晋升”做成更智能的自动化:根据预设阈值自动调整权重,甚至自动合并多个指标的评分来决定晋升。这很自然,但我觉得短期内手动模式仍然会占大多数,因为推理负载的多样性决定了自动判定很容易误伤。
我自己更期待的一个方向是“候选存活成本预估”。现在评估成本往往要等灰度跑完看账单,如果能提前根据实例规格、请求量和平均运行时长模拟成本差异,那评估效率会高很多。另一个方向是跨候选的上下文缓存共享,如果候选切换时不丢 prefix cache,TTFT 指标会更平稳,不会因为冷交换而产生假阳性。
这些都是额外脑洞,回到当下,Endpoint Candidates 还是那句话:把灰度发布思维塞进推理端点里。它解决的是“从模型到生产之间的信任问题”,不花哨,但很实用。
我个人在实际操作中的体会是,别急着把“晋升”交给自动化。先把手动灰度跑顺,把候选命名、指标模板、回滚预案这些基础动作固化下来,再考虑自动化。最后再分享一个小技巧:每次灰度开始时,给候选端点加一个带有版本号的响应头,比如x-llm-version: v2-l4,这样调试时抓包一眼就能看出请求命中了哪个候选,排查效率翻倍。新功能不可能解决所有部署问题,但至少它把最容易翻车的那一段路,铺了一层减速带。