
1. 先搞清楚ai-engineering-from-scratch到底要解决什么事很多人看到“ai-engineering-from-scratch”这个标题第一反应是“我要从零开始学人工智能”然后一头扎进吴恩达的机器学习课、啃《花书》、背一堆公式。我当年也是这么过来的结果发现这条路走偏了。从零开始做AI工程和从零开始学算法理论完全是两码事。前者的目标是让一个AI系统在真实业务里稳定地产生价值后者是理解模型为什么能工作。两个都需要但你得清楚自己手里拿的到底是哪个地图。我见过太多人模型在Jupyter Notebook里跑得飞起准确率刷到95%一部署到线上就崩。不是模型不行是工程链路断了数据没接好、依赖环境不一致、接口吞吐扛不住、日志打不出来、模型更新一次要跑两天人工流程。这些问题的解法全部落在“工程”这两个字上而不是“算法”两个字里。所以这篇东西不是教你调参的也不是给你列一堆论文的。我想分享的是当我拿到一个AI落地的需求从零开始把一个项目推到生产环境整个链路里我会怎么考虑问题、怎么选工具、怎么排优先级。适合谁看适合那种已经会跑Python、大概知道机器学习和深度学习是什么但还没完整做过一个线上AI项目的开发者。也适合刚转到AI工程方向不知道从哪下手的同学。1.1 它和算法研究、数据分析不是一回事先做个最简单的区分。算法研究的核心是提出新方法、发论文评价标准是刷榜、涨点、比别人效果好。数据分析的核心是回答业务问题评价标准是能不能给出清晰的结论和改进动作。AI工程的核心是把模型变成产品的一部分评价标准是系统稳定性、响应时间、资源成本、迭代效率以及最终业务指标有没有改善。我把这三者的差别摊开讲维度算法研究数据分析AI工程核心问题能不能提出更好的模型业务发生了什么为什么怎么让模型长期稳定产生价值交付物论文/实验代码报告/图表服务/系统/流水线关键指标精度、SOTA提升口径一致、结论可靠延迟、吞吐、可用性、迭代周期失败方式指标不涨结论用不上部署失败、线上出错、维护不动你从零开始走AI工程这条路目标就是第四个象限。算法能力是地基但你会发现真正占用时间的是数据管道、模型服务化、监控告警、版本管理这些听起来不那么“性感”的东西。当年我带第一个线上项目的时候整整两周都在和数据管道纠缠模型训练只花了两天。这个比例一点都不夸张。1.2 一个AI工程的完整闭环长什么样很多教程把重点放在“训练模型”这一步好像模型训完项目就结束了。实际上一个能用的AI工程至少包含六段需求理解把“我们要用AI提升XX效率”翻译成具体的输入输出、质量标准和约束条件。数据工程采集、清洗、标注、校验、版本化。没有数据闭环后面全是空中楼阁。模型训练包括基线模型、特征工程、调参、实验记录。这是大家最熟悉但往往最不重视工程化的一段。模型部署把训练好的模型封装成接口处理依赖、资源、并发。监控运维盯延迟、吞吐、内存更重要的是盯模型输出的分布漂移。迭代机制新数据怎么回流模型怎么重新训练怎么灰度发布怎么回滚。这六段缺一段项目都走不远。有人可能觉得“我先跑通一个demo再说”但我劝你从一开始就按这套闭环去想问题。因为返工成本是递增的——前期数据结构没设计好后面每训练一次都痛苦部署前没设计监控模型上线就基本是盲飞。2. 从零开始的技能栈和工具选型选型这件事网上的争论特别多动不动就是“PyTorch还是TensorFlow”“Docker是不是必须的”。我的态度很实际选我熟悉、生态够大、团队容易上手的。工具是为你服务的不是为了显得你技术高的。从零开始你的技能栈应该围绕“能不能把整个闭环跑通”来搭而不是某一环做到极致。下面按三个层次来讲每个层次我给出我实际用过并且觉得稳的组合。2.1 语言与运行环境Python够用但别只会PythonPython在AI圈的地位不用我多说模型训练、数据处理、接口开发它都能干。但要真的做工程你不能只会写Python脚本至少得懂下面几样依赖管理同一个项目里训练用一个Python版本部署又是另一个环境来回折腾几次你就懂了。我最近几个项目都切到了uv比pip快一大截锁定依赖也更干净。早期项目用requirements.txt加pip freeze踩过不少“我本地能跑”的坑后来养成了每次运行都固定版本的毛病。别嫌麻烦这个习惯能救你命。# 用 uv 创建虚拟环境并锁定依赖 uv venv .venv --python 3.11 source .venv/bin/activate uv pip install -r requirements.txt uv lockShell基础Linux命令、环境变量、进程管理、定时任务这些决定了你能不能自己把服务拉起来、查问题。Docker基本功不需要精通K8s但至少要能写一个能跑的Dockerfile知道镜像和容器的区别知道怎么排查容器日志。这里面有大量环境不一致的问题用容器能解决90%。FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY src/ ./src/ CMD [uvicorn, src.main:app, --host, 0.0.0.0, --port, 8000]这是最小可用形态还是能看出你在做什么。2.2 数据、实验和模型管理是我最看重的一层训练代码只是AI工程里的一块砖。真正支撑起整个项目的是数据怎么管、实验怎么记、模型怎么存。数据管理别把所有数据堆在一个文件夹里文件名带V3_final这种。用版本化的思路去管简单点的做法是把原始数据、中间特征、最终训练集放到不同的目录并记录数据来源和处理脚本版本。团队有条件就上DVC之类专门工具个人项目至少保留一份data_prep脚本确保任何时间点都能用原始数据重建出训练集。实验记录我见过有朋友用文件名记录参数model_lr0.001_bs32_acc0.91.pkl短时间可以两个月后就完全看不懂了。推荐从第一天就用MLflow或WandB这类工具哪怕只是本地起一个MLflow server。它记的不只是参数和指标还能把数据集版本、代码commit、环境依赖一起绑进去。下面是我在项目里最常用的MLflow记录方式很简略但够用import mlflow mlflow.set_experiment(churn_prediction) with mlflow.start_run(): mlflow.log_param(learning_rate, 0.001) mlflow.log_param(batch_size, 32) mlflow.log_metric(val_auc, 0.892) mlflow.log_artifact(model.pkl)模型注册当你有好几个候选模型或者要区分“开发中”“预发布”“生产”状态时用MLflow Model Registry或类似服务。它的价值是你永远知道线上跑的是哪个版本出了事能精准回滚到上一版。2.3 服务化部署从Notebook到API之间缺的那几步训练完模型只是完成了整个链路里最小的一段离对外提供服务还差很远。我不推荐直接把Notebook交给后端做接口。原因是Notebook跑模型的方式没有固定的依赖边界也没有清晰的输入输出结构后面排错会很痛苦。一个干净的做法是把模型推理逻辑抽成一个独立的Python服务接口定义成标准的HTTP API再包一层Docker。我之前接过很多奇奇怪怪的后端需求比如“能不能返回一个权重让前端自己算”这种设计基本就是在给后面挖坑。你需要设计清楚的是接口的输入输出格式、错误处理、超时控制。再往上一层是入口网关、弹性扩容、API鉴权这些内容前期不是每个项目都需要但你至少要知道自己将来会面临什么。别让模型推理永远裸奔。3. 一个能落地的AI项目我是怎么从零一步步搭起来的理论知识讲再多不如走一遍。我拿一个虚拟的项目来拆解假设业务方希望用AI来自动审核一份合同里的关键条款是否齐全目标是把审核效率提升30%。这类项目非常典型跟风控、内容审核、文档分类这些场景底层逻辑一致我就按这个例子带着你走一遍全流程。3.1 先把业务问题翻译成模型问题这个步骤最容易被跳过但偏偏是最重要的。业务方说“帮我自动审核合同”你不能上来就训练模型。你得先搞清楚输入是什么是PDF、Word还是纯文本输出是什么是一个完整/不完整的标签还是具体缺了哪一条条款准确率要求多高漏判的代价大还是误报的代价大数据从哪里来有没有历史审核记录线上实时性要求多高是异步跑一遍还是用户等几秒出结果我当时和业务方来回对了三轮最终把需求收敛成输入一段合同正文文本输出“是否包含五类必备条款”的多标签结果。因为数据里有大量历史合同和人工审核意见这个目标可以标注也可以建规则做基线。这件事的教训是不要在需求不清晰的时候讨论模型选型。先谈清楚边界和质量标准模型是最后顺理成章的结果。3.2 数据管道的“最小可用”版本数据管道听着高级其实就是一套“把原始数据变成训练数据”的流程。我一般这样拆接收原始文件放到固定存储目录记录文件名和来源。解析文件格式转成统一文本格式。做基础清洗去页眉页脚、去乱码、切分段落。生成标注数据先找专家标一批再用规则辅助扩张。划分训练集/验证集/测试集保存划分逻辑。我特别想强调一件事数据切分不能随机要按合同ID或者客户ID切。因为同一份合同的多个段落高度相似如果随机切模型可能在验证集上虚高线上就拉胯。我当年因为这个翻过车后来切数据都默认按实体维度切。标注这个环节也要提前想好。不要一上来就追求“标注得又多又精细”先标几百条把标注规范跑顺再把量做大。标注规范要写清楚边界案例比如“合同编号缺失算不算条款不齐”“引用了旧版法律条文怎么处理”。这些模糊地带不定义清楚标注员之间的不一致会让模型输出变得不稳定。3.3 基线模型、评估指标和实验记录缺一不可第一次跑模型别追求花哨先建立一个简单的基线。我建议的路线是先用规则比如“包含‘违约金’三个字就算有违约条款”看看能覆盖多少。规则的好处是可解释、可以跟业务方对口径。再用简单模型文本分类用TF-IDF加逻辑回归或LightGBM往往比一上来就微调BERT更稳还能给你一个可靠的下限。看看误差在哪里把误判样本筛出来归纳是哪几类问题再决定要不要上深度学习。评估指标一定要结合业务场景。拿合同审核来说漏检一条重要条款可能带来法律风险所以召回率的优先级高于精确率但如果误报太多审核人员要花大量时间复核也受不了。我会用Pk或F1这类综合指标同时把召回率卡在一个业务方接受的底线之上。建议是把每个类别的混淆矩阵拉出来逐类看效果而不是只看一个总分。所有实验都要记录。同一份数据、同一个参数为什么不记录因为你过两周大概率不记得当初怎么调的了。我复盘过往项目时发现能救命的不是“我记得”而是实验记录里那一行行参数和指标。3.4 训练调优里容易被忽视的细节当你开始优化模型时最容易犯的错是“动辄换模型架构”。实际上我做得最多的优化反而是数据层面的文本清洗规则有没有误伤比如把关键条款里的标点删了或者把“壹佰万元”里的汉字转数字转错了。训练集和验证集的数据分布一致吗有没有某类样本在验证集特别多。类别不平衡问题处理了吗比如“保密条款”出现频率极高“解除条款”很少出现模型很容易偏向多数类。模型侧我从零开始调整时会按“先数据增强再调整阈值再尝试更复杂模型”的顺序走。阈值调整是一个性价比非常高的操作模型输出的概率值往往直接取0.5判断但业务上你完全可以设定recall优先的阈值比如低于0.3才判负。这个操作只要一行代码却能大幅改善业务体验。# 按业务优先级调整阈值宁可多报不可漏报 pred_proba model.predict_proba(text)[:, 1] labels pred_proba 0.3别小看这个细节。有太多人把模型调参调到天上去结果忘了业务需要的只是一个更合理的阈值。4. 让模型在生产环境里稳定跑起来模型训好只是完成了一半从训练环境搬到生产环境你会遇到一系列新问题。这一部分在整个博文里我觉得最值得细看因为网上教程很少讲。4.1 推理服务封装和接口设计我最常用的方案是FastAPI加Pydantic原因很简单开发速度快、自带参数校验、交互文档好看、异步性能也不错。下面是一个非常简化的文本分类推理服务from fastapi import FastAPI, HTTPException from pydantic import BaseModel app FastAPI() class PredictRequest(BaseModel): text: str max_length: int 512 class PredictResponse(BaseModel): label: str confidence: float app.post(/predict, response_modelPredictResponse) def predict(req: PredictRequest): try: label, confidence model_service.predict(req.text, req.max_length) return PredictResponse(labellabel, confidenceconfidence) except Exception as e: raise HTTPException(status_code500, detailstr(e))几个经验接口只接收最少的参数。宁可内部去推断也不要让调用方传一堆可选参数否则联调成本很高。请求和响应统一用JSON schema字段命名要跟调用方提前定好。模型加载放在启动时不要每次请求都重新load。我见过有人把模型加载写进函数体里导致一次请求要等十几秒纯属自杀式设计。设置超时和错误码。模型推理偶尔会崩接口必须能优雅地把异常暴露出来而不是让上游调用方猜。用模型版本号作为接口路径的一部分比如/v2/predict。这样后端升级新模型时可以保留旧接口方便灰度切换和回滚。另外如果你的模型推理要跑GPU服务化时一定要想好显存分配。多进程部署时每个进程加载一个模型会重复占显存我常用的方式是把推理进程单独拉成Sidecar或独立服务避免跟Web主进程互相拖累。4.2 上线之后的监控、版本管理与回滚上线不是终点是起点。模型服务上线后你会面对三类监控基础运维监控CPU、内存、显存、请求量、P95延迟、错误率。缺了这些你连服务是否健康都说不清楚。数据分布监控线上输入的数据分布跟训练集是不是越来越远。比如合同格式变了、新增了一种模板模型可能直接失准。业务效果监控模型推荐的结果有没有真的提升业务指标这一步往往要跟业务团队一起打点。我最适配的工具组合是Prometheus采集指标Grafana画看板每次发布都留一个可回滚的版本号。模型版本管理这一块我用MLflow记录线上模型版本每次切换新模型都会把旧模型的存储路径留好。真出了事回滚就是改个环境变量或改个服务配置的事。# docker-compose 里切换模型版本示例 # MODEL_VERSIONv3 # 新模型出问题就改回 MODEL_VERSIONv2 后重启服务这里我见过最惨烈的翻车现场是有人直接覆盖了模型文件没有留下任何备份线上模型效果崩了以后找不到旧版本只能重新训练白白耽误两天。从那以后我给自己定了一条死规矩任何模型artifacts都按版本号记录只增不改发布只允许用不可变的版本引用。4.3 性能优化批处理、缓存和硬件选型用户量一大单个请求慢慢推理必然撑不住。性能优化一般从三个方向下手批处理如果模型是深度学习模型GPU的并行能力很强单条请求一条条推浪费严重。可以把多个推理请求聚合到一个Batch里一次前向推完再拆开返回。实现上可以做一个简单的队列攒够N条或时间到M毫秒就触发一次推理。缓存很多输入文本在业务上高度重复比如同一份合同反复被审、同一个风险文本被多次检测。用一个带TTL的缓存层能显著降低峰值压力。硬件选型不是所有模型都要上GPU。中小语料下的文本分类、推荐排序用CPU加LightGBM可能就够成本低很多。GPU的真正优势在稠密深度模型和大Batch推理。我从成本角度给过很多团队建议先跑CPU基线看延迟和吞吐是否符合要求不够再考虑GPU。# 批处理伪代码 batch_inputs [] while True: batch_inputs.extend(queue.get_batch(max_size32, timeout_ms50)) if len(batch_inputs) 1: batch_outputs model.predict_batch(batch_inputs) for output in batch_outputs: queue.put_result(output)还有一个细节是预热warm-up。很多深度学习模型首次推理时非常慢因为有些初始化操作是延迟执行的。我会部署完成后主动发几个测试请求把模型预热好再放流量进来。5. 我踩过的五个坑以及对应的排查思路从零到一的过程里坑多得数不清。我挑五个最典型的每一个都让我痛苦过。5.1 数据漂移比模型效果下滑更难发现线上效果突然变差但模型本身没有改过很多人第一反应是重新训练。我遇到过实际原因是业务方改了数据来源新的合同模板格式和训练集差很远模型输出分布整个都变了。排查这种问题必须依赖数据分布监控。你可以定期比对线上推理输入的文本长度、关键词频率、类别概率分布一旦发现分布偏移超过阈值就触发告警不要等业务反馈。5.2 离线指标很好看线上效果崩了我早期做过一个分类模型离线AUC到0.95上线后业务反馈一塌糊涂。后来排查发现三个原因第一离线测试集是随机划分的同一消息的多个相似片段被分到两个集合数据泄漏指标虚高。第二线上真实输入包含很多扭曲文本和emoji预处理阶段根本没覆盖。第三正样本在线上出现的比例远低于训练集模型输出大量误报。这个教训让我养成了两个习惯训练集测试集按业务实体划分训练前在a/b两套真实采样数据上先跑通一次。5.3 实验记录不全等于白训练以前有段时间我训练模型时参数是随手改的哪个模型效果最好全凭记忆。后来想复现一个效果好的版本发现代码早就改了参数也找不到了数据也被覆盖了只能凭感觉重新调。从那时起我把实验记录当成代码的一部分。每次启动训练前我都会确保至少记录了数据版本、代码commit、关键参数、模型metrics这四样缺一样都不开始。5.4 环境依赖锁不住复现变成玄学团队里有一个经典场景A同学说他本地训练精度到了0.92B同学在另一台机器上同一份代码跑了半天只有0.88于是大家怀疑数据没传全。其实很可能只是numpy或scikit-learn版本不一致。我现在无论训练还是推理全部用Docker镜像固化环境并要求镜像带版本标签。同一个镜像在开发机和生产环境里必须完全一致才能避免这类争议。5.5 安全、合规和权限边界被忽视AI服务一旦处理真实数据尤其是有敏感信息的业务数据就必须考虑权限和审计。我踩过的一个坑是接口没有做鉴权导致内部服务被异常调用流量打满连带影响其他业务。后来的做法是所有AI服务默认加token校验敏感数据字段脱敏接口日志不记录原文。这些内容看起来跟模型没直接关系但线上事故往往就出在这里。6. 写在最后给想“从零开始”的人几句实在话ai-engineering-from-scratch这条路说难也难说简单也简单。难在你什么都得懂一点数据、算法、部署、监控它是一个完整的系统简单在你不需要一开始就追求完美只要把闭环跑通再慢慢补课就比大多数人走得远。我有两个建议给刚开始的朋友。第一个建议是“先跑通再优化”。不要一开始就想着搭一个多豪华的平台。拿一个小数据集把一个最简单的模型部署到线上用脚本打流量把监控告警加上这个最小闭环跑通之后你对AI工程的理解会提升一大截。第二个建议是“把重复的事情自动化”。每次手工跑数据预处理、手工记录实验、手工部署短期看很省事长期看是在给自己挖坑。省下的大脑带宽应该花在真正重要的事情上——理解业务需求、分析模型错误、设计更好的迭代方案。我自己到现在也还在不断踩新坑。每个看似简单的线上问题背后都可能藏着你没想过的数据问题、环境问题或协作问题。但正是这些麻烦让AI工程变得比单纯调模型有意思得多。希望这篇内容能让你少走一点我走过的弯路。