
1. 项目概述什么是“AI工程从零开始”先直接说结论ai-engineering-from-scratch 这个项目翻译成大白话就是“不靠现成API、不靠别人封装好的框架从底层原理到生产落地把AI工程这条链路完整走一遍”。它面向的不是调包侠而是想真正理解AI系统为什么能跑、怎么跑得稳、线上出问题了怎么排查的人。我最初看到这个标题时第一反应是这又是一个挂羊头卖狗肉的教程合集。但真正把内容筛了一遍之后发现它和其他“XX天学会AI”最大的区别在于它强调从零构建。举个例子现在很多人用LangChain写RAG应用两小时就能跑通一个demo。但问一句“向量检索的召回率为什么下降了”十个人里有八个答不上来——因为大家都只看到了框架层的API没看到检索链路内部的相似度计算、索引结构、重排策略这些底层机制。这个项目想解决的恰恰是这类“知其然而不知其所以然”的问题。那么它适合谁坦白讲不适合纯小白也不适合只想快速出活的人。它适合这几类人群有Python基础写过一些深度学习代码但总觉得自己是“调参侠”“搬运工”想往AI工程方向深入的人。已经用现成框架如LangChain、LlamaIndex做过AI应用但遇到性能瓶颈、线上问题无从下手想补齐底层原理的人。刚转行做AI应用开发想系统梳理“数据→模型→检索→推理→部署→监控”完整链路的人。这个项目最大的价值不是给你一堆代码让你跑而是帮你建立一套AI工程化的心智模型。后面我会拆开讲这套心智模型具体包含哪些环节、每个环节有哪些核心决策点、哪些地方最容易踩坑以及我实操下来觉得最值得借鉴的几条经验。2. 整体思路拆解为什么“从零”比“从框架”更重要2.1 工程化AI的完整链路是什么在拆解这个项目之前先定义清楚“AI工程”这四个字到底覆盖了什么。很多人以为AI工程就是训练模型、调参、部署API其实这只是最后一步。真正完整的AI工程链路比大多数人想象的要长得多。我按照实际项目推进的顺序把整条链路分成六个环节需求定义与可行性评估搞清楚要解决什么问题是否真的需要AI现有数据够不够用传统规则方法能不能解决。这一步最容易被跳过但恰恰是最省钱的一步。数据工程包括数据采集、清洗、标注、增强、版本管理。在真实项目中这一环占用整个项目周期60%以上的时间却很少被初学者重视。模型开发与训练从baseline到调优涉及模型选型、超参数搜索、评估指标设计、过拟合防控。推理链路设计数据预处理、prompt组装、模型推理、后处理解析、缓存策略。部署与交付模型服务化、接口设计、资源估算、容器化部署、灰度发布。监控与迭代线上效果监控、数据漂移检测、A/B实验、持续再训练。这个项目最聪明的地方在于它把上面六个环节全部拆开每个环节都从最基础的原理讲起然后手把手带你在没有现成框架依赖的前提下用最朴素的工具把这套链路搭起来。走完一遍之后你会对每个环节的输入、输出、瓶颈、优化方向有切肤感受。2.2 为什么我推荐“从零手写”的学习方式主流的学习路径是装好依赖库→跑通demo→改参数→上线。我的态度很明确这条路不坏但天花板低。纯靠框架拼出来的AI应用遇到三类问题会直接卡壳——一是效果达不到预期时不知道往哪个环节调二是线上性能和成本失衡时不知道怎么定位瓶颈三是换了业务场景后原来的代码不知道怎么改才能复用。“从零手写”恰好在三个维度补掉了这个短板。维度一链路感知。自己写过向量索引、写过prompt解析器、写过缓存组件之后你对每个环节的“物理成本和逻辑代价”会有直觉。比如你会明白为什么向量检索里面用HNSW索引比暴力搜索快几十倍代价是召回率稍微下降——因为你亲手实现过这两种检索方式知道它们各自的遍历逻辑。维度二排查能力。线上出问题时90%的情况不是模型突然变笨而是数据、配置、环境、接口出了问题。如果你对链路里的每个环节都门儿清排查速度会快一个数量级。维度三框架的“祛魅”。市面上的AI框架层出不穷今天LangChain明天LlamaIndex后天又出个新工具。如果你只依赖框架的抽象每次换框架都等于重新学。但如果你理解底层原理会发现所有框架都是在解决同样几个问题——提示词管理、上下文组装、调用编排、结果解析。底层逻辑通了框架只是外套。从认知科学的角度讲这叫“生成效应”。自己去构建一遍某个系统比单纯阅读它、使用它记忆留存率高出一大截。2.3 方案选型技术栈的核心考量这个项目在技术选型上有一句话我印象深刻“不为新技术而新技术一切以工程效率优先”。具体到落地它的技术栈大致是这样一套链路环节所选技术选型理由语言基础Python 3.10AI生态最成熟工程效率最高向量检索自建索引 FAISS先理解原理再用工业级库提升性能模型推理PyTorch / HuggingFace生态完善调试方便服务框架FastAPI轻量、异步支持好、自带API文档部署Docker 单机脚本先用简单方案跑通再考虑K8s监控结构化日志 自定义指标够用即可避免被监控平台本身拖慢进度这个选型背后有个很重要的思路不要一上来就上大而全的架构。很多初学者一听到“AI工程”就以为必须上Kubernetes、上分布式、上GPU集群——大错特错。中小规模的AI应用一台带GPU的服务器或者云主机完全够用真正的瓶颈压根不在架构规模而在数据质量、提示词设计和推理链路的稳定性。先把单机的链路跑得干干净净再考虑分布式扩展这是工程上的常识。站在企业的角度多花一分钱在过度设计上都是无谓的成本。3. 核心细节解析从零搭建AI工程链路的关键环节3.1 数据工程容易被忽视的“隐形地基”说句行业里的大实话很多搞AI的人嘴上说的是“算法工程师”实际干的活是“数据搬砖工”。数据清洗、去重、格式转换、质量抽检这些听着没技术含量实际决定了你后面所有环节的成败。Garbage in, garbage out这句话在AI工程里是唯一铁律。3.1.1 数据的三个核心原则我在实操中总结了数据处理的三个原则适用所有AI项目。第一单一数据源。所有原始数据只保留一份任何清洗、增强操作都基于这份原始数据派生不允许原地修改。这样做的好处是当你发现某一步清洗规则有问题时可以从原始数据重新跑一遍而不是在已经被污染的数据上继续叠加错误。第二数据版本化。每跑一次清洗流程都要记录当时的清洗规则、输入数据量、输出数据量、异常样本数量。听起来很麻烦但线上模型效果突变时你第一件事要查的就是训练数据是不是被动过。第三抽检闭环。清洗后的数据必须人工抽检不低于5%。我在实践中发现很多清洗脚本对常见的边界情况处理不完美比如全角半角混用、非法字符、JSON截断。不抽检你根本发现不了这些隐患。3.1.2 标注工作的工程化管理做AI工程绕不开数据标注这个环节。哪怕用的是大模型做自动标注也需要设计Prompt、抽检标注结果、处理争议样本。标注这一环的操作要点有三个设计标准化的标注规范文档每个字段写明定义、边界、反例。模糊的定义是标注质量最大的杀手。利用简单的投票机制或规则校验自动剔除明显异常样本。比如所有标注结果完全一致的往往说明标注任务太简单或存在作弊。标注数据按批次管理每批次记录标注人员、时间、版本出了问题能精准定位。说实话很少有人对数据标注环节感兴趣但真正做过生产级AI项目的都知道数据质量直接决定模型效果天花板。这个项目里花了大量篇幅在讲数据工程我很认同。3.2 模型开发与训练Baseline先行优化在后3.2.1 搭建Baseline的正确姿势模型训练这一环新手最容易犯的错误是一上来就挑战大模型、搞复杂的多阶段训练。我的建议是始终先跑通一个最简单的Baseline哪怕效果很差之后再逐步加复杂度。为什么因为Baseline的价值不在于效果好而在于它验证了整个数据处理链路和评估链路是否正确。如果你的Baseline能顺利跑完训练、推理、评估全套流程说明链路通畅了。之后每次优化都是在前一步基础上做增量修改出问题时能快速定位。实操中我的Baseline流程是固定这么几步用全部数据的一小部分比如5%快速跑一轮训练确认没有报错。跑一次全量训练记录训练日志和评估指标。将模型推理结果导出人工抽检100条。把抽检结果整理成错误分析报告明确下一步优化的优先级。这几步走完你对数据的分布、模型的强项弱项就有了第一手感知。3.2.2 超参数调优不是玄学是系统工程超参数调优经常被拿来当玄学讲什么“炼丹术”“调参侠”都是因为缺少一套系统的调优方法。我的建议是分三个层次粗调先固定一批合理值学习率1e-3、batch size取最大能跑的跑几个epoch看loss趋势是否收敛。如果loss完全不动先查数据问题和梯度问题不要盲目调参。细调确认loss正常下降后重点调学习率和batch size。学习率太大容易震荡、太小收敛太慢一般用余弦退火或warmup策略解决起步不稳的问题。精调做小范围网格搜索或贝叶斯优化同时关注正则化系数、dropout率这些防止过拟合的参数。我见过太多人花一个星期的GPU时间跑完几十组实验最后选了一个验证集指标最好的模型上线之后效果一塌糊涂。什么原因过拟合了。所以评估时不要只看单一指标至少要看验证集和训练集的指标差。差得太多说明过拟合严重模型泛化能力存疑。3.3 推理链路从Prompt到结构化输出的完整闭环这一节是这个项目里我觉得最有实操价值的部分。很多人以为写了Prompt、调了接口、拿到返回结果就算完成了推理链路但实际生产环境中这一环的工程复杂度远高于想象。3.3.1 Prompt模板管理的工程化方案在生产项目中Prompt不是一次性写死的它要持续迭代。所以工程上必须把Prompt当作代码一样管理。我推荐的做法是每个Prompt模板独立成文件遵循命名规范。比如extract_entities_v3.j2这种。模板中的变量用{{变量名}}占位不在字符串里直接拼接。这样既避免格式错误也方便统一管理。Prompt版本和代码版本一一对应。每次改Promptgit commit信息里必须写明修改原因和预期影响。线上Prompt修改要走灰度流程不能直接全量切换否则效果回退了都不知道是哪次改动引起的。另外要特别提醒一个坑上下文长度的控制。大模型的上下文窗口是有限的动态拼入的资料越多推理延迟越高费用也越高。我实测过当输入token数翻倍时推理时间大约增加60%-80%。所以Prompt模板设计时需要主动做长度控制比如对检索回来的文档做截断、压缩、重排只保留最高质量的内容喂给模型。3.3.2 结构化输出的解析与兜底大模型输出天然是自由文本但在工程链路里系统可能需要的是JSON、Markdown表格、评分结果等结构化数据。这个环节的工程处理是关键。实际操作时我一般做三层兜底在Prompt中强制要求输出格式比如“只输出JSON不要输出任何其他内容”。拿到模型输出后先做格式校验用正则或JSON解析器判断是否合规。不合规时按策略降级——先尝试截取JSON片段再解析还不行就重试一次重试仍失败则返回兜底结果比如“提取失败”并打日志记录。有人觉得这是小事但真到了线上模型输出轻微偏离格式就会直接导致链路崩溃。没有兜底策略的推理链路等于裸奔。3.3.3 缓存策略少烧钱、降延迟的利器推理链路建立之后一个经常被忽略但效果显著的工程优化是缓存的引入。实际业务场景里用户的问题高度重复。比如客服场景中“怎么退款”“物流到哪了”这类问题高峰期占比超过40%。如果每次用户提问都调用一次大模型既费钱又慢。引入缓存之后命中率能做到30%-50%资源和成本都是实打实的节省。缓存的粒度我建议做两层语义缓存用户的问题先经过向量化和最近的缓存问题做相似度比较。相似度超过阈值比如0.85时直接返回缓存结果不再调用大模型。精确缓存用规范化后的问题文本作为key完全相同的问题直接命中。实现上不需要引入什么复杂的中间件早期用Redis就够了。命中率和成本节省比能给你最直观的工程收益反馈。3.4 部署与交付“能跑”不等于“可用”3.4.1 模型服务的异步与并发设计刚跑通模型推理时直接用同步接口返回结果这在Demo阶段没问题但一旦QPS上来同步接口的阻塞问题会迅速暴露。在大模型场景下一次推理动辄3-10秒如果接口是同步阻塞的那么每请求都占用一个Worker线程长达数秒并发能力被压缩到极低。工程上必须引入异步机制接口层用异步框架接收请求立即返回task_id后端把推理任务丢到消息队列或进程内任务队列推理完成后通过Webhook、轮询或SSE通知客户端。这是我非常建议所有AI工程师认真落地的一环它改变的不是代码风格而是对服务吞吐量和用户体验的整体设计思路。很多初学者部署完模型发现API一上量就超时多半是同步阻塞的锅。3.4.2 资源估算与成本控制模型部署时最容易被忽略的是显存和延迟的关系。我见过有人把7B模型部署在T4显卡上单次推理延迟到十几秒以为是自己代码写得有问题其实是显存带宽不够用。粗略的估算公式是这样的模型显存占用大约等于参数量乘以精度字节数。7B参数、FP16约14GB显存再算上KV Cache和运行时开销至少需要24GB左右。单卡吞吐量上限取决于显存带宽。T4的带宽只有约320GB/sA100是约2TB/s同样一个7B模型生成一个token所需的显存读取量大约是参数量乘以2字节所以每生成一个token的时间计算下来A100比T4快6倍左右。不要觉得估算公式麻烦真正做一次部署预算你就会发现这个公式能帮你避免大量试错成本。部署阶段的建议是先用容器封装模型服务保证环境一致性通过请求排队、超时控制、并发限制保护后端服务提供/health健康检查接口方便后续接入负载均衡模型版本用标签区分灰度切换时能快速回滚。3.4.3 推理加速的优先级顺序关于推理加速网上教程很多但我会建议按以下优先级排缓存层优化最便宜收益最大输入压缩减少token数如主动截断、摘要提取KV Cache复用的调优如果是自建推理服务量化FP16→INT8看业务是否能接受精度损失升级硬件最贵最后考虑如果你把顺序搞反了一上来就买A100结果发现瓶颈在数据读取和接口设计上那这笔钱就白花了。4. 实操过程与核心环节实现4.1 第一轮从零搭建一个最小可用的问答系统这个项目最核心的实践项目是带你把一个基于知识库的问答系统从零搭起来。整个过程分四个阶段我这里按实际操作顺序完整复盘一遍。阶段一数据准备与处理。用公开的中文问答数据集作为输入完成清洗、格式转换、按段落切分、生成向量表示四步。注意切分时不要按固定长度硬切要按语义完整性来切比如按段落和句子边界。我当时硬切的效果检索召回率直接掉了七八个百分点这个教训很深刻。阶段二构建检索模块。先用纯Python实现一个暴力向量检索遍历所有向量算余弦相似度跑通之后替换为FAISS的IndexFlatIP。再把结果合并实现简单的重排逻辑——比如对召回的文档按关键词命中数量和位置做二次排序把最相关的排到最前面。阶段三组装提示词与模型推理。设计Prompt模板将用户问题和检索结果嵌入调用大模型API生成答案。关键点是把Prompt模板写成独立的配置文件方便之后迭代。阶段四封装成服务。用FastAPI把链路封装成POST /chat接口输入用户问题输出答案、检索到的文档、处理耗时三样内容。同时加上请求日志和耗时统计。这套最小系统跑通之后整个链路的开发周期一个有Python基础的工程师应该控制在两周以内。完成之后你会对每一个环节的“手感”有极为直观的认知。4.2 完整配置指南从零构建一个RAG服务的步骤为了让你能直接参考落地我把这套RAG服务的关键配置步骤整理成清单。第一步初始化项目结构。建议目录划分如下project_root/ ├── data/ # 原始数据存放 ├── scripts/ # 数据处理脚本 ├── src/ │ ├── preprocess.py # 数据清洗与切分 │ ├── embed.py # 向量化与索引构建 │ ├── retrieve.py # 检索逻辑 │ ├── prompt.py # Prompt模板管理 │ ├── llm.py # 大模型调用封装 │ └── app.py # FastAPI服务入口 ├── config/ │ ├── settings.py # 全局配置 │ └── prompts/ # Prompt模板文件 ├── logs/ # 日志目录 └── requirements.txt这个结构不复杂但很清晰你后续去加功能、替换组件、排查问题都能快速定位到相应文件。很多人项目写着写着就变成一个大文件后面基本没法改这是最典型的工程债。第二步数据处理脚本的核心逻辑。清洗规则包括去重、去HTML标签、统一大小写、规范标点。切分规则是优先按\n\n切分如果一个段落超过300字再按句号或问号切成不超过300字的切片。这个长度上限是根据embedding模型的最大输入token数反推的建议在实际项目中用Tokenizer先做字符到token的换算再定。第三步检索服务的设计。离线阶段用embedding模型将文档切片转化为向量存入FAISS索引。在线阶段用户查询被向量化后在索引中检索Top-KK值通常取5-10。K太大噪声增多K太小关联信息可能漏掉。我实测下来在大多数问答场景下K8是一个合理起点之后可按业务调整。第四步Prompt模板设计。这个模板的核心是三点一是明确系统的角色定位二是限定输出格式三是给出“如果检索内容不相关直接说明不知道”的兜底指令。这一条兜底指令极其重要它能显著降低模型胡编乱造的概率。第五步上线配置。FastAPI使用GunicornUvicorn Worker的方式启动配置并发数在4-8之间。日志用JSON格式结构化输出每条日志带上请求ID方便链路追踪。显存监控用NVIDIA官方工具或自写脚本定时采集写入日志。4.3 QA系统核心参数计算与效果调优把系统跑通之后必然要进入调优阶段。以下几个参数是我在实际项目里反复验证过对效果影响最大的参数名推荐值范围影响方向调优心得文档切片长度200-500字切太短则语义碎片化切太长则检索精度下降按内容类型灵活调整技术文档可以偏长FAQ可以偏短检索Top-K5-10K太大会引入噪声太小会遗漏关键信息从K8开始看错误分析报告再微调重排策略关键词命中向量融合只靠向量检索会漏掉精确匹配可以从简单的线性加权开始温度参数0.1-0.3温度太高会胡编乱造太低则缺乏多样性问答场景一律用低温创意写作才需要高温最大输出token数200-800太长会增加延迟和费用先压短不够再加不要一上来就给很大的额度这套参数不是拍脑袋定的。比如文档切片长度我最早用固定500字切分结果很多语义完整的长段落被拦腰切断检索回来的内容信息大量缺失改成按语义边界切分后End-to-End指标稳定提升了15%。这些细节光看框架文档是学不到的。5. 常见问题与排查技巧实录5.1 检索效果差的排查清单做RAG类项目线上最常收到的问题是“AI回答得不准”。很多人的第一反应是“换个更好的大模型”但我的经验是检索环节出问题的概率远高于模型本身。一个典型的排查顺序是这样的先看检索回来的文档本身质量如何。如果检索回来的片段和问题关联度不高那问题出在“召回”跟生成模型无关。检查文档切分是否合理。是不是把原本连贯的上下文切碎了切碎之后语义信息被严重压缩。检查向量化的一致性。训练时用的分词器和检索时用的分词器是否一致有无大小写归一化差异检查重排逻辑。Top-K召回后是不是被错误排序导致高相关的片段被排到了后面最后才检查Prompt设计。看模型是否正确利用了检索到的信息来组织答案。我遇到过的最极端的案例是检索效果差是因为embedding模型在离线处理文档时走了GPU但没有锁随机种子导致同一条文档每次向量化结果都略有不同在索引里形成了不一致的表示。这种细节不逐环排查很难定位。5.2 服务不稳定的三大根因AI服务上线后表现不稳定我相信这是所有AI工程师都会遇到的课题。梳理下来我见过的“服务不稳”绝大多数源于以下三种情况第一并发场景下的优雅降级缺失。模型推理服务在高并发下会排队积压如果接口没有超时控制和重试上限就会产生雪崩效应。一套合格的方案必须包含超时后快速失败、队列长度限制、降级兜底比如返回提示语而不是一直转圈。第二模型输出解析失败。大模型返回的结果偶尔不符合预期格式如果解析逻辑没有兜底一个字段解析失败就可能让整个请求500。可以设置多级兜底策略解析失败时至少返回一个可读的提示。第三底层依赖更新引发的兼容性问题。框架库升级后API变了、行为变了模型服务可能悄悄出错。我的习惯是应用代码和依赖库版本全部锁死升级必须走单独的验证流程绝不允许线上环境直接升级。5.3 成本失控是怎么发生的最后聊一个容易被忽视但老板一定关心的问题AI应用的成本。起点是调用模型API的费用但成本失控往往发生在细节上。Prompt里塞了太多不必要的样例和冗余指令导致每一轮对话的token数量虚高没有缓存机制相同的问题反复调用模型产生费用历史对话无限累积上下文越来越长费用成倍增长。我见过一个月成本超预算将近三倍的项目排查下来就是这三个问题叠加。解决方式也很直接对Prompt做“瘦身运动”删掉一切可有可无的内容在服务层强制加入语义缓存历史对话按窗口大小裁剪超出的部分改用外部记忆存储不喂给大模型。把这三点落实通常能省下30%-50%的调用费用。这数字很可观而且纯靠工程手段就能实现不需要牺牲任何体验。5.4 一个完整的线上debug实录分享一次真实的排障经历。某个QA服务的准确率在某天突然下降了10个百分点表现是用户问一些简单的常见问题AI却答非所问。我的排查顺序是这样的先看线上日志指标发现P95延迟没有明显波动说明不是服务性能问题。抽检一批失败样本发现失败集中在某些特定产品线的问题上。检查索引文档的版本号发现问题那天有一次文档更新任务但好像没跑完。核查任务日志发现新文档只写入了一部分切片的向量索引旧数据又没被清理导致检索池里新旧文档混在一起。根因找到了当时做了增量更新但清理策略不完善。解决的方案是给每次文档更新加上完整的状态控制先写入新索引、再原子切换生效、最后清理旧索引。经此一役这个项目里“索引管理”被提升到了与模型调优同等的优先级。这类问题如果你没有亲手从头搭建过整套链路几乎不可能快速定位。这也再次印证了“从零做起”的工程价值。回过头来说ai-engineering-from-scratch 给我最大的启发是AI工程不是某一个单点技术而是一整套围绕数据、模型、推理链路的系统工程。你可以在任何一环引入框架来提效但前提是你理解那一环的原理、知道它可能出什么问题、以及出了问题怎么降级。我个人体会最深的就是这套“链路心智”比任何框架和工具都值钱它让你在任何新的AI技术面前都能快速拆解它的本质而不是被花哨的概念带着走。