第一次看到《ai-engineering-from-scratch》这个名字时我想到的是GitHub上那批“build your own X”仓库——把平时当黑盒使用的东西拆开亲手重建一个最小版本然后才真正理解它。这两年“AI工程”被各种招聘JD和热搜词反复提起但真正动手从零搭过一条完整AI系统的人其实比想象中少得多。跑通一个模型跟交付一个AI系统之间隔着数据、评估、部署、监控、成本控制这一整条工程链。今天这篇帖子就把我从零实操的完整路线写出来给有基本编程基础、正在转AI工程的软件工程师参考也适合模型调了很久、但总在工程化环节卡壳的同学。1. 到底什么算AI工程先别急着写代码我见过不少新人一上来就抱着PyTorch教程猛啃或者到处问“大模型微调用什么框架”。这些当然都是AI工程的一部分但远远不是全部。想从零开始先把概念边界划清楚后面才不会走偏。1.1 从“跑通模型”到“交付价值”之间的距离很多人理解的AI开发就是训练一个模型调好准确率就完事。但真实业务里模型只是系统里的一个小零件。拿最简单的文本分类举例模型本身可能只有几十行代码但要把这个分类器变成线上服务你得想清楚一连串问题训练数据从哪来、标注质量怎么保证、模型上线后遇到没见过的文本怎么办、推理延迟能不能扛住流量、出错之后怎么回滚、模型效果下降谁能第一时间发现。这些问题合在一起才叫AI工程。传统软件工程处理的是确定性逻辑输入输出可预期、可复现AI系统处理的是概率输出同一个输入今天可能返回A明天可能返回B。这种本质差异导致传统软件那套工程质量体系直接套在AI上会失灵。最典型的就是单元测试普通代码可以断言“输入11必然等于2”但模型没法断言“这条评论必然被判为负面”而且模型效果还会随着数据分布变化而漂移。所以AI工程必须额外处理“效果度量”和“不确定性管理”这两件事。从零做AI工程的第一课就是接受“没有100%正确”这个前提。系统设计、错误兜底、监控报警全都是围绕这个前提展开的。如果还抱着“我把模型训练好就万事大吉”的思路那做出来的东西基本只能停在notebook里。1.2 AI工程师和算法工程师到底差在哪AI工程师和算法工程师这两张title经常被混着用但实际侧重完全不同。算法工程师的KPI通常是模型效果F1涨了多少、AUC提升了多少核心精力放在模型结构设计、特征工程和实验迭代上。AI工程师的KPI往往是系统能不能稳定运行上线率、可用性、响应延迟、推理成本、数据回流机制、模型漂移监控。一个关心“能不能更准”另一个关心“能不能一直准”。我说这个区别不是想划清边界而是想说明“从零开始做AI工程”必须同时具备两个视角。只会训练模型、不会部署的人做出来的东西永远停在实验室只懂工程部署、不懂模型原理的人遇到效果问题只能瞎调参数连调参方向都判断不了。真正的AI工程师是那种能在数据集、模型、服务和业务指标之间来回穿梭的人——哪一头出了问题都能第一时间定位到具体环节。这也是为什么我推荐从零完整做一个小项目而不是只跟着教程训练一个模型就结束。只有把全链路手动走一遍你才知道每个环节之间的接口长什么样、哪些地方容易出错、出了问题应该去哪排查。1.3 为什么“从零开始”反而是最快的路径“从零开始”听起来低效本质上是把黑盒打开的过程。直接用开源大模型API能很快上线一个demo但你对里面的工程细节完全没有感知自己从零搭一条最小闭环哪怕做得非常简陋也能把每条数据流、每个模块边界都摸透。很多初学者总是纠结应该先学PyTorch还是先学FastAPI其实答案不是二选一——完整走一遍最小项目之后你自然就知道自己缺哪块再回头针对性补课比漫无目的地刷教程高效得多。从零开始还有一个隐藏好处因为每一步都是自己搭的你会清楚每个模块的来龙去脉。后来换成更复杂的框架时你知道那些配置项在解决什么问题而不是照着别人的配置文件盲目复制。这份“知其然也知其所以然”的底子就是“from scratch”最值钱的部分。2. 从零搭建AI系统的整体设计思路开始动手之前先想清楚要做一个什么系统。我强烈建议第一次从零做AI工程别一上来就挑战“写一个类似ChatGPT的东西”先选一个小而完整、结果可验证的场景。友善提醒任务越具体你越能聚焦到工程本身而不是被各种陌生的算法细节带走注意力。2.1 先定场景再选模型一个贯穿全文的案例这篇文章后面所有的实操我统一拿“客服问答助手”当例子。为什么不选图像分类或者语音识别因为文本类任务上手门槛最低而且从数据标注到模型部署链路最典型、最容易复现。需求拆解很简单用户进客服页面输入一句话系统返回最合适的预置回答。比如用户问“怎么申请退款”系统返回退款流程用户问“人工客服几点上班”系统返回服务时间。业务上有个硬约束答案必须来自知识库不允许模型自由发挥因为客服场景一旦编造内容会造成很严重的信任问题。这个约束直接决定了技术路线不能是开放式的生成模型而应该是一个检索问答系统核心是“语义匹配”。这个设计决策背后有一条通用原则先定义不可接受的错误再选模型。如果允许AI自由生成大模型很合适不允许编造就老老实实做匹配和检索。很多AI项目失败不是模型不够强而是场景约束没想清楚就直接上大模型最后输出不可控根本没法上线。想清楚这个问题比选任何模型都重要。2.2 技术栈选型足够简单又要能撑到生产第一次做项目技术栈最忌讳“全都要”。什么分布式训练、推理加速、Kubernetes编排现阶段统统不需要。我的默认组合是环节选型理由开发语言Python 3.10AI生态最全写起来快资料好找数据处理pandas、NumPy、scikit-learn清洗、分词、跑传统基线模型都够用深度学习框架PyTorch灵活社区资料多调试工具丰富向量检索轻量版FAISS量大再换Milvus海量问答对召回十万级规模足够服务框架FastAPI自带异步和OpenAPI文档部署简单实验跟踪MLflow实在不想装就用结构化的文件夹记录参数、指标避免实验混乱部署Docker 一台云服务器隔离环境方便迁移和回滚这个组合里没有任何新潮框架因为从零开始最重要的是降低变量数量。技术栈越陌生出问题时你越分不清是自己代码的问题还是框架用法的问题。生产中真正决定成败的往往不是用了多先进的框架而是有没有一整套跑得通的最小闭环。先把主流程用最朴素的工具跑通后面再逐步替换组件每一步都还有清晰的基准可以对比。2.3 最小闭环架构数据、模型、服务、反馈四件套一个AI系统再复杂核心链路段就是四段数据、模型、服务、反馈。数据决定模型的上限模型把数据里的规律提取出来服务把模型包成别人能用的API反馈闭环让系统持续变好。这四段缺一环都叫不完整系统只能叫demo。具体到客服问答助手完整数据流是用户问题进来后先用检索模块从知识库召回最相似的若干条问答对再把“用户原始问题召回结果”一起交给排序模块挑出最匹配的一条最后把这条的标准答案返回给用户。冷启动期间可以用规则兜底召回相似度低于设定阈值时直接提示“已转接人工客服”绝对不硬答。整条链路搭完后你会发现真正花时间的根本不是模型训练而是数据清洗、评测集建设和阈值调整。这也再次印证了“工程”和“算法”的区别——算法关心怎么把准确率提升0.5个百分点工程关心怎么让这0.5个百分点在真实流量里稳定地兑现并且出了问题能快速发现、快速恢复。3. 实操用最小闭环跑通AI系统这一部分我按实际操作顺序展开。你可以照着我这个流程做也可以换成自己的数据和业务场景核心流程不变。每一个步骤我都会说明为什么这样做以及我当时踩过的坑。3.1 数据和评测集最容易被低估的一环先解决数据从哪来。客服问答这个场景公开数据集不少金融、电商领域都有现成的客服语料。如果完全找不到合适的也可以直接整理知识库问题列表把FAQ里的“常见问题”当作标准问题再从真实客服聊天记录里捞用户真实问法。实在没有数据就先手工整理50到100个高频问题当种子数据系统上线后再从日志里补充真实用户问题。数据拿到手之后重头戏是划分数据集。很多新手习惯把数据随机切一刀就开训这样做出来的模型指标虚高因为训练集和验证集里极可能混入同义问法造成数据泄漏。举个例子“怎么退货”和“退货流程是什么”意思是同一件事如果一条在训练集、一条在验证集模型相当于“见过答案再考试”线上效果一定会大打折扣。正确做法是按“意图簇”划分先把意思相近的问题归成一组再以组为单位整体划分到训练集、验证集或测试集保证测试集和训练集里不出现相同意图的样本。顺便讲一下我常用的标注方法。客服问答的标注不是逐条写答案而是维护一张“标准问题-标准答案表”再把收集来的真实用户问法映射到标准问题上形成“相似问法列表”。这样做的好处是数据天然形成了“用户问法映射标准问题ID”的监督信号既能拿来训练匹配模型也能直接做检索效果评估。标注规范里还要写清楚边界情况包含数字的具体问题、骂人的话、中英混杂的句子分别该归到哪一类避免标注员之间口径不一致。3.2 模型训练与调优第一次别急着上大模型训练阶段最容易犯的错是一上来就微调大模型跑一轮好几个小时却连“传统模型能不能打”都没验证过。我建议的顺序是先用词频特征加逻辑回归跑基线再试中等复杂度的模型最后才考虑大模型或者专门的向量模型。这样做不是排斥先进技术而是先搞清楚投入产出比。为什么这么麻烦因为如果逻辑回归都能达到85%准确率而你用BERT精调了三天也只从85%涨到85.2%这0.2%的收益可能要付出十倍推理成本业务上不一定划算。工程师一定要有能力回答“值不值”这个问题而不是永远追求指标最高。具体到客服问答这个案例第一步可以用BM25先做一个纯关键词检索的baseline。BM25完全不懂语义但用户问“怎么退款”时能精确命中“退款流程”里的强关键词覆盖相当大一部分高频场景。这一步会把工程链路全部打通后面升级换了模型只需要替换内部实现接口和评估代码全都不用变。第二步再升级成向量检索用预训练中文Sentence-BERT模型把用户问题和标准问题各算成一个向量然后算余弦相似度做召回。这一步的关键是订好阈值逻辑相似度高于0.8直接返回命中的答案在0.6到0.8之间进入人工审核通道或者返回“您是想问以下问题吗”让用户二次确认低于0.6直接转人工客服。千万不要指望模型永远正确给不确定性留一个兜底出口这是AI工程里最重要的一课。训练过程中还有一件事必须做——记录实验。每跑一轮实验都要记下用了哪个模型、哪份数据、哪个随机种子、哪个超参数、验证集指标是多少。我第一次做的时候就偷懒没认真记录半个月后想找回最好的那个配置发现完全想不起来当时的参数组合只好凭记忆重试白白浪费两天。后来老老实实配置了MLflow每个实验自动记录代码版本、模型文件、参数和指标就再也没出过这种问题。3.3 部署与监控模型上线只是开始模型训练完下一步是把它包成服务。FastAPI是首选只需要十几行代码就能定义一个接口自带参数校验和OpenAPI文档联调阶段特别方便。典型的接口代码如下from fastapi import FastAPI from pydantic import BaseModel class QueryItem(BaseModel): question: str app FastAPI() def retrieval_answer(question: str): # 内部实现召回 排序 阈值判断 兜底转人工 return {answer: 请稍等正在为您转接人工客服..., source: fallback} app.post(/api/v1/qa) async def qa_endpoint(item: QueryItem): result retrieval_answer(item.question) return result这里有几个容易被忽略的工程细节。第一是超时和大流量保护推理接口必须设置超时和并发上限比如单实例最多同时处理32个请求超过直接返回繁忙状态防止模型把服务进程彻底拖死。第二是模型预热很多框架加载模型是懒加载第一个请求会特别慢部署脚本里要在进程启动后先自测调用一次接口把模型真正加载进内存再对外开放流量。部署用Docker最省事把Python环境、模型文件、服务代码全部打进镜像保证“本机跑得好好的线上也跑得好好的”。启动命令里加一个--workers 2让Uvicorn开两个进程吞吐量立刻翻倍。如果你还想再稳一点前面加一层Nginx做负载均衡和静态资源代理整体架构就基本撑得起小流量的真实业务了。上线之后的监控分两层。第一层是系统指标接口延迟、错误率、CPU和内存占用这些决定服务是不是活着。第二层是模型指标用户点击“有用/无用”的反馈率、回答被转人工的比例、知识库每类问题的命中率这些决定服务到底有没有价值。很多项目只盯第一层结果服务很稳但效果很烂用户流失了都没发现等反应过来已经晚了。第二层数据一定要定期回流到数据集里形成“线上数据—再训练—再评估—再上线”的闭环这才是AI工程与传统软件开发最大的不同。4. 常见问题与排查技巧实录从零做到上线我踩过的坑不少。这些问题在教程里很少被详细讲但实操中几乎每个人都会遇到所以单独整理成下面几类每条都配上我的排查思路。4.1 训练阶段的高频翻车现场最典型的是数据泄漏。我第一版数据直接随机划分验证集指标好得离谱但一放到线上就原形毕露。排查方法很简单按前文说的“意图簇”重新分组划分然后检查测试集和训练集里有没有相同意图的样本。如果有重新划分直到两组完全不重叠为止。这一步做完验证集指标通常会明显下降但那个数字才更接近真实线上表现。第二个高频问题是类别不均衡。客服场景里“退款”“物流”这类问题占大头“投诉”“开发票”这类偏门问题只有零星几条模型会倾向于把所有问题都判成大类别导致小众类别完全被忽略。解决办法是先统计意图分布对稀疏类别做样本加权或者在loss里给少数类提高权重。这里要特别提醒准确率在类别不均衡时分文不值一定要看每个类别的召回率、精确率和F1重点盯少数类别的表现最好直接打印混淆矩阵。第三个问题是过拟合。现象是训练loss还在下降验证指标已经不涨甚至开始下跌。常规手段无非降学习率、早停、加dropout、减小模型复杂度但最直接有效的还是扩充训练数据。如果数据没法再扩可以做文本数据增强把“退款”同义词替换成“退钱”“退费”把“快递”替换成“物流”“包裹”增加问法多样性。文本数据增强比图像容易操作效果也立竿见影。4.2 上线后的典型事故与排查思路上线后最常遇到的问题一句话概括就是“训练时效果很好线上拉垮”。遇到这种问题我的排查顺序是固定的先看数据分布有没有变再看训练和部署的预处理有没有不一致最后才去怀疑模型本身。这个顺序非常重要因为前两类的排查成本很低而重新训练模型的成本很高。数据分布漂移是最隐蔽的原因。业务季节性变化、用户语言习惯改变、新活动上线带来新问题都会让线上真实问法和训练集差别变大。比如促销季大量用户问“满减怎么算”而训练集里根本没几条。这个没法完全避免只能靠监控回答满意率和转人工率来提前感知并且定期把线上新问题补充进训练集重新训练。预处理不一致也特别常见而且非常冤。训练时你可能对用户问题做了去特殊字符、转小写、分词部署代码里却忘了做同一套操作导致线上输入和训练时看到的分布完全不一样效果自然暴跌。排查办法很简单把同样的几十条样本分别走训练时的预处理流程和线上的预处理流程对输出结果逐条对比差异一眼就能看出来。延迟问题则是另一个高发事故。向量检索在知识库规模变大后会明显变慢问答对超过十万条还纯用内存暴力计算响应时间可能超过可接受的线上标准。这时候要引入FAISS或者Milvus建立索引把召回的时间复杂度从线性降到对数级。实测下来一万条问答对暴力搜索只要几毫秒百万条就要几十毫秒以上接近线上延迟红线所以规模一大必须果断上向量数据库别犹豫。4.3 几条“文档里没有”的实战心得第一把“阈值”当成一等公民来调而不是只调模型参数。客服问答系统里很多“效果不好”的问题本质上是“阈值不合适”跟模型本身关系不大。花半小时把相似度阈值从0.7调到0.75带来效果提升可能比换一个大模型更明显。调阈值的时候一定要在单独固定的评测集上进行并且记录每次调整对应的指标不要跟着线上反馈反复拍脑袋改不然很难收敛。第二先加缓存再谈优化。用户提的问题高频重复率极高很多问题你其实已经回答过一遍了。对完全相同的或者高度相似的问题加一层Redis缓存命中就直接返回上一次的结果能省掉大量重复推理计算。这个方案实现成本极低但是对延迟和成本的改善立竿见影尤其是在模型推理比较贵的场景下缓存一天帮你省掉的API调用费用相当可观。第三保存每个模型版本时把“评测集指标线上反馈指标数据版本”一起存下来。模型不是越新越好有时候旧模型在新的数据分布下反而更稳定。有了版本管理出问题才能快速回滚到历史上表现最好的版本。工具上MLflow、DVC都很好用实在不想引入新工具至少用命名清晰的文件夹把模型文件按“日期准确率备注”的方式保存重点是要让一周后的自己能看懂现在保存的东西。第四上线前做一次“消融测试”把系统里的任何一个模块去掉或者换成最朴素的版本看效果到底掉多少。我做过一次这样的测试结果发现去掉经典检索模块只保留向量检索最终效果反而变好于是果断删掉那一大段代码系统瞬间清爽了。这套方法不但能验证每个模块的真实价值还能帮你砍掉一堆“感觉有用但实际没用”的复杂度。系统越简单维护成本越低出问题的概率也越小。5. 写在最后这个项目带给我的东西如果把这些内容浓缩成一句大实话我想说AI工程不是“更高级的算法”而是一整套围绕不确定性模型展开的工程体系。模型训练只是其中一环数据治理、评测设计、部署监控、反馈闭环每一环都可能成为系统的瓶颈。我自己从零完整做完一遍之后最大的变化是看问题的方式变了——现在看到一个AI应用第一反应不再是“它用了什么模型”而是“它的数据从哪来、错了会发生什么、怎么知道它什么时候开始不行”。最后再分享一个我自己反复在用的技巧无论启动什么AI项目都先花半天时间做一个“最不能被外部依赖的版本”——只用规则或者传统模型把整条链路完整跑通。这个版本不需要多聪明但是一定要完整。有了它你再逐步拔高每个环节每一步都能单独验证是不是真的变好了。做到这一步你才算真正把“AI工程”这四个字从名词变成了自己的能力。这个项目后续还可以往几个方向扩展增加多轮对话管理把上下文信息纳入检索排序引入大模型做兜底回答生成但要设计幻觉控制策略搭建A/B测试框架在真实流量里验证每个模型版本的优劣。每一条单独拿出来都能写一整篇我打算后面逐个整理把这套从零开始的工程笔记持续完善。如果你正准备启动自己的“from-scratch”项目我的建议很简单挑一个小场景把闭环跑通然后再谈其他。