ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从零搭建AI工程能力:数据、模型、服务与部署全链路实战指南

从零搭建AI工程能力:数据、模型、服务与部署全链路实战指南 1. 从零搭建AI工程能力为什么大多数人卡在第一步就放弃了这两年“AI工程”这个词被说得太多了多到有点泛滥。打开任何一个技术社区满屏都是“大模型应用开发”“RAG实战”“Agent落地”但真正动手从零搭一套能跑起来的AI工程链路时你会发现一个很尴尬的现实教程要么停留在调API的层面要么一上来就甩给你一个几十个依赖的仓库让你自己啃。中间那段“从会写Python到能交付一个AI系统”的路几乎没人好好讲。ai-engineering-from-scratch这个方向之所以值得单独拿出来聊是因为它瞄准的正是这段被忽略的中间地带。它不是教你训练一个千亿参数模型也不是让你背Transformer的每一行公式而是解决一个更实际的问题一个有一定编程基础的人怎么从零开始把数据、模型、服务、评估、部署这几块拼成一个真正能用的AI工程系统。我见过太多人在这条路上折戟。有人卡在环境配置CUDA版本和PyTorch对不上折腾三天放弃了有人能跑通demo但一换成自己的数据就各种维度不匹配还有人模型训出来了却不知道怎么把它变成一个别人能调用的服务。这些问题的共同点是它们都不是“算法问题”而是“工程问题”。而工程问题恰恰是大多数教程避而不谈的。这篇内容适合三类人第一类是有Python基础、想往AI方向转的开发者第二类是做过后端或数据工程、想补齐AI这块拼图的工程师第三类是学生或自学者手里有项目但不知道怎么把它做成一个“像样”的系统。我会把从零搭建AI工程能力的完整路径拆开讲清楚每一步为什么这么做、坑在哪里、怎么绕过去。不堆砌名词只讲能落地的东西。2. 先搞清楚AI工程到底在工程什么别一上来就写模型2.1 AI工程和算法研究的本质区别很多人对AI工程的误解是从把“AI工程”等同于“调模型”开始的。实际上在一个真实的AI系统里模型代码往往只占整个代码库的5%到10%。剩下的90%是什么是数据管道、特征处理、服务封装、监控告警、版本管理、评估体系。这就是AI工程和算法研究的根本区别。算法研究关心的是“这个模型在标准数据集上能不能刷到更高的指标”而AI工程关心的是“这个系统在生产环境里能不能稳定地、可复现地、可维护地输出符合预期的结果”。前者是单点突破后者是系统工程。我举个具体的例子你在论文里看到一个模型准确率95%很兴奋地想用到自己的项目里。但真正落地时你会发现你的数据分布和论文里的完全不一样你的推理延迟要求是100毫秒以内而那个模型跑一次要2秒你的线上环境没有GPU只能CPU推理。这些问题论文不会告诉你答案只有工程能解决。所以从零搭建AI工程能力第一步不是去学某个新模型而是建立“系统思维”。你要习惯问自己数据从哪来、怎么清洗、怎么版本化模型怎么训练、怎么评估、怎么选型服务怎么部署、怎么扩缩容、怎么监控这些问题听起来很“后端”但它们才是AI工程的主干。2.2 一个最小可用的AI工程系统包含哪些模块我把一个最小可用的AI工程系统拆成五个模块这个拆法是我自己踩了很多坑之后总结出来的不一定标准但足够实用。第一个模块是数据层。包括数据的采集、清洗、标注、存储和版本管理。很多人忽略数据版本管理结果模型效果回退了都不知道是哪批数据的问题。第二个模块是实验层。包括训练脚本、超参数管理、实验追踪。这一层的核心诉求是“可复现”你今天跑出一个好结果下周还能不能复现出来。第三个模块是评估层。包括离线评估和在线评估离线看指标在线看业务效果。第四个模块是服务层。把模型封装成API处理并发、超时、降级。第五个模块是监控层。监控模型的输入分布、输出分布、延迟、错误率及时发现数据漂移。这五个模块不需要一开始就全部建好但你在设计任何一个小项目时脑子里要有这张图。比如你做一个文本分类的小工具哪怕只写一个脚本也可以顺便把数据版本用文件名带日期、实验记录用个简单的日志文件、评估指标打印出来存成JSON这些习惯带上。习惯比工具重要。2.3 为什么建议从“小闭环”而不是“大而全”开始新手最容易犯的错是一上来就想搭一个“平台”。我见过有人第一个项目就想做一套完整的MLOps平台结果三个月过去了连数据加载都没跑通。正确的做法是走“小闭环”选一个足够小的任务把数据、训练、评估、服务这条链路完整地走一遍哪怕每个环节都很简陋。比如你可以选“垃圾邮件分类”这种经典任务。数据用公开数据集模型用最简单的朴素贝叶斯或者逻辑回归评估用准确率和F1服务用Flask写一个接口。整个链路走通可能只需要一两天。但这一两天里你会遇到真实的问题数据怎么读进来、中文怎么分词、模型怎么保存、接口怎么接收JSON、怎么处理异常输入。这些问题解决一遍你对AI工程的理解就超过看十篇教程。小闭环的价值在于它让你在低风险的环境下暴露所有工程问题。等你把这条链路走顺了再换更复杂的模型、更大的数据、更严的延迟要求你就有底气了。反过来如果你一上来就搞大项目每个环节都是新的出了问题你根本不知道是哪一层的问题。3. 环境与工具链的选型少即是多别被工具绑架3.1 Python环境管理的血泪教训Python环境管理这件事说起来简单做起来能逼疯人。我早期用系统自带的Python装包装到系统崩了后来用virtualenv但忘了激活环境装到了全局再后来用conda结果conda和pip混用依赖冲突到怀疑人生。这些坑我相信很多人都踩过。我的建议很明确用conda管理环境用pip装包但两者不要混用同一个包。具体做法是用conda create创建一个干净的环境指定Python版本然后在这个环境里优先用conda装那些有复杂二进制依赖的包比如PyTorch、NumPy用pip装纯Python的包。如果你不确定某个包该用哪个就统一用pip但装之前先conda list看一眼有没有已经装过的版本。还有一个更省事的方案是用uv这是这两年新出的Python包管理器速度快得离谱而且能很好地处理依赖解析。我现在的习惯是新项目直接用uv建虚拟环境uv venv然后uv pip install比conda轻量很多。但如果你要用CUDA相关的深度学习框架conda的生态还是更成熟一些这个要看你具体做什么。提示不管用哪种工具一定要把环境依赖导出成文件requirements.txt或environment.yml并且提交到版本控制。我吃过太多次“本地能跑、换台机器就崩”的亏根源都是依赖没锁死。3.2 深度学习框架的选择逻辑框架选型这个问题网上吵得很凶但我的观点很务实看你的任务和团队。如果你是做研究、发论文、需要快速试新结构PyTorch现在是事实标准动态图写起来舒服社区活跃遇到问题好搜。如果你是做工业部署、对推理性能要求极高TensorFlow的生态在某些场景下还是有优势尤其是TF Serving和TFLite。但如果你做的是“AI工程”而不是“模型研究”我建议你不要过早绑定框架。把模型训练和模型推理分开看训练阶段用PyTorch快速迭代推理阶段用ONNX做中间格式再根据部署环境选ONNXRuntime、TensorRT或者其他推理引擎。这样你的工程链路不会被某个框架锁死。对于从零开始的人我的建议是先用PyTorch把整个链路跑通因为它的调试体验最好报错信息相对友好。等你对整体流程有感觉了再去研究推理优化。不要一上来就纠结“哪个框架快”你连baseline都没有比什么快。3.3 实验追踪工具从Excel到专业工具实验追踪这件事很多人一开始用Excel记记着记着就乱了。我经历过那个阶段一个模型改了十几个超参数最后不知道哪个配置对应哪个结果。后来我开始用TensorBoard再后来用MLflow现在基本是MLflow加一个简单的表格记录。对于从零开始的人我的建议是先用最土的办法但要有结构。你可以建一个CSV文件每次实验记一行字段包括实验ID、日期、数据集版本、模型类型、关键超参数、评估指标、备注。这个CSV文件放在项目根目录提交到Git。等你实验多了自然会发现需要更专业的工具那时候再迁移到MLflow或Weights Biases也不迟。不要一上来就上重型工具因为工具本身有学习成本而且会分散你对核心问题的注意力。我见过有人花一周配MLflow结果模型还没开始训。工具是为你服务的不是反过来。3.4 版本控制不只是代码还有数据和模型Git管代码是常识但AI项目里数据和模型也需要版本管理。数据版本管理有个简单原则原始数据不动处理后的数据带版本号。比如原始数据放在data/raw/处理后的数据放在data/processed/v1/、data/processed/v2/。每次处理逻辑变了就生成新版本不要覆盖旧的。模型版本管理也是类似思路。每次训练产出的模型文件命名带上日期和关键配置比如model_20240115_lr0.001_bs32.pth。同时用一个JSON文件记录这个模型的元信息训练数据版本、超参数、评估指标。这样你回滚的时候知道回滚到哪个。如果项目大了可以考虑DVCData Version Control这类工具它能把大文件用Git管理起来。但对于个人项目我建议先用文件夹和命名规范简单直接不容易出错。4. 数据管道AI工程里最脏最累但最重要的活4.1 数据清洗的常见陷阱与处理策略数据清洗这件事教科书上讲的都是“处理缺失值、异常值、重复值”但真实场景远比这复杂。我做过一个文本分类项目数据是从网上爬的里面混了大量HTML标签、乱码、重复内容。如果直接拿去训练模型学到的全是噪声。我的处理流程一般是这样的先去重用哈希或者SimHash把完全重复和近似重复的去掉然后处理编码问题统一转成UTF-8遇到无法解码的字符直接丢弃接着清洗文本去掉HTML标签、特殊符号、多余空白最后做长度过滤太短的和太长的都去掉因为极端长度的样本往往质量有问题。这里有个经验清洗规则要可配置、可追溯。不要把这些规则硬编码在脚本里而是写成一个配置文件每次清洗生成一份报告记录去掉了多少条、为什么去掉。这样你后面发现数据量不够时知道去哪找回那些被过滤的样本。还有一个容易被忽略的点是标签质量。很多公开数据集的标签是有噪声的尤其是众包标注的。如果你发现模型在训练集上表现很好但验证集很差除了过拟合也要怀疑标签是不是有问题。我一般的做法是随机抽100条人工检查一遍如果错误率超过5%就要考虑清洗标签或者换数据集。4.2 特征工程在深度学习时代还有没有必要这个问题经常被争论。有人说深度学习端到端不需要特征工程了有人说特征工程依然是关键。我的观点是看数据量和任务类型。如果你有百万级以上的数据和足够大的模型端到端学习确实能学到好的表示特征工程的价值相对下降。但如果你数据量小几千到几万条特征工程依然是提升效果最划算的手段。举个例子我做用户行为预测时原始数据是用户的点击序列。如果直接丢给模型模型需要从序列里自己学出“最近一次点击”“点击频率”这些模式。但如果我手动构造出“过去7天点击次数”“最近一次点击距今天数”“点击类别的分布”这些特征模型在小数据上收敛快得多效果也更好。所以我的建议是先做一版baseline不加任何手工特征看效果。如果效果已经满足需求就不用折腾了。如果不够再逐步加特征每次加一类看指标变化。这样你能清楚地知道哪些特征有用哪些是噪声。4.3 数据加载的性能优化别让IO成为瓶颈数据加载慢是训练时的常见问题。我见过有人训练一个epoch要两小时其中一小时半在等数据。这种情况通常是数据加载没做好。优化的思路有几个层次。最基础的是用DataLoader的num_workers参数开多进程加载这个能带来几倍的提升。再进一步是把数据预处理成二进制格式比如NumPy的.npy或者HDF5比每次读CSV或JSON快很多。如果数据能全部放进内存那就直接放内存别每次从磁盘读。如果放不下考虑用内存映射memmap的方式。还有一个技巧是预取。PyTorch的DataLoader本身有预取机制但你可以通过调整prefetch_factor来优化。另外如果你的数据增强很耗时考虑把增强放在GPU上做或者用更快的增强库。我自己的经验是数据加载优化到“GPU利用率能稳定在80%以上”就差不多了。如果GPU利用率忽高忽低说明数据加载是瓶颈要继续优化。如果GPU一直跑满那说明数据加载没问题可以不用管了。4.4 数据版本管理与可复现性数据版本管理是AI工程里最容易被忽视但出问题最致命的一环。我经历过一次事故模型上线后效果突然下降排查了两天才发现是数据管道上游改了字段名导致某几个特征全是空值。如果当时有数据版本管理和校验这个问题在训练时就能发现。我的做法是每次数据更新生成一个数据指纹。指纹可以简单点就是文件内容的MD5或者更复杂的统计摘要行数、列数、每列的均值方差。训练脚本启动时先校验数据指纹和预期不符就报错退出。这样能防止“用错数据训练”这种低级但致命的错误。另外训练脚本里要记录用了哪个版本的数据。我一般会在模型元信息里存一个data_version字段指向数据目录的版本号。这样模型出问题时能快速定位到是哪批数据训出来的。5. 模型训练与评估从能跑到跑得好之间的鸿沟5.1 训练脚本的工程化改造新手写的训练脚本往往是“一坨”代码数据加载、模型定义、训练循环、评估、保存全混在一起。这种脚本跑一次可以但想改点东西就痛苦了。我的建议是从第一个项目开始就把训练脚本拆成几个部分配置、数据、模型、训练、评估。配置用YAML或者argparse管理所有超参数都从配置读不硬编码。数据部分封装成Dataset和DataLoader模型部分单独一个文件训练循环单独一个函数评估单独一个函数。这样你想换模型只改模型文件想换数据只改数据文件。还有一个习惯是日志。不要只用print用logging模块把日志同时输出到控制台和文件。日志里要包含时间戳、当前epoch、loss、指标。这样训练崩了你能从日志里看到崩之前发生了什么。5.2 过拟合与欠拟合的实战判断过拟合和欠拟合的判断教科书上讲得很清楚训练loss降但验证loss升就是过拟合两个都高就是欠拟合。但实战中情况往往更微妙。我遇到过一个情况训练loss和验证loss都在降但验证指标不涨。这可能是评估指标和loss不一致导致的比如loss是交叉熵但业务指标是F1这时候要看业务指标。还有一种情况是训练初期验证指标比训练指标还好这通常是验证集太小或者分布和训练集不一致。处理过拟合的手段大家都知道加数据、加正则、加Dropout、早停。但我的经验是优先加数据其次调模型复杂度最后才加正则。因为正则调参很玄学加数据是最实在的。如果数据加不了再考虑简化模型或者加正则。处理欠拟合通常是模型太小或者训练不够。先加大模型或者延长训练如果还不行检查数据特征是不是有问题或者学习率是不是设得太小。5.3 评估指标的选择别只看准确率准确率是最直观的指标但在很多场景下会误导你。比如一个二分类任务正负样本比例是1:99模型全预测负类准确率也有99%但这个模型毫无价值。这时候要看精确率、召回率、F1或者AUC。选择指标的原则是指标要能反映业务目标。如果业务是“宁可错杀不可放过”那召回率优先如果业务是“不能误伤”那精确率优先。如果是排序任务看NDCG或者MAP。如果是生成任务看BLEU、ROUGE或者人工评估。还有一个实践是多指标一起看。我一般会同时记录准确率、F1、AUC训练时看趋势选模型时综合判断。不要只盯一个指标容易过拟合到那个指标上。5.4 交叉验证与数据集划分的注意事项数据集划分看起来简单但坑不少。最常见的问题是数据泄漏训练集和验证集里有重复样本或者验证集的信息在训练时被用到了。比如你做时间序列预测随机划分数据集就会导致未来信息泄漏到训练集。正确做法是按时间划分用过去的数据训练未来的数据验证。交叉验证在小数据集上很有用但要注意如果数据有分组结构比如同一个用户的多个样本要用GroupKFold保证同一组的样本不会同时出现在训练和验证集。如果是时间序列要用TimeSeriesSplit。还有一个细节是验证集的代表性。验证集要能代表真实分布如果验证集是从某个特定来源采的而线上数据来源更多样那验证集上的好效果不一定能迁移到线上。我一般会留一个“测试集”完全不参与调参只在最后评估一次作为对线上效果的估计。6. 模型服务化把模型变成别人能用的东西6.1 从脚本到API最小服务化路径模型训好了怎么让别人用最简单的办法是写一个Flask或者FastAPI应用加载模型暴露一个HTTP接口。这个路径很短但有几个细节要注意。第一是模型加载时机。不要在每次请求时加载模型那样太慢。要在服务启动时加载一次放在全局变量里。第二是输入校验。用户传上来的数据可能格式不对、缺字段、类型错误要在入口处校验返回明确的错误信息。第三是异常处理。模型推理可能失败要捕获异常返回500错误而不是让服务崩掉。一个最小的FastAPI服务大概长这样from fastapi import FastAPI, HTTPException from pydantic import BaseModel import joblib app FastAPI() model joblib.load(model.pkl) class Input(BaseModel): text: str app.post(/predict) def predict(inp: Input): if not inp.text.strip(): raise HTTPException(status_code400, detailtext is empty) try: result model.predict([inp.text])[0] return {prediction: int(result)} except Exception as e: raise HTTPException(status_code500, detailstr(e))这个服务很简陋但已经能用了。你可以用uvicorn跑起来然后用curl测试。6.2 批处理与并发性能优化的第一课单条推理往往很慢因为模型的前向计算有固定开销。如果业务允许尽量做批处理。比如一次请求带多条数据模型一次前向算完比循环单条快很多。并发方面Python有GIL多线程对CPU密集型任务帮助不大。如果是CPU推理用多进程如果是GPU推理可以用异步或者线程池因为GPU计算时GIL会释放。FastAPI本身支持异步你可以把推理函数写成async但注意如果推理是CPU密集的async反而可能变慢因为会阻塞事件循环。这种情况用run_in_executor丢到线程池里。还有一个优化是模型量化。把FP32的模型转成INT8推理速度能快2到4倍精度损失通常很小。PyTorch有动态量化几行代码就能搞定。如果延迟要求高这个值得做。6.3 服务监控上线只是开始服务上线不是终点而是起点。你需要监控几个东西延迟P50、P95、P99、错误率、输入分布、输出分布。延迟和错误率是基础用Prometheus加Grafana就能搞定。输入分布和输出分布是AI服务特有的因为模型对分布变化很敏感。如果线上输入分布和训练分布差异变大模型效果会下降这叫数据漂移。监控的方法是定期统计输入的均值、方差、类别分布和训练时对比。我一般会写一个简单的监控脚本每小时跑一次统计最近一小时的输入特征和基线对比超过阈值就告警。这个脚本不复杂但能帮你提前发现问题。6.4 模型更新与回滚机制模型不是上线就一劳永逸的需要更新。更新的方式有两种全量替换和灰度发布。全量替换简单但风险大新模型有问题就全挂了。灰度发布是先让一小部分流量走新模型观察一段时间没问题再全量。回滚机制也很重要。新模型上线后如果指标下降要能快速回滚到旧模型。实现方式是模型文件带版本号服务启动时加载指定版本回滚就是改配置重启。更高级的做法是热加载不重启服务就能切换模型但这个复杂度高小项目没必要。我的经验是每次模型更新都要有记录更新了什么、为什么更新、更新后的指标变化。这样出问题时能快速定位。7. 踩过的坑与实战心得7.1 那些让我熬夜的依赖冲突依赖冲突是AI工程里最烦人的问题之一。我印象最深的一次是PyTorch和某个数据处理库依赖了不同版本的NumPy装了这个那个就崩。排查了半天最后发现是conda和pip混用导致的。解决依赖冲突的经验是尽量用同一个包管理器并且锁版本。如果必须混用先装底层依赖NumPy、SciPy再装上层。遇到冲突时用pip check看哪些包不兼容然后手动调整版本。实在搞不定就新建一个干净环境从头装。还有一个技巧是用Docker。把环境打包成镜像本地和线上用同一个镜像就不会有“本地能跑线上不能跑”的问题。Dockerfile里把依赖装好镜像构建一次到处运行。这个对团队协作尤其重要。7.2 模型效果不达预期时的排查顺序模型效果不好不要瞎调参。我一般的排查顺序是先看数据再看评估再看模型最后看超参数。看数据有没有标签错误、数据泄漏、分布不一致。看评估指标选得对不对验证集划分有没有问题。看模型模型容量够不够结构合不合理。最后才是调超参数学习率、batch size、正则化系数。这个顺序的原因是数据问题是最常见的而且改数据比调参收益大得多。我见过太多人花几天调参最后发现是数据标签错了。7.3 从个人项目到团队协作的工程习惯个人项目可以随意一点但如果你想往团队协作走有些习惯要早点养成。第一是代码规范用black格式化用flake8检查别让代码风格成为协作障碍。第二是文档README写清楚怎么装、怎么跑、怎么测。第三是测试核心函数要有单元测试数据管道要有集成测试。这些习惯在个人项目里看起来是负担但在团队里是刚需。早点养成后面省事。7.4 持续学习AI工程的知识更新节奏AI这个领域变化快但工程部分的变化其实没那么快。数据管道、服务化、监控这些底层原理几年不变。变的是工具和模型。我的学习策略是底层原理深挖上层工具浅尝。比如数据版本管理的原理内容寻址、快照要懂但具体用DVC还是别的工具会用一个就行。模型方面不用追每一个新模型但要知道主流模型的适用场景和优缺点。遇到具体任务时能快速选型就行。真正要花时间的是工程能力怎么设计可维护的系统、怎么排查问题、怎么优化性能。这些能力是通用的不会过时。最后分享一个我自己的习惯每做完一个项目写一份复盘记录做了什么、遇到什么问题、怎么解决的、下次怎么改进。这份复盘比任何教程都有价值因为它是你自己的经验。ai-engineering-from-scratch这条路走一遍不容易但走通了你就有了别人拿不走的能力。
返回列表