你说你要从零开始搞AI工程,但你现在大概率正躺在收藏夹里吃灰。我身边有太多人买过《Build a Large Language Model From Scratch》的中文版,也有人保存了一堆“从零训练一个模型”的视频链接,真正跑通一遍的凤毛麟角。问题不在资料不够,而是大多数人不知道“从零开始”到底意味着什么,更不知道这条路值得走的真实成本。
这篇内容我想跟你聊透一件事:AI工程里的“from scratch”,到底是从哪个零开始,以及一个从业者真正动手时该走哪几步。我把自己的路线图、参数配置、踩过的坑全摊开在这里,希望能帮你少走几个月的弯路。
1. 从零开始做AI工程的路线图:先想清楚“为什么”
1.1 所谓“从零开始”,到底是从哪个零开始
我见过太多人一上来就问“怎么从零训练一个大语言模型”,结果聊两句就发现,他就是想调一个现成的开源模型做微调。“从零”这个词在AI工程里至少有四个不同的起点:
- 从数据开始:自己采数据、清洗数据、构造高质量语料库,然后用别人的模型架构去训练。
- 从架构开始:自己写Transformer、写Attention、写位置编码,不直接用现成的库,把模型定义和训练循环全部从纯数学公式实现。
- 从推理开始:基于现有开源模型,自己动手实现推理逻辑、KV Cache、采样策略,理解模型从输入到输出的完整链路。
- 从工程部署开始:把训练好的模型接入实际业务,解决延迟、吞吐、显存、成本这些问题。
任何一个方向都值得花时间,但它们产出和难度完全不同。坦白讲,如果你没有训练过哪怕一个小模型,直接去读那本经典书,效率会很低。更合理的路径是先搞清楚自己想解决什么业务问题,再选择“零”的起点。
我个人的建议是:第一轮“从零”选择最小闭环,第二轮再扩展。也就是先基于一个开源小模型跑通全流程——数据处理、训练、评测、部署,把工程感建立起来;然后再动手去复现架构细节,比如自己写一个单卡能跑起来的Transformer训练脚本。这样既不会因为目标过大而放弃,又能真正积累底气。
1.2 四条路线:推理模型、大语言模型、专用模型、Agent
网上现在最热的话题是“build a reasoning model from scratch”和“build a large language model from scratch”。新闻和收藏夹不会告诉你的是,这两条路线差异极其巨大,你的机器配置决定了你该走哪条。
- 推理模型(Reasoning Model):核心任务不是学知识,而是学会“多用一步思考再回答”。这类模型在数学、逻辑、代码层面的进步明显,训练时需要构造大量推理链数据,并配合强化学习或蒸馏技术。适合你手里预算有限,但想把现有开源模型“变聪明”的场景。
- 大语言模型(LLM):核心任务是把通用知识和语言能力压缩进参数里。这条路需要的数据量极大、算力门槛极高,单机甚至几台机器都撑不起一次像样的全量预训练。个人开发者做这个,基本是在交学费。
- 专用模型(Domain Model):在通用模型基础上专攻某一个业务域,比如法律、医疗、客服。这条路对数据和评测的要求远高于对机器配置的要求,是目前普通团队最容易出成果的方向。
- Agent工程:严格说不算“训练模型”,而是用现成模型组装解决复杂任务的工作流,配合工具调用、记忆、规划机制。它的代码编写量大,但算力成本极低,见效最快。
这四条路线其实可以形成一个递进关系。我周围绝大多数能坚持半年的朋友,都是从第四条路线的产品感受到位后,开始反向补第一条路线的知识。你先搞清楚你的目标是“会调模型”,还是“会造模型”,这决定后面三个月你该干什么。
1.3 路线选择的四个判断维度
在选择具体路线的时候,我建议你用四个维度来打分,别凭感觉:
| 维度 | 权重建议 | 判断方式 |
|---|---|---|
| 算力预算 | 40% | 你每月能承受的GPU租赁/购买成本是多少 |
| 时间投入 | 20% | 每天能保证多少小时连续开发 |
| 业务资源 | 25% | 是否有来自真实业务的独有数据支撑 |
| 团队技术栈 | 15% | 团队成员对Python/深度学习框架的熟悉程度 |
举个例子,你手里只有一两张消费级显卡(显存24G左右),时间和代码能力都一般,那么直接走“从零训练LLM”显然不合理。更现实的选择是:用开源的7B或13B模型做量化推理和LoRA微调,然后花时间补数据工程和评测这套方法论。理由非常朴素:消费级显卡上的全量训练跑一次实验就要一周,而微调一次只要几小时,实验密度决定了你的学习效率。
反过来,如果你手里有H系列级别的算力预算,那你完全可以考虑做一个“从零开始的领域推理模型”:用开源底座蒸馏推理能力,再配合自采数据继续训练。这条路径兼顾了“造模型”的成就感和“出交付”的现实约束。
2. 数据工程:很多人以为“从零”是从代码开始,其实是从这里开始
2.1 数据清洗与去重,决定了你模型的下限
我见过不少新手,花了一周时间把模型代码写好,然后直接把网上爬下来的语料喂进去,训练出来的模型一开口就是重复的垃圾话。为什么?因为数据里充斥了大量重复内容、模板化文本和隐藏的噪声标签。模型学习的是统计规律,你给它的语料有多脏,它输出的内容就有多脏。
清洗这一步没有太多花活,核心就是三板斧:
- 重复检测:按文本的哈希值做精确去重,再按n-gram重叠率做模糊去重。模糊去重时,我用的是MinHash+LSH,把大规模语料的相似度计算复杂度降到一个可以接受的范围。
- 质量过滤:基于启发式规则(比如文本长度、标点覆盖率、字母数字比)和分类器打分(用一个小模型判断文本是否为高质量内容)联合过滤。
- 安全过滤:把涉及个人信息、违规内容的文本直接丢掉,这一步不是形式,是为了让后续工作不会招惹麻烦。
清洗完之后,还需要解决“缺数据”的问题。一个常见做法是合成数据。我试过用强大的商用模型做教师模型,让它输出领域相关的问答对、思维链样本,再用规则过滤。这里有个重要细节:合成数据比例不要超过整体训练数据的30%,否则模型会学到教师模型的风格偏置,生成内容会越来越“同一个味儿”。
2.2 Tokenization:比你想的更影响训练效果
很多人都会用现成的Tokenizer直接开工,但如果你真想做“from scratch”,我建议至少在概念层面吃透Tokenization的原理,否则你会被很多诡异现象卡住。
Tokenizer的本质是“字词与ID之间的映射表”。它的粒度选择直接影响序列长度、计算效率与跨语言能力。常见的三种做法:
- Word-level:直接按空格或标点切词。简单粗暴,但词表巨大,遇到未登录词只能丢成UNK,小语种直接报废。
- Character-level:按字符切。词表极小,但序列变长,模型需要花大量参数去学习字符组合规律,训练成本高。
- Subword(BPE/Unigram):介于两者之间,把常用词根或词缀切成子词单元。GPT、LLaMA系列用的基本都是这类方案。
如果你打算从子词单元开始训练自己的Tokenizer,有个容易忽略的坑:vocab_size设置得太大,embedding矩阵会吃掉大量显存。比如vocab_size=50k,embedding维度=4096,光embedding层的参数量就是50k×4096≈2亿,约800MB的显存只为了存词向量。这也是为什么很多小模型干脆直接复用大模型的Tokenizer,因为重新训练一个更优的Tokenizer,需要的数据量和调参成本实在太高。
动手做的时候,我建议你把vocab_size控制在模型参数总量的1/10左右,然后再配一个足够大的语料来训练BPE。最终词表里不确定要留多少token,可以用一个简单的经验法则:跑一次小规模的训练,观察不同token的出现频率分布,把出现次数极少的token抛弃掉,换成语料里更常见的片段。
2.3 数据配比与课程学习
训练数据不像炒菜,不能把所有的料一股脑倒进去。不同来源的数据,对模型能力的影响方向是不一样的。通用网页文本给模型常识,代码数据给模型结构思维,数学推理数据给模型逻辑链能力,对话数据给模型交互感。
我推荐的做法是:先按业务目标定一个基础配比,比如:
- 通用网页语料:45%
- 代码数据:20%
- 领域专业知识:20%
- 对话与指令数据:10%
- 思维链/推理样本:5%
然后引入“课程学习”的思想,让训练过程由易到难。具体操作上,前10%的训练步数只喂高质量、低难度的通用语料,用来稳定loss;中间80%混入业务数据和代码数据;最后10%加入指令和推理数据。这样做的好处是让模型先学会语言基础,再去学复杂映射,收敛稳定很多。
我还试过一个更激进的做法:把同一份数据从粗到细过三遍,第一遍用长截断的文本,第二遍用中等截断,第三遍用核心片段,等价于让模型看数据时先看轮廓再看细节。效果上,评测分数略有提升,但提升最大的其实是训练稳定性——loss曲线少了很多毛刺,这点在后面的章节会展开说明。
3. 架构选型与训练配置:不追求最前沿,追求可复现
3.1 架构选型:Transformer是默认项,但不是唯一项
自己训练模型时,最容易犯的错误是一上来就堆最新架构:Mamba、混合专家、多查询注意力,全都要。实际上,模型架构没有优劣,只有匹配不匹配。
如果你只是单卡做微调或小规模预训练,标准的Decoder-only Transformer + RoPE + SwiGLU + Pre-Norm就够了。这四个组件的组合已经被无数模型验证过稳定可靠,复现资料也多。等你把训练链路跑通,再逐步替换成Grouped Query Attention省显存,或者尝试Mamba之类的线性注意力,心里有底得多。
我踩过一个真实的坑:有一版实验用了带MoE的架构,但负载均衡loss权重没调好,结果大量token掉进同一个专家,模型后期loss完全降不下去。后来我花了三天检查数据、调学习率都没用,最后定位到是MoE路由塌缩。这场事故教会我一个原则:第一次做新实验时,把模型规模砍半,确认baseline能稳定收敛后再放回完整配置。
3.2 超参数选择与缩放律
训练参数不要瞎猜,至少先看一下经典的Scaling Law公式再决定。简单版本是,模型参数量N、训练数据token数D与最终loss之间存在幂律关系。也就是说,如果你把模型参数翻倍,但数据量不翻倍,收益会迅速边际递减。
实际操作上,我通常按照这个顺序定参数:
- 根据可用的总GPU显存,反推模型参数量的上限。
- 用经验法规定训练token数大约是模型参数量的20~40倍。比如训练一个1.3B的模型,语料量大概在26B~52B tokens之间。
- 学习率峰值设置在1e-4到3e-4之间,先跑500~1000步,观察loss是否按预期下降。
- batch size不超过总token数的0.5%,防止模型更新步数过少。
这里有一个具体计算案例:假设你有4张A100(每张80G),目标训练一个7B模型。粗略估算,7B模型在BF16混合精度下,模型权重加优化器状态加梯度,大约需要:
- 权重:7B×2Bytes = 14GB
- 梯度:7B×2Bytes = 14GB
- AdamW优化器状态:参数(7B×4Bytes)+ 动量(7B×4Bytes)= 56GB
这意味着每张卡至少要90GB以上,4张A100也只能勉强塞下,且没有空间放激活值。这个估算直接说明了一个残酷事实:单人或小团队用商用卡全量训练7B,经济上完全不划算,LoRA或QLoRA微调才是现实选择。如果你想训练自己的模型,把目标定在0.5B~1.5B之间,卡的压力会小很多。
3.3 优化器与学习率调度
优化器方面,AdamW是绝对的主流,理由很朴素:它处理稀疏梯度和不同参数尺度差异的能力比SGD稳得多。很多人为了省显存换用AdamW的8bit版本,我建议你在第一次跑通时不要换,保持标准版本,线路通了再去优化显存。
学习率调度,我用的是warmup + cosine decay。推荐配置:warmup步数占总步数的3%-5%,然后用余弦退火把学习率从峰值逐步降到峰值的1/10左右。warmup的目的是防止初期梯度爆炸,会掉得很快,不用慌。cosine decay到后期loss也会有平台期,这个和模型的学习能力无关,更多是数据信息已经被充分榨取的表现。
顺便提一句batch size的bs趋势:在传统分布式训练里,增大batch size通常会要求同步提高学习率。如果你把batch size从128调到512,同时不动学习率,模型大概率收敛明显变慢。一个粗略的参考是把学习率乘以sqrt(4),即2倍。这个关系不完全精确,但能保证训练不至于崩掉。
4. 训练过程的关键细节:看懂loss曲线,救你无数次
4.1 Loss曲线怎么读:不是所有下降都值得开心
训练早期的loss曲线往往像心电图,抖动很大,这很正常。真正要留意的是以下几个信号:
- Loss平台期:连续几千步loss不变,你需要检查是否存在数据泄漏导致模型记忆了答案,或者数据配比失衡,比如领域知识太多太重复。
- Loss反弹:出现过拟合的典型信号,或者学习率过高。先降学习率,如果还反弹,再检查数据重复率。
- Loss突刺:个别step loss突然飙升后又恢复,多半是某个batch里混入了异常数据,或优化器状态被极端梯度污染了。我的处理办法是在数据管线里加配置文件式的过滤规则,把文本长度异常超大或超小的样本直接丢出训练集。
每当我看到新手在loss平台期调了半天模型架构,我就知道他把因果关系搞反了:大多数情况下,loss平台期跟你的模型架构没关系,而是数据和训练配置出了偏差。我有个快速诊断流程:先用同一个模型跑一个极少量的子集,比如5000条样本,如果loss能顺畅下降,说明架构代码没问题;如果再跑一个完整数据的子集,loss下降变慢,就能坐实是数据问题。
4.2 训练稳定性问题与检测
训练崩溃(NaN、梯度爆炸)是每个人的必修课。最常见的三个原因:
- 学习率过大:解决方法是Warmup + 梯度裁剪,把梯度范数裁剪到1.0左右。
- 数据数值异常:文本里有超长的数字串或特殊字符,会让注意力计算中的Softmax进入饱和区。建议在Tokenizer阶段直接设置max_length,超长截断。
- 混合精度精度不足:FP16在小梯度值下会下溢,建议用BF16,它对loss值范围的容忍度高得多。
训练中途千万不要只盯着loss看。有条件就定期(如每500步)跑一次小评测集,看BLEU、准确率或者人工抽样的文本质量。我见过一个模型,loss从2.1降到1.8,看着很漂亮,生成出来的中文却全是“的”和“了”,因为这是最容易拟合的统计模式。loss是代理指标,最终要解决的业务问题才是真目标。
4.3 微调与强化学习:从“会说话”到“会推理”
如果你是走“build a reasoning model from scratch”这条路,训练流程跟普通预训练完全不同。核心分三个环节:
- 构造思维链数据:每个训练样本包含“问题-思路-解答”三段。思路部分不要只写一句话,要展开成多步推理:已知条件、中间结论、候选方案排除、最终推导。为保证数据质量,我习惯先用规则图谱校验结果,再人工抽检5%。
- 监督微调(SFT):把构造好的思维链数据用标准交叉熵损失微调底座模型,这个阶段让模型理解输出格式和推理节奏。训练时注意让模型学习的是“思考过程”而不只是“答案格式”,因此loss的计算不能只放在答案部分,思路部分也要参与训练。
- 偏好优化(DPO):这一步比PPO稳定得多,不需要额外训练一个奖励模型。核心逻辑是:收集同一个问题下“模型自己生成的多种解法”,让领域专家或规则系统打分,把正确答案对上的样本归为偏好对,然后通过DPO来加大正确解法和错误解法的概率差。
我自己在DPO里踩过的坑是温度参数太高导致采样出的负样本过于离谱。负样本如果差到完全不在谱上,DPO会让模型过度收敛到“只输出唯一标准话术”,失去多样性。调整方法是把采样温度控制在0.7到0.9之间,并用拒绝采样过滤掉明显低质量的负样本。
5. 推理与部署:模型训完,这才是真正价值兑现的开始
5.1 推理显存估算:为什么模型能跑,但服务跑不动
训练完成之后,很多人马上把模型部署上线,结果发现单个并发请求都喘不过气。原因在于推理阶段除了模型权重占用的显存,还有KV Cache这个最大隐性开销。
KV Cache的大小计算公式并不复杂:
KV Cache字节数 = 2(K和V两组) × 层数 × 注意力头数 × 头维度 × 序列长度 × 精度字节数
举个例子,一个7B模型,通常有32层,32个注意力头,头维度128,如果用户输入的序列长度是2048:
- 单头单层的KV Cache = 2 × 2048 × 128 × 2Bytes(BF16) = 1MB
- 单层全部注意力头 = 32 × 1MB = 32MB
- 全模型 = 32层 × 32MB = 1GB
也就是说,每处理一个2048长度的序列,单靠KV Cache就要吃掉1GB显存。如果你的服务同时来4个并发,就得预留4GB以上给缓存。很多人没算清这笔账,选了“看起来够用”的显存,结果上线第一天就被流量击穿。
好在现有推理框架已经内置缓存管理,比如vLLM的PagedAttention,把KV Cache按页管理,能明显提升显存利用率。我的建议是:部署前先压测,调好max_num_seqs和gpu_memory_utilization参数,这个参数决定多大比例的显存被用来做缓存,设置为0.85通常是安全值。
5.2 量化选型:从FP16到INT4的取舍
量化是我认为对普通团队“最友好的性能优化”方案。它思路朴素:把模型参数从高精度浮点数压缩成低精度整数。常见方案有:
| 方案 | 精度 | 显存占用(7B模型) | 质量损耗 | 适用场景 |
|---|---|---|---|---|
| FP16/BF16 | 16bit | ~14GB | 无 | 基准测试、追求最高质量 |
| INT8(W8A8) | 8bit | ~7GB | 极小 | 延迟敏感型业务 |
| INT4(W4A16) | 4bit | ~4GB | 中等 | 显存紧张的本地部署 |
选择哪个取决于模型是“输出给用户直接看”还是“输出给另一个模型解析”。如果是前者,INT4在复杂逻辑任务上的生成质量下降能感知到;如果是后者,量化带来的语义理解偏差,可能让整个人Agent流水线出错。所以我在做Agent系统的模型路由时,会优先把好模型部署给“复杂推理”节点,量化版本部署给“简单抽取”节点,这样既控制了成本,又保住了体验。
5.3 投机采样:把速度再提升一档
如果你把模型部署到实际业务里,大概率会遇到一个问题:单卡推理速度跑不满用户的等待耐心阈值。这时除了上更小模型、换量化,还有一个被很多人忽略的正向加速手段——投机采样(Speculative Decoding)。
它的核心思路是:用一个小模型(draft model)快速生成一串候选token,大模型(target model)再一次性验证这串token是否可接受。如果小模型足够聪明,能猜中大部分token,那么大模型只需要做一次批量前向就能确认,推理延迟大幅降低。如果猜错了,就退回正确位置重新生成,保证最终输出和大模型单独生成的概率分布完全等价。
实操上,我用过LLaMA系列小模型做draft model,将大模型的同一序列长度推理提速约1.6-2.1倍。但有个前提条件:小模型和主干模型的词表必须完全一致,否则无法直接做token映射。如果你的draft model词表与大模型不一致,就得先在词表层面做对齐,这个工程量有时候比提速收益还大。
6. 评测、对齐与踩坑记录:模型好不好,最终要拿到场景里验一验
6.1 评测集:通用基准是参考,自己造的才是信任
BBH、MMLU、HumanEval这些公开基准可以帮你横向对比模型能力,但你最终要解决的具体任务,它们很可能根本覆盖不到。所以我会做一套“领域评测集”,流程如下:
- 从历史业务数据中抽取真实请求,人工标注正确答案,构建大概200-1000条样本的小评测集。
- 把评测集按难度分成三档:简单(单步知识检索)、中等(多步推理)、困难(条件约束不明确)。
- 每次训练后跑全量评测,记录分档准确率,而不仅仅是总分。
这样做的好处是能快速判断新迭代是全面变强,还是靠牺牲某类能力换另一个指标。举个真实例子,有一次我调高数据里代码的比例,MMLU分数只是小降,但领域评测里的“长文档归纳”分档准确率掉了近10个点。如果只看通用基准,这次迭代会被误判为“无损升级”。
6.2 对齐的基本功:从安全话题到风格控制
对齐(Alignment)不是玄学,本质上是“让模型输出符合人类期望”的系统工程。最基础的三板斧:
- 指令遵循:训练时把指令与回答的边界规范成固定模板,让模型学会区分“命令”和“内容”。
- 拒绝能力:当请求明显超出模型能力或违反基本规则时,模型应能明确表示无法完成,而不是强行生成模糊答案占位。这需要在训练数据里有意识地构造负面样本。
- 风格控制:如果业务场景是客服,输出必须简洁温和;如果是代码助手,输出必须结构清晰。风格对齐可以在SFT阶段通过大量干例子完成,也可以在推理阶段用System Prompt约束。
从我实践来看,很多新手把对齐当成“加一段prompt”,这是天大的误解。Prompt只是在推理时约束模型,对齐是在训练时重塑模型,两者的力度差异巨大。举个直观例子:一个未对齐的模型,你给一万句“请友善回答”的提示,它可能还是输出嘲讽;但你要是SFT阶段用两万条友善风格的语料教它,它会自发地保持稳定语调。
6.3 实操中的高频坑:一份值得收藏的避坑清单
我把过去踩过的坑整理成一个速查表,希望能帮你绕开:
| 问题现象 | 可能原因 | 处理方法 |
|---|---|---|
| 训练loss一直不降 | 数据没有洗好,或学习率过小 | 先用小数据集验证代码是否跑通,再看数据清洗 |
| 验证集loss回升 | 训练数据与验证集有重叠 | 做严格去重,检查数据泄漏 |
| 输出内容重复 | 上下文长度超出训练时的长度 | 重新统计训练语料的长度分布,适当增加截断 |
| 中文生成英文 | 词表中中文token数量太少 | 换一个中文友好的Tokenizer或扩充中文语料 |
| 模型推理非常慢 | 未使用KV Cache或未做缓存复用 | 框架默认开启,检查配置是否被关闭 |
| 部署后首字延迟很高 | Prefill阶段计算量过大 | 优化首字延迟,考虑用更小块来切分输入 |
第6条值得多说两句。推理延迟分两段:首字延迟(用户发出请求到第一个字返回的时间)和整体延迟(整个回复生成结束的时间)。很多人只盯整体延迟,忽略了首字延迟是用户感知最强烈的指标。首字延迟的主要消耗在Prefill阶段,也就是对输入序列做并行预计算。输入越长,首字延迟越高。如果一个用户粘性很高的应用首字延迟超过3秒,体验一定崩。优化方向是缩短每次请求的输入长度(比如把无关历史折叠掉)、用投机采样减少生成轮数、或把计算密度低的请求路由到小模型。
最后
我写这篇长文的时候,又回想起自己第一次在单卡上跑通一个小模型的训练流程时,一百多个小时后看到loss降到一个理想范围,那一刻确实有“一扇门打开”的成就感。但真正让我受益的,是之后无数次在推理环节被显存击穿、在评测环节被领域指标打脸、在部署环节被延迟折磨出来的工程感。
如果你问我:现在开始,从零做AI工程,第一步该干嘛?我的回答不是“去租GPU”,也不是“去看那本经典书”。而是先拿到一份真实业务的数据,哪怕只有几千条,然后在你熟悉的框架里,把一个开源小模型微调起来,跑通评测和部署。这一步做完,你自然知道自己下一个“零”在哪里。
最后分享一个我从踩坑中摸索出的习惯:每次实验之前,先写半页实验笔记,记录数据版本、模型配置、预期结果、评估方式。不用写得多高级,但一定要写清楚“为什么做这个实验”。AI工程最贵的不是显卡,是时间,而减少时间消耗最好用的工具,就是记下你上次踩坑的位置。