我见过太多从零起步的AI项目,死法都出奇一致:代码在笔记本上跑通了,demo演示很顺利,一上生产环境就崩。崩溃的原因几乎从来不是"模型不够聪明",而是整个工程体系根本撑不住真实的数据流、并发请求和迭代节奏。这几年我一直跟团队强调一个观点——AI工程(AI Engineering)的本质,不是从零训练一个模型,而是从零搭出"基础设施—数据—训练—部署—监控—迭代"这条完整的链路。
今天这篇就把我从零做AI工程的完整思路摊开来讲。内容包括算力选型、数据工程、训练调优、模型服务化、成本控制这些绕不开的环节,也会穿插一些只有亲手踩过坑才总结得出来的经验。适合正准备启动第一个系统级AI项目的工程师、想从算法岗往工程侧延伸的朋友,也包括那些已经跑通过几个demo、但始终上不了线的创业团队。如果你是第一次接触这个概念,我建议从头读;如果你已经在某个环节里挣扎,可以直接跳到对应章节。
1. 先对齐认知:AI工程是系统工程,不是"训练模型"
1.1 模型只占20%,剩下的80%是什么
很多人对AI工程的理解是:把PyTorch写熟,把模型训到收敛,然后把权重文件丢给后端。这是把AI工程窄化成"模型训练"了。实际情况是,一个AI系统从立项到稳定运行,模型算法部分通常只占到20%左右的工作量,剩下80%都花在数据治理、训练平台、部署链路、监控反馈、成本控制这些不显眼但决定成败的地方。
打个比方。你要开一家餐厅,菜谱和主厨手艺是核心竞争力,但真正决定餐厅能不能持续营业的,是供应链、后厨动线、出餐流程、服务团队和财务模型。AI模型就是那道招牌菜,AI工程则是整个餐厅的经营体系。菜再好,供应链断了、出餐太慢、顾客排队半小时,一样关门。
所以我在这篇文章开头想先做一件事:帮你把"AI工程到底在解什么题"的坐标系建立起来。如果你带着"调参炼丹"的预期来读,后面很多内容会显得啰嗦;如果你认同"让模型稳定交付价值"才是核心目标,那这篇文章的每一个章节都是你迟早要面对的问题。
1.2 从零到生产的人工智能工程链路
从零开始做一个AI工程,链路大致是:业务定义 → 数据获取与清洗 → 标注与划分 → 基线模型 → 训练迭代 → 评估与选择 → 模型导出 → 服务化部署 → 线上监控 → 反馈回流 → 再次迭代。这个链路呈飞轮状,不是一次走完就算结束的。
其中容易被新手忽略的是两端的环节。前端,"业务定义"决定你要解决什么问题、用什么指标衡量成功。很多项目败在对齐不到位:模型团队追求loss下降,业务方关心用户留存,两边聊不到一块。后端,"反馈回流"决定系统能不能随着数据分布变化持续进化。一次成功上线只是起点,之后会有数据漂移、badcase回流、模型版本管理等一系列问题等着你。
这篇文章的章节排序,就是按照这条链路从零到一展开的。你不需要一次性读完再动手,完全可以边做边回头查阅,但至少在大脑里要清楚:任何一个环节出问题,整个系统都会卡住。
2. 从零起步的算力与基础设施选型
2.1 自建机房、云GPU、抢占式实例,怎么选
算力是AI工程里最花钱也最容易选错的第一站。我见过有人一上来就采购了一整台8卡服务器,结果项目做了三个月就停在那吃灰;也见过创业团队只靠云上按需实例撑过了从零到十万用户的全过程。选型的核心逻辑不是"哪种最好",而是"你现在处在什么阶段"。
我自己常用的判断框架是这样的:
- 单人开发、还在验证想法阶段:优先云GPU按需实例,小时计费,随时释放,避免沉没成本。
- 团队有稳定训练需求、每天都要跑实验:可以用包月或预留实例,配合抢占式实例跑非关键实验。
- 卡常年满负荷、算力占比稳定超过70%:这时候才需要考虑自建或托管机房。
有一个容易被忽略的点:除了GPU本身,还要算上存储和带宽。很多团队卡在数据加载上,数据集几十个GB放在普通云盘上,每轮训练光读数据就浪费四分之一的时间。SSD云盘和更高的内网带宽虽然单价贵一点,但折算到训练时间上往往是划算的。
另外,算力一旦规模化,分配问题就会浮现。谁在用哪张卡、某个实验实际消耗了多少GPU小时、账单怎么拆分,这些在只有一两个人的时候无所谓,但到了七八个人的团队就会变成管理灾难。建议从第一天就养成记录GPU使用率的习惯,后面会轻松很多。
2.2 框架选型不是玄学
框架选型这个问题,每半年就有人拿出来吵一轮。我的结论很简单:从零开始的AI工程,默认选PyTorch,除非你有明确到无法忽视的理由去选别的。
PyTorch的优势在于:动态图调试友好,出错时的堆栈信息贴近源码,社区生态几乎覆盖了训练的每个环节——预训练模型库、数据集工具、分布式训练方案都是现成的。你遇到的大多数问题,在社区里都能搜到解法。
TensorFlow/Keras的优势在生产部署链路成熟,如果你所在团队的历史存量都在这个生态里,没必要强行迁移。JAX在科学计算和研究场景有优势,但工程配套相对需要自己拼装,从零起步的团队不推荐拿它当主力。
比框架选择更重要的,是固定版本。我一度在同一个项目里见过torch 1.13、2.0、2.1三个版本跑不同模块,复现一个线上问题要折腾半天。正确的做法是把CUDA版本、PyTorch版本、主要依赖库的精确版本号锁进环境配置文件里,任何人拉下来都能还原出完全一致的环境。
2.3 环境一致性是团队协作的第一道坎
"本地能跑,服务器崩"是我听过最多的求助。原因是绝大多数人把环境配置写在记忆里,而不是写进代码里。
从零开始,我建议至少做到三步:第一,用容器把训练和推理环境固化;第二,requirements锁定精确版本,不要用范围符号;第三,基础镜像固定tag,不要用latest。这三步听起来简单,真正做到位的团队比例比我预想的低很多。
容器化还有一个隐藏好处:它强制你把代码、数据路径、依赖关系显式化。当模型可以在一套全新环境中30分钟内从零跑起来,你的项目就具备了复现能力,这是后面所有工程化动作的地基。
3. 数据工程才是真正的护城河
3.1 先解决"数据从哪来,能不能用"
数据获取看起来最简单,实际上坑最多。从零起步时,你首先要想清楚数据来源的合法边界:公开数据集要看协议是否允许商用,爬取数据要评估是否涉及个人信息和版权保护的内容,企业内部数据要注意脱敏。这些不是法务部门的事,一线工程师必须自己有意识地建立红线意识,否则项目上线前会让团队陷入被动。
数据来源通常有三条路:公开数据集、业务埋点、人工采集。公开数据集上手快,但往往和真实场景有偏差;业务埋点是最佳数据源,但前期没有用户量就积累不出规模;人工采集质量高但成本大。一个务实策略是:先用公开数据集把流程跑通,同时开始设计和埋点采集,逐步用真实数据替换公共数据。
千万别迷信"数据越多越好"。脏数据带来的负面影响,一定大于数据量增加的正面收益。我见过一个文本分类项目,加了十万条爬虫数据后效果反而下降,查下来发现这些数据里有大量重复、错别字和标签错位,模型学到的是噪声,不是规律。
3.2 清洗与去重的实战:一次惨痛教训
说一个我自己经历过的案例。早年间做评论情感分析,从某平台爬了几万条评论,做了简单的字符串去重就开始训练。loss下降很漂亮,验证集表现也不错,一上线就露馅:大量相似评论被判断错,用户投诉量飙升。
排查了很久,最后发现根因是数据去重不到位。字符串完全一样的评论确实去掉了,但很多用户把同一句话复制后微调几个字,或者在不同话题下发布语义完全相同的评论,这些在训练集里以"看似不同、实则同源"的形式反复出现,导致模型对这部分高频模式严重过拟合。
从那之后,我的数据流水线里必做两步去重:精确去重用哈希,语义去重用向量化加聚类。具体做法是,把每条文本转成embedding向量,计算向量之间的相似度,把相似度高于阈值(比如0.85)的样本聚到一起,每组只保留一条代表样本。文本领域这个方案效果非常可靠;如果是图片或视频数据,也可以采用感知哈希加特征向量相似度的组合。数据质量差一个点,模型效果可能掉五个点,这句话一点不夸张。
3.3 标注规范、质检与一致性
监督学习绕不开人工标注。很多项目把标注当作"外包出去就完事"的工作,结果数据集里充满了标注员的个人理解偏差:同一类样本在不同标注员手里可能被分到不同类别,模型在这种混乱标签上训练,性能自然上不去。
我建议从零开始就建立一套轻量级的标注质量管理流程。第一,写清楚标注规范,规范里必须有明确的定义、正反例、边界情况和判定规则,最好配上可视化示例。第二,设置质检抽检环节,一般是5%到10%,抽检出的错误反馈给标注员修正。第三,定期计算标注一致性指标(比如Cohen's Kappa),低于阈值就要回头培训和统一标准。
这套流程可能让标注周期变长20%,但它给你带来的是干净可靠的训练信号。从工程角度讲,先把标注统一性做到健康值,再谈模型优化。
3.4 给数据集建模:版本、血缘与划分
很多人对数据集的保管方式就是硬盘里放一个文件夹,今天改一版,明天再改一版,最后根本分不清哪个版本对应哪次训练。代码有版本管理,数据集也必须要有。
我的实践习惯是在项目内规划一个标准化的数据目录:原始数据放raw目录,永远只读;清洗后放processed目录;划分好的训练、验证、测试集放split目录。每次生成数据集时,记录生成脚本、数据来源、数据量、标签分布,写进一个数据清单文件。这样任何一个时间点,你都能回溯出"这次模型是用什么数据训出来的",对排查线上问题和复现实验结果帮助极大。
同时要保留一套固定的测试集,用来做不同版本模型的对比评估。这套测试集可以定期更新,但要避免用测试集去做训练时的early stopping,否则就污染了评估的独立性。测试集是你的底线,底裤不能乱动。
4. 模型训练与迭代:从能跑通到收敛体面
4.1 第一个目标不是指标,而是链路通畅
新手拿到数据后的第一反应通常是直接上大模型、满怀期待地等loss下降。但我的建议正好相反:第一次训练要刻意用一个小模型、小批量、极短的epoch数,目标只有一个——确认整条训练链路是通的:数据加载没有Bug,标签和输入对得上,损失函数能正常计算,梯度能正常回传,显存没有泄漏。
这个阶段花不了多少时间,但能把很多隐患提前暴露。我见过太多人花两小时调了一个大模型,结果第500步才发现训练循环把标签写错位了,整个实验直接作废。小模型快速冒烟测试成本极低,收益率却极高。
冒烟测试通过后,再切到正式模型和全量数据训练。这时候也不要急着锁定参数,先观察前几百步的loss曲线是否在缓慢下降、学习率是否导致loss发散。这些信号是后续调参的起点。
4.2 训练日志里到底要记录哪些值
我见过不少团队的训练日志只有一行loss,其他全靠脑补。排查问题的时候只能靠猜,效率极低。
我自己训练时一定会记录下面这些字段:
| 字段 | 作用 |
|---|---|
| train loss | 确认模型在训练集上是否在学 |
| val loss / val metric | 确认泛化能力,防止只看训练loss陷入乐观 |
| learning rate | 确认学习率调度是否正确生效 |
| gradient norm | 判断是否梯度爆炸或消失 |
| GPU显存占用 | 判断显存分配是否稳定、是否需要调整batch size |
| 每epoch耗时 | 预测整体训练时间、判断是否遇到效率瓶颈 |
| token/s或样本/s | 数据加载、计算之间是否存在瓶颈 |
这些指标全部写入结构化日志,配合实验管理工具,你才能在不同实验之间做横向对比。光针对loss调参数就像蒙着眼睛开车,偶然而又危险。
4.3 从过拟合到欠拟合,调整顺序怎么排
模型训练常见的病有两种:欠拟合(train loss降不下去)和过拟合(train loss很低但val loss很高)。很多人在调参时没有顺序,想到什么调什么,效果自然忽好忽坏。我常用的排查顺序是:
先看train loss是否正常下降。如果train loss根本不降或降得极慢,优先检查学习率,太高会发散,太低会滞涩;调参时可以用学习率扫描,从1e-4到1e-2间隔几个数量级试一遍。如果train loss降了但val loss高,那就是过拟合,处理顺序是:先增加数据增强或正则化,再考虑减小模型容量,最后才动网络结构。
还要留意loss震荡和不稳定。如果训练过程loss一直在剧烈波动,常见诱因是batch size太小或学习率太高。batch size小意味着梯度估计噪声大,损失面就波动大;此时可以加大batch size、降低学习率,或者引入梯度裁剪。
从零开始调模型,不要指望一步到位。把每一次实验当成一个有记录的观测,逐步缩小参数空间,最终得到的不是"某个参数值",而是一个对问题空间的稳定理解。
4.4 显存不足与训练加速的几个管用套路
显存不够是训练阶段出现频率最高的报错。最快的解法是减小batch size,但单纯减小batch size会影响训练稳定性。工程上更成熟的几个方案是:
- 梯度累积:小batch前向计算、反向累积梯度,攒到等效大batch再更新参数。效果上等价于大batch训练,显存占用却很小。
- 混合精度训练:用FP16计算、FP32存储权重,显存占用直接减半,多亏GPU架构对半精度的优化,训练速度通常还能提升。
- 梯度检查点:用重计算换显存,训练速度会略降,但在超大模型场景下是保命手段。
分布式训练是另一个话题。单机多卡用数据并行通常最容易落地;模型大到单卡放不下再考虑张量并行、流水线并行。我的建议是:先把上面三个单卡时代的技巧用好,再考虑分布式。过早引入分布式会让调试复杂度成倍上升,得不偿失。
5. 模型部署与服务化:最后一公里最考验工程力
5.1 从checkpoint到可推理的模型
训练得到的checkpoint并不能直接扔给后端,中间还有模型导出这一步。常见路径是:PyTorch模型先转成TorchScript或ONNX格式,再由推理框架加载。
导出过程中最容易踩的坑是动态形状问题。很多模型在训练时输入是固定的(batch, seq_len, dim),但上线后请求长度各不相同。如果导出时没有声明动态轴,推理框架会强制所有输入对齐到固定形状,要么报错要么浪费算力。导出前一定要确认模型能处理动态输入,或者在服务层做长度分桶。
如果追求极致推理性能,可以再走一步TensorRT之类的深度优化,它会在你的GPU型号上做算子融合和内存复用。但要注意,TensorRT的优化结果和硬件型号强绑定,换卡就要重新优化。前期建议先用ONNX配合推理框架跑通,性能不够时再做深度优化。
5.2 API服务化的常见形态:同步、异步与批处理
模型服务化最朴素的形态是同步请求:用户请求进来,模型前向推理,返回结果。但真实场景里同步推理往往会成为性能瓶颈。GPU最擅长的是批量计算,单条请求进去GPU利用率很低,延迟高还浪费算力。
我在实际项目中通常这样设计:在线推理接口做成同步式,适合交互延迟敏感的场景;离线批量任务用异步队列,请求先入队,后台批量攒够一定量或等待时间达到阈值再统一推理,显著提升吞吐量。还有一条重要原则:模型服务要和Web框架解耦。GPU推理进程和Web框架进程分开部署,Web层负责鉴权、限流、参数校验,GPU层专注推理,这样单点故障的影响面才可控。
有个真实教训。早期做的一个文本生成服务,直接把大模型和前端的HTTP框架揉在一个进程里,上线第一天被用户请求打爆,GPU显存直接OOM,服务一度崩溃。后来改成请求排队加动态batch,把单请求OOM变成了稳定的批量流式推理,同样的硬件条件下QPS涨了接近五倍。
5.3 模型上线前必须想清楚的灰度与兼容
模型上线不是把新权重一换就完事。新模型哪怕离线指标更好,线上出现badcase的概率依然存在,所以必须有灰度发布机制。
比较稳妥的做法是:新模型先以shadow流量模式跑一段时间,复制流量喂给新模型但返回结果不实际影响用户,用旧模型的结果做对照,评估新模型在真实输入上的表现,确认无误后再逐步放开流量。同时要保证历史版本的API兼容:模型输出的字段不能突然变化,如果确有升级必要,API要提供版本字段,并给旧版本留出足够的过渡期。
回滚预案同样重要。灰度过程中一旦发现问题,要能在几分钟内切回旧版本。这就要求模型服务本身是无状态的,权重文件、配置、代码分离管理,版本切换只是换一个加载路径。
5.4 线上监控与反馈闭环
模型上线后,真正的挑战才刚刚开始。现实世界的数据分布不是静止的,用户的用语习惯会变、业务策略会变、季节和热点都会影响输入分布,曾经的优秀模型可能悄悄退化。
线上监控至少要覆盖这几层:推理延迟的p50/p99、请求错误率、GPU利用率和显存水位。比这些更关键的是预测分布漂移。比如一个分类模型原来A类占比40%,某天开始A类占比慢慢涨到70%,这往往是输入分布已经变了。此时需要用最近一段线上数据重新做评估,并把badcase回流到标注和训练循环里。
很多团队的AI项目死就死在"模型上线即结束"。正确的心态是:上线是模型服务生命周期的开始,永久反馈闭环是它活下去的条件。没有反馈闭环的AI工程,就像一块无源之水,迟早会干涸。
6. 成本控制与团队协作:把AI工程变成可持续的事
6.1 一张实验账单提前算清楚
很多从零开始做AI的团队直到月底收到云账单才意识到成本失控,但那时已经晚了。成本控制的第一步是建立"一次实验多少钱"的心算能力。
估算公式很简单:单次训练成本 = GPU租赁单价 × GPU数量 × 单次实验时长。再乘以你一周要跑的实验次数,就能算出两周的技术验证预算。我在规划一个项目时,会先把所有预设实验列出来,估算总GPU小时数,再看预算是否匹配。如果超了,优先砍掉的是重复实验和探索性实验,而不是砍数据质量。
养成这个习惯还有个额外好处:它会倒逼你认真设计实验——每次跑之前想清楚验证什么、为什么非跑不可。很多团队跑了大量实验但收获寥寥,正是因为实验设计太随意。
6.2 用实验管理找回时间和心智
从零起步时靠Excel记录实验信息还勉强够用,但实验量一旦超过几十组,人的记忆和表格都会开始出错:上次那个效果最好的模型用的是哪个版本的数据?哪次跑出来loss最低但val崩溃,当时超参是什么?如果不记录下来,回头找答案可能要花一整天。
我强烈建议即使是小团队,也要尽早引入实验管理工具。用MLflow或者轻量的实验记录脚本,把每次实验的数据版本、代码commit、超参配置、训练日志、模型产物自动记录下来。这个积少成多的过程会在一个月后把你从"翻聊天记录找参数"的泥潭中拯救出来。
6.3 小团队别急着上大平台,先把三件事做对
我观察到一种误区:团队才三四个人,就开始讨论要不要上完整的MLOps平台和复杂流水线。我的建议是小团队从零开始,先把三件最基础的事做对:
第一,代码和环境的可复现性,容器化加版本锁定;第二,每次实验有完整记录,数据和代码可溯源到同一commit;第三,一份简洁的部署和回滚文档,确保任何一个成员在半小时内能把服务跑起来或切回旧版本。这三件事做到了,你的团队已经比大多数项目扎实。至于平台化和自动化流水线,等业务复杂度真正上来了再逐步推进,才顺理成章。
我在实际操作中最深的体会是:AI工程和传统软件开发有一个本质差异——前者每一步的结果都有随机性,模型不是"写完就结束",而是需要持续喂养和维护的活系统。从零开始做AI工程,最先要接受的就是这种不确定性和迭代节奏,然后围绕它设计你的工程体系。很多团队败在没有管理好这种不确定性,而不是模型技术不够先进。如果你现在就准备从零起步,先把数据、实验记录和反馈闭环这三件事扎扎实实做出来,后面的路会好走得多。