ARTICLE DETAIL

资讯详情

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

从零搭建AI工程体系:避开从Demo到生产的那些坑

从零搭建AI工程体系:避开从Demo到生产的那些坑 1. 从零搭建AI工程能力为什么“会调包”远远不够很多人第一次接触AI工程是从一行pip install开始的。装完框架跑通一个官方Demo看着终端里跳出几行训练日志就觉得自己已经“入门”了。可真到了要自己搭一个能用的系统时问题就来了数据怎么组织模型怎么选训练崩了怎么查推理慢得像蜗牛怎么办上线之后怎么监控这些事官方文档不会一条条教你网上的教程也大多只讲“怎么跑通”不讲“为什么这样跑”。ai-engineering-from-scratch这个标题核心不在“AI”而在“engineering”和“from scratch”。它强调的不是调包能力而是从零开始构建一套完整AI工程体系的能力。换句话说它关心的不是“模型能不能跑”而是“这套东西能不能稳定、可维护、可扩展地跑下去”。这跟单纯学算法、学调参是两码事。算法解决的是“模型效果好不好”工程解决的是“系统能不能用、好不好用、能不能持续用”。我见过太多团队算法同学在Notebook里把指标刷得很漂亮一交给工程同学上线性能直接打三折。原因往往不是模型不行而是工程链路里到处是坑数据预处理和训练时不一致、特征在线上取不到、batch size设得太大导致显存溢出、推理服务没有做并发控制、日志埋点缺失导致出了问题无从查起。这些问题每一个都不难但凑在一起就足以让一个看起来“已经跑通”的项目彻底失败。所以这篇内容适合谁如果你是刚入行的AI工程师想搞清楚一个完整AI系统到底包含哪些环节每个环节的关键决策点在哪里那这篇就是写给你的。如果你是有一定经验的开发者想补上工程化这块短板把“能跑”变成“能扛”那这篇同样有参考价值。如果你只是对AI好奇想了解一个AI产品背后到底发生了什么那也可以跟着看下去我会尽量用生活化的类比把复杂概念讲清楚。接下来我不会按“数据、模型、训练、部署”这种教科书目录来写而是按一个真实项目从零到一的时间线把每个阶段最容易踩的坑、最关键的决策、最容易被忽略的细节一条条拆开讲。你可以把它当成一份“AI工程避坑地图”也可以当成一个从零搭建项目的操作手册。不管你是哪种读法我都建议你边看边对照自己手头的项目看看哪些地方你正在踩坑哪些地方你还没意识到有坑。2. 项目启动前必须想清楚的五件事2.1 先定义“成功”长什么样再动手写代码很多项目失败不是因为技术不行而是因为一开始就没定义清楚“做成什么样才算成功”。是准确率到90%还是响应时间低于200毫秒还是每天能处理100万条请求这三个目标对应的技术方案完全不同。如果你一开始说“我要做一个AI客服”那这个目标太模糊了没法指导技术选型。你得把它拆成可量化的指标意图识别准确率不低于92%单次响应时间不超过300毫秒支持50路并发每天能处理10万轮对话。这些指标一旦定下来后面所有决策都有了依据。模型选型时你会知道不能选太大的模型因为延迟扛不住架构设计时你会知道必须做缓存因为并发要求高数据标注时你会知道哪些类别必须优先保证质量因为它们的准确率直接影响整体指标。反过来如果你一开始没定这些做到一半发现模型太大跑不动再回头换模型前面很多工作就白费了。我自己的习惯是在项目启动前写一份“一页纸规格说明”里面只写三件事这个系统要解决什么问题、成功指标是什么、明确不做什么。最后一条特别重要。很多项目做着做着就跑偏了就是因为没有明确边界。比如你做一个文本分类系统有人跑来说“能不能顺便做个情感分析”你顺手加了结果整个数据 pipeline 要改模型要重训工期直接翻倍。如果一开始就写清楚“本期不做情感分析”后面就可以理直气壮地说“这个不在范围内”。2.2 数据从哪里来比模型选什么更重要在AI工程里数据的重要性怎么强调都不为过。我甚至可以说一个项目80%的成败在数据阶段就决定了。但很多新手会把大部分精力花在模型上觉得模型越新越好、越复杂越好数据随便搞搞就行。这是典型的本末倒置。数据这件事首先要问的是“从哪里来”。是自有业务数据还是公开数据集还是需要人工标注这三种来源的工程复杂度完全不同。自有业务数据看起来最省事但往往存在严重的分布偏差——你的业务只覆盖了一部分场景模型学到的规律在真实世界里可能根本不成立。公开数据集质量参差不齐而且和你的业务场景往往有差距直接拿来用效果通常不好。人工标注最可控但成本最高而且标注质量本身就是一个大坑。我踩过最深的坑是标注一致性问题。同一个样本不同标注员给出的标签不一样同一个标注员今天和明天的标准也不一样。这种噪声数据喂给模型模型学到的就是混乱的规律指标怎么都上不去。后来我们定了一套标注规范每个类别都写了详细的定义和边界案例还做了交叉验证——每个样本至少两个人标不一致的就拿出来讨论。虽然前期慢了一点但后面模型效果稳定了很多。还有一个容易被忽略的点数据泄漏。简单说就是训练数据里混入了不该有的信息导致模型在测试集上表现很好一到线上就崩。比如你做时间序列预测如果用未来数据去预测过去那指标肯定好看但没有任何实际意义。再比如你做用户流失预测如果特征里包含了“用户已经注销”这种信息那模型当然能“预测”准但这在真实场景里根本拿不到。数据泄漏的排查没有捷径只能靠对业务的理解和对数据来源的仔细审查。2.3 技术选型别追新追合适技术选型是另一个容易上头的地方。新手往往喜欢用最新的框架、最潮的工具觉得这样才“专业”。但实际项目中稳定性和社区支持比新特性重要得多。你选了一个刚发布三个月的框架遇到问题搜不到答案官方文档还不全最后卡在一个小bug上耗掉一周这种代价太大了。我的选型原则很简单优先选社区活跃、文档齐全、有成功案例的方案。具体来说深度学习框架方面PyTorch和TensorFlow二选一就行看团队熟悉哪个。PyTorch在研究社区更流行调试起来更直观TensorFlow在生产部署方面积累更深工具链更完整。没有绝对的好坏只有适不适合你的团队。推理服务方面如果追求极致性能可以考虑TensorRT或者ONNX Runtime如果追求开发效率直接用框架自带的serving方案也行。数据库方面特征存储可以用Redis或者Feast日志存储用Elasticsearch或者ClickHouse这些都有比较成熟的实践。关键不是选哪个而是选完之后要理解它的边界——Redis适合存低延迟的小特征不适合存大块文本ClickHouse适合做聚合分析不适合做点查。用错了地方再好的工具也白搭。还有一个选型误区是“过度设计”。有些团队一上来就搞微服务、搞Kubernetes、搞特征平台结果项目本身才几十个QPS维护成本比收益还高。我的建议是先跑通最小闭环等业务量真的上来了再逐步演进。一开始用Flask写个简单的推理接口后面扛不住了再换Triton或者TorchServe这个路径完全没问题。工程上最怕的不是“不够先进”而是“过度复杂”。2.4 环境管理别让“在我机器上能跑”成为借口“在我机器上能跑”这句话大概是工程领域最招人恨的一句话了。它背后反映的是环境不一致的问题开发环境、测试环境、生产环境的Python版本不一样、依赖包版本不一样、甚至操作系统都不一样。这种问题在AI项目里尤其严重因为AI项目的依赖特别多而且版本之间经常有冲突。解决这个问题的标准做法是容器化。Docker可以把你的代码、依赖、环境变量全部打包成一个镜像在任何支持Docker的机器上都能以相同的方式运行。但容器化本身也有坑镜像太大、构建太慢、GPU支持配置复杂。我的经验是基础镜像尽量选官方的、精简的版本比如pytorch/pytorch:2.0-cuda11.7-cudnn8-runtime这种不要自己从零搭。依赖安装用requirements.txt或者poetry管理版本号尽量写死不要用latest。GPU支持方面确保宿主机装了正确的驱动容器里用--gpus all启动就行。除了容器化还有一个好习惯是“环境即代码”。也就是说环境的搭建过程要写成脚本或者配置文件而不是靠手动操作。比如用Dockerfile描述镜像构建过程用docker-compose.yml描述服务编排用Makefile描述常用命令。这样任何人拿到你的项目都能一键复现环境而不是靠口口相传的“你先装这个再装那个”。2.5 版本控制代码要管数据和模型也要管Git管代码大家都熟悉但AI项目里数据和模型也需要版本控制。你改了数据预处理逻辑模型效果变了你得知道是逻辑改对了还是数据变了。你调了超参数模型指标提升了你得知道是哪个参数起了作用。这些都需要版本管理。数据版本控制可以用DVC或者Pachyderm它们可以把大文件存在对象存储里Git里只存元数据。模型版本控制可以用MLflow或者Weights Biases它们可以记录每次实验的超参数、指标、模型文件方便对比和回溯。如果团队规模小不想引入太多工具至少也要做到“每次实验都记录在一个表格里”包括数据版本、代码版本、超参数、指标。这个习惯看起来麻烦但当你需要复现三个月前的一次实验结果时你会感谢自己当初记了这些。3. 数据管道的搭建从原始数据到训练样本3.1 数据清洗别急着喂给模型先看看数据长什么样拿到原始数据的第一件事不是写模型而是做探索性数据分析。你得知道数据里有什么有多少条样本每个字段的分布是什么样的有没有缺失值有没有异常值标签分布均衡吗这些问题不搞清楚后面全是坑。我见过一个团队拿到数据直接开训训了一周发现模型效果怎么都上不去。后来一查发现数据里有30%的样本标签是错的——标注员把两个类别的定义搞混了。这种问题如果一开始做一下标签分布检查很容易就能发现。比如两个类别的样本量差不多但其中一个类别的样本特征明显更接近另一个类别那就很可疑。数据清洗的常见操作包括去重、处理缺失值、处理异常值、统一格式。去重不是简单地把完全相同的行删掉而是要根据业务含义判断什么是“重复”。比如用户行为日志里同一秒内的多次点击可能是重复上报也可能是真实行为得看业务逻辑。缺失值处理要看缺失比例和缺失原因如果某个字段缺失超过50%可能直接删掉这个字段更合适如果缺失比例不高可以用均值、中位数或者模型预测来填充。异常值不一定要删有时候异常值恰恰是重要信号比如欺诈检测里的异常交易。3.2 特征工程让模型看到“好”的数据特征工程是AI工程里最考验功力的环节。同样的数据不同的人做出来的特征模型效果可能差好几个点。但特征工程没有标准答案它高度依赖业务理解。比如做电商推荐用户最近7天的点击次数、加购次数、购买次数这些统计特征通常比原始行为序列更有效。但具体用几天、用什么统计量得靠实验来定。特征工程有几个原则值得记住。第一特征要有业务含义。不要为了凑数量而加一些自己都解释不了的特征这种特征往往在训练集上有效在线上就失效。第二特征要在线上可获取。训练时用到的特征线上推理时也必须能拿到而且计算逻辑要一致。我见过一个项目训练时用了“用户过去30天的平均客单价”这个特征线上推理时发现这个特征需要查历史订单表延迟太高根本没法实时计算最后只能砍掉重训。第三特征要做归一化或者标准化。不同特征的量纲差异太大会影响模型收敛尤其是神经网络。常见的做法是减去均值除以标准差或者归一化到0到1之间。还有一个容易忽略的点是特征穿越。简单说就是训练时用到了未来信息。比如你做销量预测特征里包含了“当天的促销活动”但预测场景是提前一周预测那时候促销活动还没确定这个特征在线上根本拿不到。特征穿越的排查方法是对每个特征问一句“这个信息在预测时刻真的能拿到吗”如果答案是否定的那这个特征就不能用。3.3 数据划分训练集、验证集、测试集怎么分数据划分看起来简单其实有很多讲究。最常见的做法是随机划分比如70%训练、15%验证、15%测试。但随机划分有个前提数据是独立同分布的。如果数据有时间顺序比如用户行为日志随机划分就会导致数据泄漏——未来的数据可能被划到训练集里模型在验证集上表现很好但线上效果很差。对于有时间顺序的数据正确的做法是按时间划分用过去的数据训练用之后的数据验证和测试。比如用1月到6月的数据训练7月的数据验证8月的数据测试。这样更接近真实场景因为线上预测时你永远是用历史数据预测未来。对于类别不平衡的数据划分时要注意保持每个集合的类别比例一致。比如正样本只占1%如果随机划分可能某个集合里一个正样本都没有。这时候要用分层抽样确保每个集合的正负样本比例和整体一致。如果数据量特别小还可以用交叉验证把数据分成K份轮流做验证集这样能更充分地利用数据。3.4 数据管道自动化别用手动脚本用工作流数据管道的手动操作是万恶之源。你今天手动跑一个脚本清洗数据明天手动跑另一个脚本生成特征后天手动把特征文件拷到训练目录。这种流程看起来灵活实际上不可复现、不可追溯、容易出错。正确的做法是把整个管道写成工作流用Airflow、Prefect或者Luigi这样的工具来编排。工作流的核心思想是“任务依赖”和“自动触发”。比如你定义数据清洗依赖原始数据特征生成依赖数据清洗模型训练依赖特征生成。当原始数据更新时整个管道自动跑一遍每个环节的输出都自动存到指定位置。这样你不需要记住“先跑哪个再跑哪个”也不需要担心漏了某个步骤。工作流还有一个好处是“可观测性”。每个任务的运行状态、耗时、输出都可以在界面上看到出了问题能快速定位是哪个环节卡住了。如果某个任务失败了可以配置重试策略也可以发告警通知。这些在手动流程里都很难做到。4. 模型训练与调优从能跑到跑得好4.1 基线模型先跑通再优化很多新手一上来就想训一个SOTA模型结果卡在环境配置、数据加载、显存溢出各种问题上一周过去了连个能跑的模型都没有。我的建议是先用最简单的模型跑通全流程。比如文本分类先用TF-IDF加逻辑回归几行代码就能跑出一个基线。图像分类先用预训练的ResNet做特征提取再训一个线性分类器。这个基线模型可能效果一般但它能帮你验证数据管道是否通畅、评估指标是否合理、整个流程是否跑得通。有了基线之后再逐步换更复杂的模型。换模型的时候一次只换一个变量这样才能知道效果变化是模型带来的还是其他因素。比如你先用逻辑回归得到85%的准确率换成BERT得到90%那你知道BERT带来了5个点的提升。如果你同时换了模型、改了数据预处理、调了超参数最后效果提升了你根本不知道是哪个因素起了作用。4.2 超参数调优别瞎试用策略超参数调优是另一个容易上头的地方。学习率、batch size、正则化系数、网络层数、注意力头数……参数太多了手动试根本试不过来。常见的调优策略有网格搜索、随机搜索、贝叶斯优化。网格搜索适合参数少、范围小的情况比如学习率只在0.001和0.01之间选那可以穷举。随机搜索适合参数多的情况随机采样往往比网格搜索更高效。贝叶斯优化适合评估成本高的情况它会根据之前的实验结果智能选择下一个参数组合。但不管用什么策略都要注意“过拟合验证集”。如果你在验证集上反复调参调了几十轮那验证集的信息就泄漏到模型里了最终在测试集上的表现会差很多。正确的做法是用验证集调参但调参次数要有限制最终评估用测试集而且测试集只能用一次。如果测试集结果不好不要回头再调参那说明你的验证集划分或者评估指标有问题。4.3 训练过程监控别等训完再看结果训练一个模型可能要几个小时甚至几天如果等训完再看结果发现问题就晚了。正确的做法是实时监控训练过程。关键指标包括训练损失、验证损失、学习率、梯度范数、显存占用。训练损失下降但验证损失上升说明过拟合了该加正则化或者早停。训练损失和验证损失都不下降说明学习率太小或者模型容量不够。梯度范数突然变得很大说明可能遇到了梯度爆炸该加梯度裁剪。显存占用一直涨说明可能有内存泄漏该检查数据加载或者模型定义。这些监控可以用TensorBoard或者Weights Biases来做它们可以实时画曲线还能对比不同实验的结果。我自己的习惯是训练开始后每隔一段时间就看一眼曲线如果发现异常就及时停掉调整后再重新训。这样比训完再发现问题节省很多时间。4.4 模型评估别只看准确率准确率是最直观的指标但它往往不够。对于类别不平衡的数据准确率会误导你。比如正样本只占1%模型把所有样本都预测为负准确率也有99%但这个模型没有任何实用价值。这时候要看精确率、召回率、F1值。精确率是“预测为正的样本里有多少是真的正”召回率是“真实正的样本里有多少被预测出来了”。这两个指标往往此消彼长需要根据业务场景权衡。比如做疾病筛查宁可误报也不能漏报那就优先保证召回率做垃圾邮件过滤宁可漏掉也不能误拦那就优先保证精确率。除了这些还要看混淆矩阵了解模型在哪些类别上容易混淆。如果两个类别经常互相误判可能是这两个类别的定义本身就有重叠或者特征区分度不够。还要看错误样本分析模型错在哪里是数据问题还是模型问题。这些分析比单纯看一个数字有用得多。5. 部署与上线从实验室到生产环境5.1 推理服务别直接把Notebook搬上去Notebook里跑通的模型不能直接搬到生产环境。Notebook是交互式的生产环境是服务化的。你需要把模型封装成一个API接收请求、做预处理、跑推理、做后处理、返回结果。这个API要能处理并发请求要有超时控制要有错误处理要有日志记录。常见的推理服务方案有Flask、FastAPI、Triton Inference Server、TorchServe。Flask和FastAPI适合快速搭建开发效率高但性能和并发能力一般。Triton和TorchServe是专门为推理设计的支持动态批处理、多模型管理、GPU加速适合生产环境。选择哪个取决于你的业务量和团队熟悉程度。如果QPS不高FastAPI就够了如果QPS很高或者需要同时服务多个模型那就上Triton。不管用哪个方案都要注意几个点。第一预处理和后处理的逻辑要和训练时一致。训练时怎么归一化的推理时也要怎么归一化训练时怎么编码标签的推理时也要怎么解码。这个不一致是线上效果下降的最常见原因。第二要做好输入校验。用户传过来的数据可能格式不对、字段缺失、数值越界这些都要在预处理阶段拦住不能让脏数据进到模型里。第三要控制batch size。推理时如果一次来太多请求显存可能扛不住要做动态批处理或者请求队列。5.2 性能优化让推理快起来推理速度直接影响用户体验和服务器成本。优化推理性能有几个方向。第一模型压缩。剪枝、量化、蒸馏都可以减小模型体积、加快推理速度。量化是最常用的把FP32的权重转成INT8速度能提升两三倍精度损失通常很小。第二算子融合。把多个连续的操作合并成一个减少内存访问和kernel启动开销。TensorRT和ONNX Runtime都支持自动算子融合。第三批处理。一次处理多个请求充分利用GPU的并行能力。但批处理会增加延迟需要根据业务场景权衡。还有一个容易被忽略的点是“冷启动”。如果推理服务是按需启动的第一次请求可能要等模型加载延迟很高。解决办法是保持服务常驻或者用预热请求提前加载模型。如果用的是Serverless架构冷启动问题会更严重需要考虑用预留实例或者定时预热。5.3 监控与告警上线只是开始模型上线不是终点而是起点。线上环境是动态变化的数据分布会漂移用户行为会变化模型效果会衰减。如果没有监控你可能几个月后才发现模型已经不准了。监控的关键指标包括请求量、延迟、错误率、模型输出分布、特征分布。请求量和延迟反映服务健康度错误率反映系统稳定性模型输出分布和特征分布反映数据漂移。数据漂移的检测方法有很多简单的是比较线上数据和训练数据的统计量比如均值、方差、分位数。如果差异超过阈值就告警。复杂一点的可以用对抗验证训一个分类器区分训练数据和线上数据如果分类器很容易区分说明分布差异很大。告警之后要有人处理处理方式可能是重新训练模型、调整阈值、或者回滚到旧版本。5.4 回滚机制给自己留条后路新模型上线后效果不好怎么办必须有回滚机制。回滚的前提是版本管理每个模型版本都要有记录包括训练数据、代码、超参数、评估指标。回滚的时候把流量切到旧版本就行。流量切换可以用A/B测试框架来做也可以简单地改一下路由配置。回滚的触发条件要提前定好。比如新模型上线后如果错误率超过1%或者延迟超过500毫秒或者关键业务指标下降超过5%就自动回滚。这些条件要写成代码自动执行不要靠人工判断。人工判断往往犹豫不决等决定回滚的时候损失已经造成了。6. 那些文档里不会写的实战经验6.1 关于数据脏数据比没数据更可怕我做过一个项目数据量很大但质量很差。标注员为了赶进度很多样本都是随便标的。模型训出来之后在测试集上指标很好看因为测试集也是同一批人标的标准一致。但上线之后用户反馈效果很差。后来我们重新标了一批高质量数据虽然量只有原来的十分之一但模型效果反而更好。这件事让我深刻体会到数据质量比数据数量重要得多。宁可要一千条干净的数据也不要一万条脏数据。6.2 关于模型简单模型往往更实用新手喜欢用复杂模型觉得越复杂越厉害。但实际项目中简单模型往往更实用。简单模型训练快、推理快、容易调试、不容易过拟合。我见过很多项目最后上线的就是一个逻辑回归或者XGBoost效果不比深度学习差但维护成本低得多。所以我的建议是先用简单模型如果效果不够再换复杂模型。不要为了“用上深度学习”而用深度学习。6.3 关于工程可维护性比性能更重要性能优化很重要但可维护性更重要。一个性能很好但没人能看懂的代码不如一个性能一般但结构清晰的代码。因为业务会变需求会变模型会换只有可维护的代码才能适应变化。可维护性的关键包括模块化、注释清晰、配置和代码分离、日志完善。这些在项目初期可能觉得麻烦但到了后期你会感谢自己当初写了这些。6.4 关于协作文档和沟通比代码更重要AI项目通常需要多人协作数据工程师、算法工程师、后端工程师、产品经理。每个人关注的点不一样如果没有好的文档和沟通很容易各做各的最后拼不起来。我的经验是每个环节都要有文档数据字典、特征说明、模型卡片、API文档。这些文档不一定要很正式但一定要有而且要随着项目更新。沟通方面定期开会对齐进展和问题比在群里零散地聊有效得多。6.5 关于心态接受不完美持续迭代AI项目很少有“一次做对”的。第一版模型效果不好是正常的第一版系统有bug是正常的第一版上线被用户吐槽也是正常的。重要的是快速迭代每次解决一个问题每次提升一点。不要追求完美追求持续改进。我自己的项目第一版通常都很粗糙但跑通之后后面优化起来就快了。最怕的是卡在某个环节不动那项目就永远上不了线。7. 从零到一之后下一步往哪走当你跑通了一个完整的AI项目从数据到模型到部署都走了一遍接下来可以往几个方向深入。第一自动化。把数据管道、训练、评估、部署全部自动化做到数据更新后模型自动重训、自动评估、自动上线。第二平台化。把常用的功能抽象成平台比如特征平台、模型平台、实验平台让团队其他人也能快速复用。第三规模化。支持更多模型、更大数据量、更高并发这需要更复杂的架构设计。第四智能化。用AutoML、神经架构搜索等技术减少人工调参用主动学习减少标注成本。但不管往哪个方向走基础工程能力都是前提。数据管道不稳自动化就是空中楼阁模型部署不可靠平台化就是灾难系统架构不清晰规模化就是堆机器。所以如果你还在从零到一的阶段不要急着追新概念先把基础打牢。基础打牢了后面学什么都快。我自己在这个领域摸爬滚打这么多年最大的体会是AI工程没有捷径但有方法。方法就是理解每个环节的原理知道每个决策的理由踩过坑之后记住教训。这篇内容里的每一条经验都是我或者我身边的同行真实踩过的坑。希望你看完之后能少走一些弯路把项目做得更稳、更好。
返回列表