
1. 从零手搓AI工程为什么我不建议你直接调包很多人一上来就想跑通一个能对话的模型或者直接拉一个开源仓库改改就上线。我见过太多团队在“调包”阶段看着效果不错一到真实业务里就翻车——延迟飙到几秒、并发一上来就崩、成本失控、输出不稳定。问题不在于模型本身而在于AI工程这件事被严重低估了。它不是一个pip install就能解决的活儿而是一整套从数据、推理、服务到监控的系统工程。“ai-engineering-from-scratch”这个方向核心价值就在于把AI应用从“能跑”推到“能扛”。它适合两类人一类是想真正理解AI系统内部运转机制的开发者另一类是受够了调包黑盒、想自己掌控每一层细节的工程师。你不需要先成为算法专家但你需要愿意动手把每一层拆开看一遍。这篇文章我会按我自己从零搭一套AI工程链路的顺序来讲重点放在那些文档里不会写、但实际踩过才知道疼的地方。先说一个反直觉的结论从零构建AI工程最难的不是模型推理而是围绕推理的那一圈“脏活”。数据怎么进、请求怎么排队、显存怎么管、失败怎么重试、成本怎么算——这些才是决定一个AI应用能不能上生产的关键。下面我按模块拆开讲每个模块都会说清楚“为什么这么做”以及“我实际踩过什么坑”。2. 推理层选型别被benchmark数字骗了2.1 推理引擎的三种路线与适用边界从零做AI工程推理层是你第一个要做的重大决策。市面上大致三条路线直接用原生框架PyTorch/TensorFlow做推理、用专用推理引擎如ONNX Runtime、TensorRT、用面向大模型的服务框架如vLLM、TGI这类。这三条路不是谁替代谁而是对应不同阶段。原生框架推理最灵活适合研究和快速验证但它的吞吐和显存利用率在并发场景下很难看。专用推理引擎通过图优化、算子融合、量化把单次推理压到极致适合中小模型和边缘部署。面向大模型的服务框架则解决了KV Cache管理、连续批处理continuous batching这些大模型特有的问题是当前对话类应用的主流选择。我自己的经验是如果你的模型参数量在10B以下且请求模式简单优先考虑ONNX Runtime或TensorRT如果是对话类、请求长度差异大、并发要求高直接上vLLM这类框架别自己造轮子。我早期试过用原生PyTorch加自己写的批处理逻辑结果在请求长度参差不齐时显存碎片严重吞吐只有后来换框架的三分之一。2.2 显存估算一个必须自己算一遍的账很多人部署时显存不够就加卡其实先算清楚账能省很多钱。大模型推理的显存占用主要分三块模型权重、KV Cache、激活值。模型权重好算参数量乘以精度字节数比如7B模型用FP16就是约14GB。KV Cache是变量公式大致是KV Cache 2 × 层数 × 注意力头数 × 头维度 × 序列长度 × 批大小 × 精度字节这个公式里序列长度和批大小是你能控制的。我实际部署一个7B模型时一开始按最大序列长度4096预留KV Cache结果单卡只能跑批大小2吞吐惨不忍睹。后来把最大长度压到1024并开启分页注意力批大小提到16吞吐翻了近6倍。关键认知KV Cache往往比模型权重更吃显存而它的大小直接由你的业务请求长度分布决定。所以上线前一定要统计真实请求的长度分布别拍脑袋设最大值。2.3 量化省显存但别省过头量化是省显存和提速的常用手段INT8、INT4甚至更低。但量化不是免费的午餐它会在精度上做妥协。我的建议是权重可以量化到INT8基本无损INT4要看你任务的容错度。做分类、抽取这类任务INT4通常没问题做需要精细推理的生成任务INT4可能让输出质量明显下降。实测中我发现一个容易忽略的点量化后的模型在长文本生成时更容易出现重复和退化。原因是量化误差在自回归生成中会累积。所以如果你要做长文本要么保留FP16要么用量化感知训练过的模型别直接拿训练后量化PTQ的版本硬上。3. 服务层把推理包装成能扛并发的API3.1 请求队列与背压没有它系统一定会雪崩推理服务最容易被忽视的就是队列和背压。你可能会想我起个FastAPI收到请求就调模型不就行了在低并发下确实能跑但一旦请求速率超过推理速率请求就会堆积内存暴涨最后整个服务挂掉。背压机制的本质是当系统处理不过来时主动拒绝或排队而不是无限接收。我的做法是在推理服务前加一层有界队列队列满了直接返回429。队列长度根据你的推理延迟和可接受等待时间来定。比如单次推理200ms你希望用户最多等2秒那队列长度就是10左右。这个数字不是拍脑袋是算出来的。另外队列要区分优先级短请求优先处理能显著降低平均延迟因为长请求会阻塞后面的短请求。3.2 批处理策略动态批处理比静态批处理好在哪里静态批处理是攒够N个请求一起推理动态批处理continuous batching是每个推理步都重新组批。后者对大模型服务几乎是必须的因为请求长度差异大静态批处理会让短请求等长请求浪费大量算力。我实测过一个场景混合了长度50和长度2000的请求静态批处理下短请求的平均延迟被拉高到接近长请求的水平而动态批处理下短请求能快速返回。如果你用的是支持连续批处理的框架一定要开启它这是吞吐和延迟双赢的少数优化之一。代价是框架复杂度高调试起来麻烦但值得。3.3 超时与重试重试不是越多越好推理请求超时后重试是常见做法但重试会放大负载。如果系统已经过载重试只会让它更过载形成雪崩。我的经验是重试必须配合退避和熔断。第一次失败等100ms重试第二次等300ms连续失败达到阈值就熔断一段时间直接拒绝新请求。另外要区分可重试和不可重试的错误。网络抖动导致的失败可以重试但模型返回格式错误这种重试也没用。我见过有人把所有异常都重试三次结果一个格式bug导致请求量翻三倍直接把服务打挂。4. 数据与上下文AI工程里最脏最累的活4.1 上下文窗口管理截断、摘要还是检索大模型的上下文窗口有限而真实业务里输入往往超长。处理方式有三种直接截断、滚动摘要、检索增强。截断最简单但会丢信息摘要会引入额外推理成本和信息损失检索增强RAG则依赖检索质量。我的实践是混合策略近期对话保留原文远期对话做摘要外部知识走检索。这样既控制了上下文长度又保留了关键信息。具体比例要看业务客服场景近期对话权重要高知识问答场景检索权重要高。这里没有万能公式只能根据badcase不断调。4.2 检索增强的坑召回不等于有用RAG看起来简单——把文档切块、向量化、检索、拼进prompt。但实际做起来坑一个接一个。最常见的是检索回来的内容相关但不解决问题。比如用户问“怎么退款”检索到的是“退款政策说明”但用户其实想要的是“退款操作步骤”。这是语义相似但意图不匹配。解决办法是在检索后加一层重排序rerank用交叉编码器对候选做精排。我实测重排序能把Top1准确率提升20%以上。另一个坑是切块策略切太大检索不精准切太小丢失上下文。我的经验是按语义边界切块大小控制在200到500字并保留一定的重叠。重叠是为了防止关键信息被切断。4.3 数据清洗垃圾进垃圾出如果你用业务数据做微调或构建检索库数据清洗是绕不过去的。我见过太多团队直接把数据库导出就往里灌结果模型学到一堆格式噪声。清洗至少要做这几件事去重、去HTML标签、统一编码、过滤过短和过长的样本、去除敏感信息。这里有个容易忽略的点去重不只是文本完全一致还要做语义去重。业务数据里大量“换个说法”的重复样本会让模型过拟合到某些表达。我一般用向量相似度做近邻去重阈值设在0.95左右效果比较稳。5. 可观测性没有监控的AI服务等于裸奔5.1 必须埋的三个指标延迟、吞吐、成本AI服务的监控和普通Web服务不同除了QPS和错误率你必须盯住三个指标推理延迟P50/P95/P99、吞吐tokens/秒、单次请求成本。延迟决定用户体验吞吐决定你能扛多少量成本决定你能不能赚钱。我特别强调P99延迟因为AI服务的延迟分布往往长尾很重。平均延迟200ms看着不错但P99可能到3秒那1%的用户体验极差。长尾通常来自长请求和批处理排队需要单独分析。成本指标要拆到每次请求包括GPU时长、显存占用折算、如果用了外部API还要算token费用。我见过团队上线后才发现某些请求成本是预期的十倍原因是没限制最大输出长度模型一直生成到上限。5.2 日志与追踪出问题时能定位到具体请求AI服务的日志要比普通服务更详细。除了请求ID、时间戳还要记录输入长度、输出长度、使用的模型版本、检索命中的文档ID、推理耗时分解。这样出问题时你能快速定位是检索问题、模型问题还是服务问题。追踪方面我建议给每个请求打上完整的链路ID从入口到检索到推理到后处理全链路可查。有一次线上出现输出乱码靠链路追踪发现是某个检索文档编码有问题十分钟就定位了。没有追踪的话这种问题能查一整天。5.3 告警阈值怎么定别拍脑袋告警阈值定太松没意义定太紧天天误报。我的方法是基于历史数据的分位数。比如P95延迟过去一周稳定在500ms那告警线设在800ms超过就说明有异常。成本告警按小时聚合超过历史均值的1.5倍就触发。另外要区分告警级别。延迟升高是警告错误率飙升是严重成本异常是提醒。不同级别走不同通知渠道避免告警疲劳。我吃过亏一开始所有告警都发到同一个群结果大家都不看了真出问题时反而没人响应。6. 成本控制AI工程里最现实的一课6.1 推理成本的三块构成与优化顺序推理成本大致分三块GPU算力、显存占用、网络传输如果跨节点。优化顺序应该是先降显存再降算力因为显存往往是你能否用更便宜卡的关键。量化、KV Cache优化、批处理都能降显存。算力优化主要靠批处理和算子优化。批处理提升吞吐直接摊薄单请求算力成本。我实测把批大小从1提到8单token成本能降60%以上。但批大小不是越大越好太大延迟会上升要找到吞吐和延迟的平衡点。6.2 缓存最容易被低估的省钱手段很多AI请求是重复或高度相似的。比如FAQ类问题用户问法不同但意图相同。做一层语义缓存命中直接返回能省下大量推理成本。缓存键用输入的向量表示相似度超过阈值就命中。我做过一个统计客服场景下语义缓存命中率能到30%以上直接省掉三成推理量。缓存要注意失效策略模型更新或知识库更新后要清理缓存否则会返回过时答案。6.3 按需扩缩容别让GPU空转GPU很贵空转就是烧钱。如果你的流量有明显波峰波谷一定要做按需扩缩容。缩容的难点在于判断什么时候可以缩我的做法是看队列长度和GPU利用率的组合。队列为空且利用率低于30%持续5分钟就缩一个实例。扩容则看队列增长趋势提前扩别等打满再扩。这里有个坑冷启动。新实例加载模型要时间如果扩容太慢流量高峰时来不及。所以要么预热实例池要么用更快的模型加载方式。我一般保留一个最小实例数保证基本盘高峰再扩。7. 我踩过的几个典型坑与排查思路7.1 显存泄漏重启能解决但要知道为什么有段时间服务跑几个小时就OOM重启就好。这种显存泄漏最难查因为不是必现。我的排查思路是先看是不是KV Cache没释放再查是不是有请求异常导致中间张量没回收最后看框架本身有没有bug。后来定位到是异常请求触发了某个分支中间变量没释放。解决办法是在推理入口加try-finally确保资源释放并对异常请求做长度限制。经验任何可能抛异常的地方都要保证资源释放AI服务里显存就是命。7.2 输出不稳定温度参数和随机种子用户反馈同样的问题有时答得好有时答得差。排查发现是温度参数设太高导致输出随机性大。生成类任务温度一般设0.7左右抽取类任务设0到0.3。另外如果要做可复现的测试固定随机种子。但要注意固定种子不等于完全可复现因为批处理顺序、GPU非确定性算子都会影响结果。所以测试时不要追求逐字一致而是看语义是否稳定。7.3 检索召回率突然下降索引和模型版本要对齐有次检索效果突然变差查了半天发现是向量模型更新了版本但索引还是用旧模型建的导致向量空间不一致。教训向量模型和索引必须版本绑定更新模型必须重建索引。这个坑很隐蔽因为检索还能返回结果只是质量下降不报错。8. 从零到一之后持续迭代的几个方向把基础链路跑通只是开始。后续迭代我建议按这个优先级先做质量评估体系没有评估就没法优化再做A/B测试能力能对比不同策略然后做自动化回归防止改一处坏一处最后做成本优化把每一分钱花在刀刃上。质量评估这块人工评估贵且慢自动评估又不准。我的折中是用强模型做裁判配合人工抽检。裁判模型对输出打分人工定期校准裁判的准确性。这样能兼顾效率和可信度。A/B测试要注意流量分配和指标定义。AI服务的指标不只是点击率还要看回答质量、用户满意度、成本。我一般同时看三到五个指标避免优化一个指标把另一个搞崩。这套东西我从零搭过不止一遍每次都有新坑。但每踩一次坑对系统的理解就深一层。调包能让你快速看到效果但从零构建才能让你在出问题时知道往哪查、怎么修。如果你也在做类似的事欢迎交流你踩过的坑。