外面很多人一看到“ai-engineering-from-scratch”这个标题,第一反应是“又一个教你怎么调SDK的教程合集”。但说句实在话,如果只是把别人的模型接口包一层、把Prompt调得顺一点,那叫“API集成工程师”,不叫AI工程。真正能叫“from scratch”的,是你从理解问题、设计数据、训练/微调模型、到把它塞进生产系统扛住真实流量,整条链路都能自己画出来、跑起来、排掉坑。这篇文章我想认真聊聊,一个完全没有AI工程基础的人,或者说有一定软件基础但没系统做过AI项目的人,怎么从零开始把这条链路走通,以及这条路上有哪些不踩就不知道怎么避的坑。
先说清楚这篇文章适合谁。如果你是个后端工程师、前端工程师、运维,或者刚毕业但已经能独立写业务代码的人,想往AI工程方向转型,那这篇文章就是给你看的。如果你已经是天天训练模型的算法工程师,想看看工程化怎么落地,也有参考价值,但很多基础内容你会觉得啰嗦。文章不会教你背哪个框架的API,也不会给你一串魔改参数让你照着抄,而是把一套从零构建AI工程能力的完整路径拆开,讲清楚每一步为什么这么做、做了之后能用它解决什么问题、以及实践中掉过的坑。
1. 内容整体设计与思路拆解
1.1 先搞清楚“AI工程”到底解决什么问题
很多人误解了一件事,觉得AI工程就是把模型跑起来。实际上“把模型跑起来”可能只是整个项目里最简单的一环。一个真实的AI系统,尤其是要长期维护、持续迭代、面对真实用户的那种,它面对的复杂度远不止“模型推理”本身。
我倾向于把AI工程拆成下面这几个核心子系统:
- 数据侧:数据采集、清洗、标注、版本管理、分布探测。这部分决定了模型的“上限”。
- 模型侧:基座选择、微调策略、训练/推理资源规划、评测方法。这部分决定了“能不能达到上限”。
- 工程侧:服务化封装、并发控制、缓存设计、降级兜底、监控告警。这部分决定了“上线之后会不会出事”。
- 迭代侧:数据回流、模型重训、AB实验、回归测试。这部分决定了“半年后这个系统还活不活”。
你看,真正可持续发展的AI项目,模型训练只占其中一小块。大多数人栽跟头,不是模型训不出来,而是数据没管好、服务扛不住、回归测不明白。所以“from scratch”的第一课其实是思维转换:从一个“写代码的人”变成一个“对系统整体负责的人”。
1.2 为什么“工程化”比“算法创新”更重要
这个观点可能有点反直觉,特别是我跟很多算法出身的朋友聊,他们觉得算法牛才是真牛,工程化就是“调包”。但现实是,在一个商业系统里,算法创新能带来的提升往往是边际性的,而工程化水平直接决定了系统能不能稳定运行、能不能快速迭代。
打个比方,算法创新像是给汽车换一个更高效的发动机,工程化则是保证这辆车的底盘、悬挂、转向、刹车都在最佳状态。发动机动力提升10%可能很费劲,但如果底盘松了、刹车失灵了,那这辆车根本没法开上路。AI项目到了生产环境里,最大的风险恰恰是这些“不性感”的工程环节:请求超时、显存泄漏、数据倾斜、评估集污染、监控缺失。
所以我带新人做AI项目,第一件事不是让他去读论文,而是让他把整个系统的数据流图画出来。模型在哪儿训练、在哪儿推理、数据从哪儿来、预测结果送到哪儿去、失败之后怎么兜底。能把这张图画清楚,AI工程就算入门了一半。
1.3 给“从零开始”定一个合理的学习路径
这里我要特别声明一下,学习路径这件事,没有绝对正确的答案,只有适合某个阶段的选择。下面这条路径,是我在多次带人和自己复盘的基础上整理出来的,比较适合“有代码基础但没有完整AI项目经验”的人。
- 第一阶段:搞定基础工具链。Python、Docker、Linux操作、Git,这是四块基石。很多人上来就啃PyTorch,结果连虚拟环境都搞不明白,代码跑起来依赖冲突一堆,这是最大的时间黑洞。
- 第二阶段:吃透一条最小闭环。目标不是大而全,而是用公开数据集完整走一遍“数据处理 -> 训练/微调 -> 评估 -> 简单服务化”的流程。重点在于把每个环节的输入输出搞清楚。
- 第三阶段:深入数据工程与评估体系。这个阶段要学会数据版本管理、特征分布分析、标注质量控制、评估集设计。可以说,这阶段的水平决定了你能不能被称为“AI工程师”而不是“跑模型的人”。
- 第四阶段:生产化改造。并发、缓存、容灾、监控、日志、AB实验。把模型变成一个具备可观测性、可回滚、可迭代的服务。
- 第五阶段:全链路优化与团队协作。到了这个阶段,你要考虑成本、效率、协作流程、代码规范,输出的是“多快好省”的工程体系。
有一条经验必须提醒:不要试图跳过第二阶段。很多人一上来就想微调大模型,数据都不会规范化,跑出来的结果稀烂,然后就开始怀疑人生。实际上问题根本不在模型,在于前一步就错了。
2. 核心细节解析与实操要点:从0搭建第一个AI项目的完整拆解
2.1 工具链选型:别在起跑线被环境问题绊倒
这个阶段我不想谈“哪个框架最强”,而是想谈“哪些工具能让你最快专注到核心问题”。AI工程是个复合领域,工具链的合理组合能省掉你大量无用功。
首先是Python环境管理。我强烈建议从第一天就用Conda或者uv,别用系统自带的Python。原因是AI项目依赖复杂,numpy、torch、transformers这些库的版本兼容关系能让人崩溃。Conda最实用的功能是给你每个项目一个独立环境,今天折腾坏了不会影响明天。现在uv的体验越来越好了,速度快很多,新项目可以直接尝试。
其次是容器化。Docker基本是必须掌握的技能。为什么?因为你训练好的模型,本地跑得好好的,推到服务器上突然就出问题了,十有八九是环境不一致。Docker可以把整个环境打包,锁定Python版本、依赖库版本、系统库,到了任何机器上都是一样的行为。这个“可复现性”在AI工程里几乎是命根子。
然后是数据与实验管理。早点学会用DVC或者类似工具做数据版本管理,用MLflow或者WandB做实验追踪。这些名字你现在不熟没关系,但要清楚它们的定位:DVC管数据,MLflow/WandB管实验指标。很多人训练模型不做实验记录,一个月后回头连自己当时用的是什么参数都查不到,纯靠记忆,这是极其危险的。
2.2 数据这一步,决定了你后面是天堂还是地狱
我见过太多项目死在数据处理上。模型训练代码写得很漂亮,结果喂进去的数据有重复、有脏值、分布不对。你后面怎么调参都是白费,因为垃圾进垃圾出。
这里分享一个我实际踩过的坑。有次做文本分类项目,从网上爬了一批数据,简单做了去重和清洗就开训了。模型在测试集上表现很好,但上线后效果一塌糊涂。后来排查发现,训练集里有大量来源相同的文章,模型学到的是“来源特征”而不是“内容特征”,属于典型的“数据集泄露”。这个坑的根源是:没有对训练集和测试集做充分的分布隔离,更没有检查两边是否存在同源样本。
正确的做法是:
- 先做数据探查:用pandas_profiling或ydata-profiling快速生成数据报告,看缺失值、分布、类型。
- 再做重复检测:不仅做完全重复检测,还要做近似重复检测(比如SimHash),特别是从网上采集的数据。
- 最后做分布验证:训练集、验证集、测试集在各个类别上的比例要基本一致,避免训练集和测试集分布差异过大导致评估失真。
另一个反直觉的经验:测试集有时候要“脏”一点。什么意思?真实线上数据是在不断变化的,广告文案在变、用户表达方式在变、新品在出。如果你的测试集太“干净”,它对真实场景的代表性就差,评估结果虚高。建模的时候留出5%-10%的“脏数据”做测试,更能反映真实水平。
2.3 数据版本化,从第一天就要养成习惯
这个点被提得很少,但我觉得它异常重要。你现在觉得数据只有自己一个人用,不用管版本。但AI项目几乎一定会发生这样的事:模型上线后发现效果不好,你想回退到几天前的版本,但你手里有几份数据文件已经分不清哪个是哪个了。如果一开始就用DVC这类工具做数据版本管理,每一次数据变更都会留下记录,想回退就回退,想对比就对比,能省下大量时间。
具体用法不复杂,核心就是把数据文件交给DVC管理,用git维护一份“数据指针”。每次数据更新时提交一次版本,配合实验记录里的参数和指标,你就能完整复盘出“这个版本的数据配这个版本的参数,跑出了这个指标”的全过程。这在排查问题、复现实验结果时价值极大。
3. 实操过程与核心环节实现:走通“数据处理 -> 模型训练 -> 服务化”的最小闭环
3.1 一个具体可复现的文本分类实战
光讲理论很虚空,我拿一个极其常见的任务——文本多分类——来示范整个闭环。假设我们要做一个“用户反馈自动分类”系统,把用户反馈分成“咨询”、“投诉”、“建议”、“表扬”四类。这个任务足够经典,又不会复杂到劝退新手。
第一步:准备数据。你要先有一批标注好的反馈文本。标注数量不用多,初始阶段每类200-500条就够,总共800-2000条。重点是要保证类别均衡、文本长度分布合理。如果没有现成数据,可以把公开的电商评论数据集拿来做替代练习。
第二步:做文本预处理。这一步的核心是去噪,但别过度清洗。比如中文场景,我建议保留标点符号,因为它还是有用的特征,只做去除HTML标签、异常字符、统一大小写(英文场景)这类操作。不要动停用词,不要做太多规则清洗,因为很多看起来像噪音的内容,模型其实是能学出规律来的,你人工删掉反而破坏信息。
第三步:选择基座模型。对于样本量只有千级的文本分类任务,直接fine-tune一个中文BERT或者它的蒸馏版本DistilBERT就够用了。从HuggingFace上用transformers库加载,几行代码就能开始训练。需要注意的是,这里要区分“全参数微调”和“冻结主干只训练分类头”,虽然现在来说这个问题已经不算复杂,但对新手仍然值得了解——至少模式要对,训练时要清楚自己在微调什么。
3.2 训练脚本里最容易忽略的参数细节
关于微调,很多人的关注点在“学习率是不是调对了”,但我想说的是,先把哪些参数影响上限搞清楚,要比盯着学习率更重要。
- max_length:文本长度超过这个值会被截断。设得太小丢信息,设得太大浪费显存。先统计一下数据里的长度分布,取90%分位数比较稳妥。
- batch_size:能调多大调多大,但要结合显存。新手最容易忽略的是“实际batch大小”不等于你代码里写的那个值。如果你用了梯度累积,有效batch_size = batch_size * 累积步数。
- 学习率:微调场景下,跟预训练模型的学习率建议在2e-5到5e-5之间。如果从头训练模型,才需要用到1e-4甚至更大的值。很多新手拿从头训练的经验来微调,学习率设大了,一轮loss就飞了。
- 训练轮数:不要盲目追求多轮。正常的经验是看验证集指标,早停是必须的。存最佳模型而不是最后一轮模型。
还有一个细节:数据集的划分要在预处理之后做,但要在训练脚本里保证可复现。加上固定随机种子,并且用stratified split按类别比例划分,这样多次跑出来的评估结果才有一致性,不是每次都在撞运气。
3.3 评估不是“准确率”那一项
准确率是最常用也最骗人的指标,尤其是类别分布不均衡的时候。四类文本分类如果“咨询”占了70%,你全部判定为“咨询”,准确率都有70%,但这显然没解决问题。
正确做法是同时看每一类的precision、recall、F1,再算一个macro-F1作为整体指标。还要看混淆矩阵,弄清楚到底是哪两类之间容易混淆。这类分析能直接指导下一步的工作重心,比如“投诉”和“建议”混淆严重,可能就是因为两者的语言边界本来就很模糊,需要从业务侧厘清定义,而不是单纯调模型。
评估集的设计也同样重要。注意,我讲的“评估集”不是简单从一个总集里随机切出来,而是要在真实使用场景里取样。很多项目用随机切分出来的测试集来评估模型,测试集和待预测的数据分布不完全一致,导致线上效果远低于测试结果。建议留出“时间上靠后”的数据做测试集,模拟未来待预测数据的分布。
3.4 模型服务化:从“能跑”到“能用”
训练完模型,很多人就停在这里。但真正的工程化,是从“能跑”开始的。用FastAPI这类工具做一个HTTP推理服务不算难,核心就三步:加载模型、定义输入输出格式、调用模型返回结果。
但这个过程中有几个非常容易踩坑的工程问题:
第一,模型加载耗时。模型加载往往需要几秒到几十秒,不能在每次请求时都重新加载。正确做法是服务启动时加载一次,放到全局变量或依赖项里,之后所有请求共享。
第二,并发与显存管理。GPU显存是共享的,多个并发请求会同时抢占显存。如果推理框架不做并发控制,轻则请求排队,重则显存溢出。常见方案是用消息队列削峰,或者干脆用CPU推理(部分蒸馏模型在CPU上的推理速度是可以接受的)。
第三,输入校验与容错。线上请求永远比你想的乱:空文本、超长文本、非法字符、恶意注入。服务端要先做校验,超长的截断,不合适的拒绝,让模型尽量处理“符合预期”的输入。
第四,缓存设计。如果业务场景里大量请求是相近的文本(比如同一件商品的多个用户反馈),可以用文本哈希做结果缓存,命中缓存直接返回,降低模型负载。缓存键就是标准化后的文本哈希值,简单好用。
4. 常见问题与排查技巧实录:AI工程中那些“逼疯人”的坑
4.1 训练集表现好,测试集崩了
这是最高频的问题,没有之一。原因往往是数据集泄露,或者是训练集和测试集分布不一致。排查思路按顺序来:
- 检查预处理逻辑是否有信息泄漏,比如用全量数据计算归一化统计量(比如全量文本的平均长度)再切分,就会造成泄漏。
- 检查是否存在近似重复样本横跨训练集和测试集。
- 检查各类别在训练集和测试集的分布差异,如果差异很大,模型很难泛化。
4.2 推理延迟太高,线上扛不住
先别急着换更小的模型。首先检查服务端是不是在每次请求时都做了一遍重复的预处理工作,比如分词、规范化。这些操作应该只做一次并缓存。然后是批量推理的场景有没有利用起来,成批推理比单条推理吞吐量高出不少。再考虑模型蒸馏和量化,这是最后的手段,而不是第一手段。
4.3 上线后效果比离线评估差
几乎所有人都会遇到。这里要区分是数据漂移还是服务端处理不一致。数据漂移好理解,线上的文本风格和训练时有差异。服务端处理不一致则要注意:离线训练时你用的预处理函数是不是和线上推理时完全一致?我见过因为离线分词用的一个版本、线上用的另一个版本,导致线上效果下降的案例。这种问题往往藏得很深,排查非常费劲,所以从一开始就要把预处理封装成同一个共享模块,离线在线都调用它。
4.4 显存溢出或训练特别慢
显存溢出多半是batch_size设太大或max_length过长,可以调小。训练慢则可能是数据加载流程里出现了瓶颈,最常见的是每次step都从磁盘读文件,而不是提前把数据加载到内存或者做预取。用DataLoader的num_workers和pin_memory能明显改善。
下面整理一个简易故障速查表,方便对照:
| 症状 | 最可能的原因 | 建议动作 |
|---|---|---|
| 训练loss下降但验证集指标不变 | 数据泄漏或评估集分布不一致 | 检查切分逻辑、重复样本、类别分布 |
| 训练Loss为NaN | 学习率过大、文本包含异常值 | 降低学习率,清洗特殊字符 |
| 线上效果比测试差很多 | 预处理不一致或数据漂移 | 统一预处理模块,监控线上输入分布 |
| 推理延迟高 | 未做缓存或批量推理 | 加缓存、合并推理请求 |
| 服务重启后效果不同 | 随机种子未固定或模型权重保存不当 | 固定种子,保存best model时记录指标 |
5. 从最小闭环到可迭代的AI系统工程
5.1 建立持续的模型评估机制
很多团队把模型上线当作终点,这是一个危险的误判。真实业务环境是随时间变化的,模型的输入分布也在变。如果不对线上的预测质量做持续采样和评估,你无法知道模型是什么时候开始悄悄变差的。
我给大家一个很轻量但有效的做法:每周从线上请求中随机抽一批(比如200-500条)做人工标注,然后跟模型预测结果对比,计算当周的线上准确率。坚持做几周,趋势线一出来,比任何告警都直观。如果发现某个类别的准确率持续走低,那就说明数据分布漂移了,该考虑重训了。
5.2 数据回流与持续优化:让系统自己变强
模型上线的意义不是“结束”,而是“开始”。用户的真实反馈、客服的纠偏操作、业务的规则变更,这些都是高价值的数据来源。把这些数据回流到训练集里,定期(比如每周或每月)做一次增量微调或重训练,模型才能跟上数据分布的变化。
这里有个工程要求:数据回流必须自动化。人工操作一旦多了就会乱、会漏。你需要设计一个简单的数据管道,把线上收集的样本自动写入一个待标注队列,标注完成后自动合并到训练集,然后触发训练任务。整个流程落在CI/CD体系里,每次训练自动记录数据版本、代码版本、参数和指标,形成一个真正可追踪的迭代闭环。
5.3 关于成本与效率的一些个人建议
最后聊一个偏管理和策略的话题:AI工程的成本控制。大模型时代,很多人默认“堆算力”,但真正好的AI系统工程师,脑子里应该始终有一本“成本账”。数据是否真的需要每次都从头收集?模型是否一定要用最大的?推理是否必须上GPU?答案往往是“不需要”。很多时候优化数据标注流程、给热数据做缓存、把模型量化一下,省下来的成本比优化模型结构还多。
我个人的体会是,AI工程的核心竞争力不是会用哪个新框架,而是能不能在质量、速度、成本三者之间找到那个平衡点。这个能力不是看书学来的,是不断在实战中试错、复盘、优化沉淀出来的。你现在从零开始走这条路,会遇到很多次失败和卡壳,但每解决一个实际问题,你的工程能力就扎实一分。
最后再分享一个亲测有效的习惯:每完成一个阶段,花15分钟写一份简短复盘,记录遇到了什么问题、怎么排查解决的、下次怎么做能更快。这在当时看来不怎么起眼,但半年以后再翻,你会发现那就是你从新手成长为老手最清晰的轨迹。