
1. 从零搭建AI工程体系为什么我劝你别一上来就调包ai-engineering-from-scratch这个标题第一次看到的时候我愣了一下。不是因为陌生恰恰相反是因为太熟悉了——过去两年里我见过太多人问我想学AI工程该从哪开始然后得到的回答清一色是先跑通一个demo再说。跑通demo当然没错但问题在于绝大多数人跑完demo之后就卡住了不知道下一步该往哪走也不知道自己手里那个能跑的东西离工程两个字到底差了多少。我自己带过几个刚入行的同学也帮朋友做过一些AI应用的技术选型咨询。一个很普遍的現象是大家把会用某个框架的API等同于懂AI工程。这两件事之间的差距大概相当于会煮方便面和能开一家小面馆之间的差距。方便面谁都会煮但面馆要考虑的东西就多了——食材供应链、出餐效率、口味稳定性、成本控制、高峰期并发、食品安全、客户投诉处理等等。AI工程也是一样模型调用只是最表层的那一层底下还有数据管道、特征管理、实验追踪、模型版本、服务部署、监控告警、成本优化、效果回归这一整套东西。所以当我看到ai-engineering-from-scratch这个项目标题的时候我的第一反应是终于有人愿意把从零这两个字当回事了。不是从零开始调API而是从零开始理解一个AI系统到底由哪些部分组成每个部分解决什么问题它们之间怎么协作以及在实际落地的时候哪些地方最容易出问题。这篇文章我想聊的就是基于这个标题所指向的那套完整知识体系。我会按照一个AI项目从想法到上线的真实路径来展开把每个阶段的核心任务、常见坑点、以及我自己的实操经验都摊开来讲。不管你是刚转行想入局AI工程的新人还是已经能跑通模型但总觉得心里没底的开发者应该都能从里面找到对自己有用的东西。提示这篇文章不涉及任何具体平台的部署细节也不推荐任何需要特殊网络环境才能使用的工具。所有讨论都基于通用的工程实践和公开可获取的技术方案。2. 先搞清楚AI工程到底在工程什么2.1 模型只是冰山一角水面下的部分才是重头戏很多人对AI工程的想象是这样的拿到数据训练模型部署上线完事。但真实情况是训练模型在整个项目周期里占的时间可能连20%都不到。剩下80%的时间花在哪了花在数据清洗、标注管理、特征工程、实验对比、服务封装、性能调优、线上监控这些事情上。我拿一个具体的场景来举例。假设你要做一个商品评论的情感分析系统用来帮运营团队快速发现差评并预警。这个需求听起来很简单对吧无非就是调一个分类模型输入评论输出正面/负面。但真做起来你会遇到这些问题评论数据从哪来数据库里存的是原始文本里面有HTML标签、表情符号、各种网络缩写直接喂给模型效果很差得先做清洗。标注数据从哪来没有标注数据就没法训练模型。是自己标还是找外包标注标准怎么定这个手机还行吧到底是正面还是负面模型选哪个用现成的预训练模型微调还是从头训练微调的话选哪个基座训练数据要多少训练完了怎么评估准确率95%听起来不错但那5%错在哪了是差评被漏掉了还是好评被误伤了不同错误的代价一样吗上线之后怎么服务是做成API让运营系统调用还是批量跑QPS要求多少延迟要求多少线上效果怎么监控模型今天判断的准确率跟昨天比有没有下降下降了怎么发现发现了怎么处理你看这些问题没有一个能靠调个API解决。它们才是AI工程真正要面对的东西。模型本身当然重要但模型只是整个系统里的一个组件就像发动机只是汽车里的一个部件。你不会因为买了一台好发动机就觉得自己会造车了同样的道理你也不应该因为会调模型就觉得自己懂AI工程了。2.2 从零开始意味着什么一份能力清单那从零开始到底要从哪些地方开始我根据自己的经验把AI工程需要的能力拆成了几个层次。你可以对照着看看自己目前在哪一层下一步该往哪走。能力层次具体内容典型表现基础层Python编程、数据结构、基本算法能写脚本处理数据能看懂开源代码数据层数据采集、清洗、标注、版本管理能构建可复用的数据处理管道模型层模型选型、训练、评估、调优能根据任务选择合适的模型并完成训练工程层服务封装、API设计、容器化、CI/CD能把模型变成稳定可用的线上服务运维层监控、告警、日志、成本管理能保证系统长期稳定运行并控制成本业务层需求分析、效果定义、迭代规划能把业务问题翻译成技术方案并持续优化大部分刚入行的人卡在第二层和第三层之间。能跑通训练脚本但数据处理还是手工操作能调出不错的指标但不知道怎么把模型变成别人能用的东西。而从第三层往第四层走是另一个大坎因为工程层和运维层涉及的东西跟模型训练完全是两套知识体系。ai-engineering-from-scratch这个方向的价值就在于它试图把这几层能力串起来讲而不是只盯着模型那一层。接下来我就按照这个框架把每一层的关键点和实操方法展开来说。3. 数据管道AI工程的地基也是最容易被糊弄的地方3.1 数据清洗不是跑个脚本那么简单我见过太多项目在数据清洗这一步翻车。翻车的方式五花八门但根本原因都差不多把数据清洗当成了一个一次性的、可以随便应付的任务。真实情况是数据清洗是一个需要持续迭代的过程。你今天写的清洗规则明天可能就不适用了因为数据分布会变。比如你做电商评论分析平时处理的都是正常用户的评论突然有一天来了一批刷单的评论内容全是好评好评好评你的模型没见过这种模式判断就会出问题。这时候你需要更新清洗规则把这些异常数据识别出来。一个可维护的数据清洗管道应该包含这几个部分原始数据层不做任何修改地保存原始数据方便回溯和重新处理。清洗规则层把清洗逻辑写成可配置的规则而不是硬编码在脚本里。验证层清洗完之后自动检查数据质量比如空值比例、异常值比例、分布变化等。版本层每次清洗后的数据都打上版本标签方便对比和回滚。我自己的习惯是用配置文件来管理清洗规则类似这样# cleaning_rules.yaml rules: - name: remove_html_tags type: regex pattern: [^] action: replace replacement: - name: normalize_whitespace type: regex pattern: \\s action: replace replacement: - name: filter_short_text type: length min_length: 5 action: drop - name: detect_spam type: keyword keywords: [好评好评, 刷单, 返现] action: flag这样做的好处是当数据分布变化需要调整规则时你改配置文件就行不用去翻代码。而且规则本身也是可版本管理的出了问题能查到是哪次规则变更导致的。3.2 标注管理别让标注质量成为模型的天花板标注数据的质量直接决定了模型效果的上限。你用一个标注错误率20%的数据集训练模型模型准确率不可能超过80%。这个道理很简单但实际操作中标注质量往往是最容易被忽视的环节。我参与过一个文本分类项目一开始为了赶进度标注工作外包给了一个团队标准文档只写了半页纸。结果标注完成之后一检查发现不同标注员对同一个样本的判断一致性只有70%左右。这意味着有30%的样本换个人标就会得到不同的标签。用这样的数据训练模型模型学到的就是标注员的随机性而不是真正的分类边界。后来我们重新做了标注规范把每个类别的定义、边界情况、示例都写清楚还加了标注员之间的交叉验证机制。具体做法是定义清晰的标注标准每个类别给出3-5个正例和3-5个反例边界情况单独说明。标注员培训让所有标注员先标一批相同的样本对比结果讨论分歧。交叉验证每个样本至少由两个人独立标注不一致的进入仲裁流程。持续抽检标注过程中定期抽检发现质量下降及时纠正。这套流程走下来标注一致性从70%提升到了92%以上模型效果也跟着上了一个台阶。所以我的经验是在标注上多花的时间会在模型效果上加倍还回来。3.3 数据版本管理别让上次那个数据成为未解之谜数据版本管理是另一个容易被忽略的环节。我遇到过好几次这样的情况模型效果突然下降了想排查原因结果发现训练数据已经变了但没人记得是什么时候变的、为什么变的。最后只能重新跑一遍浪费大量时间。解决这个问题的方法很简单给数据打版本。每次数据发生变化就生成一个新版本记录变更内容、变更时间、变更原因。可以用DVC这类工具来做也可以自己用文件系统加元数据的方式实现。关键是要养成习惯把数据当成代码一样管理。一个最小可用的数据版本管理方案大概长这样import hashlib import json from datetime import datetime def create_data_version(data_path, description, parent_versionNone): 为数据集创建一个版本记录 # 计算数据指纹 with open(data_path, rb) as f: data_hash hashlib.md5(f.read()).hexdigest() version_info { version: data_hash[:8], created_at: datetime.now().isoformat(), description: description, parent: parent_version, data_path: data_path, hash: data_hash } # 保存版本记录 version_file fversions/{version_info[version]}.json with open(version_file, w) as f: json.dump(version_info, f, indent2) return version_info这个方案很粗糙但核心思想是对的每次数据变更都有记录出了问题能追溯。等团队规模大了再迁移到更专业的工具上也不迟。4. 模型开发从选型到评估的完整闭环4.1 模型选型别追新追合适模型选型是很多人纠结的地方。我的建议很简单先看任务类型再看数据规模最后看资源约束。不要因为某个模型在榜单上排名高就选它榜单上的任务跟你的任务可能完全不是一回事。拿文本分类来说如果你的数据量在几千条到几万条之间用一个中等规模的预训练模型微调就足够了。没必要上最大的模型因为大模型在小数据集上更容易过拟合而且推理成本高。如果你的数据量只有几百条那可能连微调都不需要直接用特征工程加传统机器学习方法效果可能更好。我整理了一个简单的选型参考表数据规模任务复杂度推荐方案理由 500条简单分类传统ML 特征工程数据太少深度学习容易过拟合500-5000条简单分类中小预训练模型微调预训练模型能提供不错的起点5000-50000条中等复杂度中等预训练模型微调数据量足够支撑微调 50000条高复杂度大模型微调或从头训练数据量足够可以考虑更大模型任意规模生成任务预训练生成模型 微调生成任务对预训练依赖更强这个表当然不是绝对的但可以作为一个起点。实际选型的时候还要考虑推理延迟要求、部署环境限制、团队技术栈等因素。4.2 训练实验管理别让实验结果变成一笔糊涂账模型训练是一个高度迭代的过程。你可能会尝试不同的超参数、不同的数据增强方式、不同的模型结构每次实验都会产生一组结果。如果没有好的实验管理很快就会陷入混乱不记得哪个配置对应哪个结果不知道哪个实验是最优的无法复现之前的实验。我自己的做法是用一个简单的实验记录表来管理字段包括实验ID实验时间数据版本模型配置模型类型、超参数训练配置学习率、批次大小、训练轮数评估指标准确率、召回率、F1等备注这次实验想验证什么可以用Excel管理也可以用MLflow、Weights Biases这类工具。工具的好处是能自动记录很多信息还能可视化对比。但不管用什么工具核心原则是一样的每次实验都要有记录记录要足够详细能让别人包括未来的自己复现。注意实验记录里一定要包含随机种子。我踩过这个坑同一个配置跑两次结果不一样排查了半天才发现是随机种子没固定。4.3 评估指标准确率不是唯一的标准模型评估是另一个容易出问题的地方。很多人只看准确率但准确率在很多场景下是有误导性的。比如一个二分类问题正样本占90%负样本占10%模型把所有样本都预测为正准确率也有90%但这个模型完全没有用。正确的做法是根据业务场景选择合适的评估指标。我一般会同时看这几个准确率整体判断正确的比例适合类别均衡的场景。精确率预测为正的样本中真正为正的比例适合对误报敏感的场景。召回率真正为正的样本中被预测出来的比例适合对漏报敏感的场景。F1分数精确率和召回率的调和平均适合需要平衡两者的场景。AUC-ROC模型区分正负样本的能力适合评估排序质量。除了这些通用指标还要看业务指标。比如你做差评预警那差评召回率可能比整体准确率更重要因为漏掉一个差评的代价比误报一个差评的代价大得多。评估的时候还要注意区分训练集、验证集和测试集。我见过有人用测试集调参调完之后在测试集上报告结果这相当于作弊。正确的做法是训练集用来训练模型验证集用来调参和选模型测试集只在最后用一次用来报告最终效果。5. 工程化落地把模型变成别人能用的服务5.1 服务封装API设计不只是包一层模型训练好了下一步是把它变成别人能调用的服务。这一步听起来简单但实际上有很多讲究。首先是接口设计。一个好的模型服务接口应该满足这几个条件输入输出明确输入格式、输出格式、字段含义都要写清楚。错误处理完善输入不合法、模型推理失败、超时等情况都要有明确的错误码和错误信息。版本管理接口要有版本号方便后续升级而不影响已有调用方。限流和鉴权防止滥用保护服务稳定性。我一般会用FastAPI来封装模型服务因为它自带文档生成、数据校验、异步支持开发效率很高。一个典型的模型服务大概长这样from fastapi import FastAPI, HTTPException from pydantic import BaseModel import time app FastAPI(titleSentiment Analysis API, version1.0.0) class PredictRequest(BaseModel): text: str request_id: str None class PredictResponse(BaseModel): label: str confidence: float request_id: str latency_ms: float app.post(/v1/predict, response_modelPredictResponse) async def predict(request: PredictRequest): start_time time.time() if not request.text or len(request.text.strip()) 0: raise HTTPException(status_code400, detail文本不能为空) # 模型推理 label, confidence model.predict(request.text) latency (time.time() - start_time) * 1000 return PredictResponse( labellabel, confidenceconfidence, request_idrequest.request_id or unknown, latency_msround(latency, 2) )这个例子里有几个细节值得注意请求和响应都用Pydantic模型定义这样输入输出格式自动校验加了request_id方便追踪记录了延迟方便监控对空文本做了处理。这些细节看起来不起眼但在实际使用中能省很多事。5.2 性能优化让服务跑得又快又稳模型服务的性能优化主要从两个方向入手减少单次推理时间和提高并发处理能力。减少单次推理时间的方法包括模型量化把模型参数从浮点数转换成低精度表示减少计算量和内存占用。模型剪枝去掉模型中不重要的参数减小模型体积。推理引擎优化使用针对推理优化的运行时比如ONNX Runtime、TensorRT等。批处理把多个请求合并成一个批次一起推理提高吞吐量。提高并发处理能力的方法包括异步处理用异步框架处理请求避免阻塞。多实例部署起多个服务实例用负载均衡分发请求。缓存对重复的请求结果进行缓存减少重复计算。我自己的经验是先做批处理再做量化最后考虑多实例。批处理的效果最明显实现也相对简单。量化的效果取决于模型类型有些模型量化后精度损失很小有些则比较明显需要实验验证。5.3 容器化与持续集成让部署变成一件确定的事容器化解决的是在我机器上能跑的问题。把模型服务打包成容器镜像就能保证在任何支持容器的环境里都能以相同的方式运行。一个典型的模型服务Dockerfile大概长这样FROM python:3.10-slim WORKDIR /app # 先复制依赖文件利用Docker缓存层 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制模型文件和应用代码 COPY model/ ./model/ COPY app/ ./app/ EXPOSE 8000 CMD [uvicorn, app.main:app, --host, 0.0.0.0, --port, 8000]这个Dockerfile有几个优化点先复制requirements.txt再安装依赖这样只要依赖不变这一层就能复用缓存模型文件和应用代码分开复制方便单独更新。持续集成方面至少要保证每次代码变更都能自动跑通测试。测试内容包括数据处理逻辑的单元测试、模型推理的集成测试、API接口的端到端测试。测试通过之后自动构建镜像并推送到镜像仓库部署环节可以手动触发也可以自动触发。6. 线上运维模型上线只是开始6.1 监控体系别等用户投诉了才发现问题模型服务上线之后必须有一套监控体系来保证它能持续稳定运行。监控的内容包括几个层面系统层面CPU使用率、内存使用率、磁盘IO、网络IO、服务存活状态。这些是基础监控任何线上服务都需要。服务层面请求量、响应时间、错误率、超时率。这些指标能反映服务的健康程度。模型层面预测分布、置信度分布、特征分布。这些指标能反映模型是否在正常工作。业务层面关键业务指标的变化比如差评发现率、用户满意度等。我特别想强调的是模型层面的监控。很多团队只监控系统和服务层面模型层面完全不管。结果模型效果下降了也不知道直到业务方反馈最近怎么不准了才发现。模型监控的一个简单做法是记录每次预测的输入和输出然后定期分析预测分布的变化。如果发现某个类别的预测比例突然变化或者置信度分布明显偏移就可能是模型出了问题需要进一步排查。6.2 告警策略别让告警变成狼来了告警是监控的延伸。监控发现问题告警通知人。但告警设置不好就会变成狼来了——天天告警但每次都是误报最后大家都不看了。好的告警策略应该满足告警有意义每条告警都对应一个需要人工介入的问题。告警有分级不同严重程度的问题用不同的通知方式。告警有上下文告警信息里包含足够的信息让人能快速判断问题。告警有收敛同类问题不要重复告警避免告警风暴。我一般会把告警分成三级级别触发条件通知方式响应要求P0服务不可用、错误率超过10%电话即时消息立即响应P1响应时间超过阈值、错误率超过5%即时消息30分钟内响应P2模型指标异常、资源使用率偏高邮件当天处理告警阈值不要拍脑袋定要根据历史数据来定。比如响应时间阈值可以先跑一周看看P99是多少然后在此基础上留一定余量。6.3 模型迭代上线不是终点是新的起点模型上线之后迭代就开始了。迭代的驱动力来自几个方面数据分布变化用户行为变了数据分布跟着变模型效果下降。业务需求变化业务方有了新的要求比如要增加新的类别。模型技术进步有了更好的模型架构或训练方法可以提升效果。线上反馈用户反馈了一些bad case需要针对性优化。迭代的流程跟第一次开发类似但有几个额外的注意事项A/B测试新模型上线前先做A/B测试对比新旧模型的效果。灰度发布先让小部分流量走新模型观察一段时间再全量。回滚预案准备好回滚方案新模型出问题能快速切回旧模型。效果对比新模型上线后持续对比新旧模型的效果确认真的有提升。我自己的习惯是每次模型迭代都保留旧模型一段时间方便对比和回滚。等新模型稳定运行一周以上再考虑下线旧模型。7. 常见问题与排查技巧实录7.1 模型效果不达预期从哪里开始排查模型效果不好是最常见的问题。排查的时候我一般按照这个顺序来第一步检查数据。看看训练数据有没有问题标注是否正确、数据分布是否合理、有没有数据泄漏。数据问题是最常见的原因也是最容易被忽略的。第二步检查评估。看看评估指标是否合理、评估方式是否正确、测试集是否有代表性。有时候不是模型不好是评估方式有问题。第三步检查模型。看看模型是否过拟合或欠拟合、超参数是否合理、训练是否充分。可以通过学习曲线来判断。第四步检查特征。看看特征是否有区分度、特征处理是否正确、有没有遗漏重要特征。这个顺序的原则是先检查简单的、容易出问题的地方再检查复杂的、不容易出问题的地方。数据问题比模型问题常见评估问题比训练问题常见。7.2 服务响应慢怎么定位瓶颈服务响应慢的排查思路先看监控确认是整体慢还是个别请求慢是持续慢还是偶发慢。再看日志找到慢的请求看看慢在哪一步。然后压测在测试环境复现问题用压测工具定位瓶颈。最后优化根据瓶颈位置选择优化方案。常见的瓶颈和优化方案瓶颈位置可能原因优化方案数据预处理处理逻辑复杂、重复计算优化算法、加缓存模型推理模型太大、没有批处理量化、剪枝、批处理后处理逻辑复杂、IO等待异步处理、优化逻辑网络传输数据量大、网络延迟压缩数据、就近部署资源竞争CPU/内存不足扩容、优化资源使用7.3 线上效果下降怎么快速止损线上效果下降是最紧急的情况。我的处理流程是确认问题通过监控和日志确认效果确实下降了而不是误报。评估影响看看影响范围有多大影响了多少用户影响了哪些功能。快速止损如果有回滚方案先回滚到上一个稳定版本。排查原因在止损之后再慢慢排查原因。修复问题找到原因后修复问题重新上线。复盘总结问题解决后做一次复盘看看哪里可以改进。快速止损是关键。不要想着先找到原因再处理那样可能会让问题持续更长时间。先回滚再排查这是更稳妥的做法。提示回滚方案一定要提前准备好并且定期演练。我见过太多团队准备了回滚方案但从来没试过真到用的时候发现回滚不了。8. 我踩过的坑和总结的经验8.1 那些年我踩过的数据坑数据方面的坑我踩过不少挑几个印象深刻的说说。坑一数据泄漏。有一次做用户流失预测模型在测试集上准确率95%上线之后效果很差。排查了半天才发现训练数据里有一个特征跟标签高度相关但这个特征在预测时是拿不到的。这就是典型的数据泄漏。教训是训练时用的特征预测时也必须能拿到。坑二数据分布不一致。训练数据是历史数据线上数据是实时数据两者分布不一致。比如训练数据里某个类别的样本很少线上这个类别的样本很多模型对这个类别的判断就不准。教训是训练数据要尽量覆盖线上可能出现的各种情况。坑三标注标准不统一。前面说过了不同标注员对同一个样本的判断不一致导致模型学到的边界模糊。教训是标注标准要清晰标注质量要验证。8.2 那些年我踩过的工程坑工程方面的坑也不少。坑一没有版本管理。模型文件、配置文件、数据文件都没有版本管理出了问题不知道是哪个版本的问题。教训是所有东西都要版本管理包括代码、数据、模型、配置。坑二没有监控。服务上线之后没有监控出了问题不知道直到用户反馈才发现。教训是监控是必须的不是可选的。坑三没有回滚方案。新模型上线出问题想回滚发现旧模型已经被覆盖了。教训是回滚方案要提前准备旧版本要保留。坑四硬编码配置。数据库地址、模型路径、阈值参数都硬编码在代码里换个环境就要改代码。教训是配置要外置用环境变量或配置文件管理。8.3 给刚入行的朋友几条实在建议如果你刚开始接触AI工程我有几条建议第一先把一个完整的项目跑通。不要只停留在调包阶段试着从数据收集开始到模型上线结束完整走一遍。走一遍之后你就知道每个环节大概是怎么回事了。第二重视工程能力。模型能力固然重要但工程能力决定了你能不能把模型变成真正有用的东西。多学学软件工程、DevOps、系统设计方面的知识。第三养成记录的习惯。实验记录、问题记录、解决方案记录都记下来。好记性不如烂笔头记录能帮你节省大量重复排查的时间。第四多看看别人的项目。开源项目是很好的学习资源看看别人是怎么组织代码、怎么处理数据、怎么设计接口的。第五保持耐心。AI工程是一个需要积累的领域不可能一蹴而就。遇到问题不要急慢慢排查慢慢积累经验。这个方向后续还可以往很多地方扩展比如多模态场景下的工程实践、大规模模型服务的性能优化、AI系统的安全与合规等。每一个方向都值得深入。我自己也还在不断学习有新东西再跟大家分享。