从零构建AI工程能力:后端老兵的踩坑与重构实录 1. 从零搭建AI工程能力一个后端老兵的踩坑与重构实录ai-engineering-from-scratch这个标题第一次看到的时候我愣了一下。不是因为它有多花哨恰恰相反它朴素得有点不像这个时代的项目名。但正是这种朴素让我决定认真聊一聊这件事。过去两年我身边至少有七八个后端、前端甚至运维的朋友问我同一个问题想转AI工程到底该从哪儿下手他们不是想去做算法研究不是要发论文而是想把手头那些工程能力迁移到AI系统上——部署模型、搭推理服务、做RAG、搞数据管道、控成本、保稳定性。这些事本质上还是工程问题只不过换了个领域。我自己就是这么走过来的。三年前我还在写业务后端每天跟接口、数据库、缓存打交道。后来因为项目需要被迫接手了一个模型服务化的活儿从零开始摸索。那段时间踩的坑比之前三年加起来都多。模型加载慢、显存炸了、并发上不去、输出不稳定、成本失控……每一个问题都逼着我去理解AI系统跟传统后端到底哪里不一样。所以当我看到ai-engineering-from-scratch这个标题时特别有共鸣——它说的不是从零学AI理论而是从零构建AI工程能力这两件事差别巨大。这篇内容适合谁看如果你是有一定工程基础、想系统性地补齐AI工程能力的开发者那正好。如果你是完全的新手也没关系我会尽量把每个概念用生活化的方式讲清楚。我不会堆砌公式不会讲反向传播怎么推导我讲的是一个AI系统从代码到上线中间到底要经过哪些环节每个环节的关键决策是什么哪些坑我亲自踩过。核心关键词就一个——ai-engineering-from-scratch从零开始的AI工程。接下来我会把它拆成几个部分整体思路怎么设计、核心环节怎么实现、实操中会遇到什么问题、以及我总结出来的避坑经验。2. 整体设计与思路拆解为什么不能照搬传统后端那套2.1 先搞清楚AI工程和传统后端的本质差异很多人转AI工程的第一反应是不就是多了一个模型调用吗我在业务代码里加个HTTP请求不就行了我一开始也是这么想的结果第一个项目就被打脸了。传统后端的核心是确定性逻辑——输入A经过固定代码路径输出B。你可以写单元测试可以精确预测每个分支。但AI系统的核心是概率性输出——同样的输入模型可能给出不同的结果而且你很难用传统测试手段去验证对不对。这个差异带来一连串连锁反应。传统后端扩容加机器就行无状态服务随便水平扩展。AI推理服务呢模型本身占显存加载一次要几十秒你不能每个请求都重新加载。而且GPU资源昂贵一台带A100的机器成本可能是普通服务器的几十倍你不可能像扩CPU节点那样随便加。再比如监控传统后端看QPS、延迟、错误率就够了AI服务你还得看token吞吐、显存占用、输出质量漂移。这些指标传统监控体系里根本没有。所以from scratch的第一步不是急着写代码而是重新建立一套针对AI系统的工程心智模型。你得接受不确定性得学会跟GPU资源打交道得理解模型的生命周期管理。我见过太多人拿着微服务的经验直接套结果做出来的东西能跑但完全没法维护。2.2 分层架构把AI系统拆成能独立演进的几层踩了几次坑之后我总结出一个比较稳的分层思路。整个AI工程系统可以拆成五层每层职责清晰层与层之间通过明确定义的接口通信。层级职责关键技术点常见误区数据层数据采集、清洗、版本管理数据管道、特征存储忽视数据版本导致无法复现模型层模型训练、微调、评估训练框架、评估指标只看loss不看业务指标服务层推理部署、批处理、流式输出推理引擎、动态批处理直接上大模型不做量化应用层编排、RAG、Agent逻辑提示工程、检索增强把业务逻辑塞进提示词运维层监控、成本、灰度、回滚可观测性、资源调度用传统APM监控AI服务这个分层不是拍脑袋来的。我试过把所有逻辑揉在一起结果改一个提示词要重新部署整个服务调一次模型参数要动数据库。分层之后每层可以独立迭代——数据层换存储不影响服务层服务层换推理引擎不影响应用层。这种解耦在AI场景下尤其重要因为AI技术栈变化太快了今天用的框架明天可能就过时了分层能让你把变化隔离在局部。2.3 技术选型的核心原则够用就好别追新AI领域最大的坑之一就是技术选型焦虑。每隔几周就有新框架、新工具出来你总觉得不用最新的就落伍了。我早期也这样结果项目里塞了七八个框架维护成本爆炸。后来我定了一条原则选型只看三个维度——团队熟悉度、社区活跃度、能否平滑替换。举个例子推理引擎的选择。市面上有各种方案有的性能极致但学习曲线陡峭有的开箱即用但定制性差。我的建议是如果你团队里没人有相关经验先从最主流、文档最全的那个开始哪怕性能不是最优。因为AI工程的核心矛盾往往不是性能而是能不能稳定跑起来、出问题能不能快速定位。等系统稳定了再考虑用更激进的方案替换。替换的前提是你在服务层做了抽象换引擎不用改应用层代码。再比如向量数据库。做RAG绕不开它但选型时别一上来就纠结哪个性能高。先问自己数据量多大百万级以内很多轻量方案完全够用。我见过有人为了几万条数据上了分布式向量库运维复杂度直接翻倍纯属自找麻烦。从零构建AI工程能力克制比激进更重要。3. 核心细节解析与实操要点每个环节到底怎么做3.1 数据层别急着训模型先把数据管道搭稳我接手第一个AI项目时犯的最大错误就是跳过数据层直接搞模型。结果模型效果不好我花了两周调参最后发现是训练数据里有大量重复和脏数据。这个教训值好几万块钱的GPU时间。数据层的核心是可复现。什么叫可复现就是你今天用这批数据训了一个模型三个月后想复现还能找到一模一样的数据。这要求你做数据版本管理。别用文件名区分什么data_v1.csv、data_v2_final.csv这种命名方式迟早让你崩溃。用专门的数据版本工具或者至少用内容哈希做标识。数据清洗这块我总结了一个最小可用流程。第一步去重用哈希或者MinHash别小看去重很多公开数据集重复率能到30%以上。第二步过滤把明显无意义的样本去掉比如空文本、乱码、超短样本。第三步格式化统一成模型能吃的格式。这三步做完数据质量能提升一大截。注意清洗规则要写进代码里别手动操作手动操作不可复现。实操心得数据管道一定要做数据质量监控。我现在的做法是每次数据更新后自动跑一遍统计看样本数量、长度分布、类别分布有没有异常波动。有一次上游数据源出问题样本量突然少了一半监控直接报警避免了一次无效训练。3.2 模型层训练不是必须的微调要谨慎很多人一提AI工程就想到训练模型其实在实际工程中从头训练模型是极少数情况。大部分场景用的是预训练模型加微调或者干脆只用提示工程。所以模型层的重点不是训练算法而是评估体系。评估体系怎么建我的经验是分三层。第一层是自动指标比如分类任务看准确率、F1生成任务看BLEU、ROUGE。但这些指标只能参考不能全信。第二层是人工评估抽样一批输出让人打分这个最准但成本高。第三层是业务指标比如推荐系统的点击率、客服系统的解决率。三层结合起来才能判断模型到底行不行。微调这件事我要特别提醒。微调不是万能药很多时候提示工程能解决的问题微调反而会引入新问题。微调需要高质量标注数据需要调超参需要防过拟合成本不低。我的建议是先用提示工程和RAG把效果榨干实在不行再考虑微调。而且微调要从小的学习率开始试别一上来就大改容易把预训练学到的能力破坏掉。3.3 服务层推理部署的五个关键决策服务层是AI工程跟传统后端差异最大的地方也是坑最多的地方。我把关键决策整理成五个问题每个问题都对应一个实操要点。第一个问题用什么推理引擎如果模型不大直接用框架自带的推理接口也行。但如果要上生产建议用专门的推理引擎它们做了大量优化比如算子融合、内存复用、动态批处理。选型时重点看它支不支持你用的模型格式支不支持量化社区活不活跃。第二个问题要不要量化量化是把模型参数从高精度降到低精度能大幅减少显存占用和提升推理速度代价是可能损失一点精度。我的经验是大部分场景下INT8量化损失很小可以放心用。但要注意量化后一定要重新评估效果别想当然。第三个问题批处理怎么做动态批处理是提升GPU利用率的关键。原理很简单把短时间内到达的多个请求攒成一批一起推理GPU并行处理效率高。但批处理会增加延迟所以要设一个最大等待时间比如50毫秒超过就立即处理。这个参数要根据你的延迟要求调。第四个问题流式输出怎么实现大模型生成文本是一个token一个token出来的如果等全部生成完再返回用户要等很久。流式输出就是生成一个返回一个体验好很多。实现上一般用SSE或者WebSocket注意要处理好连接中断和超时。第五个问题怎么控制并发GPU资源有限并发太高会OOM太低浪费资源。我的做法是设一个请求队列队列满了就拒绝或者降级。同时监控显存占用设一个安全阈值超过就限流。这个阈值要实测不同模型不一样。3.4 应用层RAG和Agent的工程化陷阱应用层是离业务最近的一层也是最能体现工程能力的地方。RAG和Agent是当前最热的两类应用但工程化陷阱特别多。RAG的核心是检索增强生成流程是用户提问先去知识库检索相关文档把文档和问题一起喂给模型让模型基于文档回答。听起来简单但每个环节都有坑。检索环节分块策略很关键。块太大检索不精准块太小上下文不完整。我的经验是块大小在200到500字之间重叠50字左右具体要看文档类型。检索算法上向量检索和关键词检索各有优劣实践中经常混合使用叫混合检索。Agent的核心是让模型自主决策调用工具。工程上的难点是循环控制和错误处理。模型可能陷入死循环反复调用同一个工具也可能调用工具失败后不知道怎么处理。我的做法是设最大循环次数比如10次超过就强制终止。工具调用失败要返回明确的错误信息给模型让它决定下一步。别让Agent无限跑下去成本会失控。注意应用层的提示词一定要版本管理。我吃过亏改了一个提示词效果突然变差但不知道改之前是什么样没法回滚。现在所有提示词都存数据库带版本号可以随时切换。3.5 运维层AI服务监控到底看什么传统后端监控看QPS、延迟、错误率AI服务这些也要看但远远不够。我列一下我实际在用的监控指标。指标类别具体指标为什么重要资源指标GPU利用率、显存占用、温度直接决定服务能不能跑性能指标首token延迟、每token延迟、吞吐量影响用户体验质量指标输出长度分布、拒绝率、重复率反映模型是否正常成本指标每请求GPU秒数、token消耗控制预算业务指标任务完成率、用户反馈最终衡量标准这些指标里我觉得最容易被忽视的是质量指标。模型输出质量会漂移可能因为输入分布变化可能因为模型更新。如果不监控等用户投诉就晚了。我的做法是定期抽样输出用规则或者小模型自动打分发现异常及时告警。4. 实操过程与核心环节实现一个完整的最小系统4.1 环境准备与依赖管理说了这么多理论接下来我带你走一遍完整流程。目标是从零搭一个最小的AI工程系统包含数据管道、模型服务、简单应用和基础监控。环境用LinuxPython为主GPU可选CPU也能跑小模型。依赖管理我强烈建议用虚拟环境加锁定文件。别用全局pip迟早冲突。我习惯用conda建环境pip装包最后导出requirements.txt锁定版本。AI领域包版本兼容性很敏感锁定版本能避免很多莫名其妙的问题。conda create -n ai-eng python3.10 conda activate ai-eng pip install torch transformers fastapi uvicorn sentence-transformers chromadb pip freeze requirements.txt这里解释一下选型。transformers是模型加载和推理的基础库覆盖面广。fastapi做API服务轻量且异步支持好。sentence-transformers做文本向量化RAG检索用。chromadb做向量存储轻量适合起步。这些都是社区活跃、文档齐全的选择适合从零开始。4.2 数据管道的最小实现数据管道我写一个最简版本包含加载、清洗、分块三个步骤。实际项目会更复杂但核心逻辑就这些。import hashlib from typing import List def load_documents(path: str) - List[str]: with open(path, r, encodingutf-8) as f: return [line.strip() for line in f if line.strip()] def deduplicate(docs: List[str]) - List[str]: seen set() result [] for doc in docs: h hashlib.md5(doc.encode()).hexdigest() if h not in seen: seen.add(h) result.append(doc) return result def chunk_document(doc: str, chunk_size: int 300, overlap: int 50) - List[str]: chunks [] start 0 while start len(doc): end start chunk_size chunks.append(doc[start:end]) start end - overlap return chunks这段代码里去重用的MD5哈希简单有效。分块用滑动窗口chunk_size和overlap是我实测下来比较通用的值。注意分块最好按语义边界切比如句号、换行别硬切硬切会破坏语义。上面为了简洁用了固定长度实际项目建议加语义分割。4.3 模型服务的关键代码模型服务我用fastapi搭一个推理接口支持流式输出。核心是模型加载一次常驻显存请求来了直接推理。from fastapi import FastAPI from fastapi.responses import StreamingResponse from transformers import AutoModelForCausalLM, AutoTokenizer import torch app FastAPI() model_name your-model-path tokenizer AutoTokenizer.from_pretrained(model_name) model AutoModelForCausalLM.from_pretrained( model_name, torch_dtypetorch.float16, device_mapauto ) app.post(/generate) async def generate(prompt: str, max_new_tokens: int 256): inputs tokenizer(prompt, return_tensorspt).to(model.device) def stream(): with torch.no_grad(): for output in model.generate( **inputs, max_new_tokensmax_new_tokens, do_sampleTrue, temperature0.7, streamerNone ): yield tokenizer.decode(output, skip_special_tokensTrue) return StreamingResponse(stream(), media_typetext/plain)这里有几个关键点。torch_dtypetorch.float16用半精度减少显存device_mapauto自动分配设备。temperature0.7控制随机性太低输出死板太高胡言乱语。流式输出用生成器逐token返回。注意torch.no_grad()必须加不然会建计算图显存爆炸。实操心得模型加载一定要做预热。服务启动后先跑一次推理把CUDA核函数编译缓存建好不然第一个真实请求会特别慢。我吃过这个亏上线后第一个用户等了十几秒。4.4 RAG检索的完整流程RAG我实现一个最小版本包含向量化和检索两步。from sentence_transformers import SentenceTransformer import chromadb embedder SentenceTransformer(all-MiniLM-L6-v2) client chromadb.Client() collection client.create_collection(docs) def index_documents(chunks: List[str]): embeddings embedder.encode(chunks).tolist() collection.add( embeddingsembeddings, documentschunks, ids[str(i) for i in range(len(chunks))] ) def retrieve(query: str, top_k: int 3) - List[str]: query_embedding embedder.encode([query]).tolist() results collection.query( query_embeddingsquery_embedding, n_resultstop_k ) return results[documents][0]向量模型选的all-MiniLM-L6-v2小且快适合起步。检索top_k设3实际要根据效果调。检索到的文档拼进提示词让模型基于文档回答。提示词模板大概是基于以下资料回答问题资料中没有的信息不要编造。资料{docs}。问题{query}。4.5 基础监控的接入监控我用最简方式记录每次请求的延迟和token数定期输出统计。import time from collections import deque latency_window deque(maxlen1000) app.middleware(http) async def monitor(request, call_next): start time.time() response await call_next(request) latency time.time() - start latency_window.append(latency) if len(latency_window) % 100 0: avg sum(latency_window) / len(latency_window) print(f平均延迟: {avg:.3f}s, 样本数: {len(latency_window)}) return response这是最简版本生产环境要接专业监控系统。但核心思路一样采集、聚合、告警。延迟用滑动窗口统计避免全量数据占内存。实际还要加显存监控、错误率监控等。5. 常见问题与排查技巧实录5.1 显存溢出最常见也最头疼的问题显存溢出OOM是AI工程里出现频率最高的问题没有之一。表现是服务突然崩溃日志里一堆CUDA out of memory。原因通常有几个模型太大、批处理太大、并发太高、内存泄漏。排查思路我按顺序来。第一步看模型本身占多少显存加载后先测一下。第二步看批处理大小把batch size降到1试试。第三步看并发是不是同时来了太多请求。第四步看有没有泄漏长时间运行显存是不是持续增长。解决方案我列个表。原因解决方案注意事项模型太大量化、换小模型、多卡量化后要重测效果批处理太大减小batch size影响吞吐量并发太高限流、请求队列要设合理阈值内存泄漏检查缓存、及时释放用工具定位我踩过最坑的一次是内存泄漏。每次请求都往一个全局列表里塞数据从不清理跑了一天显存就满了。后来改成用固定大小的环形缓冲问题解决。所以写代码时一定要注意全局变量能不用就不用用了就要管好生命周期。5.2 输出质量不稳定怎么定位和改善输出质量不稳定表现为有时候回答很好有时候答非所问有时候重复啰嗦。这个问题比OOM更难排查因为它没有明确报错。我的排查方法分三步。第一步固定输入看输出是否稳定。如果同样输入输出差异很大说明是采样参数问题调低temperature。第二步看输入分布是不是有些类型的输入模型处理不好。第三步看提示词是不是有歧义。改善输出质量的手段按性价比排序。第一是优化提示词把要求写清楚给例子。第二是加few-shot示例让模型模仿。第三是调采样参数temperature、top_p配合调。第四是换更大的模型。第五是微调。我一般按这个顺序试大部分问题在前两步就能解决。注意别迷信大模型。我见过有人遇到问题就换更大的模型成本翻倍效果没提升多少。先把手头的模型榨干再考虑升级。5.3 延迟过高从首token到每token逐层排查延迟问题要拆开看。首token延迟和每token延迟是两回事。首token延迟主要花在请求处理、提示词编码、模型前向计算上。每token延迟主要花在自回归生成上。首token延迟高检查这几点提示词是不是太长编码耗时批处理等待时间是不是太长模型加载是不是没预热。每token延迟高检查模型是不是太大生成是不是没用量化是不是没开KV缓存。KV缓存是自回归生成的关键优化它缓存已计算的注意力键值避免重复计算。大部分推理框架默认开启但如果你手写推理循环一定要确认开了。我早期手写循环忘了开KV缓存每token延迟高了十倍排查了半天。5.4 成本失控怎么把GPU账单压下来AI服务成本主要是GPU。成本失控通常是因为资源利用率低。我总结几个降本手段。第一动态启停。没请求的时候把模型卸载有请求再加载。适合低频场景代价是冷启动延迟。第二量化。INT8量化能省一半显存可能还能提速。第三批处理。把多个请求攒一起GPU利用率上去了单位成本就下来了。第四模型分级。简单请求用小模型复杂请求用大模型别所有请求都上大模型。第五缓存。相同或相似请求直接返回缓存结果省一次推理。我实测下来组合使用这几个手段成本能降60%以上。但要注意降本不能牺牲太多体验要找到平衡点。比如缓存要设合理的过期时间和相似度阈值不然返回过时结果就麻烦了。5.5 常见问题速查表问题现象可能原因快速排查解决方向服务崩溃显存溢出看日志OOM量化/限流/减批输出乱码编码问题检查tokenizer统一编码格式响应超时生成太长看max_tokens限制生成长度效果变差数据漂移对比历史输出重新评估/微调并发上不去同步阻塞看是否异步改异步/加队列成本飙升资源浪费看GPU利用率动态启停/量化6. 我踩过的坑和给你的建议6.1 别一上来就追求完美架构我刚开始做AI工程时总想设计一个完美的架构能支持所有场景。结果花了一个月设计代码没写几行。后来我换了个思路先跑通最小闭环再逐步优化。最小闭环就是一个模型能加载一个接口能调用一个请求能返回结果。就这三件事先做出来。做出来之后你才知道真正的瓶颈在哪才知道该优化什么。这个思路帮我省了大量时间。因为AI领域变化太快你设计的完美架构可能三个月后就过时了。不如先跑起来保持灵活随时调整。从零构建AI工程能力快速迭代比完美设计重要得多。6.2 一定要做实验记录AI工程有大量实验试不同的模型、不同的参数、不同的提示词。如果不记录你很快就会忘记哪个配置效果好。我现在的做法是每次实验都记下来日期、配置、数据、结果、结论。用简单的表格就行关键是坚持。这个习惯帮我避免了很多重复劳动。有一次我想试一个参数组合翻记录发现半年前试过效果不好直接省了半天时间。实验记录还能帮你发现规律比如某类参数总是效果差以后就不用试了。6.3 保持对新技术的好奇但克制AI领域每周都有新东西。我的态度是保持关注但别急着用。新东西往往不稳定文档不全社区小出问题没人帮你。等它成熟了社区大了再考虑引入。我一般会等一个技术出现半年以上有足够多的生产案例才考虑在项目里用。但关注还是要关注的。我每周花一两个小时看看新论文、新工具了解趋势。这样当需要做技术选型时心里有数。关注和采用是两回事别混为一谈。6.4 工程能力比算法能力更重要最后说一个可能有点反直觉的观点。在AI工程这个领域工程能力比算法能力更重要。算法决定了模型的上限但工程决定了系统能不能稳定运行、能不能控制成本、能不能快速迭代。我见过算法很强但工程很弱的人做出来的demo很惊艳但一上生产就崩。也见过算法一般但工程很强的人做出来的系统稳定可靠持续迭代最终效果反而更好。所以如果你是从传统工程转过来的别觉得自己算法不行就没优势。你的工程能力、系统思维、稳定性意识在AI工程里非常值钱。把算法当黑盒用把工程做到极致这就是一条可行的路径。当然基本的算法概念要懂不然没法跟算法同学沟通也没法判断方案可行性。但不需要精通到能推导公式的程度。从零构建AI工程能力说到底是一个持续学习和实践的过程。没有捷径但有方法。先跑通最小闭环再逐步优化做好实验记录避免重复劳动保持好奇但克制别追新追到坑里发挥你的工程优势把系统做稳。这些就是我三年下来最真实的体会。