尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

AI工程全链路拆解:从数据到部署的系统构建实战

AI工程全链路拆解:从数据到部署的系统构建实战 我最早接触ai-engineering这个词是在一个GitHub仓库的命名里看到from scratch的后缀。当时第一反应是都2024年了谁还从零学AI工程框架随手pip install模型一行Transformer调用LLM调API就能跑何必自虐。直到后来我亲眼见过太多Demo跑通、上线翻车的项目才明白这个from scratch到底在说什么。它不是让你从反向传播的数学公式手推一遍也不是逼你从零实现ResNet。它是把AI项目从数据到部署的全链路工程能力一层一层拆开重新建立系统认知。很多团队卡住的地方根本不是模型不够新而是数据管道一塌糊涂、实验不可复现、评估指标和业务目标对不上、模型上线后没人敢动。这套东西没有人手把手带你捋一遍你只能靠踩坑去学成本极高。这篇文章就是把我这些年摸索、踩坑、复盘出来的AI工程全景拆给你看。内容覆盖数据工程、建模训练、评估体系、服务部署、监控闭环这几个核心模块适配刚入门想建立体系感的算法工程师也想转岗AI的软件开发者以及所有被模型训练完只是开始这句话毒打过的从业者。我会尽量用项目实操的视角讲该贴代码贴代码该给参数给参数把为什么这么做说透。1. AI工程到底在做什么先跳出模型思维1.1 从一次真实的翻车事故说起2021年我参与过一个内容推荐项目团队里有个背景很漂亮的算法同学花了两个月时间把离线AUC从0.73刷到了0.81模型效果看起来完美。上线之后监控显示点击率确实涨了两个点但人均阅读时长掉了快五分钟整个业务盘子是亏的。后来排查发现模型学到的模式是标题越夸张点击越高但夸张标题带来的都是无效点击用户点进去两秒就关掉了。这个案例对我来说是当头一棒。模型指标再好也不代表系统成功。AI工程本质上是用模型解决业务问题的系统工程模型只是中间产物而不是交付物。你交付的是一个持续运转、可监控、可迭代的智能系统这个系统好坏的唯一标准是业务指标不是模型指标。从那以后我给自己定了一条规矩任何AI项目先写清楚业务成功标准再谈模型用什么。这一步看起来废话但绝大多数项目跳过了它导致后面所有环节都要返工。1.2 全链路拆解从训练模型到运营系统我习惯把一个AI工程拆成五个节点每个节点都有明确的输入输出和验收标准。第一个节点是业务定义。弄清楚你要优化的业务指标是什么这个指标和模型输出之间是什么映射关系有哪些约束条件。第二个节点是数据工程包括采集、清洗、标注、版本管理这个环节消耗的时间和精力往往超过建模但最容易被低估。第三个节点是建模与训练这是大多数教程的起点和终点但在工程视角里它只是中间环节。第四个节点是评估体系不仅要有离线评估的准确率和召回率更要有在线评估的设计思路。第五个节点是部署与监控闭环模型上线后你能不能及时发现效果衰减、数据漂移能不能快速迭代。这五个节点不是线性的而是一个闭环。某个环节出了问题可能要把前面所有节点重新走一遍。你现在回头看那些demo跑通就以为完成了的项目问题几乎都出在只做了第三个节点的一部分其他四个节点全都靠脑补。2. 建立最小技术栈选型逻辑比工具本身更重要2.1 语言和框架为什么是Python加PyTorch很多人问从零开始要不要直接上中文大模型微调框架或者直接学某个端到端平台。我的态度一直是先扎扎实实把基础技术栈吃透。基础技术栈的核心其实是Python加PyTorch这一套原因不是它们性能最好而是生态最完整、调试最方便、从科研到工程切换成本最低。Python不必多说AI领域的语法糖和第三方库都是围绕它长的。PyTorch更关键的是它的动态图机制方便你做快速实验和调试。你可以在训练循环里随意打印中间变量改一行代码重新跑一次这种灵活性在探索阶段是不可替代的。对比之下TensorFlow当年的静态图模式新手常常被先构图再执行这件事卡住排查问题也难。我实测下来PyTorch的迁移路线是最平滑的先用它做研究实验上线时再用TorchScript或者ONNX做部署心智负担很小。这里提一句数学基础。线性代数要懂矩阵相乘和维度变化概率论要懂分布和期望微积分要懂梯度的直觉就够了。你不需要像数学家一样推导一切但至少在看到loss不收敛的时候能大概判断是梯度消失、学习率过大还是数据分布出了问题这个判断力完全来自基础不是调包。2.2 服务化与容器化FastAPI加Docker的组合AI工程师不止是训练模型最终要让别人能用上这个模型。搭建推理服务我用FastAPI的次数最多。它性能好、自动生成API文档、对异步支持到位写一个极简推理服务也就几十行代码。之前用Flask写过性能差一截而且异步支持弱遇到并发请求直接卡死换FastAPI之后清爽太多。from fastapi import FastAPI from pydantic import BaseModel import torch app FastAPI() class InputText(BaseModel): content: str model None app.on_event(startup) def load_model(): global model model torch.load(model.pt, map_locationcpu) model.eval() app.post(/predict) def predict(data: InputText): tokens encode(data.content) with torch.no_grad(): logits model(tokens) pred logits.argmax(dim-1).item() return {label: pred}Docker的作用则是把运行环境打包避免在我机器上跑得好好的到你机器上就报错。尤其AI项目对Python版本、CUDA版本、依赖库版本都极其敏感环境漂移是家常便饭。我自己的习惯是Docker加docker-compose把服务、数据库、缓存编排起来本地开发和生产环境保持一致能省掉八成环境问题。2.3 实验管理不记账的炼丹都是耍流氓模型训练耗费最大的资源不是算力是人的注意力。我见过太多人跑完一版实验参数没记录数据版本没存代码改没改也说不清两个星期后根本不知道当前最优模型是怎么训出来的。这个问题的解法是引入实验管理工具我主力用的是MLflow。MLflow能帮你在每次训练时自动记录超参数、指标曲线、模型产物和代码版本。你跑完几百组实验之后可以在界面里对比不同参数组合的曲线快速锁定最优模型。更关键的是它可以和模型注册中心打通线上跑的模型版本一目了然回滚时知道应该回滚到哪一版。我从MLflow之后再也没出现最佳模型不知出处的情况强烈建议从零就开始用。3. 数据工程最容易忽略却最值钱的环节3.1 数据清洗不是机械劳动是侦探工作很多人拿到数据集直接开始训练这个习惯非常危险。真实世界的数据全是脏的。缺失值、重复样本、离群点、错误标注、分布偏移任何一个都可能让模型学到错误模式。我举一个真实例子。之前做一个风控模型训练数据的负样本里混了一批测试环境产生的模拟交易这些交易金额都在同一个区间特征分布和真实数据完全不一样。如果不去清洗模型会学到金额在这个区间的交易是安全的上线就被薅秃。所以数据清洗的核心不是写几个dropna和fillna而是理解业务逻辑知道每条数据从哪来、为什么缺失、为什么异常。实操上我建议每拿到一份数据先做一套体检报告字段缺失率、唯一值数量、数值字段的均值分位数、类别字段的分布TopN、目标变量在不同特征维度上的分布差异。这套体检报告能帮你快速定位数据质量隐患知道哪些字段值得投入精力做特征工程哪些字段干脆删掉。3.2 标注规范多花一小时是为了省后面十天如果要训练一个有监督模型标注质量直接决定了模型上限。我见过太多团队在这个环节省功夫几个人凭感觉标注标准都不统一结果模型训出来效果差然后疯狂调模型其实问题在标注。我的经验是任何标注任务开始前必须先写一份标注规范文档把每个类别的定义、边界案例、模糊情况处理方式写清楚。标注过程要有抽检机制用Kappa一致性系数评估标注者之间的一致性。如果一致性低于0.8说明任务定义不清楚要先解决规范问题再继续标注。这里插一句数据增强和数据清洗要分开看。增强是在已有数据基础上做变换增加样本多样性清洗是去掉错误和无效样本。两者目的不同但都重要不要因为有了大模型自动标注就跳过人工质量抽检。3.3 数据版本管理:没有数据版本控制的实验等于没有地基代码有Git版本管理数据集同样需要版本管理。DVC是当前最流行的数据版本管理工具之一它像Git一样帮你记录数据集的每个版本支持从远程存储拉取特定版本。我把数据和代码的版本用同一个commit绑定跑实验时记录commit hash。这样任何时候回看某次实验都知道当时用的哪版代码、哪份数据、哪组参数。这个习惯一开始会觉得很繁琐但当项目迭代三个月后再做一次模型复现时就会发现它价值连城。没有版本控制你复现不了自己的模型更别谈后续优化。3.4 数据泄漏最隐蔽的坑数据泄漏是机器学习项目里最阴险的问题之一因为它在离线指标上会让你觉得模型很优秀上线后却立刻原形毕露。常见泄漏类型有三种。第一种是目标泄漏特征里包含了和要预测的目标直接相关的信息。比如预测用户是否会违约却把是否逾期作为特征这是最典型的错误。第二种是时间泄漏用未来数据预测过去。比如训练集和测试集按用户划分而不是按时间划分导致测试集里存在训练期之后的信息。第三种是预处理泄漏对全量数据做归一化时用了测试集的均值方差这在引入数据依赖时也要格外小心。我自己的教训是做数据处理时必须保证训练集和测试集分开处理一切统计量只从训练集计算。这个原则写进了我们团队的代码审查清单每个数据预处理模块都要经过专门检查。4. 建模与训练把基本功打扎实4.1 从baseline开始别一上来就上大模型我见过太多初学者拿到任务第一反应是我要用BERT/LLM直接干。这种冲动可以理解但工程上几乎总是从最简单的baseline开始。最简单的baseline比如逻辑回归或线性模型作用类似房子的地基检查——它能用极低成本告诉你数据里是否存在有效信号。如果简单模型效果就很差说明特征工程或数据质量有问题这时候换成再复杂的模型也是白搭。反之如果简单模型表现尚可就为后续复杂模型的提升幅度提供了一个基准线。没有基线你根本无法判断复杂模型到底带来了多少增益。我习惯的流程是先跑一个线性模型记录各项评估指标然后逐步增加复杂度例如加入正则项、用树模型、逐步走向深度学习模型。每一步都在前一步的基线上增量迭代出问题时也能定位是数据、特征还是模型结构的问题。4.2 损失函数和优化器理解比调参更重要损失函数是模型努力的方向。分类问题用交叉熵回归问题用均方误差。换损失函数之前要想清楚你的业务目标到底是什么。很多排序任务用点击率作为训练目标但阅读时长同样重要因此会设计成多目标损失融合点击和时长两个信号。理解这一点就不会病急乱投医随便换损失函数。优化器方面我从SGD开始接触现在主力用AdamW。AdamW收敛稳定、和Transformer体系搭配默契。学习率的设置很关键过大会导致loss震荡不收敛过小会让训练慢到怀疑人生。现在流行用warmup加余弦退火前面几百步用小学习率让模型稳定启动再逐步增大再衰减。这个节奏对新手来说最容易踩坑的是学习率太大看一眼loss曲线如果是乱蹦乱跳第一件事就是调小学习率。4.3 手写训练循环一次刻骨铭心的成长虽然PyTorch Lightning、Hugging Face Trainer能帮你省掉很多代码但我坚持认为每个AI工程师至少手写过一次完整的训练循环。代码其实不复杂核心就是取数据、前向传播、算损失、反向传播、更新参数、记录指标。这个过程帮你建立对训练过程最底层的心智模型。你会理解为什么要在每个epoch设model.train()和model.eval()因为BatchNorm和Dropout在训练和推理时行为不同。你会理解梯度累积是什么因为它本质上是用多个小batch的梯度模拟一个大batch的效果。这些理解在遇到问题时非常关键尤其是大规模训练和分布式训练场景没有底层直觉很难定位问题。4.4 显存爆掉每个炼丹师都必须面对的日常CUDA Out of Memory也就是OOM是我训练生涯里遇到过最多的报错。最常见的诱因是batch size太大模型输入过长中间激活值把显存填满了。排查路径是我每次都会走的先逐步调小batch size确认能跑通再尝试梯度累积用多个小batch的梯度累加模拟大batch再开启混合精度训练通过半精度减少显存占用现在的新显卡对此支持很好。如果数据本身太大比如超长文本可以分段处理。如果模型太大可以考虑模型并行或卸载优化器状态。但工程上先做这三板斧大部分情况都能缓解。如果最后实在不行再去考虑换更小的底座或者做量化。GPU显存不是估出来的是测出来的。跑训练脚本之前先用一个batch试一次看看显存占用再安全地往上加batch_size比瞎猜靠谱得多。5. 评估体系指标选对了方向才不会跑偏5.1 离线指标地图不同任务看不同指标评估指标的选择直接决定了你会把模型往哪个方向优化。分类任务里准确率对类别不平衡的数据极不友好。假如99%是负样本模型全部预测负类也能拿到99%准确率看起来很漂亮实际毫无用处。这种情况我更关注F1-score和AUCF1兼顾精确率和召回率AUC看排序能力。回归任务用MAE还是RMSE也有讲究。MAE对所有误差一视同仁RMSE会放大大误差的影响。如果你的业务里偶尔出现一个极端预测值会造成严重后果那RMSE更符合业务感受如果你只关心平均误差选MAE更直观。排序任务则要看NDCG或RecallK这类指标关注的是模型把该排前面的排到前面了没有。这些指标的边界条件必须清楚否则就会出现我开头说的那种情况离线指标很漂亮业务指标崩了。5.2 评估集怎么划分决定了你评估的可信度随机划分是最常见的做法但很多时候它并不适用。比如时间序列预测必须用前一段时间训练、后一段时间测试模拟真实的用历史预测未来场景。如果随机划分未来信息会泄漏到训练中离线指标会虚高。做推荐系统时也常按照用户划分避免来自同一用户的样本同时出现在训练和测试集中。另一个问题是数据重复。很多人从网上爬来的数据集里包含大量近似重复文本直接划分会让模型在测试集上表现虚高因为它早就见过相似的样本。我处理文本数据时会先做去重和相似度聚类再划分这样才能保证评估集真正挑战模型的泛化能力。5.3 人工评测LLM时代不可省略的环节传统模型的离线指标相对成熟但生成式模型时代BLEU和ROUGE这类自动指标和人类感受之间存在明显差距。一篇文本BLEU很高读起来却可能生硬不自然。我在做大模型相关项目时一直保留人工评测这个环节。人工评测需要有标准化的维度比如相关性、流畅性、有害性。标完还要算一致性多人打分怎么对齐。做这件事确实费时费力但它是保证模型质量的最后一道防线。如果没有人工评测你根本不知道自动指标在骗你。6. 部署与服务化从notebook到系统的距离6.1 模型服务化的核心矛盾把模型跑起来和把模型服务化之间隔着一道鸿沟。本地notebook里一张一张跑batch和线上一次请求要毫秒级响应是完全不同的工程世界。核心矛盾有三个延迟、吞吐、资源占用。延迟是单次请求的响应时间要求快吞吐是单位时间处理的请求数要求多资源是CPU和GPU要求省。这三个目标互相制约。我给自己的设计顺序是先定延迟上限再压吞吐最后在满足前两者的前提下尽量降低资源成本。推理服务在文本模型上通常用流式输出因为首字延迟降到几百毫秒才体验好。但训练好的大模型在GPU上跑一次forward所需的算力很高必须通过量化、批处理、缓存等技术手段去优化。6.2 模型压缩量化、剪枝与蒸馏的取舍上线前经常要面对模型太大、推理太慢的问题。三个常用手段量化、剪枝、蒸馏。量化是把模型的浮点数权重从FP32变成INT8或者更低。我做过的项目里INT8量化能在几乎不掉点的前提下把推理速度提升两三倍显存占用降低到原来的四分之一。剪枝是去掉不重要的神经元或注意力头让模型变得更稀疏但对精度影响可能更大通常需要配合重训练。蒸馏则是用一个复杂的大模型当老师训练一个小模型去模仿它小模型推理更快但训练成本高。这三者的选择依据是业务对精度的要求。如果精度是硬指标优先考虑蒸馏如果只是带宽敏感量化性价比最高。6.3 批处理优化不适合并行的瓶颈GPU推理的本质是并行计算单条请求往往无法吃满GPU算力。在大模型生成场景一次请求生成一串tokenGPU内存大部分时间都在等待计算。提高吞吐的常用思路是动态批处理。把多个并发请求攒到一起拼成一个batch一次forward处理多份数据。实现上可以用简单的队列加微批调度也可以用专门的推理框架来做。这个机制可能增加单次请求的等待时间所以要在延迟和吞吐之间做权衡。我实测过一个部署在CPU上的推荐模型加了一个微批处理后吞吐提升了近四倍延迟只增加了百分之二十性价比极高。6.4 CI/CD和模型发布流程模型上线不能靠手动拷贝文件系统化发布流程是工程基础。我的做法是训练完成后把模型产物注册进模型仓库带上版本号和元数据。通过CI流水线自动跑一轮评测把离线指标和现存线上版本做对比。如果通过就把新模型部署到灰度环境先切一小部分流量观察效果。稳定后逐步扩大流量比例最后全量上线。这个过程听起来复杂但用现成工具做起来并不难关键是让你每次上线都有可回滚的余地和完整的事件记录模型出了问题秒级回退。7. 监控与反馈闭环上线是起点不是终点7.1 两类漂移数据在变模型在变老模型上线之后最怕的不是代码bug而是模型慢慢变笨。原因就是数据漂移和模型漂移。数据漂移指线上真实数据的特征分布和训练时有偏差用户行为变了、商品品类变了、语言表达习惯变了都会导致模型的输入分布变。模型漂移指模型的预测分布和之前相比发生明显变化模型内部老化面对新数据能力下降。监控数据漂移的常用手段是计算PSI即群体稳定性指数。如果某个特征的PSI超过阈值说明该特征的分布发生了显著变化需要人工排查是否出现新的数据模式。模型漂移则可以通过监控预测值的分布变化来感知。7.2 反馈闭环模型迭代的数据从哪来监控不仅是发现问题更是为迭代收集依据。很多模型上线后就断了数据回流用户真实反馈、业务结果、人工抽检结果这些信息都没有回到训练管道里面。没有反馈就无法真正持续优化。我的习惯是设计一套完整的日志埋点方案把所有线上的推理请求和对应的业务结果都记录下来统一存储定期清洗后汇入下一轮训练的数据集。这样每次模型迭代都能有最新的用户行为数据形成业务反馈收集、数据更新、模型重训、重新上线的正循环。8. 常见问题与排查技巧实录8.1 问题速查表我把平时踩坑最多的问题整理成了一张速查表方便遇到问题时快速定位现象可能原因排查建议Loss为NaN学习率过大、数据含NaN、梯度爆炸调小学习率、检查输入数据、加梯度裁剪训练集AUC高测试集极低过拟合或数据泄漏检查特征是否有泄漏、增加正则、增加数据量离线指标好线上业务不涨指标与业务目标不一致重审评估指标增加在线A/B验证服务吞吐极低缺少批处理、服务端阻塞用动态批处理、异步化、性能profiling模型上线后指标逐渐下降数据漂移或模型老化监控PSI、定期重训、设计自动告警训练太慢batch太小、数据IO瓶颈检查GPU利用率、预读取数据、考虑混合精度这张表不是万能药很多问题需要结合具体场景定位但能帮你快速建立排查思路不用每次都从零开始。8.2 三个让我印象最深的翻车教训第一个教训是数据预处理泄漏。有个文本分类项目我在全量数据上做TF-IDF向量化然后才切训练测试集。结果测试集里包含了一部分词表信息离线准确率虚高到接近0.95。上线后直接崩到0.78。后来重写了Pipeline保证所有拟合都只发生在训练集上公平评估才稳住。第二个教训是版本不对齐。某次上线前我把模型文件上传到了服务器但特征工程代码没有同步线上推理时特征顺序和训练时不一致模型输出变成了乱码。排查花了大半天。后来我用Docker镜像和Git commit号严格绑定特征工程代码版本不一致时拒绝发布再也不踩这个坑。第三个教训是过度优化离线指标。有一次我为了提高离线F1在损失函数里加了很多复杂的样本权重结果模型在线上的泛化能力显著下降因为那些权重放大了训练集噪声。从那以后我都先看业务反馈而不是无脑刷离线分数。结尾一点个人体会顺着ai-engineering-from-scratch这条路走下来我的最大收获是AI工程的核心问题不是模型可以多聪明而是系统可以多可靠。聪明靠算法创新可靠靠工程纪律。数据和代码的版本管理、标注规范、指标设计、发布流程、监控告警每一件事都不性感但每一件事都在决定项目的真实上限。我现在接手任何新项目第一步就是画一张全链路图数据从哪来、预测给谁用、指标是什么、出问题怎么发现、迭代靠什么驱动把这五个问题写清楚再开始动手。最后一个建议挑一个中等规模的真实任务用这套方法端到端跑通一遍比看十篇技术文章都管用。跑通的你已经不是会训练模型的人而是能交付AI系统的人。这两者之间的差距恰恰就是from scratch的价值所在。
返回列表