
如果你搜过 ai-engineering-from-scratch大概率会看到两类结果一类让你从线性代数啃起另一类直接把几百页的论文甩过来。我当年就被这样劝退过——矩阵求导啃了两周连一个能跑的模型都没见到。后来亲手带过项目、也把自己手头的系统从零推到上线再回头看这件事我得先纠正一个看法从零开始做AI工程重点从来不在从零而在工程。这篇文章想讲清楚两件事。第一一个完全零基础的人应该沿着什么顺序建立AI工程能力才能在三个月内做出能给别人用的东西。第二真正拉开车距的工作量落在哪里——不是调某个模型而是数据、检索、评测、系统设计这些看起来不酷的环节。如果你正好想入行或者已经在写接口但觉得自己只会调API这篇文章应该能帮你少走几个月的弯路。1. 先校准坐标从零不是从重造轮子开始1.1 三种起点对应三种完全不同的路线我习惯把从零开始拆成三种情况你属于哪种直接决定了你该读什么、练什么。第一种从应用开始。不会写训练代码但会用现成模型的能力做产品写提示词、搭检索、编排工具调用、处理前后置逻辑。这类工作是我见过的大多数AI工程师的日常本质上是应用层工程。第二种从模型开始。需要理解Transformer的内部机制能训练小模型、会微调开源模型知道损失函数怎么掉、数据怎么配比。这个层面解决的是模型能力边界问题。第三种从基础设施开始。做分布式训练、推理加速、模型部署的高并发服务这是平台层的工作对系统能力的要求远大于对模型原理的要求。多数人说想学AI工程其实要的是第一种加一点第二种。我的建议顺序是先用第二种的方式获得底层直觉再用第一种的方式创造实际价值最后按需补充第三种。这里有个反直觉的点真正工作里最值钱的不是我微调过一个模型而是我能把一个AI系统从需求变成稳定运行的服务。模型可以从开源社区拿来但数据整理、评测体系、故障排查这些能力没有任何一个现成模型能替你做。1.2 为什么说工程才是主线一个常见误区是把大模型当成项目的唯一变量。我在实际项目里观察下来的工作量和收益占比大致是这样的数据清洗与构造占三成检索与编排占三成评测与回归占两成真正调模型结构的部分占比很小。打个比方模型是发动机但你要交付的是一辆车。发动机的品牌可以换来换去底盘、刹车、仪表盘才是工程。引擎盖底下的事再精彩用户感受到的是整辆车的表现。所以从零这个词也别理解成从重造轮子开始。你不需要自己炼一个GPT你需要的是拥有能判断哪个轮子合适、怎么把轮子装上去、装完怎么验收的能力。1.3 同一个从零别把力气花错地方如果你的目标是学会做AI系统最不划算的做法是先把Transformer完整复现一遍再去碰业务。更划算的做法是复现一个玩具级的模型建立直觉然后把时间重点投入数据、检索、评测、可控性这些可以迁移的工程能力上。我见过有人花三个月从零写分布式训练框架结果面试产品岗位时连RAG的召回流程都说不清楚。方向比努力重要这里的方向就是——先搞清楚你到底要成为哪种工程师。2. 第一个周末亲手训练一个玩具Transformer非常值得2.1 为什么要亲手造一次模型我不是建议你去复现大模型这件事既烧钱又没必要。我建议的是用一个小到能在一个晚上跑完的模型把生成这件事的底层机制亲手摸一遍。理由有三个。第一很多API文档里的参数只有亲手写过训练和生成代码才能真正理解。temperature为什么影响随机性top-p和top-k到底在截什么这些概念在文档里看一百遍不如自己改一行参数对比输出来得实在。第二你能直观感受到上下文窗口的本质。它不是一个文件大小上限而是模型注意力能覆盖的token数量超过之后效果会迅速劣化。这个体感直接决定你以后设计RAG时会不会犯什么都往prompt里塞的错误。第三排查问题时你能区分是模型能力不行还是是工程哪里没接对。这个判断力靠调用API是练不出来的。2.2 最小复现路径与关键参数我直接给出一条我自己带新人时用的路径。数据用公开语料比如莎士比亚全集这种MB级别的纯文本就够了重点是快不是大。词表先用字符级词汇量只有几十个省去BPE的复杂度跑通之后再花半天了解BPE原理。模型6层Decoder-only Transformerd_model3848个头上下文256总参数量在千万级别。目标自回归语言建模也就是预测下一个字符。训练AdamW学习率3e-4batch 64CPU上跑一个晚上能出结果有入门级显卡的话十分钟到一小时。生成输入前缀取最后一个位置的logits除以temperature后采样。这个规模完全可以照抄再改。关键不是参数多漂亮而是你亲手写完forward和训练循环跑通第一个loss下降的曲线。2.3 核心代码骨架我用PyTorch直接写一个最小的Decoder-only结构代码刻意保持了教学性import torch import torch.nn as nn class Block(nn.Module): def __init__(self, d_model, n_head): super().__init__() self.attn nn.MultiheadAttention(d_model, n_head, batch_firstTrue) self.ff nn.Sequential( nn.Linear(d_model, d_model * 4), nn.GELU(), nn.Linear(d_model * 4, d_model), ) self.ln1 nn.LayerNorm(d_model) self.ln2 nn.LayerNorm(d_model) def forward(self, x, maskNone): # 先做LayerNorm再进注意力这是GPT-2之后的标准顺序 x x self.attn(self.ln1(x), self.ln1(x), self.ln1(x), attn_maskmask)[0] x x self.ff(self.ln2(x)) return x class TinyGPT(nn.Module): def __init__(self, vocab_size, d_model384, n_head8, n_layer6, ctx_len256): super().__init__() self.ctx_len ctx_len self.tok_emb nn.Embedding(vocab_size, d_model) self.pos_emb nn.Embedding(ctx_len, d_model) self.blocks nn.ModuleList([Block(d_model, n_head) for _ in range(n_layer)]) self.ln nn.LayerNorm(d_model) self.head nn.Linear(d_model, vocab_size) def forward(self, idx): L idx.shape[1] x self.tok_emb(idx) self.pos_emb(torch.arange(L, deviceidx.device)) # 因果掩码当前位置只能看到前面的token mask torch.triu(torch.ones(L, L, dtypetorch.bool, deviceidx.device), diagonal1) for block in self.blocks: x block(x, mask) return self.head(self.ln(x))训练循环就是一个标准的交叉熵循环前向、计算每个位置预测与真实下一个token的交叉熵、反向传播、更新参数。字符级词表下语料里所有字符都是类别loss下降得非常直观。生成部分的代码更短但包含了一个重要细节——采样def generate(model, idx, max_new_tokens500, temperature0.8): model.eval() with torch.no_grad(): for _ in range(max_new_tokens): idx_cond idx[:, -model.ctx_len:] logits model(idx_cond)[:, -1, :] / temperature probs torch.softmax(logits, dim-1) idx torch.cat([idx, torch.multinomial(probs, 1)], dim-1) return idxtemperature大于1会让分布变平、输出更随机接近0会让最高概率的token几乎被选中、输出趋于确定。这个趋于的过程自己跑一次比读十篇文章都管用。2.4 这个玩具真正教会我的四件事第一自回归生成是一步错步步错的过程。生成的token会成为下一个token的输入所以工程上要尽量让每一步都可控这正是后续做RAG、做Agent时处处设防的原因。第二token是模型的基本单位不是字。同一个词的拆法不同模型的理解就不同。很多为什么两个模型能力差这么多的问题根源在分词器。第三loss曲线的下降过程就是模型学会语料里统计规律的过程。看到loss降下去、生成文本开始有语法结构的那一刻你对训练这个词的理解会完全不同。第四你会明白为什么大模型会有幻觉——它本质是在做概率预测不是查数据库也不是回忆。这件事想明白了你设计系统时就不会期待模型记住一切而是主动给它外挂记忆。3. 从玩具到系统RAG、Agent与评测才是主战场3.1 RAG大多数业务第一个该上手的工程如果你有私有数据或者需要回答实时信息靠把全部资料塞进prompt是走不通的。RAG检索增强生成就是为这个场景设计的标准方案先从外部知识库里检索出相关内容再把这些内容作为上下文交给模型生成答案。完整链路是这样的文档加载 - 分块 - 向量化 - 存入向量库 - 查询时检索 - 重排 - 组装prompt - 模型生成 - 带引用返回。这里给一份我常用的初始参数表新手可以直接照这个起步环节常见初始值调节方向分块大小300-500个字符问答场景偏小总结场景偏大分块重叠50-100个字符防止语义被截断检索数量top 3-5先保证召回再考虑精准相似度阈值0.5-0.7太低会混入噪声重排策略查询重写 精排两步效果提升明显值得加步骤上我建议按顺序来先用正则或解析器按文档结构标题、段落、表格切分再组装出一个小而完整的测试集每次改动都跑同一组问题对比答案质量。3.2 检索质量才是RAG的天花板生成模型是固定的检索决定模型能看到什么。这句话我反复讲因为太多人把调优精力全花在prompt上忽略了上游的检索。一个实用组合是混合检索BM25做关键词召回向量模型做语义召回然后再用一个精排模型对合并结果打分取top 3。纯向量检索在专有名词、编号、代码片段上经常翻车加上BM25能补上这一块。还有一个常被忽略的点embedding模型要和你的领域匹配。通用向量模型在通用语料上表现好但在法律、医疗、代码这类专业文本上可能排序完全不对。我的经验是花一两天用你手上真实数据里的50个问题对比两三个候选embedding模型的召回情况这个投入回报极高。3.3 Agent把模型从问答机变成执行者如果说RAG是让模型学会查资料Agent就是让模型学会干活。核心机制是函数调用你给模型定义一组工具模型根据用户意图输出一个结构化的调用请求系统执行完把结果返回给模型模型再决定下一步动作。这就是经典的ReAct循环推理、行动、观察。做Agent最容易忽略的是边界。我的做法是三层防线工具白名单只开放必要的操作危险动作加确认环节循环上限和超时机制兜底。你永远不该假设模型会老老实实只调用该调用的东西。另外要把中间过程记录下来。Agent的每个推理步骤、每次工具调用、每个返回值都应该有日志否则出了问题你连复现都做不到。3.4 评测没有评测优化全是玄学很多人把系统搭起来就跑效果好不好全靠感觉。这是AI工程新手和成熟工程师之间最大的分水岭。我建议从第一天起就维护一个golden set也就是50到100条带标准答案的测试问答。每次改动——不管是换模型、调分块还是改prompt——都跑一遍对比指标变化。离线指标和在线体验要分开看前者用于快速迭代后者用抽样日志和用户反馈验证。评测指标可以分成三层来看检索层看重召回率和命中位置生成层看答案是否忠实于引用内容整体层看答案正确性和完整性。用语言模型当评判者可以有效率但注意评判模型自己也有偏好比如更长的答案容易被误判为更好。我的实操是让评判模型按维度打分同时人工抽检十分之一防止分数失真。4. 踩坑实录四场熬夜和它们背后的完整排查链路4.1 检索看起来相关但答案不对的根因一层层排到分块现象很典型知识库问答里检索出来的片段关键词都对但答案总是缺少关键步骤。多数人第一反应是换更强的模型我也这么试过没用。完整排查链路是这样的。第一步隔离变量。把检索到的片段直接打印出来人工阅读发现每个片段都恰好在句子中间断开——分块算法按固定字符数硬切把表格和步骤说明截断了。第二步修正分块策略按标题、段落边界切重叠设100字符。第三步再测发现仍有部分答案不对。接着看检索排序发现top 3几乎全在讲同一个小点上下文高度重复。第四步加入最大边际相关性去重让检索结果之间保持差异最后补一个精排模型效果才稳定下来。根因是两层叠在一起分块破坏了语义完整性排序又缺乏多样性。这个坑给我的教训是RAG的排查必须从最上游开始而不是一上来就怀疑模型。4.2 Agent在工具报错时死循环把LLM当确定性代码的代价现象Agent调用查询工具工具返回一个错误Agent重试十次还是同样的错白白消耗大量token和延迟。排查过程看trace日志发现工具返回的错误信息只有参数错误四个字。模型根本不知道该改哪里于是原样重试。这是个典型的用确定性系统的习惯去设计LLM系统的坑。修复分三步。第一步让工具的错误信息带上修正提示比如日期格式应为YYYY-MM-DD你传入的是YYYY/MM/DD第二步在工具调用层做严格校验能在模型之外拦截的错误一律不发出去第三步Agent循环加max_iterations上限超限转人工。这件事之后我对Agent的认知变了工具和系统本身的设计比模型聪明不聪明重要得多。4.3 离线评测高分线上体验翻车三种泄漏现象golden set上准确率90%上线后用户反馈却是一堆答非所问。排查链路第一步检查评测集和线上数据分布是否一致。结果发现golden set的文档和训练语料来自同一批材料属于典型的数据泄漏评测分数虚高。第二步检查评判模型是否有偏好偏差发现它把更长更详细的答案普遍评为更好而线上用户要的是准确简洁。第三步修正方法按时间切分把最新文档单独留作评测集模拟真实迭代场景评判改成按要点打分并做人工抽检。根因总结起来就是评测集和线上现实之间裂开了评测分数只是在自嗨。没有持续更新的评测集AI系统的优化都是盲目的。4.4 上下文塞得越满效果反而越差现象有人觉得多检索一些、多塞一些上下文模型总能用上吧结果token成本翻了倍回答质量反而下降。排查方式做一个对比实验。同样一组问题一组塞20个检索片段加完整历史对话一组只塞top 3片段加最近两轮对话后者效果明显更好。原因在于不相关的token会稀释注意力分配关键信息在长上下文里反而被埋没同时长上下文带来更高的延迟和成本。修复方案是检索-精排-压缩三步检索时多召回一些精排后只保留高相关片段过长的历史对话先做摘要。上下文窗口不是储物柜塞得越多越好的想法是新手最容易踩的坑之一。5. 十二周路线图与三个毕业项目把从零变成作品集5.1 两周为一个冲刺每个冲刺都产出可演示的东西学习AI工程最容易犯的错是只读不练。我给的路线是以双周为单位每个冲刺结束都必须有一个能演示的产出。时间目标冲刺产出第1-2周Python基础、PyTorch基础、环境搭建一个能跑通训练循环的demo第3-4周玩具Transformer、字符级分词能生成文本的小模型第5-6周API调用、提示词设计、结构化输出一个能回答问题的聊天机器人第7-8周RAG全栈实现个人知识库问答系统第9-10周Agent与工具调用带工具调用的客服助手第11-12周评测体系与部署上线带评测数据的在线服务前四周是在打地基后八周才是真正的AI工程主战场。很多人前两周就放弃了因为他们只做练习题不做项目。练习题给了你虚假的掌控感项目才会让你见到真实世界的混乱。5.2 三个可以直接当作品的毕业项目如果你不知道做什么我推荐三个方向全部可以用自己手头的数据完成。第一个是个人知识库问答。把你电脑里的文档、笔记、收藏文章清洗后做成RAG系统要求能准确引用来源。这个项目覆盖数据清洗、分块、检索、生成全链路。第二个是带工具调用的客服助手。定义一个查询订单状态、查物流、算价格的工具集让Agent学会在该调工具时调工具、该直接回答时直接回答之间切换。这个项目会逼你处理工具设计、错误兜底、循环限制这些真实问题。第三个是人在回路的报告生成器。让模型根据数据模板生成初稿再由人工审核确认后输出成稿。这个项目体现的是你对可控性的理解——AI系统不一定要全自动很多时候半自动才是最优解。5.3 几条只有动手才能体会的经验第一不要每周追最新模型。把一个大模型的能力边界摸透比收集十个模型的发布公告有价值得多。第二读代码优先于读论文。论文告诉你一个方法能做什么代码告诉你踩了什么坑才能跑起来。后者在工程里更稀缺。第三每次失败都留记录。我给自己定了个规矩排查超过半小时的问题必须写三行原因和处置方案。三个月后再看那本笔记比任何教程都有用。第四业务理解比模型理解更稀缺。能判断这个场景该用RAG还是微调这个错误该怪模型还是怪数据的人才是团队里不可替代的人。最后分享一个我坚持到现在的习惯每完成一个阶段写一份如果再让我做一次我会在哪里省时间的记录。我翻旧笔记时发现第一版RAG系统里有三分之二的返工都来自数据不规范和评测缺失而不是模型选型。AI工程从零到一最大的捷径其实就是一开始就把从零定义为从项目出发而不是从原理出发。想清楚这一点你已经比很多人少走三个月的弯路了。