
AI工程这个词被炒了两年多我在这个方向上也摸爬滚打了足够久今天想用自己的真实项目复盘来聊一聊。先说结论真正的AI工程不是“拿个模型调一调”而是围绕一个具体业务问题把数据、模型、评估、上线、监控全部串起来的一整套系统工程方法。标题里的“from-scratch”也不是让你从反向传播手推公式开始而是从“一个可实际交付的AI系统到底需要哪些零件”出发自己亲手从头到尾搭一遍。这篇复盘适合刚开始接触AI工程、想系统入门的同学也适合写了两三年业务代码正准备转AI方向的朋友全程会用一个客服工单自动分类项目来展开每一步的为什么和怎么选型都拆开讲。网上教你的东西大部分是工具链的堆砌今天刷一遍Prompt技巧明天看个Agent框架后天照着教程跑通一个RAG demo。看起来学了很多真拿到一个业务需求时还是不知道从哪下手。我刚开始带AI项目时就这样直到老老实实走完一整个分类系统的全流程才真正建立起对AI工程的坐标感。所以这篇文章不聊宏大的理论我就把项目里踩过的坑、做过的决策、改过的代码原原本本摊在桌子上给你看。1. 先把概念理清楚AI工程到底在做什么1.1 “零”的起点不是算法是系统认知我见过太多“从零学AI”的人第一周看Transformer结构第二周研究各种微调技巧第三周就陷入了知识焦虑——感觉什么都学了但什么都做不出。问题出在哪他们跳过了最核心的一步对整个AI系统运转骨架的建立。AI工程和机器学习研究有本质区别。研究可以只关心模型效果指标比如准确率从0.91提到0.92就算一份成果。但工程要面对的是业务方的需求合理吗数据从哪来、脏不脏模型上线后延迟多少半夜挂了怎么发现下个月数据分布变了怎么办一个真正能落地的AI系统至少包含四个层数据层怎么采集、清洗、标注、划分数据怎么保证样本分布不偏。模型层选什么架构、用预训练还是微调、训练和推理的边界在哪。服务层怎么部署成接口、响应多快、并发多少、fail gracefully。运营层线上指标怎么监控、bad case怎么回流、模型多久更新一次、成本怎么控制。这四个层合起来才叫AI工程。你可以在不读任何一篇论文的情况下完成一个能用的AI应用但如果没有这四层的系统框架读再多论文也落不了地。1.2 为什么第一个项目一定要从分类任务开始这是我很想强调的一点。起步阶段别一上来就冲大语言模型、Agent、多模态这类复杂场景。我建议所有人从“文本分类”入手理由很硬任务目标明确给定一段文本输出一个类别标签。评估标准简单清晰业务上也说人话。输出空间有限分类的预测结果可解释、可校对一旦出错能快速定位原因。不确定性可控文本分类是概率模型里最“乖”的一种任务比生成式任务好约束得多。全链路完整覆盖分类任务天然需要数据标注、模型微调、服务化部署、效果评估一步都不会少。我用这个思路带过好几个转行的同事凡是老老实实做完一个分类项目的人后面再接触RAG、Agent理解速度快得惊人因为底层骨架是一样的。而一上来就玩复杂框架的人遇到问题往往连从哪个环节排查都不知道。2. 建立AI工程核心框架一次完整的流水线长什么样2.1 从业务问题到工程方案的五个环节一个AI项目无论看起来多花哨骨架都是固定的五段式。你拿这个框架去套任何项目都适用。第一步定义目标和度量方式。业务方说“帮我搞个智能客服”你得追问是自动回答还是辅助人工自动回答答错了怎么兜底最关键的是怎么衡量“变好了”是响应时间缩短30%还是转人工率下降20%第二步数据准备。这一步通常占整个项目60%以上的精力。包括数据源梳理、字段解析、清洗去重、标注方案、训练验证集划分。第三步模型选择和训练。拿到干净的训练数据后先跑一个简单基线再用更复杂的模型逐步提升。这里的原则是能用规则解决的就别用模型能用小模型解决的别上大模型。第四步部署上线。把训练好的模型封装成服务设计接口、处理并发、做性能优化。模型本身跑得再快接口设计不合理照样被人喷“这个东西好慢”。第五步线上评估与迭代。上线不是终点是另一个起点。需要监控线上表现、定期用bad case重新训练、持续优化。打个比方这就像开一家餐厅。定义目标是确定要做川菜还是粤菜数据准备是买菜备菜模型训练是炒菜部署上线是摆盘上桌线上评估是看客人吃不吃、有没有投诉。很多人只盯着“炒菜”这一个环节食材烂、上菜慢、客人跑了这锅菜炒得再好也没用。2.2 传统软件工程和AI工程的核心差异我最初是后端出身刚接触AI时最不适应的一点是测试怎么没法写断言后来才想通AI工程和传统软件工程有本质区别。维度传统软件工程AI工程输入结构确定字段格式固定文本自然语言噪声大表达不确定逻辑确定性代码if/else写死概率模型同样的输入可能输出不同输出结果可精确复现结果带概率存在不确定性验证单元测试、断言对比指标体系、抽样人工复核、线上监控排错看堆栈、查日志就能定位数据、模型、训练、部署多环节都可能出问题传统软件工程追求的是“确定性”AI工程要做的是“管理不确定性”。你不可能让模型100%正确但要通过工程手段让它在99%的场景下可靠在1%的不确定场景下可控。这个思维转换是从传统开发转向AI工程的第一道门槛。2.3 从零开始的关键决策哪些自己搭哪些用现成“从零开始”这四个字容易把人带偏以为所有代码都要自己写。真这么干的人光数据处理和模型封装就能耗掉一个月。我的经验是从零指的是流程完整而不是重复发明轮子。需要自己做的业务问题定义、评估体系设计、数据清洗与标注方案、bad case分析、迭代节奏规划。这些都是项目特有的没有现成API能帮你。可以直接用的成熟的预训练模型、主流的训练框架如transformers、pytorch、现成的部署工具如FastAPI、ONNX Runtime。站在巨人肩膀上快速验证别自己造轮子。需要仔细判断的该用通用大模型API还是本地小模型。这个没有标准答案取决于数据隐私要求、调用成本、延迟要求。一开始可以先全用现成的跑通后评估瓶颈在哪再决定优化哪一块。我在项目早期犯过过度工程的毛病想着一开始就搭一套完整的ML平台结果大部分组件都没用上。后来学乖了先让最小的流程跑起来再逐步加东西。快速跑通比所谓“架构优雅”重要得多。3. 手把手实操从零搭建一个客服工单自动分类系统3.1 先定义清楚目标和评估口径这个项目是这样的某电商平台每天收到几千条客服工单内容五花八门需要先由机器人判断工单类型再路由给不同部门的处理人员。以前靠人工看标题和内容去判断工作量巨大现在想用AI自动打标。业务目标拆解之后其实很清楚把工单自动分为5类——账户问题、订单问题、支付问题、退换货问题、其他。评估指标分两块离线指标加权F1值。因为样本不均衡不能只看准确率后面细说。线上指标转人工率和平均处理时长。如果模型判断错了工单被打回重新路由处理时长就会飙高这个直接和业务收益挂钩。我特意去跟业务方确认了一个关键问题“模型判断不了或者判断错了怎么办”最后定下来模型置信度低于0.7的一律进人工池保证系统不会帮倒忙。这个兜底设计非常关键后面线上运行全靠它撑着。3.2 数据准备原始工单怎么变干净数据源是历史工单系统导出的CSV包含工单编号、标题文本、正文内容、最终处理标签。看起来字段齐整实际脏得厉害。空文本大概有3%的工单正文是空的只有标题。这种数据不能直接扔因为线上也会遇到。处理方式是拼接标题和正文拼完还是空的才丢弃。重复工单同一个用户反复提交的内容几乎相同如果不做去重会让模型在训练时“偏科”学会背样本而不是理解语义。标签噪声历史标签是人工打的存在一部分错标。比如用户说“退款没到账”有人标成“支付问题”有人标成“退换货问题”。这种噪声只能靠抽样复核加清洗规则没有捷径。清洗后还需要做长度分析。我发现正文超过500字的长尾样本占比很低但线上也会有不能简单截断。所以用了截断策略保留前128个token超出部分暂时忽略。如果在bad case里发现信息集中在后半段再调整策略。训练集和验证集的划分也要讲究。直接随机打乱然后split在工单场景问题不大但有些场景必须按时间切分比如数据分布会随着促销活动变化的场景。我做的是分层抽样保证每个类别在训练集和验证集中的比例一致。3.3 微调一个轻量中文文本分类模型当时我选了基于transformer结构的中文预训练模型作为底座用带标签的客服数据做微调。选择一个较小规格的模型主要考虑是推理速度和服务器成本分类任务用大号模型属于浪费。核心代码如下from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments model_name bert-base-chinese tokenizer AutoTokenizer.from_pretrained(model_name) def preprocess_function(examples): # 拼接标题和正文截断到最大长度128 text examples[title] examples[content] return tokenizer(text, truncationTrue, max_length128, paddingmax_length) dataset load_dataset(csv, data_filestrain.csv) tokenized_dataset dataset.map(preprocess_function, batchedTrue) training_args TrainingArguments( output_dir./results, learning_rate2e-5, per_device_train_batch_size32, per_device_eval_batch_size64, num_train_epochs3, evaluation_strategyepoch, save_strategyepoch, load_best_model_at_endTrue, metric_for_best_modelf1, )有几点实操经验供参考。学习率2e-5是微调中文预训练模型的稳妥起点开太大容易灾难性遗忘开太小又学不进去。训练轮数3轮只是起点我后来观察到第2轮时验证集F1就到了峰值于是改成2轮早停省了一部分训练时间。batch size选32是因为单张卡显存能塞下想要更稳可以试试16差异不大但内存占用更低。训练完成以后做了一个小实验把模型换成一款更大的中文模型再训一轮F1从0.896涨到0.903幅度不到一个点但推理时间翻了三倍。我当场决定不上大模型把精力省下来去做bad case分析和数据清洗回报率更高。3.4 服务化部署模型的最后一公里训练好的模型只是文件怎么变成能被业务方调用的接口才是工程真正的开始。我用的方案是FastAPI包裹底座模型加推理逻辑部署到容器环境。from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class RequestBody(BaseModel): title: str content: str app.post(/classify) def classify(req: RequestBody): text f{req.title} {req.content} inputs tokenizer(text, truncationTrue, max_length128, return_tensorspt) outputs model(**inputs) probs torch.softmax(outputs.logits, dim-1).squeeze() conf, pred_idx torch.max(probs, dim-1) if conf 0.7: return {category: 需要人工, confidence: float(conf)} return {category: id2label[int(pred_idx)], confidence: float(conf)}置信度低于0.7返回“需要人工”这就是之前和业务方约定的兜底机制。这个阈值不是拍脑袋定的我是在验证集上模拟了几轮看不同阈值下“召回率”和“误转率”的权衡最后取的平衡点。如果业务方人力充足可以把阈值调低一点让模型多扛一些如果人力紧张阈值调高宁可多转人工也不能给错答案。部署阶段的性能优化也重要。模型本身跑一次推理大约50毫秒看着还行但并发量一上来GPU显存和CPU占用都可能成为瓶颈。我做了三件事一是开启批处理把多个请求攒在一起推理吞吐量翻了接近一倍二是用ONNX Runtime做推理加速肉眼可见地降了延迟三是对热点样本加了缓存一模一样的工单直接返回结果连模型都不过。3.5 bad case分析模型迭代的正确姿势上线第一个月模型离线F1是0.896线上准确率看着也还不错但业务方反馈有两类工单判断特别不稳一类是用户写了“收到货发现少了东西”模型一会儿标订单问题一会儿标退换货问题另一类是用户带情绪投诉比如“你们的服务越来越差了”模型经常标成“其他”但实际业务上是支付问题引发的投诉。bad case分析的核心动作是“还原上下文”。我把这些失败样本拉出来逐条看原始文本和模型预测的置信度分布发现了规律问题出在语义边界上。“少了东西”既可能是物流环节漏发也可能是用户想退货光读这句话人都不一定知道是哪类模型当然也难判断。另一个是隐含主题只提“服务越来越差”没说支付模型没法从字面上关联到支付类目。针对性解法有两层。第一层是数据层面补充了2000条类似边界的样本重新标注、清洗、加入训练集。第二层是特征层面给模型增加一个“是否包含支付关键词”的辅助输入相当于人工把先验知识塞进去转弯。第二轮训练后两个老大难类别的F1分别从0.82和0.71提升到0.91和0.86。这件事让我深刻理解了一个道理模型效果的上限基本由数据质量决定训练技巧只能帮你在上限附近逼近。很多团队花了大力气调模型结构效果不如老老实实清洗数据、补充边界样本来得明显。4. 从Demo到生产环境必须补上的工程课4.1 可观测性先别急着优化模型先学会看监控我见过太多项目上线后一脸懵业务方说变差了但谁也说不出差在哪。根源在于没有建立可观测性体系。AI系统比普通接口需要更细粒度的观测因为它的输出是概率性的不是简单的状态码。我在这个项目里最少监控了四个维度请求量和错误率接口挂了没、被打爆了没这是最基础的。延迟分布上线前单次推理50毫秒上线后发现P99延迟到800毫秒排查结果是某段日志打印逻辑卡住了GPU去掉后恢复正常。置信度分布如果模型整体置信度开始下降说明线上数据跟训练集分布发生了偏移这是模型要退役或重训的信号。各类别的调用量与命中率哪个类别流量大、哪个类的拒识率高这些数据直接指导下一轮优化方向。具体实现也不复杂。每一条推理请求记录结构化日志包含输入指纹、预测类别、置信度、延迟和路由结果汇总到监控看板。出现异常时靠这些字段回溯定位比什么都好使。4.2 成本控制用工程手段让每一分钱花得值AI项目的成本大头不在服务器而在人力和GPU。很多团队一上模型就想着买卡、扩容其实推理成本高通常是被“模型过大、场景太窄”害的。我踩过几次坑之后总结出的经验是在入口处加上一层轻量规则过滤器。统计里超过40%的工单带“退款”、“支付失败”这类强信号词先让一套几百行规则吃下这部分确定性高的请求。规则挡不住的再进模型模型池的压力瞬间小了很多GPU的tps压力和账单同时降下来了。另一个成本杠杆是模型蒸馏。用大模型做训练时的老师教一个小模型做线上推理效果损失不到一个点延迟却降了60%。这招做在线业务必学。还有一个不大起眼但很实用的建议没事别开着GPU实例。训练任务跑完就释放按量计费环境下一个挂着不用的GPU实例一个月能烧掉你一大笔预算。4.3 迭代节奏AI系统是养出来的不是做完的模型上线后容易犯的另一个错误是把它当传统软件一样“交付完就完事”。AI系统对数据分布极度敏感促销季、产品改版、客服话术调整都会导致线上输入分布变化。我的经验是建立一个“月度重训事件触发重训”的节奏。每月定期从线上拉取新增的、已经由人工处理过的工单作为新的训练样本重新训练一次模型并做AB对比。如果线上大促或者产品重大改版导致输入剧变立即触发一次临时重训不等月底。为了保证这个节奏能在团队里跑起来数据回流通道在一开始就要建好人工处理后的结果自动写入标注池标注池定期导出为训练集。这个自动化链条才是AI系统持续有效的发动机。5. 踩坑实录与避坑清单5.1 数据泄漏最隐蔽也最致命的错误数据泄漏不是只在比赛里出现的概念业务项目里同样会发生。我犯过一次印象很深的错做训练集验证集划分时按工单号哈希取模来分看起来随机实际上有些用户的多个工单被分到了两侧。如果同一个用户的多次反馈高度相似验证集里就会出现很多“见过的”样本离线指标虚高得离谱上线马上现原形。正确做法是分层抽样先按用户ID去重再按类别比例划分。金融、医疗等场景更要注意时间泄漏必须用前N个月的数据训练后N个月的数据验证模拟真实的“预测未来”。很多人觉得这是基础中的基础但越基础越容易在赶活时忽略。5.2 只看准确率被样本不均衡坑惨项目上线前我看离线准确率0.92开心了好一阵。后来仔细一查退换货类样本占了大头模型只要无脑预测退换货就能拿个不错的准确率但支付类和账户类几乎没学到东西。准确率在分类不均衡时就是个伪指标。正确的做法是分层看各类别的精确率、召回率、F1再算加权F1作为总体指标。我后来还把“混淆矩阵”固定地打印出来给团队看哪两类经常被搞混一目了然。这种过度乐观的“准确率错觉”在业内太常见了凡是样本分布不均的数据集准确率都得打一个巨大问号。5.3 过度工程一上来就用大模型是新手最容易交的学费去年有一个咨询过来的团队业务是售后工单分类数据量不大却直接设计了一个大模型Agent方案还接了一堆乱七八糟的工具调用最终延迟高、成本大、效果也不比简单模型好多少。我帮他们收敛成“规则前置过滤轻量分类模型”的组合效果反而更稳定。这个教训的核心是能用确定性规则解决的别上概率模型能用概率解决的别上大模型。大模型数据量和算力门槛都比传统模型高除非你的任务能充分发挥它们的长处。否则最合适的模型不一定是最新的模型而是能刚好解决目标、最好维护的那个。从零开始做AI工程最大的收获不是模型效果刷到了多少分而是建立起一套“看待AI问题”的系统观。看到任何一个需求脑子里自动浮现的是数据、模型、服务、运营四个层听到任何功能想法先问评估指标和兜底方案任何一个线上异常都知道该翻哪块日志、查哪个字段。这种坐标感是刷再多教程也学不来的只能靠完整地做一两个项目去换来。拿一个分类任务练手把全链路走通你的AI工程之路就算真正开始了。