news 2026/10/1 6:25:14

从零构建大语言模型与推理模型:完整技术路线与踩坑记录

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零构建大语言模型与推理模型:完整技术路线与踩坑记录

第一次在GitHub上看到“ai-engineering-from-scratch”这类项目名时,我以为是又一个教程链接合集。真把项目从头到尾跑起来才发现,它对“从零”两个字执行得极其彻底:数据清洗自己写,分词器自己写,Transformer结构自己搭,训练循环自己调,最后甚至还要把一个reasoning model的雏形用强化学习训出来。这条路线解决的核心痛点,是很多搞LLM的人长期卡在“调包阶段”——能跑通开源模型、能写prompt,但模型一OOM、一loss不降、一回答质量稀碎,就只能靠玄学调参。

我个人的理解是,从零构建大语言模型,本质上是把“会用API的人”变成“能造引擎的人”;而从零构建一个推理模型,则是把“能造引擎的人”变成“能设计思考方式的人”。这条路线适合的人也很明确:在校学生、准备转LLM方向的算法工程师,以及那些看了无数原理文章但没亲手实现过一遍的自我怀疑者。接下来我把整个项目的拆解思路、关键实操细节和踩坑记录完整写出来,希望能帮你少走几条弯路。

1. 这个项目到底在做什么:把“会用API”变成“会造引擎”

1.1 为什么一定要走“从零”这条路

当你能用几句Prompt让GPT完成翻译、总结、代码生成时,你其实已经会“驾驶”一辆汽车了。但从零构建自己的LLM,是去把一辆车从头组装一遍,看明白每一个零件为什么存在。市面上90%的教程都停留在“如何更好地调用模型”,而“ai-engineering-from-scratch”换了个方向:用一个小规模的GPT模型,把大模型从数据处理到生成文本的完整生命周期全部跑通。

这样做的好处是,任何一个环节卡住,你都必须去查论文、读源码、盯梯度,而不是简单换个参数碰运气。我有个常打的比方:同样是喝咖啡,速溶咖啡三分钟就能冲好,但想真正理解咖啡豆的风味,你必须自己选豆、研磨、控制水温。从零构建LLM就是那套“咖啡豆到杯子”的完整流程。它带来的不只是成就感,更重要的是遇到问题时快速定位的能力——你会突然在某天凌晨明白,注意力层里的score并不是什么神秘魔法,它只是一组点积运算经过softmax归一化后的权重分配。

1.2 两个关键词:large language model与reasoning model

这里需要把两个热搜方向拆开理解:“build a large language model from scratch”解决的是“模型能不能流利地说人话”的问题,即语言结构、知识、语法习惯;“build a reasoning model from scratch”则更进一步,解决的是“模型能不能在给答案之前先想清楚”的问题。

两者不是两条平行的路,而是同一栋楼的两层。第一层是拥有足够表达能力的预训练底座,第二层是在底座之上让模型学会长思考。如果只学第一层,你会得到一个“能生成但缺乏逻辑”的模型;只学第二层,语言能力不足的情况下,强化学习得到的只会是一堆看似深刻实则空洞的“然后……然后……”。所以完整的学习路线必须先把基础LLM跑通,再去碰推理能力。这也是为什么这个标题值得完整跟完,而不是只挑一半来做。

1.3 前置知识与硬件准备

很多新手会问“我到底需要什么基础”。我的回答比较直接:能读懂Python,会一点PyTorch,概率统计知道期望和方差,基本够了。完全不熟悉深度学习也能上车,但建议先用两到三周把反向传播和矩阵乘法的直觉建立起来,否则后面盯梯度时容易一头雾水。

硬件方面不用焦虑。至少在初期阶段,一张16GB以上显存的显卡(比如RTX 4090或者A100 40GB)跑一个千万到亿参数级别的小模型绰绰有余。我用一张3090跑过0.1B规模的模型,把batch size调小、梯度累积开大,照样能完整体验预训练、SFT和RL全流程。真正的瓶颈通常不是算力,而是耐心和排错能力。

2. 整体路线设计:六个阶段为什么这么排

2.1 先解决数据,不要急着碰模型

这个项目给我的第一个重要提醒是:数据阶段永远是第一优先级的。很多人一上来就写模型结构,但如果没有干净且充足的数据,模型结构再漂亮也不过是一口废井。第一阶段要做的事情包括:数据清洗、去重、分词、滑窗切块。清洗时要处理HTML标签、重复段落、全角半角符号;去重要用MinHash或simhash把近似重复段落找出来扔掉;切块时要按模型最大长度做滑窗,同时留出重叠部分避免样本开头过于僵化。

我见过太多人直接拿网络小说当数据集,结果模型训练完满嘴“福晋”“王爷”。原因很简单:语料规模太小、领域太偏,模型把噪声当成了主要规律。数据阶段最少要完成两件事:一是确保语料覆盖足够多样的写作风格,二是统计词频分布,避免少数词过度主导训练。这一阶段决定了模型的天花板,后面的所有工程手段都只是在这个天花板之下努力逼近。

2.2 模型结构要亲手重建Transformer

“ai-engineering-from-scratch”之所以叫from scratch,是因为它不让你直接import一个封装好的Transformer。你需要把token embedding、位置编码、多头注意力、前馈网络、LayerNorm、语言模型头一步步写出来。听起来繁琐,但这是整条路线里最值得的部分。

我的经验是第一步不要急着写大模型,而是先用一个极小配置(比如2层、4头、128维)把前向传播的形状走通,确认每一步的[batch, seq_len, hidden]形状符合预期,再逐步放大。这一步的核心不是算得快,而是“形状不出错”和“掩码不犯错”。你会在过程中第一次意识到,一个看似简单的QKV投影,在不同实现里会带来完全不同的内存布局和缓存行为。

2.3 训练循环中的工程细节才是真正的门槛

模型写好后,训练环节会给你上一堂“参数敏感性”课:warmup步数、学习率峰值、权重衰减、梯度裁剪、混合精度、梯度累积,每一项都直接影响loss曲线的形状。而这一阶段恰好是普通教程最少讲透的地方。

举个最典型的例子:为什么GPT类模型训练常用3e-4量级的学习率,而不是1e-2?因为Transformer对Adam优化器的步长非常敏感,学习率过大会让注意力层的数值剧烈震荡,loss曲线像心电图一样上下乱跳;学习率过小又收敛极慢。工程上一般用warmup加余弦退火来解决:训练前几千步让学习率从零缓慢爬升,中后期再按照余弦曲线逐渐降低步长。这类细节看起来琐碎,但正是“能训练”和“能训练好”之间的分水岭。

2.4 推理与生成:模型训练完了不等于能用

训练阶段结束后,还有一个经常被忽视的部分:生成策略。这个阶段要亲手实现贪婪解码、beam search、top-k、top-p采样,并对比它们在问答、续写、翻译任务上的表现。你可能第一反应是“温度调低不就行了”,实际操作后才会发现,低温度确实能减少随机性,但也会放大重复,模型经常陷入同一个句子的死循环;而top-p采样在保留多样性的同时,能过滤掉那些低概率的垃圾候选。

此外还要理解KV Cache和增量解码。简单解释就是:生成每个新token时,都需要模型“回顾”之前所有token的Key和Value,如果不做缓存每次都从头算,生成速度会越来越慢,序列越长越明显。使用KV Cache可以让推理复杂度从近似二次方降为近似线性。这些优化点写出来可能不到十行代码,但前提是你能透彻理解注意力公式,否则很容易写出显存爆炸的版本。

2.5 评估与对齐:从“能生成”到“能干活”

预训练模型只学会了文本分布,不代表它听得懂人话。所以还需要一个阶段来覆盖指令微调(SFT)、RLHF以及更轻量的偏好优化(比如DPO)。项目里的常见做法是:先准备一批“指令-回答”样本,用标准监督学习让模型学会回答格式;再用人类偏好排序数据做对齐,让模型输出更符合实际需求。

我强烈建议把评估做成自动化脚本,而不是盯着几个生成case感性判断。至少准备三类指标:一是困惑度(perplexity),看语言建模能力是否正常;二是任务准确率,比如简单数学题正确率;三是生成多样性指标,比如重复n-gram比例。没有一套评估体系的对齐,基本等于盲人摸象,你永远不知道改动是变好了还是变坏了。

2.6 从LLM到Reasoning Model的核心路径

当你完成前五个阶段,就有了构建基础LLM的完整能力。这时才能认真谈“从零构建一个推理模型”。核心路线我概括成两条。

第一条是数据路线:构造大量带思维链的SFT数据,让模型学会“先想后答”。比如给一个问题配一段逐步推导的思考过程,再给最终答案,训练时让模型学习复现整段文本。第二条是强化学习路线:引入可验证的奖励信号,比如“最终答案是否正确”,用PPO或GRPO训练模型在探索中自发长出更可靠的长思考链。

这条路径有一个前提:底座语言能力必须足够强。如果模型连通顺句子都生成不了,所谓的思考链只会变成胡言乱语。所以前五个阶段千万不能跳过,这不是课程设计者的偏执,而是模型能力层级决定的必然顺序。

2.7 时间与成本估算

很多人关心“这么一套流程下来到底要多久”。我按单张A100 40GB的经验给你一个参考:数据清洗约2到3天,模型实现与调试约1周,预训练一个0.1B参数的模型大约4天,SFT数据构造加训练约2天,基础RL训练再花2到3天。整个项目两周到三周可以完整走完。

如果你的卡只有24GB显存,时间会拉长一倍左右,但不会不可行。关键是不要把时间浪费在无休止的超参搜索上——固定一个可靠配置跑通全流程,比在每个参数上反复纠结重要得多。先要“完成闭环”,再谈“优化指标”。

3. 核心细节实操:从零写一个最小可运行的GPT

3.1 分词器:把文本变成编号

不要一开始就依赖HuggingFace的现成tokenizer。为了理解原理,建议先用字符级分词把全流程跑通,再升级到BPE。字符级分词的词表只有几百个token,训练虽慢但极容易调试;缺点是模型需要更长的序列才能记住词法信息。而BPE(字节对编码)的实际做法是:从字符开始,反复找语料中出现频率最高的相邻字符对,合并成新token,直到达到预设词表大小。

实现BPE大约200行代码,调试的关键技巧是:把语料里出现频率最高的20个token打印出来。如果其中混着大量孤立标点,说明清洗环节出了问题;如果高频词全是“的”“了”“是”这类停用词,那是正常的,不必惊讶。分词器的规模会影响模型训练速度与显存占用,我建议从小词表(5000到10000)起步,不要一上来就上5万词表,调试时会非常痛苦。

3.2 模型结构五件套

一个最小GPT至少需要五块:token embedding矩阵、位置编码、多头自注意力、逐位置前馈网络、LayerNorm加语言模型头。我在实操中建议位置编码直接用RoPE旋转位置编码,因为它在不增加参数量的情况下,对长序列的适应性更好,训练长度1024时通常能支持到1536左右的生成。

最容易翻车的点是注意力掩码。训练时必须用causal mask,让每个位置只能看到自己左侧的token,否则模型会“偷看答案”,loss偏低到离谱——这个现象新手很容易误以为模型很厉害,实际上是因为未来信息泄漏。这里给出一个训练循环的骨架,看起来简单但每一步都值得反复检查:

for step, batch in enumerate(train_loader): x, y = batch logits = model(x) # shape: [batch, seq_len, vocab_size] loss = cross_entropy(logits.view(-1, vocab_size), y.view(-1)) optimizer.zero_grad() loss.backward() clip_grad_norm_(model.parameters(), 1.0) optimizer.step()

注意这里y必须是x向右移一位的目标序列。很多新手在这一步少shift一位,最后loss确实能下降,但生成全是乱码。

3.3 训练参数怎么起步

对于0.1B左右的小型参考模型,我建议的起步配置是:每个batch总token数约0.5M,学习率峰值3e-4,warmup步数占训练总步数的5%到10%,权重衰减0.1,序列长度512或1024。如果你只有单卡,就用梯度累积把总batch size凑够,不要为了硬塞大batch而把序列长度砍到极短,否则模型学不好长距离依赖。

一个可以自检的经验值:干净英文语料在预训练初期,cross entropy大约在3.0附近,训到几亿token后会降到2.5以下。如果你的loss一直停在5以上,优先查数据切块是不是做错了,再查模型结构形状是否正常,最后把学习率降到原来的十分之一试一轮。这里的数值不是玄学,大致可以和公开实现里的小模型loss对上,说明你的实现没有基础性错误。

3.4 生成策略的核心实现

生成阶段最常见的做法是贪心解码,即每次取概率最大的token。但你很快会发现输出非常呆板、容易重复。实操中我更推荐top-p采样:从概率累积超过阈值p的候选集合里采样,p一般取0.9,temperature取0.8。生成的文本既有连续性又有变化度,不会为了“稳”而牺牲多样性。

具体实现并不复杂,核心是先对最后一个位置的logits做温度缩放,再进入softmax,最后用累计概率筛选候选集。最容易被忽略的就是温度缩放位置——如果先softmax再做温度缩放,等于白做,因为softmax已经把所有概率压缩到0到1之间了。另外,当重复惩罚系数设置过高时,模型会为了避开重复而强行换词,输出反而变得诡异,我这个坑踩过之后,基本把惩罚系数控制在1.0到1.2之间。

3.5 一个值得做的小实验:对比位置编码

在完成最小GPT后,我强烈建议做一组对比实验:分别用绝对位置编码和RoPE训练两个同样大小、同样数据的小模型,观察验证集loss和生成长度外推能力。结果通常会非常直观——RoPE在训练长度内的表现与绝对位置编码接近,但在超出训练长度时明显更稳。

这类实验的意义不在于“创新”,而在于让你建立对组件选择的敏感度。很多人读论文时觉得“位置编码就那样”,但亲手跑一遍对比后,你会真正理解为什么现代模型普遍选择旋转位置编码,也会明白生成时不盲目拉长max_new_tokens的原因。

4. 实操记录:从零训练一个小型LLM和推理模型

4.1 数据准备:三天清洗换来的稳定训练

我要做的第一个实操案例,是用中文维基百科的一个小型dump做语料,大概2GB文本。清洗流程是:先去掉模板、引用、目录结构,再做N-gram去重,把近似重复的段落剔除,最后用正则清理代码块和表格。整套脚本跑下来耗时约三天,但换回来的好处是训练时不需要频繁抢救loss曲线。

切块阶段我用了序列长度1024、步长512的滑窗,让相邻样本有50%重叠,相当于做了一个隐性的数据增广。这样做的代价是会多一些重复训练计算,收益是样本开头多样性显著提升。如果你发现模型生成的开头越来越像模板,大概率就是滑窗步长设得太大,需要缩回来。

4.2 训练观察:loss曲线会讲故事

真正进入训练后,盯loss曲线是一件很有意思的事。前几个小时loss会从5.2快速降到3.8左右,这是模型在学习最基础的词频和句法;之后会进入缓慢下降区间,可能一次下降只有0.02,这意味着模型在从“学会句子结构”过渡到“记忆知识”。如果中途loss突然跳高再回落,多半是学习率调度切换或者采样batch不平滑引起的,不必过度恐慌。

我手动记录过一组参考数据:0.1B模型、约7亿token预算、单卡A100,整体跑下来大约四天,验证集loss最终在2.6附近。这个数值对同规模模型是比较正常的。跑完那次我最大的感受是:真实训练曲线远没有论文里画的那么平滑,学会区分“正常噪声波动”和“真实发散”非常重要,比机械地盯着loss小数点后两位有用得多。

4.3 从LLM到推理模型:先做SFT再做RL

基础模型稳定续写后,我开始往推理方向走。我用了约两万条半自动构造的推理数据做SFT,每条样本包含“问题、思考过程、最终答案”三部分。训练时只对“思考过程”和“最终答案”两部分计算loss,问题部分掩码掉,这样模型不会把提问格式也一并背下来。

SFT跑完后,模型已经能输出“先枚举可能性,再排除,最后给结论”样式的文本,但毛病也很明显:思维链经常自言自语、逻辑跳跃。接着我引入奖励模型,对“最终答案是否正确、推理步骤是否可读”打分,再用策略梯度做RL。经过约2000步训练后,生成质量明显收敛,至少不再每步都自我怀疑了。

4.4 强化学习阶段的工程细节

如果想复现这一段,我强烈建议不要一上来就上PPO,而是从GRPO入手。GRPO去掉了PPO里的一个大critic模型,只用组内相对奖励计算优势,实现难度和对显存的要求都低不少。单卡训练0.1B的模型,GRPO完全可以承受。

实操时每组采样4到8条回答,计算每条回答的正确性奖励,再和组内平均值比较得到advantage。采样参数方面,我实测temperature=0.9、top_p=0.95在推理类任务上效果比较均衡;如果发现RL之后简单问题准确率没掉,复杂问题却开始频繁乱答,就该检查奖励是否过于稀疏,同时考虑提高SFT阶段思维链样本的覆盖范围。这里有个重要体会:强化学习不会凭空创造推理能力,它更多是把SFT阶段已经“模模糊糊学会”的推理路径加固、延长。

5. 常见问题与避坑速查

5.1 Loss不降还能从哪查

loss长时间不降,基本就四类原因:数据不干净、模型实现有bug、优化器参数不合适、梯度出现nan。我的排查顺序是:先在一个batch上重放几轮训练,确认正向loss是正常的;再用torch.autograd.detect_anomaly()捕捉nan和梯度爆炸;如果前两步没查出问题,就把学习率降到原来的十分之一重新训练一轮。

如果降低学习率后曲线开始下降,说明之前主要是步长问题。另外还有一个特别隐蔽的坑:causal mask的矩阵方向搞反了,模型能看到未来token,这样loss会异常低。遇到这种“训练顺利得不像话”的情况,先别高兴,检查掩码是不是真的遮住了右上角。

5.2 模型生成重复、空洞怎么破

生成文本不断重复,第一反应是调高重复惩罚系数,但这是治标不治本。真正根源往往在训练阶段:训练数据里重复片段太多、模型欠拟合、解码温度过低。我的建议顺序是:先把采样温度提高到0.8以上看效果;如果还在固定短语之间循环,就回头清理数据里的重复段落;最后再考虑加no_repeat_ngram_size限制,比如禁止连续重复的三元组,这个方法对复读机问题见效很快。

如果是推理模型在思考阶段反复强调同一个论点,那多半是RL奖励设计鼓励了冗余。我的调整做法是在奖励函数里加入重复率惩罚,或者对推理长度做温和的截断——既要防止模型一两句话糊弄完,也不能让它注水到几千字。

5.3 显存溢出与生成长度上限

训练阶段显存溢出,最常见原因是激活值太大。解决手段有梯度累积、混合精度、激活检查点,优先级从低到高依次尝试。推理阶段则要留意KV Cache的消耗:序列长度翻倍,KV Cache占用也近似翻倍。如果发现生成时报OOM,先检查是不是没有开启增量解码,导致每个新token都要重算历史KV。

长度上限问题也和位置编码强相关。即便用了RoPE,也不建议无脑拉长生成上限。我的一般做法是训练长度设1024,部署上限设1536,超过就做滑窗截断或者对前文摘要压缩。盲目调高max_new_tokens,只会让模型后半段输出质量快速劣化。

5.4 我到现在还在用的排查顺序

说了这么多,最后分享一套我踩过无数坑后沉淀下来的排查顺序:先复现最小case,再查数据分布,然后检查模型输入输出形状,最后才动优化器参数。顺序一旦反了,很容易在调参泥潭里越陷越深,左改一下右改一下,最后一晚过去什么都没推进。

同时强烈建议每次实验只改一个变量,把loss曲线、生成样例、指标结果存成带日期版本号的实验记录。这套流程看上去很慢,却是整条路线里最省时间的部分。很多让人崩溃的排查夜,根源都是没有日志、没有表格、凭感觉做改动。定时记录,比任何花哨的框架都更能保护你的睡眠。

这些小经验,都是拿几次通宵换回来的,希望你能直接用得上。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 6:25:05

AI工程化从零开始:环境搭建、数据治理到模型部署监控全流程实战

作为常年跟AI工程打交道的人,我越来越觉得“ai-engineering-from-scratch”这个名字本身就很妙——它精准戳中了很多团队的痛点:模型大家都会训,但能从零把一个AI系统稳稳当当搭起来、跑起来、持续迭代下去的,真没多少人。这个项目…

作者头像 李华
网站建设 2026/10/1 6:22:52

Model-Optimizer:面向硬件落地的模型精简全链路方法论

1. 这不是“一键压缩”工具,而是一套模型瘦身的手术方案“Model-Optimizer”这个词最近在工程团队的 Slack 频道里高频出现,但它绝不是某个新出的 GUI 点击软件,更不是宣传页上写着“3秒提速50%”的营销话术。我第一次在客户现场听到这个词&a…

作者头像 李华
网站建设 2026/10/1 6:22:24

TensorFlow 2.x实战指南:从环境搭建到生产部署全解析

有人问我“深度学习框架选哪个”,我通常不会直接给答案,而是先问一个问题:“你怕不怕装环境,以及你最终想把模型部署到哪儿?”这个问题的背后,其实就是这几年TensorFlow和PyTorch之间反复拉扯的真实逻辑。今…

作者头像 李华
网站建设 2026/10/1 6:20:46

深度学习舌苔检测毕设项目:目标检测全套工程与训练避坑指南

简介:面向计算机、人工智能等专业课程设计与毕业设计场景,这套资料包提供了一整套深度学习舌苔检测系统。项目以Python实现,包含可运行的检测脚本、模型权重与训练日志,能够帮助学习者理解图像识别任务从数据准备、模型训练到结果…

作者头像 李华
网站建设 2026/10/1 6:20:35

基于OpenCV的PCB裸板检测:成像、对准与缺陷识别全流程

简介:一套基于OpenCV与Python的PCB板智能检测系统代码包,面向电子制造领域从事视觉检测的工程师、高职院校相关专业学生以及图像处理入门者,解决生产线中PCB焊盘缺陷、焊点质量异常、元件缺失或错位等常见质量问题的自动识别。压缩包共19个文…

作者头像 李华
网站建设 2026/10/1 6:20:11

HBuilderX入门指南:零基础快速搭建HTML网页

1. 为什么选HBuilderX?它真不是“前端界的备胎编辑器”刚接触前端开发的朋友,常被VS Code、WebStorm、Sublime Text这些名字绕晕。而HBuilderX,这个由DCloud团队打磨十年以上的国产编辑器,总在新手教程里低调出现,却在…

作者头像 李华