AI开发全自动装配线:PAI机器学习平台六道工序与落地实践 AI 开发这件事最贵的从来不是那张显卡而是人天。我在几个不同规模的团队里都见过同一个场景算法同学本地跑通了一个脚本效果还不错但要把它变成线上能扛住流量的服务中间还得有人接数据、有人配环境、有人写调度、有人做监控一来二去三个月就过去了模型还没上线业务方的耐心先没了。PAI 这类一站式机器学习平台要解决的正是这段从脚本到服务的断层——它把 AI 开发拆成数据、开发、训练、调优、部署、治理几段标准工序用一条全自动装配线的方式把它们串起来。这篇就聊聊这条装配线到底由哪些工位组成、每道工序背后的取舍逻辑是什么、以及怎么在自己的项目里把它真正跑顺。不管你是刚接触机器学习平台的新手还是已经在用 Notebook 单打独斗很久的老兵下面这些内容应该都能对上你的某个痛点。1. 先搞清楚这条装配线到底在装配什么很多人第一次打开这类平台的控制台看到一堆产品缩写——DSW、DLC、EAS、Designer、AutoML——第一反应是功能真多第二反应是我该从哪进。这其实是个很典型的误判把它当成一个功能集合去看永远理不清把它当成一条有工序顺序的产线去看马上就通了。装配线的价值不在于零件多而在于零件之间的接口是标准化的上一道工序的产出能直接喂给下一道不需要人工搬运。1.1 作坊式建模的天花板到底卡在哪先说清楚问题才知道平台在补什么。一个典型的小团队做模型流程大概是业务给一批 Excel 或者几万张图算法同学在自己电脑上清洗、写训练脚本、调参、跑通、导出模型然后找后端同学写个 Flask 接口包一层扔到一台机器上完事。这套做法在验证阶段完全够用甚至效率很高但它有三个绕不过去的天花板。第一个天花板是环境不可复现。本地装的 torch 版本、CUDA 版本、某个依赖的 commit全靠记忆三个月后想复现一版效果装环境能装两天。第二个天花板是算力不匹配。本地一张 24G 卡调参调到一半发现 batch 上不去、模型塞不下换到集群又要重写启动逻辑。第三个天花板是交付断层。训练脚本是脚本服务是服务两者之间的模型格式、预处理逻辑、特征工程代码经常对不上线上效果比离线差一截排查起来极其痛苦。这三个问题单独看都不致命叠在一起就成了模型永远在 POC 阶段的根本原因。装配线的设计目标说白了就是把这三件事分别标准化环境用镜像固化、算力用资源组调度、交付用统一的模型注册和服务协议打通。1.2 一条完整的 AI 产线该有哪几道工序把 AI 开发类比成制造业工序其实很清晰。来料是原始数据和标注打样是交互式的探索性开发批量生产是提交式的大规模训练质检是评估和调优打包出库是模型注册与服务部署售后是线上监控、数据回流和再训练。这六段里任何一段用手工方式做都会成为整条线的瓶颈。PAI 的组件划分基本就是照着这六道工序来的对应关系大致是这样工序对应组件解决的核心问题数据接入与标注数据集管理、智能标注数据版本混乱、标注成本高交互式开发DSW Notebook 实例环境可复现、算力按需申请提交式训练DLC 训练任务分布式、断点续训、队列调度自动调优AutoML、超参搜索人工调参的边际收益递减模型管理模型注册与版本模型资产可追溯、可回滚在线服务EAS 推理服务弹性扩缩容、灰度发布流程编排Pipeline、可视化建模把上面几步串成可重复执行的流水线提示组件名各家叫法不同不必死记缩写记住数据—开发—训练—调优—服务—编排这个顺序就够了换平台也是这套逻辑。1.3 为什么装配线比工具箱更值钱这是我最想强调的一点。一个平台如果只是把 Jupyter、TensorBoard、分布式训练框架、模型服务框架打包在一起那它就是一个工具箱价值有限因为这些东西你自己也能装。装配线的真正价值在接口标准化DSW 里写的代码改几行就能提交成 DLC 任务DLC 训练产出的模型注册后能被 EAS 直接拉起来Pipeline 能把取数—训练—评估—部署定义成一个带参数的模板下次换个数据集点一下就能重跑。这个差别在做第一个模型时感受不到做到第五个、第十个模型时就是天壤之别。我见过一个团队前三个模型靠人肉堆第四个模型开始失控谁改过哪份预处理代码、线上跑的是哪个 checkpoint、上次那个指标是怎么调出来的全在聊天记录里。装配线解决的正是这种模型资产化的问题它让模型从某个人的脚本产物变成组织的可管理资产。2. 六道工序逐个拆每个工位的取舍逻辑理解了整体结构接下来逐个工位看细节。这一段我会重点讲每个组件为什么这么设计因为只有理解了设计意图你才知道哪些默认配置可以信、哪些必须改。2.1 数据接入与标注来料检验是最容易被低估的一段数据这一段的坑几乎全部来自路径两个字。平台通常要求数据放在对象存储比如兼容 S3 协议的桶或者分布式文件系统里而不是你本地硬盘。这个设计不是为难人而是因为训练集群的机器是动态调度的今天这台明天那台本地盘存不住东西。我建议的做法是分层存放原始数据放一个只读的桶路径清洗后的中间数据放一个可写路径训练用的最终数据集再单独一份。听起来浪费存储但能省下巨量的排查时间——当成百上千个任务并发跑的时候你至少能确定数据被谁改过这件事不会发生。另一个必须建立的习惯是数据集版本化。平台的 Dataset 功能本质上是给一份数据打一个不可变的版本号训练任务引用版本号而不是路径。这么做的好处是半年后你还能准确说出当时那个 0.87 的指标是用哪份数据训出来的。我踩过一次坑清洗脚本改了一版重跑了训练指标涨了 2 个点团队高兴了半天后来发现是因为新数据里混进了一批之前被过滤掉的样本属于数据泄漏。如果当时数据集是版本化的这种问题一眼就能看出来。标注这块如果项目需要人工标注用平台的标注工具比自己搭一套划算得多主要省在权限管理和质检流程上。标注质量的控制技巧是先标 200 条做一致性校验让两个人独立标同一批算一下重合率重合率低于 85% 就先别往下标回去改标注规范。这个动作花半天能省掉后面返工两周。2.2 DSW 交互式开发这是打样工位不是生产工位DSW 就是一个托管的 Notebook 实例你可以选镜像、选卡型、选时长开出来直接在浏览器里写代码。听起来和自己电脑上装个 Jupyter 没区别但有两个关键差异值得说。第一个差异是镜像。平台提供的官方镜像已经把 CUDA、cuDNN、主流框架、常用加速库都配好了版本组合是经过验证的。这件事的价值在你需要换卡型的时候体现得最明显——本地 3090 上跑通的代码换到 A100 上大概率要重装环境而用镜像的话同一个镜像在两种卡上都能起。更进一步你可以基于官方镜像做自己的镜像把团队内部的工具包、私有依赖、常用脚本固化进去全组统一。我强烈建议把这个动作做掉它是环境可复现落地的唯一可靠方式。第二个差异是算力和生命周期。DSW 实例是按小时计费的你可以随时停掉。这里有个非常实用的习惯开发用小卡验证用大卡长任务一律提交出去。用一张小卡写代码、调数据管道等要大 batch 试效果的时候临时换成大卡跑几个小时跑完就停。千万别在 Notebook 里跑十几个小时的全量训练——Notebook 是交互式进程网络一抖、浏览器一关任务就断了而且占用的是宝贵的交互式资源配额。注意Notebook 里的变量状态是假持久的。你按顺序执行了几十个 cell中间某个 cell 改过又重跑过最终的变量状态可能和你从上到下重跑一遍完全不一样。上线前一定做一次 Restart Run All。2.3 DLC 提交式训练真正的批量生产车间DLC 是你把训练脚本提交上去、平台负责调度算力和容错的那套东西。它和 Notebook 的本质区别是任务是一次性的、无状态的、可重试的。这个设计带来的直接好处是断点续训和弹性容错——某台机器挂了任务自动重排从最近的 checkpoint 恢复不需要你盯着。从 Notebook 迁移到 DLC代码上要做三件事。第一把所有路径参数化从命令行参数或者环境变量读不要硬编码。第二加 checkpoint 保存和恢复逻辑按步数或者按时间定期存。第三把日志打到标准输出不要写到本地文件里平台采集的是 stdout。# 提交式任务的最小改造示意 import argparse, os, torch parser argparse.ArgumentParser() parser.add_argument(--data_dir, typestr, requiredTrue) parser.add_argument(--ckpt_dir, typestr, requiredTrue) parser.add_argument(--epochs, typeint, default3) parser.add_argument(--batch_size, typeint, default32) parser.add_argument(--lr, typefloat, default1e-4) args parser.parse_args() start_epoch 0 latest os.path.join(args.ckpt_dir, latest.pt) if os.path.exists(latest): state torch.load(latest) model.load_state_dict(state[model]) start_epoch state[epoch] 1 print(f[resume] from epoch {start_epoch}, flushTrue) for ep in range(start_epoch, args.epochs): train_one_epoch(...) torch.save({model: model.state_dict(), epoch: ep}, latest) print(f[epoch {ep}] loss{loss:.4f}, flushTrue) # 关键flushflushTrue这个细节看着不起眼但很关键。Python 的 stdout 默认是带缓冲的不加 flush 的话日志可能在缓冲区里卡着你在控制台上看到的是任务跑了但没日志白白浪费时间排查。分布式训练的启动方式平台一般支持几种框架原生的 job 类型PyTorch 的 torchrun、MPI 等你只需要在提交时声明节点数、每节点卡数和启动命令剩下的通信配置平台会注入环境变量。这里有个常见误解不是所有训练都适合分布式。数据并行在单卡能吃下模型的前提下收益明显但如果模型本身单卡放不下就得上模型并行或者 ZeRO 之类的切分策略配置复杂度会陡增。我的经验是先用单机 8 卡把流程跑通确认吞吐和收敛都正常再考虑多机。2.4 AutoML 与超参搜索自动质检不是万能质检超参搜索的逻辑很朴素给定搜索空间和评估指标让系统自动跑一堆组合找出最好的那组。它的价值取决于两个前提——你的搜索空间设计得合理以及单次训练足够快。如果单次训练要 20 小时跑 50 组就是 1000 卡时成本上完全不划算。这种情况下更实用的做法是先在小数据集上做粗搜比如用 10% 数据、3 个 epoch锁定学习率和 batch size 的量级再用全量数据在小区间内细搜。我一般的操作是两阶段第一阶段用贝叶斯优化跑 20-30 组第二阶段在最优解附近手动微调 5-8 组效果和成本比一次大搜好得多。学习率和 batch size 的关系值得单独说。线性缩放法则batch 翻倍lr 翻倍是常用的起点但它只在大 batch 的早期训练成立而且必须配 warmup。举个实际例子base 配置是 batch 32、lr 1e-4现在要上 8 卡数据并行每卡 batch 4、梯度累积 4 步global batch 就是 4×8×4128是原来的 4 倍。按线性缩放lr 可以先试 4e-4同时加 500 步 warmup。但实测下来 4e-4 往往会震荡2e-4 到 3e-4 更稳所以我的做法是把缩放结果当作上界往下探 2 个点各跑 200 步看 loss 曲线选不震荡的那个。AutoML 在结构化数据表格类上的表现通常比在视觉和 NLP 上更稳因为它本质是在搜索特征工程和模型超参的组合搜索空间相对可控。而深度学习任务的特征工程深度嵌在数据和网络结构里自动搜索的收益就没那么确定。这个差异在选型时要心里有数。2.5 EAS 模型服务出库打包的标准化模型训完最后一公里是把它变成一个能接受请求、能扩缩容、能灰度的在线服务。EAS 的设计思路是你提供一个模型文件或者镜像 一个推理入口平台负责拉起实例、挂负载均衡、做健康检查、按指标扩缩容。这里最容易被忽视的是预处理逻辑的一致性。训练时你对图片做了 resize、归一化推理时如果忘了做或者做错了参数模型不会报错只会静默地给出错误结果。解决办法只有一个把预处理代码和模型一起打成推理服务的一部分而不是放在调用方。如果预处理比较复杂建议直接自定义镜像把模型、预处理、后处理全部封进去这样线上和离线用的是同一份代码。服务上线后的容量规划用一个简单的估算就能避免大部分事故。假设压测单实例在 P99 延迟 200ms 的前提下能扛 50 QPS业务峰值是 300 QPS那至少需要 6 个实例做基线再留 30% 冗余就是 8 个。注意这里的 QPS 要按峰值算且要考虑模型加载时间——冷启动可能要 30 秒以上所以缩容不能太激进最好设一个最小实例数兜底。注意扩缩容的指标要选对。用 CPU 使用率做扩容指标对 GPU 推理服务基本没用因为 GPU 服务的瓶颈通常在显存或者请求队列长度CPU 可能一直是 20%。要么用请求排队时长要么用自定义的业务指标。2.6 模型注册与流程编排把工序串成一条线模型注册这一步很多小团队会跳过觉得我知道模型在哪。等到模型数量上了两位数这东西就成了刚需。它的核心作用是把模型变成一个带元数据的实体训练它的数据版本、超参、评估指标、训练任务 ID、谁提交的、什么时候从测试环境转到生产。有了这些出问题时你能在十分钟内定位到是哪次变更导致的而不是花两天去翻聊天记录。流程编排Pipeline是把前面几步串起来的粘合剂。它本质上是一个 DAG每个节点是一次操作可以是数据处理任务、训练任务、评估任务、部署任务节点之间用参数传递。定义一次之后换数据就能重跑甚至可以配定时触发或者数据更新触发。这才是全自动装配线真正名副其实的地方——前面那些组件是工位Pipeline 是传送带。3. 动手搭一条最小可用流水线光说概念没意义这一段我把一条从数据到服务的最小流水线从头到尾走一遍。需要说明的是下面的配置和参数是基于常见实践的合理示例具体字段名和可选值请以你所用平台的控制台或文档为准抄的时候对着模板改。3.1 第一步把资源账算清楚在开任何实例之前先算三笔账显存账、存储账、时间账。这三笔算不明白后面全是返工。显存账看的是模型能不能塞下。以 LoRA 微调一个 7B 参数的模型为例粗算过程是这样fp16 权重约 14GBLoRA 的可训练参数通常只占 0.1%-1%梯度很小忽略优化器如果用 Adam对可训练参数要存两份状态也很小真正吃显存的是激活值和 batch size、序列长度成正比。所以 24GB 卡在序列长度 1024、batch 1-2 的情况下勉强能跑但一开梯度检查点用时间换显存就舒服很多40GB 卡可以上到 batch 4-8。全参微调就是另一个量级了7B 全参用 Adam 基本要 80GB 以上需要 ZeRO-3 或者 FSDP 做切分。存储账看的是数据量和 IO 带宽。假设你有 100 万张图片平均每张 500KB总计约 500GB。如果直接从对象存储挂载读取单流带宽通常只有几十 MB/s 到一百多 MB/s一个 epoch 光读数据就要一个多小时GPU 全程在等。解决办法是把数据预先转成打包格式比如 tar shard 或者 webdataset或者干脆拷贝到高性能文件系统里这样顺序读能吃满带宽。按 200MB/s 算500GB 要 40 多分钟拷贝但一次拷贝能换来后续每轮训练几倍的加速非常划算。时间账算的是总预算。一次全量训练如果是 8 卡跑 10 小时就是 80 卡时超参搜索跑 30 组如果每组都是全量就是 2400 卡时明显不现实——这就是为什么前面强调粗搜要用小数据。把这三笔账写在纸上你才知道该申请什么规格的资源。3.2 第二步把 Notebook 代码改成可提交任务改造的核心原则是参数外置、状态外置、日志外置。参数外置前面说过用 argparse 或者配置文件状态外置指的是所有需要跨运行保留的东西模型权重、tokenizer、中间结果都写到持久化存储路径不能留在容器里日志外置就是只往 stdout 打。还有一个经常被忽略的点随机种子的设定。提交式任务在不同机器上跑环境变量、数据顺序、cuDNN 的非确定性算子都可能导致结果不一致。如果要做 A/B 对比务必固定 seed并开启框架的确定性开关PyTorch 的torch.use_deterministic_algorithms或者 cuBLAS 的环境变量代价是可能损失一点性能但换来的是可复现。# 提交任务时的典型启动配置示意字段名以平台实际为准 # 节点数: 1 # 每节点 GPU: 8 # 镜像: 自定义镜像 registry/xxx/pytorch:2.x-cu12x # 启动命令: torchrun --nproc_per_node8 --nnodes1 \ train.py \ --data_dir /mnt/data/v3/train \ --ckpt_dir /mnt/exp/run_0427 \ --epochs 5 \ --batch_size 4 \ --lr 2e-4把nproc_per_node设成每节点的卡数平台会自动注入 master 地址和端口你不需要手动配MASTER_ADDR。这一点比自己在物理机上搭分布式省太多事了。3.3 第三步配置一次分布式训练并验证吞吐配置好之后别急着跑全量。先跑 100 步看两个数字每步耗时和显存占用。每步耗时的稳定性比绝对值更重要——如果耗时在 0.8s 和 2.5s 之间来回跳说明数据加载是瓶颈GPU 在等数据。分布式训练最容易出的问题是数据加载。如果是多机每个节点都要读数据如果所有节点都从同一个远端路径读带宽会被瞬间打满。解决办法是让每个节点先把自己需要的那份数据拉到本地或者用带本地缓存的文件系统。另外DataLoader 的num_workers要设成 CPU 核数的 2-4 倍prefetch_factor适当调大这两项对吞吐的影响经常比换卡还明显。通信方面如果多机训练时发现 GPU 利用率忽高忽低先看通信是否走了高速网络。规模小的时候问题不大节点数上去之后通信会成为主要瓶颈这时候梯度累积就成了救命稻草——每一步多累积几个 micro-batch等价于放大了 global batch但通信次数减少性价比很高。3.4 第四步把模型送进服务并做一次灰度训练产出 checkpoint 之后标准动作是先在一个固定的评测集上跑评估把指标写进模型的元数据然后注册成模型的一个版本接着部署成一个服务先给一小部分流量比如 5%做灰度对比新老版本的业务指标确认没有回退再全量。灰度这一步别省。我见过不止一次离线指标涨了上线后核心业务指标反而掉了原因是离线评测集和真实流量分布不一致。灰度是唯一能在小成本下发现这个问题的手段。灰度期间要盯的不只是模型的 AUC 或者准确率还要盯延迟和错误率——新模型可能更准但更慢慢到超时之后整体体验就崩了。服务配置里有几个参数值得调。实例数至少设 2避免单点最小实例数不要设 0冷启动的几十秒对线上体验是致命的批处理如果框架支持把多个请求合成一个 batch 推理能显著提升吞吐但会增加单请求延迟需要按业务容忍度权衡。3.5 第五步用 Pipeline 把整套动作串成模板最后一步是把上面这套动作定义成一个可重复执行的流水线。结构大致是节点输入输出触发条件数据校验原始数据版本校验报告数据更新数据预处理原始数据训练集/验证集校验通过训练训练集 超参checkpoint预处理完成评估checkpoint 验证集指标 JSON训练完成条件分支指标 JSON是否继续指标达标注册模型checkpoint 指标模型版本分支通过灰度部署模型版本服务人工确认这个模板的价值在于下次数据集更新了你只需要触发一次中间所有步骤自动跑跑完给你一个可评估的模型版本。需要人工介入的只有最后一步的放量确认——把人的判断放在最该放的位置而不是让人去做搬运。4. 排查实录流水线上真正会卡住你的坑理论讲完说点真实的。下面这些是我在实际项目里反复遇到的按出现频率排。4.1 资源与配额任务一直处于排队状态最典型的现象是任务提交后一直 pending不是失败就是不起。原因通常是资源组配额不足——你要 8 卡但这个资源组当前可用只有 4 卡。排查顺序是先看任务的资源申请值和资源组的可用量再看是不是有别的任务占着。有些团队会开一堆 Notebook 实例长期挂着把交互式配额吃光了导致提交式任务排不上队。解决办法有两个层面。管理上给 DSW 设空闲自动停止策略超过 2 小时无操作自动关机这一条能省下大量浪费。技术上把长任务都迁到提交式让资源池的利用率可控。另外训练任务要设置优先级重要任务排前面探索性的任务用低优先级可以插空跑。4.2 数据路径与 IO任务跑起来了但慢得离谱现象是 GPU 利用率长期在 10%-30% 之间训练慢但没报错。九成是 IO 问题。排查方法很简单在任务里加一段纯读数据的基准测试跑 30 秒看实际吞吐。如果只有几十 MB/s而你预期是几百 MB/s那就是路径问题。常见的三个原因一是直接挂载远端存储读小文件大量随机小 IO 把带宽吃光二是num_workers设成了 0 或 1数据加载单线程三是数据格式不适合流式读比如百万张散图。对应的解法是转打包格式、调大 worker 数、预先拷贝到高性能存储。这套组合拳下来通常能把训练速度提 2-5 倍。提示路径问题里最隐蔽的一种是相对路径。本地跑的时候工作目录是你的项目目录提交到集群后工作目录变了相对路径全失效。统一用绝对路径或者用环境变量注入。4.3 分布式训练能启动但收敛异常多卡跑起来 loss 曲线和单卡完全不一样常见原因有三个。第一学习率没按 global batch 调整batch 翻了几倍但 lr 没动等价于有效学习率变小收敛变慢。第二每个进程的随机种子一样数据增广出来的图完全相同等于 batch 里有一半是重复样本。第三BatchNorm 在数据并行下统计量是按单卡算的卡数变化会改变有效 batch 的统计特性模型小时影响明显。第一个按前面说的缩放规则处理配 warmup。第二个要给每个 rank 设不同种子seed base_seed rank。第三个的解法是换 GroupNorm 或者 SyncBN或者干脆把 batch size 保持和单卡时一致用梯度累积扩 batch。4.4 推理服务压测正常线上抖动压测时 P99 很好上线后偶发超时。这类问题往往和资源争抢有关同一台机器上跑多个服务实例显存被互相挤占或者扩缩容触发太频繁实例反复启停。排查时先看实例的显存和 GPU 利用率曲线看是否有明显的尖峰再看扩容日志如果十分钟内扩了又缩了三次那就是阈值设得太敏感。稳定性优化上我一般会做三件事设最小实例数不低于 2把扩缩容的冷却时间设长一点比如扩容后 5 分钟内不再缩给服务加一个预热接口实例启动后先跑几次空推理把 CUDA kernel 编译和显存分配都做完再接入流量。第三件事对首请求延迟的改善非常明显能从几秒降到几百毫秒。4.5 成本账单出来的那一刻才发现不对成本失控通常来自三个地方闲置的 Notebook 实例、跑飞的超参搜索、以及过度配置的推理实例。第一个靠自动关机策略第二个靠设置最大并发任务数和总预算上限第三个靠压测数据说话——很多服务被配了 4 卡实际单卡就能扛住全部流量。我建议每周看一次资源使用报表重点看两个指标资源组的平均 GPU 利用率以及各个服务的实际 QPS 与配置容量的比值。前者低于 30% 说明整体浪费后者低于 20% 说明实例配多了。这两个数字看一眼通常能省下 30% 以上的成本。4.6 常见问题速查表现象最可能原因快速验证方式处理动作任务长期 pending资源配额不足查资源组可用卡数调低申请值或换资源组训练极慢、GPU 空转数据 IO 瓶颈单独跑读数据基准转打包格式、加 worker多卡 loss 异常lr 未适配、种子重复对比单卡曲线调 lr、加 warmup、分 rank 种子服务偶发超时显存争抢、扩缩频繁看显存尖峰与扩容日志设最小实例、加冷却、预热线上效果回退预处理不一致对比离线特征与线上入参预处理打进推理镜像复现不出历史指标数据或环境漂移核对数据版本与镜像 tag数据集版本化、镜像固定 tag5. 选型判断什么团队该上什么团队别硬上装配线不是万能药它有明确适用边界。这一段说说我的判断标准帮你少走弯路。5.1 三类最适合上这条线的团队第一类是模型数量超过 5 个、需要长期维护的团队。数量一上来资产管理和流程复用带来的收益就指数级增长。第二类是算力需求波动大的团队平时用不了几卡偶尔要跑一次大训练自建集群利用率太低按需申请明显更经济。第三类是多人协作、需要权限和审计的团队谁提交了什么任务、用了多少资源、谁把模型放上了生产这些在平台上是天然留痕的靠人管很难。还有一个隐形但很重要的适用场景需要快速验证的新方向。预置镜像和模型库能让你在半天内跑通一个开源模型的微调比从零搭环境快太多。探索期的效率提升往往比生产期的稳定更重要。5.2 三种别急着上的情况第一种只有一个模型、一个算法同学、短期不打算扩。这种情况下平台的抽象层反而是负担装个环境、写个脚本、租台机器成本更低灵活性更高。第二种对底层有强定制需求比如要改框架的通信层、要特定的内核优化、要极致的性能调优托管平台的可控性不够自建更合适。第三种数据合规要求极高、不能出内网这个要看具体部署形态能不能满足不能满足就别勉强。另外提醒一句不要在项目最紧的时候做平台迁移。迁移本身有学习成本主线任务压着的时候做很容易两边都做不好。5.3 自建与用平台的一笔简化账粗算一下自建一套 8 卡机器硬件加机房加运维年化成本不低而且利用率通常只有三四成。用平台的按量计费单卡时价格看着贵但只有真正跑的时候才花钱如果月均使用时长不到满负荷的一半用平台往往更省。当然这只是纯算力账人的时间没算进去——自建要有人维护驱动、监控、调度这部分人力成本经常被忽略。我的经验判断是算法团队少于 5 人、算力需求不连续的项目优先用平台超过 10 人、算力需求稳定且持续的项目可以算算自建的账。中间地带看具体的资源波动情况。6. 几条让流水线真正跑顺的经验最后分享几个我认为最值钱的实践习惯都是踩过坑之后总结的。镜像一定要自己管。别长期用官方镜像直接跑生产任务官方镜像会更新某天 tag 变了你的结果就复现不出来。正确做法是基于官方镜像构建自己的镜像用明确的 tag甚至用 digest 固定。这个动作花半天能省未来无数次为什么结果不一样的排查。命名和标签规范要早定。实验目录、模型版本、服务名称统一用一套命名规则比如项目-任务-日期-序号。再配合标签团队、用途、数据版本后面做成本分摊和资产检索时会感谢自己。这个规范定晚了历史资产基本等于不可用。小步快跑别追求一步到位。我见过团队一上来就要搭一条全自动的流水线把数据、训练、评估、部署、监控全串起来结果两个月过去还在调编排。正确顺序是先把手动流程走通确认每个环节都能跑再把其中重复度最高的两步自动化逐步扩展。流水线是一步步长出来的不是一次设计出来的。保留一条离线可复现的路。平台再方便也要保证在脱离平台的环境里能跑通核心训练脚本。这不是不信任平台而是给自己留后路——换平台、做审计、给外部复现结果都用得上。具体做法是核心代码不依赖平台 SDK平台相关的部分数据读取、分布式启动用适配层隔离。监控指标要盯业务不要只盯模型。AUC 涨了但转化率没动说明模型优化的方向可能不对模型没变但线上效果掉了说明是数据分布漂移。这两种情况都只能靠业务指标发现纯看模型指标永远看不出来。把模型指标和业务指标放在同一张看板上是让 AI 项目真正产生价值的最后一步。实际操作下来我最深的体会是这类平台最大的价值不在于让你少写多少代码而在于强迫你把流程标准化。很多团队在自建的时候也知道该做版本管理、该做模型注册、该做灰度但因为没有工具约束永远排在待办列表最后。上了平台之后这些变成了默认路径不走反而更麻烦。这种顺手就把规范做了的效果比任何流程文档都管用。至于具体用哪个组件、怎么配参数反而是次要的——把工序想清楚工具怎么选都不会太离谱。