
从零手搓AI工程一个资深从业者的完整拆解与实操复盘这两年“AI工程”这个词被说得太多了多到有点泛滥。招聘网站上挂着“AI工程师”的岗位点进去一看有的要求写Prompt有的要求会调LangChain有的干脆就是数据标注换个马甲。我自己在这个圈子里摸爬滚打了十来年从最早的机器学习流水线到现在的LLM应用开发踩过的坑比写过的代码行数还多。所以当我看到“ai-engineering-from-scratch”这个标题的时候第一反应不是“又一个教程”而是——终于有人愿意把这件事从头到尾讲清楚了。这篇文章我想做的事情很直接把“从零构建AI工程能力”这件事拆开揉碎告诉你每一步到底在做什么、为什么这么做、以及我实际踩过哪些坑。不管你是刚转行想入局的新人还是已经在大厂做后端想往AI方向靠的老手甚至是产品经理、技术管理者想搞清楚AI工程到底是怎么回事这篇内容都能给你一个可落地的参考框架。我不会只讲概念每个环节都会给出具体的工具选型、参数配置、代码示例和避坑指南。全文会比较长建议先收藏再慢慢看。1. 先搞清楚AI工程到底在工程什么1.1 从“炼丹”到“盖楼”的认知转变很多人对AI工程的误解来自于把“训模型”等同于“做AI”。我刚开始也这样觉得能跑通一个BERT微调脚本就了不起了。但真正到了生产环境才发现模型训练在整个AI工程链路里可能只占20%的工作量剩下80%全是工程问题数据怎么清洗、特征怎么存储、推理怎么加速、服务怎么部署、效果怎么监控、模型怎么迭代。打个比方训模型像是“炼丹”你在实验室里用少量数据反复调试追求的是那个accuracy数字好看。但AI工程是“盖楼”你要考虑地基稳不稳数据质量、水电通不通特征管道、住户住得舒不舒服推理延迟和吞吐、物业能不能持续维护监控和迭代。炼丹师可以只关心丹好不好但盖楼的人要对整栋楼负责。所以“from scratch”的第一步不是去学PyTorch的API而是建立正确的认知框架AI工程是一个端到端的系统工程模型只是其中一个组件。你需要同时具备数据工程、软件工程、MLOps和领域知识的复合能力。这也是为什么很多纯算法背景的人转AI工程会不适应——他们习惯了在Notebook里跑实验但生产环境不会给你Notebook的容错空间。1.2 一个完整的AI工程链路包含哪些环节我把AI工程链路拆成六个核心环节每个环节都有独立的工具生态和最佳实践问题定义与数据获取明确业务目标确定是分类、回归、生成还是排序问题然后找到对应的数据源。这一步最容易被忽视但方向错了后面全白搭。数据工程与特征管理数据清洗、去重、标注、增强以及特征存储和版本管理。这是最脏最累但最关键的环节。模型训练与实验管理模型选型、超参调优、实验追踪、模型版本管理。这里需要的是系统化的实验方法论不是碰运气。模型评估与验证离线评估、在线A/B测试、偏差检测、鲁棒性测试。评估指标的设计直接决定了模型上线的成败。推理服务与部署模型压缩、推理加速、服务封装、弹性伸缩。这是从实验室到生产的关键一跳。监控、迭代与治理效果监控、数据漂移检测、模型再训练、成本控制、合规审计。这六个环节不是线性的而是循环迭代的。你上线了一个模型监控发现效果下降就要回到数据环节排查原因然后重新训练、评估、部署。整个链路像一个飞轮转得越快AI产品的竞争力越强。1.3 为什么“from scratch”比“调包”更有价值现在市面上有太多“三行代码调用大模型API”的教程看起来很爽但一旦遇到问题就抓瞎。你不知道为什么延迟高、为什么效果不稳定、为什么成本失控。而“from scratch”构建的能力让你在遇到问题时能逐层排查知道瓶颈在哪、怎么优化。我举个真实的例子。之前团队用某个开源框架做RAG应用上线后用户反馈“回答不准确”。如果只会调包你可能只会去调Prompt。但如果你理解整个链路就会依次排查文档切分是否合理、Embedding模型是否适合中文、向量检索的top-k设置是否合理、重排序模型是否必要、生成模型的温度参数是否过高。最后我们发现是文档切分粒度太粗导致检索到的上下文包含太多噪声。这个问题调Prompt是解决不了的。所以“from scratch”的价值不在于让你重复造轮子而在于让你理解轮子是怎么转的这样你才能判断什么时候该换轮子、什么时候该修轮子。2. 环境搭建与工具链选型别一上来就堆框架2.1 开发环境从裸机到容器化的渐进路线我见过太多新手一上来就装一堆框架结果环境冲突搞了三天。我的建议是分阶段来第一阶段裸机Python环境。用conda或者uv创建一个干净的虚拟环境Python版本选3.10或3.11这两个版本对主流AI库的兼容性最好。不要用系统自带的Python也不要在base环境里装东西。我个人的习惯是每个项目一个独立环境命名用项目名加日期比如aieng-202501。conda create -n aieng-202501 python3.11 conda activate aieng-202501 pip install numpy pandas scikit-learn jupyter第二阶段引入核心框架。根据你的方向选择。做传统ML就装XGBoost、LightGBM做深度学习就装PyTorch我个人偏好PyTorch调试体验比TensorFlow好太多做LLM应用就装transformers、langchain、sentence-transformers。注意版本兼容性PyTorch的CUDA版本要和你的显卡驱动匹配这个坑我踩过不止一次。第三阶段容器化。当你需要部署或者团队协作时Docker是必须的。我建议用NVIDIA的CUDA基础镜像然后在此基础上装依赖。Dockerfile里注意把依赖安装和代码拷贝分开利用层缓存加速构建。FROM nvidia/cuda:12.1.0-runtime-ubuntu22.04 RUN apt-get update apt-get install -y python3.11 python3-pip COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD [python, serve.py]注意不要用latest标签的镜像版本锁定是生产环境的基本素养。我见过因为基础镜像更新导致CUDA版本不匹配、整个服务挂掉的事故。2.2 工具链选型每个环节只选一个主力工具工具链选型的原则是每个环节选一个主力工具把它用透而不是每个都浅尝辄止。下面是我实际用下来最顺手的组合环节推荐工具选型理由替代方案实验追踪MLflow轻量、自托管、API友好Weights Biases数据处理Polars比Pandas快5-10倍内存占用低Pandas特征存储Feast开源、支持在线离线一致性Tecton模型服务FastAPI ONNX Runtime灵活、性能好、生态成熟TorchServe向量检索Qdrant部署简单、过滤功能强Milvus监控Prometheus Grafana事实标准、社区活跃Evidently这个组合不是唯一的但经过多个项目验证稳定性和开发效率都不错。选型的时候不要追新要看社区活跃度和文档质量。一个工具如果GitHub上最近半年没更新或者文档写得像天书直接pass。2.3 硬件与成本别被“算力焦虑”绑架很多人觉得做AI一定要有A100其实大部分场景下消费级显卡甚至CPU就够了。我的经验是传统ML和中小规模深度学习一张RTX 4090甚至3060就够显存12G以上基本能覆盖80%的实验需求。LLM微调7B模型用QLoRA在24G显存上可以跑13B需要40G左右70B建议用多卡或者云服务。LLM推理7B模型用llama.cpp在CPU上也能跑只是延迟高一些。生产环境建议用vLLM或者TGI做批处理推理。成本控制的核心是“按需使用”。实验阶段用本地卡训练大模型时临时租云GPU推理服务用弹性伸缩。我见过团队为了“以防万一”常年租着8卡A100结果利用率不到10%纯属浪费。实操心得在云上租GPU时优先选按量付费而不是包月。训练任务用spot实例能省60%以上成本只要你的代码支持checkpoint续跑。我一般会在训练脚本里每500步存一次checkpoint这样即使实例被回收也能快速恢复。3. 数据工程AI工程里最不性感但最要命的部分3.1 数据清洗的五个必做步骤数据清洗没有捷径但有清单。我每次拿到新数据集都会按这个顺序过一遍去重精确去重用哈希近似去重用MinHash或SimHash。文本数据里重复样本会导致模型过拟合我见过一个分类任务因为训练集有30%重复验证集准确率虚高到95%上线后直接掉到60%。缺失值处理数值特征用中位数填充类别特征用众数或单独设一类。但要注意缺失本身可能是信息比如用户没填年龄可能意味着他不信任平台这个信号可以单独做一个二值特征。异常值检测用IQR或者Z-score但不要无脑删。先搞清楚异常值是错误还是真实极端情况。金融风控里那些“异常”交易往往才是最有价值的样本。格式统一日期格式、编码格式、单位统一。我踩过最坑的一次是训练数据里日期有“2024-01-01”和“01/01/2024”两种格式模型直接学废了。标注质量检查如果是人工标注一定要做一致性检验。让两个人标同一批数据算Kappa系数低于0.6就说明标注规范有问题得重新培训标注员。import polars as pl df pl.read_csv(raw_data.csv) df df.unique(subset[text], keepfirst) df df.with_columns([ pl.col(age).fill_null(pl.col(age).median()), pl.col(category).fill_null(unknown) ]) df df.filter( (pl.col(amount) 0) (pl.col(amount) 1e6) )3.2 特征存储别再用CSV传来传去了小项目用CSV没问题但一旦涉及训练和推理的一致性就必须上特征存储。核心痛点是训练时用的特征计算逻辑和推理时必须完全一致否则会出现“训练-服务偏差”training-serving skew。Feast是我用得比较顺手的方案。它的核心概念是feature view和entity你定义好特征的计算逻辑Feast负责离线存储用于训练和在线存储用于推理的同步。from feast import FeatureView, Field, FileSource from feast.types import Float32, Int64 driver_stats FileSource(pathdata/driver_stats.parquet) driver_fv FeatureView( namedriver_stats, entities[driver_id], schema[ Field(nameavg_rating, dtypeFloat32), Field(nametotal_trips, dtypeInt64), ], sourcedriver_stats, )注意特征存储不是银弹。如果你的特征计算逻辑很简单比如就是原始字段用数据库视图也能凑合。但一旦涉及窗口聚合、跨表join特征存储能帮你省掉大量对账时间。3.3 数据版本管理DVC还是LakeFS数据版本管理经常被忽视直到你发现“上周那个效果很好的模型现在复现不出来了”。DVC适合小团队和Git集成好但大文件多了之后性能下降。LakeFS适合大数据量支持分支和原子提交但部署复杂度高。我的建议是数据量小于100G用DVC大于100G用LakeFS。不管用哪个核心原则是每次训练必须记录数据版本号模型artifact里要包含数据版本信息。这样出问题时才能回溯。4. 模型训练与实验管理从碰运气到系统化4.1 实验追踪让每次训练都有迹可循没有实验追踪的团队80%的时间在重复劳动。MLflow是我最推荐的入门工具轻量、API简单、UI够用。核心用法就三个概念experiment、run、metric。import mlflow mlflow.set_experiment(text-classification) with mlflow.start_run(run_namebert-base-lr2e5): mlflow.log_params({lr: 2e-5, batch_size: 32, epochs: 3}) # 训练代码... mlflow.log_metrics({accuracy: 0.92, f1: 0.91}) mlflow.pytorch.log_model(model, model)关键是要养成习惯每次训练都开一个run参数、指标、模型、甚至数据版本都记进去。我见过团队用Excel记实验结果三个月后没人记得哪行对应哪个模型。4.2 超参调优网格搜索是最笨但最稳的方法超参调优的方法很多网格搜索、随机搜索、贝叶斯优化、Hyperband。我的经验是参数少于4个网格搜索简单可靠。参数4-8个随机搜索效率比网格高。参数多于8个贝叶斯优化Optuna但要注意过拟合验证集的风险。Optuna的用法很直观import optuna def objective(trial): lr trial.suggest_float(lr, 1e-6, 1e-3, logTrue) batch_size trial.suggest_categorical(batch_size, [16, 32, 64]) # 训练并返回验证集指标 return val_f1 study optuna.create_study(directionmaximize) study.optimize(objective, n_trials50)实操心得超参调优时一定要留一个“从未参与调优”的测试集。我见过太多团队在验证集上反复调参最后测试集效果差一大截。验证集用于调参测试集只在最终评估时用一次。4.3 模型版本管理别再用文件名区分了model_v1.pth、model_v2_final.pth、model_v2_final_真的最终版.pth——这种命名方式我见过太多次了。正确的做法是用模型注册表Model Registry。MLflow的Model Registry可以给模型打标签、标记阶段Staging/Production/Archived、记录版本历史。mlflow.register_model( model_urifruns:/{run_id}/model, nametext-classifier )然后通过API获取生产环境模型model mlflow.pyfunc.load_model(models:/text-classifier/Production)这样你的推理服务永远加载的是正确的版本回滚也只需要改一个阶段标记。5. 推理服务与部署从实验室到生产的关键一跳5.1 推理加速量化、蒸馏、编译三板斧模型训练完只是开始推理性能才是用户能感知的。三个最有效的加速手段量化把FP32转成INT8或FP16模型体积缩小4倍推理速度提升2-3倍精度损失通常小于1%。PyTorch的动态量化一行代码搞定model torch.quantization.quantize_dynamic( model, {torch.nn.Linear}, dtypetorch.qint8 )知识蒸馏用大模型教小模型小模型推理快但效果接近大模型。适合对延迟敏感的场景。编译优化用ONNX Runtime或者TensorRT把模型编译成计算图消除Python解释器开销。ONNX的转换torch.onnx.export( model, dummy_input, model.onnx, input_names[input], output_names[output], dynamic_axes{input: {0: batch}, output: {0: batch}} )注意量化后一定要重新评估效果。我遇到过量化后某些类别的召回率掉10个点的情况原因是那些类别的特征分布比较极端量化误差被放大了。5.2 服务封装FastAPI 批处理 异步推理服务的核心指标是延迟和吞吐。FastAPI是Python生态里最顺手的Web框架但要注意几个点批处理单个请求推理浪费算力攒一批一起推理能提升吞吐。可以用asyncio做微批处理。异步推理是CPU/GPU密集型不要阻塞事件循环。用run_in_executor把推理放到线程池。健康检查/health端点要检查模型是否加载成功而不是只返回200。from fastapi import FastAPI import asyncio from concurrent.futures import ThreadPoolExecutor app FastAPI() executor ThreadPoolExecutor(max_workers4) app.post(/predict) async def predict(request: PredictRequest): loop asyncio.get_event_loop() result await loop.run_in_executor( executor, model.predict, request.text ) return {result: result}5.3 弹性伸缩K8s HPA 自定义指标生产环境的流量是波动的固定副本数要么浪费要么扛不住。K8s的HPA可以根据CPU/GPU利用率自动伸缩但默认指标不够灵敏。更好的做法是用自定义指标比如请求队列长度。apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: inference-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: inference-service minReplicas: 2 maxReplicas: 10 metrics: - type: Pods pods: metric: name: inference_queue_length target: type: AverageValue averageValue: 5实操心得伸缩策略要设置冷却时间避免频繁扩缩容导致服务抖动。我一般设置扩容冷却30秒、缩容冷却300秒。缩容比扩容慢因为缩容太快容易导致请求超时。6. 监控、迭代与常见问题排查6.1 效果监控别只看准确率模型上线后准确率只是冰山一角。需要监控的维度包括数据漂移输入数据的分布是否变化。用PSIPopulation Stability Index或者KS检验。概念漂移输入和输出的关系是否变化。这个更难检测通常通过效果指标下降来间接发现。延迟分布P50、P95、P99延迟不要只看平均值。成本每次推理的GPU耗时、API调用费用。Evidently是一个不错的开源工具可以生成数据漂移报告from evidently.report import Report from evidently.metric_preset import DataDriftPreset report Report(metrics[DataDriftPreset()]) report.run(reference_datatrain_df, current_dataprod_df) report.save_html(drift_report.html)6.2 常见问题速查表问题现象可能原因排查方法解决方案线上效果远差于离线训练-服务偏差对比训练和推理的特征值统一特征计算逻辑用特征存储推理延迟突然升高请求量突增或模型退化看QPS和延迟曲线扩容、限流、检查模型版本某些样本预测异常数据漂移或异常输入分析异常样本的输入分布加输入校验、重新训练模型效果逐渐下降概念漂移监控效果指标趋势定期再训练、在线学习GPU利用率低批处理大小不合理看GPU利用率和批大小调大批处理、用推理服务器内存泄漏缓存未清理或循环引用监控内存增长曲线定期重启、修复代码6.3 再训练策略定时还是触发式再训练有两种策略定时比如每周一次和触发式效果下降到阈值时。我的建议是两者结合定时再训练作为兜底保证模型不会太旧。触发式再训练作为补充当数据漂移超过阈值或效果下降超过5%时立即触发。再训练不是简单的重新跑一遍要包含新数据加入、旧数据采样防止遗忘、超参重新调优、A/B测试验证。我见过团队直接全量重新训练结果新模型在某些老类别上效果暴跌就是因为没有做数据采样平衡。7. 我踩过的那些坑和给你的建议7.1 五个让我印象深刻的翻车现场翻车一数据泄漏。做用户流失预测时我不小心把“最近一次登录时间”这个特征放进去了。结果模型在离线评估时AUC 0.98上线后完全没用——因为流失用户根本不会登录这个特征在预测时根本拿不到。教训任何特征都要问自己“预测时这个值能拿到吗”。翻车二版本不匹配。训练时用PyTorch 1.13部署环境是1.12模型加载直接报错。教训用Docker锁定所有依赖版本训练和推理用同一个镜像。翻车三批处理大小设置不当。为了降低延迟把batch_size设成1结果GPU利用率只有5%吞吐量惨不忍睹。后来改成动态批处理延迟只增加了10ms吞吐量翻了8倍。翻车四忽略冷启动。服务刚启动时模型还没加载到GPU第一批请求全部超时。后来加了预热逻辑启动时先跑几次空推理。翻车五监控缺失。模型上线后没做监控两周后才发现效果已经掉了一半。原因是上游数据源改了字段格式导致特征计算全部出错。教训监控不是可选项是必选项。7.2 给不同阶段从业者的建议刚入行的新人不要一上来就学大模型。先把传统ML的完整链路跑通一遍从数据清洗到模型部署用一个小数据集比如Titanic或者IMDB走完全流程。理解每个环节在做什么比会用多少框架重要得多。有经验的开发者你的优势是工程能力短板可能是数学和算法。建议补一下概率统计和优化理论不需要学到能推导公式但要理解每个算法的假设和适用场景。另外多参与实际业务问题的讨论AI工程的价值在于解决问题不在于模型多先进。技术管理者不要用“模型准确率”作为唯一KPI。AI项目的成功取决于端到端的交付包括数据质量、服务稳定性、用户体验和成本控制。给团队留出做数据工程和监控的时间这些工作不出彩但决定成败。7.3 这个领域后续可以怎么扩展AI工程还在快速演进几个值得关注的方向一是LLM应用的工程化包括RAG、Agent、Function Calling的工程实践二是MLOps和LLMOps的融合传统的模型监控方法需要适配大模型三是边缘AI如何在资源受限的设备上部署模型四是AI安全和合规包括偏见检测、可解释性、隐私保护。我个人的做法是每季度选一个方向深入一下不求全面但求理解核心原理。这个领域变化太快追热点追不过来但底层的能力——数据工程、系统设计、实验方法论——是相对稳定的把这些打扎实上层的东西学起来就快。最后分享一个我一直在用的学习方法每学一个新工具或新方法就写一个最小可运行的demo然后把它集成到一个真实项目里。只看文档不写代码等于没学。而只写demo不集成到项目理解深度也不够。只有真正在项目里踩过坑知识才会变成你自己的。