AI工程从零搭建:为什么我劝你别一上来就啃论文
发布时间:2026/11/4 10:49:22 锦皓数字建站

1. 从零搭建AI工程能力为什么我劝你别一上来就啃论文ai-engineering-from-scratch这个标题我第一次看到的时候心里咯噔了一下。过去两年多我带过不少想转AI工程方向的同事和实习生十个里有八个上来就问我是不是得先把Transformer那篇论文吃透是不是得先把反向传播手推一遍每次我都得花半小时把他们从学术路线拽回工程路线。这个项目标题之所以值得单独拿出来聊是因为它戳中了一个非常真实的痛点AI工程和AI研究是两条完全不同的路而市面上绝大多数教程都在用研究生的方式教工程师。先把话说清楚这里讲的AI工程不是让你去发明新的注意力机制也不是让你去刷SOTA榜单。它指的是把一个已经存在的模型稳定、高效、可维护地跑在真实业务里。这中间涉及的东西非常具体——数据怎么清洗和版本化、推理服务怎么部署、显存怎么省、延迟怎么压、效果怎么评估、线上出问题怎么排查。这些东西论文里基本不写但恰恰是决定一个AI项目能不能落地的关键。我见过太多团队模型选得漂漂亮亮demo跑得风生水起一上生产就崩QPS一高就OOM输入长一点就超时换个模型版本整个服务要重写。这些坑本质上都是工程能力缺失而不是算法能力缺失。ai-engineering-from-scratch这个方向的价值就在于它试图把这条工程链路完整地、从零地讲清楚而不是丢给你一堆API文档让你自己悟。这篇文章适合谁看如果你是刚转AI方向的后端工程师、想从算法调参转向工程落地的同学、或者带小团队要做AI产品但不知道从哪下手的技术负责人那接下来的内容应该能帮你少走至少半年的弯路。我会按照我自己实际搭过几套AI服务的经验把从零构建AI工程能力的路径拆开讲包括思路、关键细节、实操步骤和踩过的坑。不吹不黑全是能直接抄作业的东西。2. 整体设计思路AI工程能力到底该按什么顺序搭2.1 先搞清楚工程和研究的分界线在哪很多人搭AI工程能力失败根本原因是一开始就没分清边界。我习惯用一个很土的类比研究是造发动机工程是把发动机装进车里还能让它跑十万公里不出事。造发动机的人关心热效率、燃烧模型装车的人关心的是散热、油路、震动、维修便利性。两者需要的技能树重合度其实很低。具体到AI领域研究侧关心的是损失函数设计、网络结构创新、训练策略工程侧关心的是推理性能、服务稳定性、数据管道、成本控制。你去看那些真正在生产环境跑AI的团队算法工程师和工程工程师的分工是非常明确的。所以from scratch的第一步不是学算法而是建立工程视角一个模型从训练完到用户能用中间要经过哪些环节每个环节的瓶颈在哪。我一般会把这条链路拆成五段数据准备、模型获取与微调、推理服务化、效果评估与监控、迭代与成本优化。这五段里纯算法含量最高的其实是第二段其余四段全是工程活。而恰恰是这四段决定了项目能不能活下来。2.2 为什么我建议从推理服务倒着学常规教程都是从数据开始讲一路讲到部署。但我实际带人的经验是倒着学效率更高。也就是先搞明白一个模型怎么变成一个能对外提供服务的接口再回头去补数据和微调。理由很实在。你先把推理服务跑起来就能立刻获得正反馈——你能亲眼看到输入一段文字、返回一段结果这种即时反馈对学习动力的维持非常关键。更重要的是只有服务跑起来了你才会真正遇到那些工程问题并发怎么办、显存不够怎么办、响应太慢怎么办。带着这些问题回去学数据处理和模型优化目标感完全不一样。我试过两种带人方式。正着学的往往在数据清洗阶段就卡住因为不知道清洗成什么样才算对缺乏下游反馈倒着学的先跑通一个最小服务然后发现哦原来输入格式是这样再回去处理数据就有的放矢。实测下来倒着学的人平均两周能独立跑通一个完整链路正着学的要一个月往上。2.3 技术选型的核心原则能跑起来比跑得漂亮重要选型这块我踩过的坑最多必须单独说。新手最容易犯的错是追新——看到某个新框架性能提升30%就立刻换结果生态不成熟遇到问题搜不到答案一个人卡三天。我的选型原则就三条第一社区活跃度优先于性能指标。一个GitHub issue响应及时的框架比一个benchmark高5%但没人维护的框架值钱得多。第二优先选和你现有技术栈能融合的。你团队全是Python后端就别为了追求极致性能去上C推理框架维护成本会吃掉所有收益。第三先用最笨的方案跑通再优化。一开始就用最朴素的Flask包一个模型能跑就行等真的遇到性能瓶颈了再换。这里给一个我常用的选型对照都是实际项目里验证过的场景推荐方案理由避坑提示快速验证/内部demoFastAPI 原生推理开发快调试方便别用于生产无并发保护中小规模生产FastAPI ONNX Runtime性能与易用平衡注意算子兼容性高并发生产Triton Inference Server动态批处理强学习曲线陡配置复杂边缘/端侧ONNX Runtime 量化体积小依赖少量化精度损失要评估这张表不是让你照抄而是让你理解每个选择背后的权衡逻辑。选型的本质是在开发效率、运行性能、维护成本三者之间找平衡点没有银弹。3. 核心细节解析从零搭建必须啃下的几块硬骨头3.1 数据管道最不起眼但最要命的一环数据这块我见过最离谱的案例是一个团队花了三个月调模型最后发现是训练数据里有15%的重复样本导致过拟合。数据管道的核心不是清洗得干净而是可复现、可追溯、可版本化。什么叫可复现就是今天用这批数据训出来的模型三个月后你用同样的流程还能训出一样的。这就要求你把数据处理的每一步都脚本化而不是在Jupyter里手动点。我自己的习惯是任何数据操作都写成一个独立的Python脚本输入输出都是文件路径中间不依赖任何内存状态。可追溯指的是每条数据能查到它的来源和处理历史。这个在出问题时救命。比如模型对某类输入表现异常你能快速定位是训练数据里这类样本太少还是清洗时被误删了。实现上不需要多复杂一个带时间戳和来源标记的元数据表就够了。可版本化是很多人忽略的。数据是会变的你今天爬的数据和明天爬的不一样。如果不做版本管理模型效果波动时你根本不知道是模型的问题还是数据的问题。我的做法是每次数据处理产出一个带哈希值的快照目录训练时记录用的是哪个快照。工具上DVC或者简单的目录命名规范都能实现不必上重型方案。提示数据清洗阶段一定要保留原始数据所有清洗操作产出新文件绝不覆盖原始数据。我吃过这个亏一次误操作把原始数据覆盖了整个项目回滚了两周。3.2 模型获取与微调别急着从头训练from scratch这个词容易让人误解以为什么都要自己从头搞。实际上99%的工程场景都不需要从头训练模型。你需要的是选一个合适的基座模型然后用你的数据做微调或者直接做提示工程。选基座模型看三个维度能力匹配度、许可协议、部署成本。能力匹配度是指这个模型擅长的任务和你的需求是否一致比如你做代码补全就别选一个主打对话的模型。许可协议这个坑很深有些模型看着好用但商用受限一定要提前确认。部署成本就是显存占用和推理速度一个70B的模型效果再好你只有一张24G的卡也白搭。微调这块我的建议是先别微调。先用提示工程和少样本示例试试很多时候效果就够了。真到了提示工程解决不了的地步再考虑微调。微调也分好几种全参数微调、LoRA、QLoRA。全参数微调效果好但成本高LoRA在大多数场景下效果接近全参但显存占用低一个数量级QLoRA进一步压缩但会损失一点精度。我实测过一个对比同一个任务全参微调需要4张A100跑8小时LoRA一张A100跑3小时效果差距在2%以内。对于绝大多数业务场景这2%不值得多花十倍成本。所以我的默认推荐是LoRA起步效果不够再考虑全参。3.3 推理服务化把模型变成产品的关键一跃模型训练完只是个文件要变成产品必须服务化。这一步的坑最多我按重要性排个序。第一是并发模型。Python有GIL单进程跑推理会阻塞。常见做法是用多进程或者异步框架。但异步框架遇到CPU密集的推理任务时事件循环会被阻塞反而更慢。我的经验是如果推理是GPU任务用异步框架配合批处理如果是CPU任务直接多进程更省心。第二是批处理。单条推理GPU利用率极低批处理能大幅提升吞吐。但批处理会引入延迟——你得等凑够一批才能处理。这里有个经典权衡批越大吞吐越高但延迟越大。生产环境一般用动态批处理设置一个最大等待时间比如10毫秒超时就发车。Triton在这方面做得很好自己实现的话要小心线程安全问题。第三是显存管理。模型加载占显存中间激活占显存批处理又放大显存占用。OOM是推理服务最常见的崩溃原因。我的做法是启动时先做压力测试找到最大安全批大小然后硬编码一个上限宁可拒绝请求也不OOM。同时开启显存碎片整理长时间运行的服务显存碎片化很严重。第四是健康检查。服务要能被监控系统探活。但AI服务的健康检查不能只检查端口通不通还要检查模型是否真的能推理。我一般会准备一条固定的测试输入健康检查时跑一遍确认输出正常。这样能发现模型加载失败、显存耗尽等深层问题。3.4 效果评估没有评估就没有迭代AI项目和传统软件最大的区别是它没有明确的对错。传统接口返回错误码就是bugAI模型返回一个不太对的结果你很难定义它是不是bug。所以评估体系是AI工程的核心基建。评估分两层离线评估和在线评估。离线评估用标注好的测试集算准确率、召回率、F1这些指标。但离线指标好不代表线上效果好因为线上数据分布和测试集往往不一致。所以必须有在线评估通过用户反馈、点击率、人工抽检等方式收集真实表现。我强烈建议在项目第一天就搭好评估框架哪怕很简陋。一个能自动跑测试集、输出指标对比的脚本价值远超你的想象。因为模型迭代时你需要快速判断新版本是不是真的比旧版本好。没有评估框架你只能靠感觉而感觉在AI领域极不可靠。评估集本身也要维护。我见过团队用同一个测试集调了半年模型最后模型在这个测试集上表现完美线上却一塌糊涂——典型的过拟合测试集。正确做法是测试集定期更新或者留一部分从不参与调优的黄金集。4. 实操过程手把手跑通一个最小AI工程链路4.1 环境准备与依赖管理先把环境搭起来。我推荐用conda管理Python环境因为AI相关的包依赖关系复杂conda处理得比pip好。但conda装包慢所以我的习惯是conda建环境pip装包。conda create -n ai-eng python3.10 conda activate ai-eng pip install fastapi uvicorn onnxruntime transformers版本管理上一定要用requirements.txt或者pyproject.toml锁定版本。AI生态更新极快今天能跑的代码下周可能就崩了。我一般用pip freeze导出精确版本然后在CI里用这个文件重建环境。GPU环境还要注意CUDA版本和驱动版本的匹配。这个坑我踩过无数次。原则是先看驱动支持的最高CUDA版本再选框架版本而不是反过来。用nvidia-smi查驱动版本然后去框架官网查对应的CUDA要求。4.2 一个能跑的最小推理服务先写一个最朴素的版本别追求性能from fastapi import FastAPI from pydantic import BaseModel import onnxruntime as ort import numpy as np app FastAPI() session ort.InferenceSession(model.onnx) class Request(BaseModel): text: str app.post(/predict) def predict(req: Request): inputs tokenize(req.text) outputs session.run(None, {input: inputs}) return {result: outputs[0].tolist()}这个版本能跑但有几个明显问题同步阻塞、没有批处理、没有错误处理、没有健康检查。但它的价值在于让你先看到结果。跑起来之后你可以用curl测试curl -X POST http://localhost:8000/predict \ -H Content-Type: application/json \ -d {text: 测试输入}看到返回结果的那一刻整个链路就通了。接下来才是优化。4.3 加上批处理和并发保护同步版本在并发下会排队延迟飙升。改造思路是用一个后台线程做批处理请求进来先入队凑批后统一推理。import asyncio from queue import Queue from threading import Thread request_queue Queue() BATCH_SIZE 8 MAX_WAIT 0.01 def batch_worker(): while True: batch [] start time.time() while len(batch) BATCH_SIZE: try: item request_queue.get(timeoutMAX_WAIT) batch.append(item) except Empty: break if time.time() - start MAX_WAIT: break if batch: run_batch(batch) Thread(targetbatch_worker, daemonTrue).start()这段代码的核心是攒批逻辑要么凑够BATCH_SIZE要么等够MAX_WAIT谁先到就发车。BATCH_SIZE和MAX_WAIT要根据你的硬件和延迟要求调。GPU强、延迟要求松就调大批延迟敏感就调小。并发保护方面加一个信号量限制同时处理的请求数超过就返回429。这比让请求堆积到OOM要好得多。4.4 健康检查与优雅关闭健康检查接口要真的检查模型状态app.get(/health) def health(): try: test_input np.zeros((1, 128), dtypenp.int64) session.run(None, {input: test_input}) return {status: ok} except Exception as e: return {status: error, detail: str(e)}, 503优雅关闭是指服务收到停止信号时先把队列里的请求处理完再退出而不是直接杀掉。FastAPI配合uvicorn可以用lifespan事件实现。这个细节在滚动更新时特别重要不然会丢请求。4.5 容器化与部署最后打包成Docker镜像。Dockerfile要注意几点基础镜像选带CUDA的层数尽量少模型文件用volume挂载而不是打进镜像镜像会巨大。FROM nvidia/cuda:12.1-runtime-ubuntu22.04 RUN apt-get update apt-get install -y python3.10 python3-pip COPY requirements.txt . RUN pip install -r requirements.txt COPY app/ /app/ WORKDIR /app CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000]部署时用docker-compose或者k8s都行小项目compose足够。关键是配置好资源限制特别是GPU的显存限制防止一个容器吃光所有显存。5. 常见问题与排查技巧实录5.1 推理服务典型故障速查实际运维中遇到的问题八成集中在这几类。我整理成表方便对照排查现象可能原因排查方法解决思路服务启动即OOM模型太大/批大小设置过大看启动日志显存占用减小批大小或换量化模型运行一段时间后OOM显存碎片/内存泄漏监控显存随时间变化定期重启/开启碎片整理延迟突然飙升批处理等待/GC停顿看P99延迟曲线调小MAX_WAIT/优化GC输出结果不稳定并发写共享状态检查全局变量加锁或改无状态设计健康检查通过但请求失败检查太浅手动发真实请求健康检查用真实推理这张表是我从多次线上事故里总结的每一条背后都有血泪。特别是最后一条健康检查只检查端口结果模型加载失败服务还显示健康流量打进来全挂这种事故最坑。5.2 那些文档里不会写的避坑经验第一个坑模型文件路径写死。开发时用绝对路径部署到容器里路径变了直接崩。正确做法是用环境变量或者相对路径启动时校验文件存在。第二个坑忽略冷启动时间。大模型加载要几十秒如果健康检查在加载完成前就开始探活服务会被反复重启。要设置足够的initialDelaySeconds。第三个坑日志打太多。推理服务日志量巨大如果不做采样磁盘很快写满。我的做法是正常请求只记摘要异常请求记全量。第四个坑不做输入长度限制。用户传一个超长文本直接把显存撑爆。必须在入口做长度校验超长直接拒绝。第五个坑版本升级不做灰度。新模型直接全量上线效果变差才发现。一定要支持多版本共存按比例分流。注意以上每一条我都亲身踩过尤其是输入长度限制这条一次线上事故就是因为没做校验一个用户传了十万字的文本整个服务雪崩。5.3 性能优化的优先级排序很多人一上来就想着优化模型其实性能优化的收益排序是这样的批处理 量化 模型裁剪 换框架。批处理几乎零成本就能提升数倍吞吐量化能再提升一倍左右模型裁剪和换框架收益递减但成本递增。我的一般流程是先上动态批处理观察吞吐提升然后做INT8量化看精度损失是否可接受如果还不够再考虑换更小的模型或者蒸馏。绝大多数场景前两步就够了。量化这块要注意不是所有模型都适合INT8。有些模型量化后精度掉得厉害必须做量化前后的精度对比。我一般会准备一个小测试集量化前后各跑一遍精度掉超过3%就放弃量化。6. 能力进阶路线从能跑到跑得好6.1 第二阶段该补哪些能力跑通最小链路只是起点。接下来要补的能力我按优先级排监控告警、A/B测试、成本核算、自动化评测。监控告警是保命的。要监控的指标包括QPS、延迟分布、错误率、显存占用、GPU利用率。延迟不能只看平均值要看P95和P99平均值会骗人。告警阈值要根据历史数据设别拍脑袋。A/B测试是迭代的基础。新模型上线前先小流量对比用数据说话。实现上可以在网关层做分流按用户ID哈希保证同一用户始终看到同一版本。成本核算是很多团队忽略的。AI服务的成本主要在GPU要算清楚每个请求的成本才能判断业务是否可持续。我一般会记录每个请求的推理耗时乘以GPU单价算出单次成本。自动化评测是把评估框架接入CI每次模型更新自动跑测试集指标不达标就阻止上线。这一步做完整个AI工程链路才算闭环。6.2 我个人的学习路径建议如果你现在从零开始我建议的路径是第一周跑通最小服务第二周加上批处理和监控第三周搭评估框架第四周做一次完整的模型迭代。一个月下来你对AI工程的全貌就有体感了。学习资源上别贪多。官方文档永远是最好的老师遇到问题先查文档再搜索。社区方面找几个活跃的开源项目读源码比看十篇教程都有用。我当年就是靠读一个推理框架的源码把批处理、显存管理这些概念彻底搞明白的。最后说个心态问题。AI工程这个方向技术更新快今天学的东西明年可能就过时。但底层能力——并发、性能、稳定性、成本——这些是不变的。把底层打扎实上层工具怎么换都不慌。我见过太多人追着新框架跑结果每个都只懂皮毛遇到问题还是抓瞎。沉下心把一条链路走通走深比什么都强。这个方向后续还能往很多地方扩展比如多模态服务的工程化、模型编排、边缘部署等等。但那是跑通基础之后的事了先把眼前这条链路跑顺比什么都实在。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。