想象你经营着一家连锁餐饮集团。总厨房(Triton 推理服务器)把最好的厨艺固化成一道道标准菜品(模型),再统一送给全国的分店(客户端应用)出餐。总厨房的菜谱架(模型仓库)上,每道菜都有好几版配方:v1 是初版,v2 是改良版,v3 是换了新调料的最新版。问题来了——怎么让这些配方版本井井有条地共存?怎么确保新配方先在少数顾客身上试吃(灰度发布),确认好吃再全面推广?怎么做到不关店就换菜单(热切换),让顾客永远等不到打烊?Triton 的多模型版本管理,就是这套“中央厨房管理手册”。本文不堆术语,用看得见摸得着的厨房故事,带你搞懂模型仓库的目录组织、版本策略、灰度发布和热切换,从此部署多版本模型不再手忙脚乱。

岗位关联

对 AI 工程师来说,多模型版本管理是模型从实验走向生产的“最后一公里”:掌握它,你才能让模型安全迭代、随时回滚,成为真正扛得住线上流量的人。

目录
  1. 可视化演示
  2. 框架初识
  3. 仓库结构
  4. 版本目录
  5. 版本策略
  6. 多模型并行
  7. 灰度发布
  8. 热切换技术
  9. 实践要点
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示Triton推理服务器的多版本模型管理机制,包括流量路由分配、灰度发布策略与不停服热切换过程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

流量路由模式 客户端请求经Triton服务器路由至多版本模型,按策略分配流量 灰度发布:V3小流量验证→逐步放量→全量切换 traffic(v_i)=w_i/Σw_j 支持版本策略:all/latest/specific

框架初识

一家连锁餐饮集团的总厨房每天要接待几十家分店的订单,后厨里有煎炒烹炸各种炉灶。总厨房并不亲自去每家分店炒菜,而是把每道菜的做法封装成标准流程,分店只需要报菜名,总厨房就按流程出菜。Triton 推理服务器就是这个“总厨房”——它把 PyTorch、TensorFlow、ONNX 等各种框架训练出来的模型统一管理起来,对外暴露一套标准的 HTTP 或 gRPC 接口。分店传菜单(客户端发请求),总厨房接单、分配炉灶、出菜、上菜,一气呵成。

用户最关心的是“这道菜好不好吃”,而总厨房管理者关心的是“高峰期一小时能出多少道菜”。衡量总厨房效率的指标,就是推理吞吐量:单位时间内能处理多少个推理请求。

总厨房的厉害之处不在单道菜炒得多快,而在几百个炉灶同时开工还能井井有条。理解 Triton 的角色定位后,我们接着看它的“菜谱架”——模型仓库是怎么摆放的。

Throughput=NrequestsTtotal\text{Throughput} = \frac{N_{\text{requests}}}{T_{\text{total}}}
吞吐量 = 处理完的请求总数 ÷ 总耗时。好比记录后厨从早十点到晚十点一共端出了多少道菜,再除以营业时长。
  1. 请求总数 N_requests统计窗口内成功完成的推理请求总个数,好比厨房一小时端出的菜品总数。
    NrequestsN_{\text{requests}}
  2. 总耗时 T_total从统计开始到结束经过的墙钟时间,相当于后厨营业的总时长。
    TtotalT_{\text{total}}
  3. 吞吐量 Throughput两者相除得到每秒处理的请求数,即厨房一小时内平均出菜速度。
    Throughput=NrequestsTtotal\text{Throughput} = \frac{N_{\text{requests}}}{T_{\text{total}}}

仓库结构

后厨最怕什么?调料找不到、菜谱乱放。所以总厨房有一面巨大的菜谱档案柜:第一层抽屉按菜品分,第二层抽屉按配方修订版分,最里面夹着每版配方的完整做法。Triton 的模型仓库就是这面档案柜,它有一套严格的目录组织规则,乱放目录 Triton 就“找不到菜谱”。

标准结构是四层:仓库根目录 → 模型名目录 → 版本号目录 → 模型文件。启动 Triton 时通过 --model-repository 参数指定仓库根目录,Triton 启动后会递归扫描每个模型目录,读取其中的 config.pbtxt 配置文件,弄清楚“这道菜叫什么、用什么锅炒、最大一锅能炒几份”(模型名称、框架类型、最大 batch)。模型权重文件则放在对应的版本号目录里,比如 model.pt。

把模型文件按“模型 / 版本”两级目录摆放整齐,是 Triton 能自动发现和管理版本的前提。档案柜摆好了,接下来给每个配方修订版建立编号规则。

RepoPath=root/model_name/version_id/model_file\text{RepoPath} = \text{root} / \text{model\_name} / \text{version\_id} / \text{model\_file}
模型仓库路径 = 根目录 / 模型名 / 版本号 / 模型文件。就像档案柜的“柜号 / 抽屉 / 夹层 / 菜谱纸”。
  1. 仓库根目录 rootTriton 启动时用 --model-repository 参数指向的顶层目录,相当于档案柜总柜。
    root\text{root}
  2. 模型名 model_name每个模型一个子目录,对应一种菜品一个档案夹。
    model_name\text{model\_name}
  3. 版本号 version_id正整数子目录,同一种菜的不同配方修订版。
    version_id\text{version\_id}
  4. 模型文件 model_file实际的权重与配置文件,就是菜谱正文。
    model_file\text{model\_file}

版本目录

档案柜里同一道菜可能有十几个修订版:v1 是第一版配方,v2 调整了火候,v3 换了新酱料。后厨怎么区分它们?靠的就是目录名——目录名是几,这版配方就是几号。Triton 对版本号有两条硬性规定:必须是正整数,必须用来做目录名。它不要求版本号从 1 开始连续排列,也不认 v1.0 这种带小数点的名字,更不认 beta 这种字母代号。

多版本共存在 Triton 里是常态。你可以同时在 质检模型/1/、质检模型/2/、质检模型/3/ 三个目录里各放一份模型文件,Triton 启动时会把它们全部扫描出来。至于哪个版本真正上灶对外服务,由版本策略决定——这是下一节的事。版本目录管理的核心,就是维护好这个“可见的版本集合”。

版本目录是“有哪些配方可选”,而策略是“今天用哪个配方”。两者配合,才能让总厨房既保留所有修订版,又只推出当前认定的那版。

V={v1,v2,…,vn},vi∈Z+\mathcal{V} = \{v_1, v_2, \ldots, v_n\},\quad v_i \in \mathbb{Z}^{+}
某模型的所有版本号构成一个正整数集合。版本目录就是把这些数字变成文件夹摆在仓库里。
  1. 版本集合 V某个模型目录下所有版本号构成的集合,相当于菜谱档案夹里的修订版清单。
    V\mathcal{V}
  2. 元素 v_i单个版本号,必须是正整数,比如 1、2、3。
    viv_i
  3. 正整数约束版本号只认数字、不认字母和小数,这是 Triton 的硬性规则。
    vi∈Z+v_i \in \mathbb{Z}^{+}

版本策略

档案柜里躺着三版配方,灶台上却不能同时炒三个版本的同一道菜——总得有个“今天用哪版”的规矩。Triton 把这个规矩写在每个模型的 config.pbtxt 里,名叫 version_policy。它有三种玩法:latest 表示加载编号最大的 N 个版本,适合“新版优先”的日常迭代;specific 表示只加载明确指定的版本,适合“只信某一版”的严格管控;all 表示全部加载,适合做多版本对比实验。

用 latest 策略时,配置里写 num_versions,比如 num_versions: 2,就会把版本号最大的两个版本都加载进显存,但只让最大的那个对外服务。这里要注意一个容易踩的坑:num_versions 是“最多加载几个”,不是“只加载编号为几”。如果新版加载失败,Triton 会退回加载次新的版本继续服务,就像主厨请假时二厨顶上,不会让灶台空着。

版本策略就像总厨的值班表:今天谁掌勺,由规矩说了算。掌勺定下来了,可总厨房同时开着几十个灶台炒不同的菜——这就是多模型并行管理。

vactive=max⁡({v∣v∈Vloaded})(latest 策略)v_{\text{active}} = \max\left(\{v \mid v \in \mathcal{V}_{\text{loaded}}\}\right) \quad (\text{latest 策略})
采用 latest 策略时,对外服务的版本号 = 所有已成功加载的版本中编号最大的那个。
  1. 已加载版本集合 V_loadedTriton 启动或轮询时发现并成功加载的版本号集合。
    Vloaded\mathcal{V}_{\text{loaded}}
  2. 条件 v ∈ V_loaded只有真正加载成功的版本才参与竞选,加载失败的版本不算数。
    {v∣v∈Vloaded}\{v \mid v \in \mathcal{V}_{\text{loaded}}\}
  3. 取最大值 max在候选版本中挑编号最大的一个对外服务,这就是 latest 策略的执行动作。
    max⁡(⋅)\max(\cdot)

多模型并行

真正的总厨房不会只做一道菜:剁椒鱼头、宫保鸡丁、清蒸鲈鱼同时开火,每道菜占一个灶台。Triton 也一样,一个推理服务器可以同时加载多个不同的模型。质检模型、推荐模型、翻译模型放在同一个仓库里,彼此井水不犯河水,这就是“同仓共存”。

但灶台(GPU 显存)是有限的。多个模型同时加载,显存占用是叠加的。如果总占用超过 GPU 显存上限,要么新模型加载失败,要么老模型被挤出内存。Triton 的调度器负责协调:它按请求排队调度推理任务,并支持在多个 GPU 之间做负载均衡和资源隔离。你能通过配置给不同模型分配不同 GPU,避免“一道菜占满整个厨房”。

多模型并行让总厨房一台服务器顶十台,但一次上新菜不能全厨房一起换——万一新配方不好吃,砸的是整家店的招牌。所以,聪明的总厨会选择先试菜。

Mtotal=∑i=1kMi≤MGPUM_{\text{total}} = \sum_{i=1}^{k} M_i \leq M_{\text{GPU}}
所有已加载模型的显存占用总和不能超过 GPU 显存上限。好比同时开火的菜品占用的灶台总面积不能超过厨房可用的台面。
  1. 模型显存 M_i第 i 个模型在显存中的占用,包括权重参数和中间计算结果缓存。
    MiM_i
  2. 总显存 M_totalk 个模型占用之和,相当于所有菜同时备料占用的台面总和。
    ∑i=1kMi\sum_{i=1}^{k} M_i
  3. 容量约束总和必须不超过 GPU 显存上限,超出就会加载失败。
    ≤MGPU\leq M_{\text{GPU}}

灰度发布

米其林餐厅推新菜,绝不会第一天就让全店顾客都点它。通常是先邀请一小批老食客试吃,反馈好了再逐步扩大范围,最后才写进正式菜单。这个“小范围试吃→逐步扩大→全量推出”的过程,在模型上线里叫灰度发布。新版本模型放到 Triton 的版本目录后,服务端确实已经把 v3 加载好了,但流量怎么分,主动权在客户端手里。

具体做法是:调用方(可能是你的网关脚本或业务代码)根据随机数、用户 ID 哈希等规则,把一定比例的请求路由到新版本,其余留在旧版本。比如先放 5% 流量到 v3,观察准确率、延迟、错误率等指标,没问题就调到 20%、50%,最后 100%。一旦新版本指标异常,立刻把流量切回旧版本,这就是回滚机制——因为旧版本一直没删,随时能接住流量。

灰度发布解决了“新菜好不好吃”的问题,但它依赖一个前提:切流量和回滚都不能让顾客等太久。这就轮到热切换技术登场了。

Rnew=α⋅Rtotal,Rold=(1−α)⋅RtotalR_{\text{new}} = \alpha \cdot R_{\text{total}},\quad R_{\text{old}} = (1 - \alpha) \cdot R_{\text{total}}
灰度比例 α 表示切给新版本的流量占比。α=0.2 时,新版本吃 20% 的请求,旧版本吃剩下 80%。
  1. 总请求量 R_total灰度期间入口处的全部推理请求,相当于来试菜的顾客总数。
    RtotalR_{\text{total}}
  2. 灰度比例 α切给新版本的流量比例,是 0 到 1 之间的小数,0.2 表示两成流量。
    α\alpha
  3. 新旧分流新版本拿到 α 比例,旧版本拿 (1-α) 比例,两者互补且和为 1。
    Rnew=α⋅RtotalR_{\text{new}} = \alpha \cdot R_{\text{total}}

热切换技术

传统餐厅换菜单,得打烊关门、贴新菜单、重新布置后厨,顾客只能吃闭门羹。而总厨房的“电子菜单”可以做到不关门换菜单:新版本目录一放好,Triton 自动发现并加载,加载期间正在处理的请求继续跑完,新请求自动落到新版本上——整个过程顾客无感知。这就是热切换,或者说热加载。

Triton 的热加载靠两种机制驱动:默认的轮询模式会定期扫描模型仓库目录,发现新版本目录就自动加载;也可以通过 model_control_mode 设为 explicit,用 API 手动触发加载。无论哪种方式,核心原则都是“旧版本不撤、新版本就位、失败能回退”。新版本加载失败时,Triton 会保持旧版本继续对外服务,不会出现“新旧都挂了”的空窗。热切换做得越好,服务的可用率越高。

热切换让“换菜单”不再惊动顾客,但这套厨房体系要长期稳定运转,还有不少经营细节要注意。最后我们聊聊实战中的那些坑。

A=TuptimeTuptime+TdowntimeA = \frac{T_{\text{uptime}}}{T_{\text{uptime}} + T_{\text{downtime}}}
可用率 = 可用时间 ÷(可用时间 + 不可用时间)。热切换的目标就是让不可用时间趋近于零。
  1. 可用时间 T_uptime服务正常处理请求的累计时间,相当于后厨正常营业的时长。
    TuptimeT_{\text{uptime}}
  2. 不可用时间 T_downtime因重启、切换失败等原因导致的累计停摆时间,相当于打烊时间。
    TdowntimeT_{\text{downtime}}
  3. 可用率 A可用时间占总时间的比例,越接近 1 说明热切换做得越好。
    A=TuptimeTuptime+TdowntimeA = \frac{T_{\text{uptime}}}{T_{\text{uptime}} + T_{\text{downtime}}}

实践要点

经营一家总厨房,光会炒菜不够,还要会算库存、看报表、清过期食材。Triton 多版本管理的实战同样有四个必修课。第一是显存占用:上线前用“参数量 × 精度字节数 × 冗余系数”估算单模型显存,再乘以模型数量,确保不超 GPU 上限。第二是日志监控:时刻盯着推理延迟、吞吐量、加载失败次数和版本切换事件,这些是灰度发布中判断“新菜行不行”的依据。第三是版本清理:新版本稳定运行一段时间后,及时删除不再需要的旧版本目录,释放磁盘和显存。第四是配置校验:每次改动 config.pbtxt 前先在测试环境跑一遍,避免线上加载失败。

把这四件事做到位,你的“中央厨房”就能长期稳定出餐。版本管理不是把模型文件堆进目录就完事,而是一套从组织、策略到发布、回滚的完整经营哲学。

Mmodel=P×B×cM_{\text{model}} = P \times B \times c
单模型显存估算 ≈ 参数量 × 单参数字节数 × 冗余系数。FP32 一个参数占 4 字节,FP16 占 2 字节,冗余系数通常取 2~3。
  1. 参数量 P模型权重参数个数,比如 70 亿参数的大模型。
    PP
  2. 单参数字节数 B不同精度占用不同字节,FP32 占 4 字节,FP16 占 2 字节。
    BB
  3. 冗余系数 c推理框架额外缓存和中间张量带来的倍数,通常取 2 到 3 估算。
    cc

AI 应用场景

电商搜索排序模型灰度发布

阶段:模型上线与迭代

解决的问题:传统方式一次性把新排序模型全量上线,点击率反而下降时只能紧急回滚,整个过程中用户体验受损、业务指标波动大。使用 Triton 多版本管理后,新旧版本共存,通过客户端按比例切流量,风险可控。

具体案例:某电商平台的搜索团队用 Triton 同时管理排序模型 v1、v2、v3。新模型训练好后放进 v3 目录,客户端按用户 ID 哈希把 5% 的搜索请求路由到 v3,其余留在 v2。监控一小时后发现点击率提升 3%,于是逐步放大到 20%、50%、100%。整个过程用户无感知,服务器没重启过。

大模型推理服务热更新

阶段:推理服务运维

解决的问题:大语言模型动辄几十 GB,停机升级意味着线上服务中断,对内部工具和外部客户都不可接受。Triton 的热切换让新版本目录就绪后自动加载,旧版本继续服务,加载失败自动回退。

具体案例:某企业内部 LLM 服务最初用 FP32 精度部署,团队训练了 FP16 量化版本,期望降低显存占用量、提升吞吐。他们把量化模型放进 v2 目录,借助 Triton 轮询机制自动加载,随后用监控脚本对比两版的首 token 延迟和生成质量,确认无损后删除旧版本。

金融风控模型秒级回滚

阶段:风险控制与合规

解决的问题:风控模型的误杀率直接关系用户投诉和资损。新模型上线后一旦发现拒绝率异常,必须秒级切回旧模型。Triton 保留多个版本并支持客户端快速切换路由,让回滚变成“改一个开关”的事。

具体案例:某金融科技公司的反欺诈团队在 Triton 中保留 v1(稳健版)和 v2(激进版),灰度期间监控到 v2 的误杀率比 v1 高出 1.5 个百分点后,立即在路由配置中把流量全部切回 v1,整个过程不到 1 分钟,期间无请求中断。

Python 演示

python80 行
#!/usr/bin/env python3# -*- coding: utf-8 -*-"""Simulate Triton model repository version management and gray release."""import osimport random  MODEL_NAME = "quality_check"REPO_ROOT = "./model_repository"REQUIRED_FILES = ["model.pt", "config.pbtxt"]  def build_repo(model_name=MODEL_NAME, versions=(1, 2, 3), root=REPO_ROOT):    """Create the standard Triton repository directory layout."""    paths = []    for ver in versions:        vdir = os.path.join(root, model_name, str(ver))        os.makedirs(vdir, exist_ok=True)        for fname in REQUIRED_FILES:            path = os.path.join(vdir, fname)            if not os.path.exists(path):                with open(path, "w", encoding="utf-8") as f:                    f.write("# placeholder: %s v%s\n" % (model_name, ver))        paths.append(vdir)    return paths  def gen_config(policy="latest", num_versions=2, versions=(1, 3)):    """Generate config.pbtxt with latest or specific version policy."""    head = [        "name: \"%s\"" % MODEL_NAME,        "platform: \"pytorch_libtorch\"",        "max_batch_size: 8",    ]    if policy == "specific":        policy_block = ["version_policy {", "  specific {"]        for v in versions:            policy_block.append("    versions: %d" % v)        policy_block.append("  }")        policy_block.append("}")    else:        policy_block = [            "version_policy {",            "  latest {",            "    num_versions: %d" % num_versions,            "  }",            "}",        ]    return "\n".join(head + policy_block) + "\n"  def gray_release(weight_new=0.2, total_reqs=10000):    """Route requests by ratio: weight_new goes to v3, the rest to v2."""    cnt_old = 0    cnt_new = 0    random.seed(42)    for _ in range(total_reqs):        if random.random() < weight_new:            cnt_new += 1        else:            cnt_old += 1    return cnt_old, cnt_new  def main():    paths = build_repo()    print("repository built:")    for p in paths:        print("  " + p)    cfg = gen_config(policy="latest", num_versions=2)    print("config.pbtxt:")    print(cfg)    old_cnt, new_cnt = gray_release(weight_new=0.2, total_reqs=10000)    total = old_cnt + new_cnt    print("old v2 = %d (%.1f%%), new v3 = %d (%.1f%%)" % (        old_cnt, old_cnt * 100.0 / total, new_cnt, new_cnt * 100.0 / total))  if __name__ == "__main__":    main()
目的:用 Python 模拟 Triton 模型仓库的标准目录搭建、版本策略配置生成,以及灰度发布中的流量分配逻辑。
  1. os.path.join(root, model_name, str(ver))拼出“仓库根目录 / 模型名 / 版本号”三层路径,对应菜谱档案柜的抽屉编号。
  2. os.makedirs(vdir, exist_ok=True)自动创建版本目录,目录名就是版本号,有同名也不报错。
  3. with open(path, "w", encoding="utf-8") as f:写入占位的模型文件和配置,真实项目中这里放的是模型权重。
  4. "name: \"%s\"" % MODEL_NAME生成 config.pbtxt 中的模型名声明,Triton 靠它识别模型。
  5. " versions: %d" % v生成 specific 策略的版本枚举行,明确指定加载哪些版本号。
  6. if random.random() < weight_new:按灰度比例 α 决定当前请求去新版本还是旧版本,这就是客户端分流的本质。
  7. random.seed(42)固定随机种子,保证流量分配结果可复现,方便测试验证。

常见误区

误区我以为模型版本目录必须按照 1、2、3 连续排列,中间缺一个数字 Triton 就会报错,所以每次升级都要补全所有编号。

正解版本号只需要是正整数,完全不需要连续。Triton 会扫描目录下的所有数字子目录,latest 策略取其中编号最大的 N 个。比如目录里只有 1 和 3,num_versions: 2 时会把 1 和 3 都加载进来。就像菜谱修订版可以跳过 2 直接出 3,厨师不会因为少了一版就炒不了菜。

为何常见:日常开发中版本号习惯从 1 连续递增,大家容易把这种工程习惯当成框架的硬性约束。

误区升级模型后旧版本占磁盘又占显存,既然不用了就应该立刻删掉,反正留着也是浪费。

正解旧版本是回滚的安全垫。灰度期间新旧版本必须共存,一旦新版本指标异常,要立刻把流量切回旧版本。而且注意区分:只有被策略选中加载的版本才占显存,没被选中的旧版本目录只占磁盘,成本很低。正确做法是等新版本稳定运行一段时间后再清理旧版本目录。

为何常见:磁盘和显存紧张时第一反应就是“删文件释放空间”,但忽略了版本管理最重要的回滚价值。

误区我以为把新版本放进目录、改一下 config.pbtxt 里的版本策略,Triton 就会自动把 20% 的流量切给新版本。

正解改配置只是让 Triton 加载新版本,流量如何分配由调用方决定。Triton 负责“多版本都在、按策略提供服务”,但“这 100 个请求里哪些去 v3”需要客户端自己根据随机数、用户 ID 哈希等规则路由。把流量分配写成服务端自动完成,是初学者最常见的误解。

为何常见:“服务端能加载多版本”和“服务端会自动分流”是两件不同的事,容易混为一谈。

误区换个模型版本肯定要重启 Triton 服务,不然新目录不会被识别,重启一下最稳妥。

正解Triton 默认通过轮询机制定期扫描模型仓库,新版本目录就绪且文件完整时,它会自动加载,不需要重启进程。加载失败时旧版本继续服务,请求不中断。重启反而会造成服务停摆,是最不应该采用的方式。只有当配置了 model_control_mode: explicit 时才需要用 API 手动触发加载,但也比重启优雅得多。

为何常见:传统服务改配置基本都要重启进程,惯性思维让人忽略了 Triton 动态加载的设计。

面试题

Q1. Triton 模型仓库最基本的目录层级是?

单选题 · easy

  • A.仓库/模型名/版本号/模型文件← 正确答案
  • B.仓库/版本号/模型名/模型文件
  • C.模型名/仓库/版本号/模型文件
  • D.任意目录结构都可自动识别

答案:A。Triton 要求标准的四层结构:仓库根目录下先按模型名分目录,再在模型目录下按版本号分子目录,模型文件放在版本目录里。好比档案柜“柜号/抽屉/夹层/菜谱纸”的顺序,乱放系统就找不到。

Q2. latest 策略中 num_versions: 2 的含义是?

单选题 · easy

  • A.只加载编号最大的两个版本← 正确答案
  • B.每个请求都加载两份副本
  • C.模型必须同时运行两个实例
  • D.版本号必须设置为数字二

答案:A。num_versions 表示“最多加载最大的几个版本”。比如仓库里有 v1、v2、v3,设置 2 就加载 v3 和 v2,但只有最大那个 v3 对外服务。这是 latest 策略的核心配置。

Q3. 灰度发布中,流量按比例路由到新旧版本通常由谁实现?

单选题 · mid

  • A.修改配置文件中的版本策略
  • B.客户端按比例路由到不同版本← 正确答案
  • C.重启服务器来切换新老版本
  • D.删除旧版本目录强制走新版

答案:B。Triton 负责把多个版本都加载好,但流量分配是调用方的责任。客户端按随机数、用户 ID 哈希等规则把一部分请求打到新版本,这就是灰度发布的流量分配环节。

Q4. 关于 specific 策略与 latest 策略的区别,正确的是?

单选题 · mid

  • A.特定版本 vs 最新版本策略← 正确答案
  • B.两者本质上完全相同无差异
  • C.specific 仅支持 TensorFlow
  • D.latest 可以指定任意版本号

答案:A。specific 策略需要显式列出要加载的版本编号,只加载这些;latest 策略自动加载编号最大的 N 个。前者像“只认特定配方”,后者像“自动用最新配方”。两者的加载逻辑完全不同。

Q5. 关于 Triton 热切换,下列说法正确的是?

单选题 · mid

  • A.必须重启服务才能加载新版本
  • B.热切换会丢弃所有在途请求
  • C.新版本就绪后自动加载服务← 正确答案
  • D.热切换只能应用于 GPU 模型

答案:C。Triton 默认轮询模型仓库,新版本目录就绪且文件完整时自动加载,正在处理的请求继续跑完,整个过程不重启、不丢请求,CPU 和 GPU 模型都支持。这就是“不关店换菜单”。

Q6. 模型仓库中的版本目录名必须满足哪个条件?

单选题 · mid

  • A.任意字符串都可以作为目录名
  • B.必须是大于零的正整数编号← 正确答案
  • C.必须从零开始的连续整数编号
  • D.带字母前缀的数字编号形式

答案:B。Triton 只认正整数目录名作为版本号,不要求连续,不允许字母、小数或负数。版本号是 Triton 识别“哪版配方”的唯一依据,命名错了直接加载失败。

Q7. 多个版本同时存在时,Triton 对外服务的方式是?

单选题 · hard

  • A.所有版本轮询参与推理负载均衡
  • B.只有策略选中的版本对外服务← 正确答案
  • C.所有版本随机选择参与推理
  • D.每次只允许一个模型版本存在

答案:B。多个版本可以同时加载到显存,但对外提供推理服务的只有策略选中的那个(如 latest 中编号最大的版本)。其他加载的版本更像备胎,不对外接客。这与负载均衡是完全不同的概念。

Q8. 以下属于 Triton 版本策略的是?

多选题 · easy

  • A.latest 策略按最新加载← 正确答案
  • B.specific 策略按指定加载← 正确答案
  • C.random 策略随机加载版本
  • D.poll 策略定时扫描加载

答案:AB。Triton 的 version_policy 支持 latest、specific、all 三种。random 不是合法策略,poll 是指模型控制模式(轮询扫描)而不是版本策略,两者容易混淆。

Q9. 灰度发布的正确步骤包括?

多选题 · mid

  • A.先构建新版本到模型仓库中← 正确答案
  • B.验证新版本推理结果正确← 正确答案
  • C.逐步加大新版本的流量比例← 正确答案
  • D.立即删除旧版本释放资源

答案:ABC。灰度发布先要把新版本放进仓库并验证单个请求正确,然后从小比例流量开始逐步放大,全程监控指标。旧版本是回滚的安全垫,绝不能一开始就删除,否则新版本出问题就无路可退。

Q10. 关于 Triton 版本切换与回退,正确的有?

多选题 · hard

  • A.新版加载失败时自动回退旧版← 正确答案
  • B.latest 加载失败仍保留旧版本← 正确答案
  • C.specific 版本缺失时模型报错← 正确答案
  • D.版本切换必须重启整个服务

答案:ABC。新版本加载失败时旧版本继续服务,这是 Triton 保证可用性的关键机制;latest 策略下最新的加载失败也不影响次新版本;specific 指定的版本缺失会导致该模型报错。而版本切换完全不需要重启服务,热切换就是为此设计的。