多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

从零构建AI工程:数据管道、模型训练到部署监控的完整链路实战

从零构建AI工程:数据管道、模型训练到部署监控的完整链路实战 很多刚入行的朋友一听到从零构建AI工程这几个字第一反应就是去搜各种框架文档、跑几个Demo、调几个API然后觉得自己算是入门了。但真到了要独立扛一个AI项目的时候问题就全冒出来了模型选型凭感觉、数据管道一跑就崩、上线之后延迟高得离谱、成本失控、效果还忽好忽坏。这些问题的根源其实不在于你某个工具用得熟不熟而在于你对整个AI工程链路的底层拼图缺少一张完整的地图。ai-engineering-from-scratch这个主题说的就是从最底层开始把AI工程当作一门系统工程来搭建而不是当作调包游戏来玩。它适合那些已经会写Python、懂一点机器学习基础但还没真正独立交付过一个完整AI系统的开发者也适合那些做了几年后端或数据工程想转AI方向但不知道从哪下手的同学。我自己的经验是真正拉开差距的不是你会不会用某个库而是你能不能在没有现成模板的情况下从数据、训练、评估、部署到监控把整条链路自己串起来并且知道每个环节为什么这么设计。这篇文章我会按照一个真实项目的推进顺序来展开从环境与思维准备到数据管道的搭建再到模型训练与评估的工程化最后落到部署、监控和成本控制。每一块我都会讲清楚为什么这么做以及我踩过哪些坑尽量让你看完之后能直接动手复现而不是停留在概念层面。1. 先把从零这件事想清楚AI工程到底在工程什么1.1 为什么大多数人学AI工程会走偏我见过太多人学AI的路径是这样的先学numpy和pandas然后学sklearn再学PyTorch接着跑一遍MNIST和CIFAR-10最后找个预训练模型微调一下觉得自己会了。这条路本身没错但它训练的是模型使用能力不是工程能力。两者的区别在于前者是在别人搭好的轨道上开车后者是要自己铺轨道、造车站、还得保证列车准点运行。AI工程的核心难点从来不是模型本身。模型是公开的论文是公开的权重也是公开的。真正难的是你的数据从哪来、怎么清洗、怎么版本化你的训练怎么复现、怎么追踪实验你的评估指标怎么定义、怎么防止过拟合到测试集你的模型怎么打包、怎么部署、怎么在流量波动时不崩上线之后效果衰减了你怎么发现、怎么回滚。这些东西没有任何一门课会系统教你因为它们太脏了不够性感但恰恰是决定项目生死的地方。所以from scratch的第一层含义不是让你从零实现一个Transformer而是让你从零搭建一套能支撑AI项目持续迭代的工程体系。这个认知转变非常关键想不清楚这一点你后面学再多工具都是散的。1.2 一个最小可用的AI工程骨架长什么样在动手之前我建议你先在脑子里建立一个最小骨架。一个能跑起来的AI工程项目至少包含五个部分数据层、训练层、评估层、服务层、监控层。数据层负责数据的采集、清洗、存储和版本管理训练层负责实验管理、超参配置、模型产出评估层负责离线指标和线上指标的对齐服务层负责模型推理的接口封装和性能优化监控层负责线上效果和数据漂移的追踪。这五层不是并列的而是有依赖关系的。数据层的质量决定训练层的上限评估层的设计决定你能不能信任服务层的结果监控层则是把线上反馈重新喂回数据层的闭环。很多人只做了中间两层前后都断了所以项目永远停留在Demo能跑上线就废的状态。我自己的做法是哪怕项目再小也先把这五层的目录结构和接口约定好。比如数据层统一用data/raw、data/processed、data/versioned三个目录训练层统一用配置文件驱动而不是硬编码参数评估层统一输出一份标准格式的评估报告。这些约定看起来是小事但它们决定了你三个月后还能不能看懂自己写的代码。1.3 工具选型别一上来就上重型武器新手最容易犯的错就是一上来就搭一套工业级的技术栈Kubernetes、MLflow、Feast、Airflow全套安排上。结果光环境就配了两周业务代码一行没写热情先耗光了。我的建议是工具选型要跟着项目阶段走而不是跟着最佳实践走。项目初期你需要的是一台能跑训练的机器、一个Git仓库、一个简单的配置文件系统。实验追踪用TensorBoard或者直接写日志文件就够了数据版本用DVC或者干脆用带时间戳的目录也能凑合。等到项目真的跑起来、需要多人协作了再逐步引入MLflow、Airflow这些工具。工具是解决问题的不是制造问题的。这里有个判断标准当你发现某个操作你重复做了三次以上并且每次都要手动记参数、手动对比结果的时候就是引入工具的时候。比如你开始记不清哪个模型是用哪组超参训出来的那就该上实验追踪了比如你开始搞混数据集的版本那就该上数据版本管理了。按需引入而不是按图索骥。2. 数据管道AI项目里最脏也最值钱的部分2.1 数据清洗不是跑个脚本而是一套可复现的流程我敢说一个AI项目70%的时间花在数据上而其中一半的时间花在重新处理数据上。为什么因为大多数人的数据清洗是一次性的脚本跑完就扔没有版本、没有日志、没有中间产物。等到模型效果不对想回溯的时候发现根本不知道当时用的是哪版数据。正确的做法是把数据清洗当成一条管道来设计。原始数据进raw目录只读不改清洗脚本从raw读输出到processed每一步清洗都记录输入输出的行数、字段变化、异常值处理情况最终用于训练的数据再固化到versioned目录带一个明确的版本号。这样任何时候你都能回答这个模型是用哪版数据训的。清洗脚本本身也要工程化。不要写成一坨几百行的process.py而是拆成独立的步骤函数每个函数只做一件事输入输出都是DataFrame或者文件路径。这样你可以单独测试每一步也可以灵活组合。我习惯用pandas配合pandera做数据校验在每一步之后断言数据符合预期比如用户ID不能为空金额必须大于0一旦不符合就报错中断而不是让脏数据悄悄流到下游。2.2 数据版本管理为什么Git不够用很多人觉得数据用Git管就行了反正也是文件。但Git是为代码设计的不是为数据设计的。一个几百MB的CSV文件提交几次仓库就膨胀到没法用了而且Git的diff对二进制数据毫无意义你根本看不出两版数据差在哪。数据版本管理的核心需求有三个能追溯、能对比、能回滚。轻量方案可以用DVC它把大文件存在外部存储Git里只存指针文件这样既能版本化又不撑爆仓库。重一点的方案可以用专门的feature store但对小项目来说过度了。我自己的习惯是如果数据量在GB级别以下用DVC加一个对象存储就够了如果数据每天都在变那就得考虑增量处理和快照机制。这里有个容易忽略的点数据版本不仅要管训练数据还要管特征工程之后的特征数据。因为特征工程逻辑一变同样的原始数据产出的特征就完全不同。所以特征数据的版本要和特征工程代码的版本绑定最好在特征文件里直接写入生成它的代码commit hash这样出问题能精确定位。2.3 数据漂移上线之后才想起它就晚了数据漂移是指线上数据的分布和训练数据不一致这是模型效果衰减的头号杀手。但大多数人是等线上效果掉了才去查那时候已经晚了。正确的做法是在数据管道里就埋好漂移检测。具体怎么做在训练时对每个关键特征计算统计量比如均值、方差、分位数、类别分布存成一份基线画像。上线之后定期对线上数据算同样的统计量和基线对比。如果某个特征的分布偏移超过阈值就触发告警。常用的指标有PSI群体稳定性指数和KL散度PSI大于0.2通常就值得警惕了。我踩过的坑是一开始只监控了数值特征忽略了类别特征。结果某个类别特征的取值集合悄悄变了模型对新增的类别完全没概念预测结果离谱。后来我把类别特征的取值覆盖率也纳入监控才算补上这个漏洞。所以漂移检测要覆盖所有输入特征不能只盯着数值型的。3. 训练与评估让实验可复现、结果可信3.1 实验管理别再用文件名记参数了我见过太多人的实验管理方式是model_v1.pth、model_v2_final.pth、model_v2_final_真的final.pth。这种命名方式在实验超过十个之后必然崩溃因为你根本记不清每个文件对应什么配置、什么数据、什么指标。实验管理的核心是配置驱动。把所有的超参、数据版本、模型结构参数写进一个配置文件YAML或JSON都行训练脚本只读配置不硬编码任何参数。每次训练产出一个独立的实验目录里面包含配置文件副本、训练日志、模型权重、评估结果。这样任何一个实验都是自包含的随时能复现。工具上轻量可以用TensorBoard加自己写的日志重一点用MLflow或者Weights Biases。我的建议是如果只是个人项目先把配置驱动和目录规范做好工具可以后加如果是团队协作那从一开始就上MLflow因为多人同时跑实验的时候没有统一的追踪平台会乱成一锅粥。3.2 评估指标离线好看不等于线上好用这是AI工程里最容易被低估的环节。很多人在离线测试集上刷到一个漂亮的指标就以为大功告成结果上线之后发现完全不是那么回事。原因通常有三个一是离线测试集和线上数据分布不一致二是离线指标和业务目标不对齐三是评估时用了未来信息造成数据泄漏。先说分布不一致。离线测试集通常是从历史数据里随机切出来的但线上数据是有时间顺序的而且会随着业务变化而漂移。所以更靠谱的做法是做时间切分用过去的数据训练用之后的数据测试这样更接近真实上线场景。如果业务有明显的周期性还要保证测试集覆盖完整的周期。再说指标对齐。比如你做一个推荐系统离线指标是AUC或者NDCG但业务真正关心的是点击率和转化率。这两个东西不总是一致有时候模型AUC更高但实际点击率反而低。所以评估阶段就要尽量引入业务指标哪怕是用离线数据做近似估计也比只看技术指标强。最后说数据泄漏这个坑太常见了。比如你在做用户流失预测特征里包含了用户最近一次登录时间而这个特征在预测时刻其实是未知的那就造成了泄漏。检测泄漏的一个笨办法是如果某个特征的 importance 高得离谱高到不合常理那大概率是泄漏了。我一般会专门做一轮去掉可疑特征的对比实验看指标掉多少掉得越多越可疑。3.3 交叉验证与超参搜索别把测试集当验证集用新手常犯的另一个错误是用测试集来调超参。调完之后报告的那个指标其实是过拟合到测试集上的没有任何参考价值。正确的做法是划分训练集、验证集、测试集三份超参在验证集上调最终模型只在测试集上评估一次。如果数据量小可以用交叉验证来充分利用数据。K折交叉验证把数据分成K份轮流用其中一份做验证其余做训练最后取平均。这样得到的评估更稳定但计算成本是K倍。我的经验是数据量在万级以下用5折交叉验证比较合适数据量大了就直接切分没必要交叉验证。超参搜索方面网格搜索在小空间里还行空间一大就爆炸。随机搜索在大多数情况下性价比更高因为高维空间里真正重要的维度往往只有几个随机采样反而更容易命中好区域。如果计算资源允许贝叶斯优化是更聪明的选择它会根据历史结果指导下一次采样但实现复杂度也更高。我一般先用随机搜索粗筛找到大致范围后再用网格搜索精调。4. 部署与服务化让模型真正跑起来4.1 模型打包别把训练代码直接搬上线训练环境和推理环境的需求是不一样的。训练需要完整的框架、数据处理库、GPU支持推理只需要模型权重和最小的依赖。如果你把训练代码整个搬到线上会带来一堆问题镜像体积巨大、启动慢、依赖冲突、安全风险高。正确的做法是把模型导出成独立的格式比如ONNX、TorchScript或者SavedModel然后用一个精简的推理服务加载它。推理服务只依赖必要的运行时不依赖训练时的那些库。这样镜像能小一个数量级启动速度也快很多。导出的时候要注意算子兼容性。不是所有的自定义算子都能顺利导出遇到不支持的算子要么改写要么用框架原生的等价实现。我踩过的坑是训练时用了一个自定义的激活函数导出ONNX的时候直接报错最后只能换成标准激活函数重新训练。所以如果你有上线计划训练阶段就尽量用标准算子别图一时方便。4.2 推理性能延迟和吞吐的权衡上线之后性能是绕不开的。推理性能有两个核心指标延迟单个请求的处理时间和吞吐单位时间能处理的请求数。这两个指标往往是矛盾的批处理能提高吞吐但会增加延迟因为要等一批凑齐。怎么权衡取决于业务场景。如果是实时交互场景比如搜索建议延迟必须控制在几十毫秒内那就得牺牲吞吐用小batch甚至单条推理。如果是离线批处理场景比如每天跑一遍用户画像那就可以用大batch把吞吐拉满。我一般会先明确业务的延迟要求再反推batch size和并发数。优化手段上模型量化是最直接有效的。把FP32量化成FP16或者INT8模型体积能减半甚至减到四分之一推理速度也能提升不少精度损失通常在可接受范围内。但量化不是无脑做的有些对精度敏感的任务量化后效果会明显下降所以量化后一定要重新评估。另外算子融合、KV缓存、动态批处理这些技术也能显著提升性能但实现复杂度更高建议按需引入。4.3 版本管理与灰度发布别一次性全量替换模型上线最忌讳的就是一次性全量替换。新模型万一有问题影响的是全部用户。正确的做法是灰度发布先让小部分流量走新模型观察一段时间确认指标正常再逐步扩大比例。灰度发布需要一套流量分配机制可以按用户ID哈希、按请求比例、按地域等维度切分。同时要保证同一个用户尽量走同一个模型否则体验会不一致。监控上要对比新旧模型的核心指标包括业务指标和系统指标一旦新模型指标明显劣化就自动回滚。模型版本管理也要做好。每个上线的模型都要有明确的版本号、上线时间、对应的训练实验、评估报告。回滚的时候能一键切回上一个稳定版本。我自己的习惯是任何模型上线前都准备好回滚脚本并且实际演练一遍确保真出问题的时候不会手忙脚乱。5. 监控与迭代上线只是开始5.1 线上效果监控技术指标和业务指标都要盯模型上线之后你要监控两类指标技术指标和业务指标。技术指标包括推理延迟、吞吐、错误率、资源占用这些反映系统是否健康业务指标包括点击率、转化率、准确率等这些反映模型是否有效。很多人只监控技术指标觉得系统不崩就行。但模型效果衰减往往是悄无声息的系统一切正常就是预测越来越不准。所以业务指标必须监控而且要设置合理的告警阈值。比如转化率环比下降超过10%就告警这样能第一时间发现问题。监控数据要能下钻。光看一个总体指标不够要能按用户分群、按时间段、按特征分布去拆解这样才能定位问题出在哪。我一般会做一个简单的监控看板把核心指标、漂移指标、系统指标放在一起每天早上扫一眼有异常再深入查。5.2 反馈闭环让线上数据反哺训练线上数据是宝贵的训练资源但很多人没有把它用起来。正确的做法是建立一个反馈闭环线上请求和结果被记录下来经过清洗和标注之后补充到训练数据里定期重新训练模型。这个闭环的关键是数据回流的速度和质量。回流太慢模型跟不上业务变化回流数据质量差反而会污染训练集。所以回流数据要经过和原始数据一样的清洗流程必要时还要人工抽检。另外回流数据往往有偏因为只有被模型预测过的样本才会被记录未曝光的数据是缺失的。处理这种偏差需要一些技巧比如用倾向性加权或者探索式采样。我自己的经验是闭环不用做得太复杂先跑通记录-清洗-补充-重训这个最小循环再逐步优化每个环节。很多团队卡在第一步连线上数据都没好好存下来那就谈不上闭环了。5.3 成本控制AI项目的隐形杀手AI项目的成本很容易失控尤其是用了GPU之后。训练成本、推理成本、存储成本、数据传输成本加起来可能远超预期。控制成本要从几个方面入手。训练方面别动不动就上大集群。先用小规模实验验证想法确认方向对了再扩大。超参搜索也要控制预算随机搜索几十次往往就能找到不错的配置没必要跑几百次。另外Spot实例或者抢占式资源能大幅降低成本但要处理好中断恢复的逻辑。推理方面能用量化就用量化能用CPU就别用GPU。很多任务其实CPU就够了只是大家习惯性地上GPU。批处理也能摊薄成本把零散请求攒成批处理单位成本能降不少。存储方面冷数据及时归档别让一堆没用的中间产物占着高价存储。我踩过最大的坑是训练的时候忘了关GPU实例周末两天白烧了不少钱。后来我养成了习惯所有训练任务都设置自动停止超过预期时间没结束就强制中断并告警。这个习惯帮我省了不少冤枉钱。6. 一些让我少走弯路的实操心得6.1 先把基线跑通再谈优化我见过太多人一上来就想搞个SOTA模型结果连一个能跑通的基线都没有。正确的顺序是先用最简单的方案跑通全流程哪怕效果一般也要保证数据、训练、评估、部署、监控这条链路是通的。有了基线之后再逐步替换每个环节看哪个环节的提升最大。基线的价值在于它给了你一个参照系。没有基线你根本不知道一个新方案是真的有效还是只是运气好。而且基线能帮你快速定位瓶颈如果基线本身就很差那问题大概率在数据或者流程上而不是模型上。6.2 日志和文档写给三个月后的自己AI项目迭代快今天想清楚的事情三个月后可能全忘了。所以日志和文档不是给别人看的是给未来的自己看的。我的习惯是每个实验都写一段简短的记录做了什么改动、为什么改、结果如何、下一步计划。这些记录积累起来就是项目的知识库。代码注释也一样重点注释为什么而不是是什么。比如这里用对数变换是因为原始分布长尾严重这种注释才有价值。至于这里加1这种代码本身已经说清楚了不用注释。6.3 别追求一步到位小步快跑才是常态AI工程没有银弹也没有一步到位的架构。你今天设计得再完美业务一变、数据一变架构就得调整。所以别在前期过度设计先把核心链路跑通遇到问题再重构。小步快跑、快速迭代比憋一个大招要靠谱得多。我自己的节奏是每两周做一次小迭代每次只解决一个明确的问题。这样既能保持进度可见又不会因为改动太大而引入难以排查的问题。迭代多了之后回头看会发现项目已经走了很远而每一步都是稳的。最后分享一个我一直在用的小技巧每次开始一个新项目先花半天时间把目录结构、配置文件模板、日志格式、评估报告模板这些脚手架搭好。这半天看起来是不产出的但它能让后面几周的开发效率翻倍而且能避免很多低级错误。这个习惯我坚持了好几年每次都能帮我省下大量返工时间。
返回列表