
真正想从零把 AI 项目搬上线的人缺的不是一两个算法而是整个“AI engineering”的工程化思维。很多人以为调通一个 Notebook 就算完事结果一上生产环境就崩数据一变模型就废这个坑我踩过太多次了。这篇东西就是写给你——想从零开始构建一个能跑的、能维护的 AI 工程而不是只会跑实验的脚本。我会按真实项目推进的顺序把需求定义、数据处理、模型选型、训练调优、部署上线、持续迭代这几个环节拆开揉碎给出可直接抄作业的流程和参数也会讲清楚每一步背后的取舍。适合刚入门但不想走弯路的工程师也适合那些想在团队里建立 AI 工程规范的技术负责人。1. 从零做 AI 工程先别碰代码——需求与可行性1.1 先回答两个问题给谁用用成什么样我见过太多项目死在没有定义清楚目标上。拿到一个 AI 任务先别急着找数据集、拉模型先用一页纸把问题说清楚。这个 AI 系统最终是给谁用的是内部运营人员辅助审核还是面向 C 端用户自动生成内容不同的用户群体直接决定了你的准确率下限和延迟容忍度。举个例子如果你做一个客服工单自动分类系统目标是让客服人员更快处理工单那准确率 85% 可能就够用——因为人工会做最终确认系统只是前置筛选。但如果你做一个全自动退款审核机器人那错误率哪怕只有 1%造成的资损也可能无法承受。所以“用成什么样”本质上是一个工程指标准确率、召回率、延迟、吞吐量、成本预算必须量化不能只说“效果要好”。我建议在写第一行代码之前输出一个一页纸的 PRD包含三块内容核心场景描述、可量化的成功指标、不做什么的边界说明。“不做什么”尤其重要它能帮你挡住后续无穷无尽的需求蔓延。比如做文本审核明确不做涉及历史、政治方向的内容理解只做业务违规词识别这样既能规避合规风险又能让模型边界清晰。1.2 可行性评估手头有什么缺什么补什么成本多少可行性评估不是写论文而是算账。你需要算清楚三笔账数据账、算力账、人力账。数据账看的是我们手头有没有带标注的数据如果没有需要多少人天去标注标注标准谁来定我做过一个实体抽取项目一开始以为直接用公网数据集就行结果发现业务术语差异极大最后不得不从零标注了两万条数据耗时三周。这个成本在项目启动前就应该估算出来。算力账更直白预训练一个大模型还是用现成的预训练模型做微调还是直接调用 API从零开始训练大模型不是一般团队该做的事成本和周期都不可控。常规做法是选一个开源的预训练模型做底座微调一个小模型或者干脆用提示词工程解决问题。算力成本要按每小时的 GPU 费用乘以预估训练时长来算还要加上实验迭代的损耗。人力账很多人会漏掉。一个 AI 工程不只是算法工程师的事至少还需要数据标注人员、后端开发、运维配合。如果团队只有一个人那就要缩小范围别想着一步到位做全流程。我最初的几个项目都是我自己硬扛数据清洗和简单部署虽然慢但至少把链路跑通了。先跑通再优化这条原则在可行性评估阶段就要定下来。2. 数据工程才是真正的起点——清洗、标注、版本管理2.1 数据采集与清洗脏数据会直接毁掉你的模型很多初学者喜欢从公开数据集起步这没问题但公开数据集与你实际业务场景的分布往往差距很大。就算你找到一份看起来能用的数据也必须做一轮彻底的清洗。我自己的经验是清洗逻辑永远先于建模逻辑数据里有什么垃圾模型就会学到什么垃圾。清洗第一步是去重。文本数据里重复样本会让模型对高频样本过拟合图片数据里近乎重复的帧也一样。第二步是处理缺失值比如把空字符串、全角空格、无意义字符统一处理掉。第三步是过滤异常样本比如一条文本的长度异常短或异常长图片分辨率过低都建议先筛出来人工查看而不是直接扔进训练集。清洗之后一定要做分布检查。我常用的是统计类别分布、文本长度分布、关键词频率分布。如果发现某个类别只有几十条而另一个类别有几万条那你模型大概率会偏向大类。这时候要么补充数据要么在训练时做重采样或设计 loss 加权。这个步骤叫数据洞察也是说服业务方“还需要再采集数据”的最有力证据。2.2 标注规范没有标准就没有高质量的监督信号如果数据需要人工标注那标注规范的制定直接决定模型上限。千万不要让标注员直接开标你需要先写一份标注手册然后至少进行两轮试标和一致性评估。标注手册不是泛泛的定义而是把每个类别都配上正例、反例、边界案例。比如做意图识别“咨询”和“投诉”的边界很容易模糊必须写明“凡包含负面情绪且要求人工介入的表述归为投诉单纯询问流程的归为咨询。”再比如做目标检测边界框的标注规则要细化到遮挡超过 50% 是否标注目标小于某个像素是否忽略这些都要提前约定。试标阶段找 2-3 个标注员各标 100 条然后算一遍 Cohens Kappa 或 Fleiss Kappa 一致性系数。如果系数低于 0.7说明标注标准不清晰需要修改手册。这个环节很多人嫌麻烦直接跳过但跳过的后果是训练集内部的标注噪声极大模型学到的是标注员个人的主观判断而不是统一的业务规律。2.3 数据版本管理回不到旧数据的 AI 工程等于没有后悔药代码有 Git数据也需要版本管理。这一点我在项目初期完全没意识到直到有一次改完清洗脚本重新生成了数据集但效果变差了想回退到旧版本却找不到旧文件只能原地重构。从那以后我强制自己用 DVC 或 LakeFS 管理数据版本。在 DVC 的使用上最简单的流程是把原始数据放在固定的目录用dvc add记录版本再把.dvc文件和代码一起提交到 Git。每次清洗或转换都用独立的脚本并记录输入数据版本和输出数据版本。这样整个实验的可复现性就能保证。你甚至可以更进一步把训练集、验证集、测试集的划分也固定下来用带哈希的文件名保存。划分集合时要注意避免数据泄漏比如同一用户的多条记录不能同时出现在训练集和测试集里否则你的评估指标会虚高上线后一测真实表现就露馅。3. 模型选型与训练调优——不追求新奇只追求稳定3.1 选型思路先定基线再谈优化模型选型的原则不是选最新的而是选最稳的。每当我开始一个项目都会先选择一个已经被广泛验证、社区资料丰富的基线模型。如果是文本分类可能先用 TF-IDF 分类器做基线如果是图像分类可能先用一个预训练的小型 CNN 做基线如果是文本生成直接用一个靠谱的预训练语言模型加提示词。基线模型的意义在于给你一个最低可用的效果参考同时帮助你验证数据链路是否通畅。如果基线跑出来的效果就很差那大概率是数据问题而不是模型问题。我见过有人直接上来就上大型模型结果跑了几天发现是数据标签错了一半白费功夫。当基线达到预期后再逐步提升模型复杂度。提升的方向有两个一是换更大的预训练模型二是针对业务数据做微调。微调时务必注意学习率设置通常采用较小的学习率比如 2e-5 到 5e-5具体值要看模型规模和数据集大小。如果学习率过大预训练的知识会被快速冲掉模型会过拟合到你要的那一点点业务数据上泛化能力反而下降。3.2 训练集/验证集/测试集划分先切数据再动模型听起来很简单但很多人会忽略划分的随机性和分布匹配。我会先把所有干净数据划分成 80% 训练、10% 验证、10% 测试。验证集用来做训练过程中的模型选择和早停测试集只允许模型定稿后跑一次避免对测试集产生间接过拟合。划分时要保证类别分布一致。如果数据不平衡可以用分层采样让每个集合里的类别比例与整体一致。我在 sklearn 里一般用train_test_split(stratifyy)但在 NLP 任务里还要注意按时间或用户维度分组。比如你做一个评论审核模型如果同一天发布的评论被分别划到训练集和测试集那模型很容易“作弊”——它的泛化能力被高估了因为测试集里的样本与训练集里的样本有太多相似上下文。早停是另一个关键机制。我会在验证集上监控 loss 或 F1当指标连续 3-5 个 epoch 不再提升就停止训练把最优 epoch 的模型保存下来。很多框架有现成的 EarlyStopping 回调但你需要自定义监控指标确保是验证集上评估的指标而不是训练集 loss。3.3 过拟合与欠拟合的排查套路模型不收敛先别慌按系统方法排查。先看训练集 loss。如果训练集 loss 不下降说明模型容量不够或数据信号太弱这时候需要加大模型、调高学习率、或者检查数据是否擦除了关键信息。再看验证集 loss。如果训练集 loss 一直降验证集 loss 却回升说明过拟合了优先手段是加正则化、加 Droupout、减小模型容量、提前停止或者扩充数据。如果是文本任务最常见的坑是词表覆盖不够。如果你的业务里有大量特殊用语而模型用的 tokenizer 不认识这些词那再好的模型也学不出语义。解决办法是在微调阶段让 tokenizer 对业务语料做一次增量训练或者干脆在数据预处理阶段把高频业务词映射成占位符。还有一类问题叫“数据集太小”。几十条到几百条数据很难训出理想效果除非用超大规模预训练模型做 few-shot 或 zero-shot。此时我建议先跑提示词工程看看 GPT 类模型能不能直接解决问题。如果效果勉强可用再考虑用这些生成结果做人工筛选扩充标注数据形成正向循环。4. 部署上线从 Notebook 到生产环境的最后一公里4.1 封装模型服务把你的模型变成一个可调用的 API训练完模型拖出.pth或.h5文件这只是万里长征第一步。你要做的是把模型封装成一个可调用的服务让后端业务代码通过 HTTP 请求或消息队列来使用它。我常用的做法是用 FastAPI 写一个简单的推理服务。请求进来先做预处理分词、归一化、图像 resize然后调用模型再做后处理概率转标签过滤低置信度结果最后返回 JSON。整个服务用一个 Dockerfile 打包镜像里锁死 Python 版本、依赖包版本这样部署到哪都一样。在封装时一定要加入兜底逻辑。比如输入文本为空、格式不对模型推理超时GPU OOM 等异常情形服务要能返回明确的错误码而不是直接把 500 抛给前端。我习惯在服务入口做输入校验在模型推理外面套 timeout并且用日志记录每一次请求的输入摘要和输出结果方便后续排查。4.2 性能优化延迟和吞吐量你都得心里有数上线前必须做压测不能等服务被真实流量打崩了再补。压测很简单用 Locust 或 wrk 模拟多并发请求观察服务在不同 QPS 下的延迟和 error rate。这里有两个指标特别关键P95 延迟和最大可承载 QPS。如果 P95 延迟太高优先优化预处理环节和后处理环节这两个环节往往比模型推理本身还耗时。比如你每次请求都要重新加载一次 tokenizer或做大量的 Python 循环这就会成为瓶颈。更常见的优化手段是模型量化。把 FP32 的权重压缩到 FP16 或 INT8推理速度能提升 2-4 倍显存占用也能减半。量化工具很多PyTorch 自带torch.quantizationONNX Runtime 也支持动态量化。如果你的服务是 CPU 部署那更要重视模型轻量化。我之前把一个 BERT 模型做蒸馏换成了 TinyBERT效果只掉了 1 个点延迟却从 200ms 降到了 30ms。这种性价比极高的优化应该放在方案评审阶段就考虑进去。4.3 模型上线不是终点而是监控的起点模型部署到生产环境后如果没有监控就是盲驾驶。需要监控的东西不止是服务器负载更要监控模型效果和输入数据的分布。我先说服务器层面CPU/GPU 使用率、内存占用、响应时间、错误率这些用 Prometheus Grafana 就能解决。但这些只是基础模型层面才是最难的。你可以记录每次用户请求的模型置信度然后每天统计置信度分布。正常情况下大部分请求的置信度应该都比较高。如果某天分布整体下移说明输入数据和训练集分布不一致了这就是数据漂移的信号。另外一定要记录 bad case。不要只记录错误率还要抽样记录错误样本定期人工复盘。你会发现很多问题在舆情爆发前就有苗头。比如某类新出现的文本写法模型不认识但你的监控指标可能还没体现出来。建立 bad case 反馈通路是 AI 工程持续迭代的核心能力。5. 长期维护与迭代——AI 工程的持续性5.1 数据漂移检测数据变了模型却没变然后它就废了你最开始的模型效果再好运行三个月后也会悄悄变差这不是模型坏了是数据分布变了。业务术语会变、用户表达习惯会变、甚至不同季节的文本风格都不一样。所以数据漂移检测必须常驻。我建议对上线的每个模型都做一个输入特征分布监控。对文本来说可以监控关键词频率、文本长度、embedding 均值对图像来说可以监控亮度分布、色彩直方图、目标尺寸分布。核心方法是定期抽取线上数据和训练集做分布距离比较比如用 PSIPopulation Stability Index或者 Wasserstein 距离。当漂移指标超过阈值就要触发告警然后进入模型重训流程。重训不是简单地把新旧数据混在一起重新跑一遍而是要重新标注新数据、检查类别体系是否还适用、重新划分训练验证集。我之前做过一个分类模型业务方新增了“退款纠纷”这一类别但原有类别里有“客户抱怨”和“售后问题”新旧类别语义重叠严重。这种时候贸然重训只会让模型左右摇摆。5.2 灰度发布与 A/B 测试新模型凭什么取代旧模型新模型训练好了不要直接全量替换线上旧模型。先做影子模式也就是把线上流量复制一份同时让新旧模型各自预测只记录结果不改变用户反馈。这样积累几天数据后就能比较新旧模型在同一批真实请求上的表现差异。如果影子模式效果不错再做灰度发布。把新模型承接 5% 到 10% 的流量配置好监控观察业务方反馈和指标变化没问题再逐步放开到 20%、50%、100%。这个流程看着繁琐但能帮你避免一次故障导致口碑崩塌。我经历过一次惨痛的教训新模型在离线测试集上 F1 提升了 3 个点我直接全量替换结果上线当天就出现大量误判因为测试集里没有覆盖某些线上特有场景。从那以后灰度发布于我而言就是铁律。A/B 测试要明确核心指标和护栏指标。核心指标是你要优化的目标比如推荐点击率、分类准确率。护栏指标是你不能变差的指标比如响应时间、投诉率。如果新模型核心指标变好但护栏指标崩了那也不能上线。5.3 文档与协作AI 工程能持续的前提是“别人能接盘”很多人忽视文档总觉得代码即文档。但 AI 工程是有数据、模型、prompt、训练配置、部署配置多种复杂资产的没有文档换个人接盘就是灾难。我会维护一份 README写清楚项目目标、数据来源、目录结构、运行步骤。另外有一份 EXPERIMENTS.md记录每次实验的配置、数据集版本、结果指标以及为什么这个实验有效或无效。这份文档不仅是给后人看的也是写给三个月后的自己看的——到时候你可能已经忘记了当初调参的细节。模型本身也要记录版本和来源。比如这个模型是在哪个基础预训练模型上继续训练的用了哪些训练数据评估指标是什么这些信息可以用模型卡Model Card的形式记录。训练后把模型文件、评估报告、样本预测结果一起打包放到模型仓库。协作方面我也建议团队内部建立一个统一的实验平台按项目、实验、模型分目录管理避免大家各自在本地跑模型最后根本合不到一起。6. 常见问题与排查技巧实录6.1 训练时 loss 抖动到飞起怎么压下来loss 震荡让人头大但原因无非那么几种。最常见的是学习率太高模型在损失曲面里左右跳跃。你可以打印每个 step 的 loss 值如果相邻 step 的 loss 波动很大先考虑把学习率调到原来的 1/5 试试。第二个常见原因是 batch size 太小梯度噪声大适当增大 batch size或者用梯度累积平滑更新。第三个原因是数据里有少量极端样本比如一条超长文本或一张异常图片导致单步 loss 爆炸可以试试梯度裁剪把梯度范数限制在 1.0 以内。如果以上方法都试了还不行检查一下 label 是否正确。有一次我自己写数据生成脚本把 label 的索引写错了导致模型等于在随机分类loss 根本压不下去。这个教训告诉我遇到异常情况先回到数据链路不要死磕模型。6.2 模型训练完预测速度极慢怎么定位瓶颈我先说一个工具逻辑先 profile再优化。不要凭感觉猜直接跑一次完整推理记录每个阶段的耗时。在代码里打点或者用 py-spy、cProfile 看热点函数。通常瓶颈出现在三种地方数据预处理中写了低效的循环、模型里有大量算子不支持批处理、后处理时逐条做了太重的计算。大多数时候预处理和后处理的优化空间比模型本身大。举个例子我做过一个实体识别服务模型推理只花了 20ms结果预处理里的分词加正则匹配花了一秒多后来把正则预编译、把分词换成轻量版整体延迟降了 80%。遇到 CPU 模型太慢优先做算子融合和模型量化。如果你在 GPU 上部署但显存占用高、吞吐量低可能是 batch size 太小或者模型里存在大量动态 shape导致 GPU 无法并行。改成固定序列长度、固定 batch size配合 TensorRT/TVM 优化吞吐量往往能提升一个数量级。6.3 模型上线后效果变差找不出原因线上效果差不要急着重训先找证据。第一步对比线上输入和训练集输入的分布看有没有数据漂移。第二步随机抽取误判样本人工分析是标注标准变化、新语义出现还是单纯的逻辑不适用。第三步检查线上预处理和训练时预处理是否完全一致。这个坑我踩过不止一次训练时对文本做了全角转半角、小写化线上服务忘了做最终效果自然对不上。还遇到过一种诡异情况线下评估时模型很稳定线上却频繁返回低置信度。后来发现线上服务调用模型时没有加载正确的权重文件服务跑的是随机初始化的模型。所以每次上线前我都要加一道模型文件哈希校验确保线上加载的版本和测试通过的版本完全一致。这些排查技巧的价值不在于让你会用一个框架而在于让你养成“系统归因”的思维方式。当 AI 系统出问题时从数据、模型、服务、配置四个层面逐层排查而不是盲目调参。这种系统性思考才是 AI engineering 和学术实验之间最本质的区别。