从零构建AI工程:数据、训练到推理的完整实战复盘
发布时间:2026/10/4 16:12:13 锦皓数字建站

咱们这行里有个很有意思的现象一说AI工程绝大多数人默认就是调API、跑开源自模型、做RAG这一套。但真当你在生产环境里吃了瘪——比如模型推理结果不稳定、领域数据一塌糊涂、迭代一个prompt要等半天——你会发现有一个东西是绕不过去的那就是从零构建模型的底层理解能力。今天这篇东西我想好好聊聊我自己从零开始构建AI工程体系的完整经历包括为什么要从最底层做起、数据与分词怎么处理、模型架构怎么选、训练过程会遇到哪些鬼问题以及怎么让一个普通语言模型真正学会思考。这篇东西适合那些不想永远当API搬运工的工程师也适合想系统入门大模型训练的开发者。很多人一听到from scratch就头大觉得要从矩阵乘法开始手写神经网络。实际上不是这么回事。我理解的从零是抛开现成的黑盒方案真正掌握从数据、分词、预训练、对齐到推理的完整链路然后按需复现和改造。这篇文章就是一次完整复盘里面的教训和弯路都是真金白银换来的。1. 为什么非要从零开始一次被迫的返工经历先交代一下背景。我之前参与过一个垂直领域的智能助手项目第一版图省事直接调了一个很流行的商用API。刚开始感觉一切美好demo跑得飞快。结果一上生产环境问题就来了延迟高到用户投诉成本随调用量增长疯狂失控最致命的是模型的输出在专业术语上频繁翻车。你让通用模型理解一线工程师的行业黑话它总给你弄出模棱两可的答案。1.1 现成方案解决不了的问题清单那段时间我列了一个问题清单每条都直指不上不下地调用API的尴尬成本不可控按token计费生产环境一旦有恶意刷量或日志重放账单直接爆炸。定制化隔靴搔痒微调API确实能用但base模型本身能力弱、参数量不够时微调能优化的上限就摆在那。推理行为不可知你永远不知道模型内部有没有被安全对齐压制了某些合理输出也不知道温度参数调低了为什么逻辑还乱。全链路依赖别人一旦上游服务变更策略或调整定价整个产品就得跟着被动。说白了从零做不是炫技是为了换回对性能、成本和行为的控制权。1.2 从零的真实边界哪些必须自己写哪些不必重造轮子这里我要说清楚我所说的从零绝不是连Transformer都要自己拿CUDA手写。合理的起点是用成熟的深度学习框架比如PyTorch做张量运算自己动手实现数据清洗、分词训练、模型结构定义、训练循环、对齐流程自己从HuggingFace等平台拉取原始基座权重在此基础上继续预训练或做领域适配或者干脆自己在一个小规模参数量上完整走一遍预训练流程彻底搞明白训练是怎么回事。我在这个项目里选的路线很有意思先做一个小规模约1.4B参数的自研模型然后在这个模型上做领域继续预训练和推理能力强化。事实证明在中等规模参数上完整走一遍流程对整个AI工程体系的认知提升是巨大的很多上层框架无法解释的问题在这个层面全部一目了然。2. 起点不是模型而是数据分词器与数据配比很多初学者一上来就打开PyTorch文档准备写transformer block但我建议把注意力先放到数据上。模型再强训练数据的质量上限就是它的能力上限。这个道理谁都听过但真正做工程时数据环节最容易被压缩也最坑人。2.1 训练自己的Tokenizer合并规则的诞生我当时做的第一件事不是定义模型架构而是先拿领域语料训练自己的BPEByte Pair Encoding分词器。很多人觉得直接用现成的GPT-2分词器不就行了吗问题在于分词器决定了模型的字母表领域里的专业术语如果被切得稀碎模型很难学到完整语义。BPE的原理可以这样理解它不断把高频出现的字符对合并成一个词元比如一开始是字母级然后er合并了ing合并了最后transformer可能成为一个整体词元。我基于约60GB的混合语料训练了一个词表大小为50K的BPE分词器关键是把领域专业词汇单独做了一个高频词库合并进语料重复出现让它们能更快被合并成整体词元。这一招实测下来后续预训练的困惑度perplexity能降低好几个点领域数据的收敛也明显更快。2.2 数据配比通用语料与领域语料的比例逻辑数据配比是个玄学但也有基本法。我当时采用了大约85%通用中文语料 10%领域技术文档 5%代码与结构化数据的配比。刚开始我犯了一个错误为了追求领域效果把领域语料占比拉到40%结果模型在通用能力上快速退化生成的句子都开始变得干巴巴。后来我才明白通用语料承担的是语言能力底座领域语料只是在这个底座上做知识注入。如果底座本身就是歪的上面加多少知识都立不住。另外代码和结构化数据我建议一定要混进去它们能极大提升模型的逻辑推理能力和指令理解能力这个经验到第五部分讲推理能力时会反复提到。2.3 数据清洗做AI工程最脏最累但最有回报的活我在这块踩的坑最惨。第一次清洗时我偷懒只是粗暴去重和过滤HTML标签结果训练出来的模型出现严重的复读机现象而且偶尔会莫名生成一大段乱码——后来定位到是语料里混入了大片Base64编码文本和异常字符。建议的处理流程是语言与编码检测用fastText做语言识别过滤非目标语言的段落精确去重用MinHash做文档级去重再用SimHash做段落级近似去重防止同一段知识被超量重复学习异常文本过滤剔除乱码、Base64、纯时间戳、连续无意义重复的段落敏感内容过滤这一步需要结合自己产品的合规要求来做做一个关键词和分类器双层过滤宁缺毋滥。整个清洗流程跑下来原始语料可能只剩60%到70%但剩下的都是能安心喂给模型的高质量内容。3. 架构与规模参数量的第一性原理数据处理完毕终于可以碰模型了。Transformer架构本身已经是标准答案没必要再自创一个全新架构。我选择的是标准的Decoder-only结构和今天大多数LLM保持一致。选择它的原因很简单生态最成熟、扩展性最好、和后续的RL对齐流程兼容度最高。3.1 选Decoder-only的原因自回归就是最朴素的推理路径Encoder-Decoder架构擅长理解类任务比如翻译、摘要但面向通用的生成和推理场景Decoder-only的自回归方式更接近人类逐字组织语言的过程。它预测下一个词的概率分布这个简单的目标函数在大规模数据和足够算力下会涌现出推理、上下文学习等复杂能力。从工程角度讲Decoder-only还有一个巨大优势训练时不需要维护编码器与解码器的数据格式对齐推理时KV Cache的缓存策略也统一省了一大堆工程麻烦。我用了一个12层、隐藏维度1536、约1.4B参数的配置。为什么是这个规模下面展开算一下。3.2 参数量、数据量与算力的三角关系训练数据量和参数量的关系业界有一个Chinchilla法则的经典结论大概需要20个token/参数才能把模型训到最优性价比。也就是说1.4B参数左右的模型理想数据量应该在28B到30B token左右。我有大约100B的清洗后语料但时间和显卡都有限所以退而求其次用15B token先做算力约束下够用的训练。这里贴一段我当时估算训练时长的逻辑假设有效吞吐是每卡每秒5000 token用8卡A10080G训练15B token那么总耗时约为15e9 ÷ (5000 × 8) ≈ 375000秒加上梯度累积和拥堵损耗大概需要5到6天整。这个规模选得非常务实参数太少学不出推理能力参数太多在有限数据下反而过拟合泛化崩坏。1B到1.4B是一个成本可控、能展现涌现前兆、又能完整走通工程链路的甜点区间。3.3 架构细节里的隐形陷阱LayerNorm与位置编码有几个工程细节如果忽略了训练过程会非常痛苦用Pre-LayerNorm还是Post-LayerNormGPT-2之后的模型基本都用Pre-LayerNorm它的梯度传播更稳定在深网络中能有效减少训练初期的不稳定。我当时选用了Pre-LayerNorm 残差连接。旋转位置编码RoPE还是绝对位置编码RoPE是目前最优解之一它在计算注意力时把相对位置信息直接编码进来外推能力比可学习位置编码强很多。我直接用了RoPE后续扩容上下文长度时基本零成本。激活函数与初始化SwiGLU激活函数是目前的主流选择比GELU在同样的算力下能带来更好的效果。初始化时注意按标准差缩放否则深层网络很容易出现激活值爆炸或消失。这些细节不花一分钱但对训练的稳定性和最终模型的表现影响巨大。4. 训练实录从loss不降到正常收敛的完整排查链路训练过程才是真正让人褪层皮的地方。我第一次真正训练1.4B模型时前24小时几乎没有睡安稳过。loss曲线就跟心电图一样向下的趋势有但抖动大到让人恐慌。这一部分我把完整排查过程写出来。4.1 卡在loss不降的72小时刚开始训练时我的loss一直原地踏步偶尔还微涨。那一刻真有点崩溃。我按照下面的顺序逐一排查检查数据加载器打印每一个batch的input和label确认标签是否对齐。果然问题出在这里我在做因果语言模型的数据拼接时把跨文档的token也串联进来导致模型试图用上一文档的信息预测下一文档开头的token直接增加了学习难度。修复方案是加入文档分隔符让注意力掩码不跨越文档边界。检查学习率我一开始用了固定的5e-4对1.4B模型配合batch size偏大导致loss震荡不收敛。换成带warmup的余弦衰减后情况立刻好转。检查梯度范数我加了梯度裁剪值设在1.0。如果裁剪后loss还是暴涨就要回头看初始化和数据中是否有NaN。别小看这三步80%的loss不降都是这三个原因排列组合出来的。4.2 学习率策略与warmup的必要性学习率是训练里最重要的超参数之一。我最终采用的策略是Warmup阶段学习率从0线性升到峰值1.8e-3配合batch size 0.5M token大约占了总步数的2%到3%。warmup不是玄学而是让优化器AdamW的一阶和二阶动量先稳定下来避免在训练初期就冲出陡坡。余弦退火峰值之后按余弦曲线衰减到峰值的十分之一。这样模型在后期能更精细地收敛而不是在最优点附近来回震荡。Batch size动态在中期适当增大batch size能减少梯度噪声我会在几个关键节点double batch size同时把学习率减半。这里我想补一句很多人喜欢反复对比跑几十组小实验来找最佳学习率但如果你的数据清洗到位、架构选择主流在一开始就按经验值设好然后把时间留给更多的数据迭代收益会更大。4.3 显存优化与分布式训练你也可能遇到OOM1.4B参数在单卡上其实也能勉强跑但速度太慢。我用的是8卡A10080G训练时开了混合精度bf16和FSDP完全分片数据并行。最核心的显存消耗大头是AdamW优化器状态它要给每个参数维护两份动量相当于每个参数基本都占用了12字节fp32的master weight加fp32的momentum和variance。加上模型本身的fp16/bf16权重一个1.4B参数模型的显存需求约等于权重2.8GBbf16 梯度2.8GB 优化器状态约6.7GB 激活值和中间缓存若干单卡整体负载很轻松就会超过40GB。FSDP的好处是把参数、梯度和优化器状态都分片到各卡上每张卡只负责一份分片训练时通过通信把需要的参数拉齐。这套方案帮我稳定跑完了全程。如果你只有4卡甚至单卡也别灰心可以用梯度累积来模拟更大的batch size虽然速度慢一点但工程逻辑一样。4.4 训练过程中学到的玄学经验有几个经验是常规文档里不会写的loss的绝对值没那么重要趋势才重要不要拿你的loss去跟别人模型的loss比因为vocab size、tokenizer、数据分布完全不同loss数值根本没有可比性。只要它在稳定下降到后期趋平就说明训练是健康的。数据Shuffle的种子训练数据必须充分打乱同一脚本跑两遍时最好是不同随机种子否则模型会隐式记住数据顺序表现为eval时好时坏。定期保存中间checkpoint每个epoch保存一次并保留最优和随机中的几个。因为后面的RL流程可能要用到不同阶段的模型权重。5. 思考不是魔法推理模型reasoning model的构建路径预训练完成之后我拿到的是一个会续写的模型但它不会答题、不会推理、不会遵循指令。这部分才是让模型真正长脑子的关键步骤。2025年这个时间点业界对推理模型reasoning model的讨论热度很高从OpenAI的o系列到DeepSeek-R1大家都在探索一条让模型在回答前多思考一步的路径。这里分享一下我自己在1.4B模型上做思考链Chain of Thought对齐的实操过程。5.1 从继续预训练到指令微调先学会说人话第一步是进行有监督微调SFT。我准备了约5万条高质量的领域指令问答对。关键是数据质量必须极高每条答案都要保证逻辑严密、格式规范。这里的技巧是不要贪多5万条精挑细选远好过50万条粗制滥造。SFT训练只用了2到3个epoch学习率比预训练低一个数量级1e-5量级否则模型会把原有的知识洗掉。SFT之后模型能回答了但仅仅是能回答遇到复杂问题会直接给一个不充分、甚至错误百出的答案。这时候我需要让它学会像一个人一样先推理再回答。5.2 推理数据的构造长思考链与格式强制构造推理数据核心是让输出包含思考过程和最终答案两部分。一种常见做法是模仿已知的开源数据格式系统指令要求模型先写推理过程然后以特定标记做分隔最后输出答案。训练时我把这两部分都作为模型要生成的token来学习。但问题来了怎么获得足够多的高质量推理过程我用了两条路人工精标找行业专家对最核心的几十个疑难问题一步不落地写出完整推导过程。这比想象中贵但你必须有一些黄金标准它们是后续强化学习的锚点。大模型蒸馏与自举让一个能力强的模型生成思路再用规则和人工抽检筛选。刚开始要筛选得严一些优先保留演绎链完整、结论正确的样本。量做到20万到30万条时效果开始明显。这里有个关键技巧在SFT训练时给思考过程部分的loss降权或者干脆只对最终答案部分计算反向传播。原因很简单思考过程可以有多种写法过度拟合某一种固定写法反而会损害模型的泛化能力。我用了最终答案loss权重为1.0、思考过程loss权重为0.3的混合策略效果明显比全量学习好。5.3 强化学习GRPO让模型学会自我纠错SFT能教模型形式上会推理但要让推理能力真正增长、让模型学会自我纠错还得靠强化学习。我采用的是目前公认稳定性相对好的GRPOGroup Relative Policy Optimization算法它在一些开源模型中已经被验证能有效增强推理能力。原理上可以这样理解让同一个模型对一个数学或逻辑问题尝试生成多组不同的思考与答案然后根据最终答案对错或其他奖励信号给每组打分分数高的回答模式被强化分数低的被抑制。这个机制不关心模型的具体思路是什么只关心最终答案对不对所以模型会自发探索出更靠谱的推理路径。我在实际跑GRPO时遇到的最大问题有两个奖励信号稀疏初期模型经常全部答错导致组内相对奖励没有区分度。解决办法是先做大量SFT冷启动让模型基础正确率达到30%到50%再上强化学习。逻辑奖励模型的设计在领域问答中我不仅校验最终答案还设置了规则打分答案关键词命中和格式强制必须包含思考标记被打乱顺序后直接给惩罚分。这套规则有效避免了模型学会答非所问但格式完美的偷懒策略。5.4 给推理模型减负的冷思考需要提醒的是推理能力不是一个二元的有/无。1.4B的模型你让它做复杂数学推理上限摆在那里。我在实践中发现小模型更适合处理中等难度的逻辑问题和工程类问答对于真正的高难度数学证明它还是会一本正经地胡说八道。所以推理模型的构建一定要结合自己产品的难度分布来定不要盲目追求R1模式否则只会得到一个又慢又不准的模型。6. 从checkpoint到服务评估、量化与部署的实战细节模型训练完只是第一步真正让它创造价值的是稳定高效地跑在生产环境里。这一部分讲部署链路里几个非常实际的问题属于那种没人提醒必然踩坑的细节。6.1 评估集设计别只盯着perplexity训练时看loss交付前必须看任务指标。我构建了一个三层评估体系通用能力层用公开的测试集比如CMMLU、CEval等监控模型是否在大规模SFT和RL后出现通用能力遗忘。领域能力层基于真实用户问题构建了一个约2000条的测试集分难度等级并带参考答案。这个集子要固定版本、固定排序避免后续迭代时因为测试集变动而无法对比。安全与合规层根据行业要求构建了敏感话题和多轮对话压力测试集确保模型输出不出格。我还养成了一个习惯每天训练完都跑一遍快速评估集约500条。这一步能最早暴露数据污染、过拟合或能力崩塌等问题。等全部训练完再评估很多问题已经病入膏肓了。6.2 量化与推理加速把模型塞进普通GPU1.4B模型在A100上跑自然毫无压力但生产环境不可能给每个实例配一张80G的卡。我需要用更廉价的推理方案。我做了几个事情INT8/INT4量化用GPTQ和AWQ两种方案对比最终AWQ在领域推理任务上损失更小。关键原因是AWQ会根据激活值的分布保留重要通道的精度比全局均匀量化聪明得多。KV Cache优化如果部署的是长上下文场景KV Cache可能比模型权重本身还占显存。这里主要是开启PagedAttention机制vLLM或SGLang都原生支持让显存按页分配而不是一次性预占。批处理与动态batching生产环境的请求到达率是波动的动态batching可以把等待中的请求聚合到一个batch推理显著提高GPU利用率。这一项优化通常能带来两到三倍的吞吐提升。6.3 服务化时的实际问题并发、时延与降级服务化还有一个很实际的问题推理服务不是无线程的。我给生产环境设置了并发上限超过上限的请求直接排队而不是无限堆积导致所有请求都超时。同时做了降级策略——如果自研模型在低置信度场景下输出不稳定会标记为需要人工复核而不是硬着头皮给用户一个错误答案。这里我强烈建议加一个请求日志和采样审计机制。每一次用户请求和模型输出都落库按天随机抽取一定比例做人工评估。这不仅是为了质量监控更是后续数据迭代的黄金来源——真实用户的坏case比你自己拍脑袋构造的测试集有价值十倍。7. 只有自己踩过坑才会懂的几条经验写到这里主干内容都讲完了最后分享几个贯穿始终的经验算是给这条路做个注脚。第一从零构建AI工程最大的成本永远不是显卡而是数据质量。你会发现绝大部分训练问题归根到底都指向训练数据不够干净、不够充分、配比不当。哪怕模型规模小一点只要数据扎实出来的效果都能让人眼前一亮反过来数据稀烂的时候堆再多卡也只是烧钱。第二接受训练是个玄学这个事实然后学会做实验记录。我建了一个非常朴素的台账每一次跑实验都记录数据版本、模型配置、学习率、loss曲线图、评估指标。模型训练这件事一切看似微小的改动都可能引发蝴蝶效应没有台账回顾时只能靠记忆去猜。到后来好几轮优化全靠翻这本台账才定位到复现问题的关键。第三小步快跑多次试验好过一次豪赌。与其毕其功于一役训练一个大模型不如先在小模型上把所有流程跑通验证数据和方案再放大规模。我用0.3B模型做各种尝试成本极低很多错误都是在那个小模型上暴露出并纠正的等确定方案后才在1.4B上正式跑。这个策略帮我避开了不少浪费算力的大坑。第四生产环境里模型的推理质量很重要但稳定性和可控性同样重要。你需要知道模型什么能做、什么不能做需要给异常输出做好兜底需要让业务方明确预期。一个偶尔惊艳但偶尔离谱的模型在业务方那里的信任度远不如一个稳定靠谱的模型。从零开始构建AI工程的这条路确实不比直接调API轻松但走完之后你会获得一个完全不同的视角你不再把一个模型当成黑盒去焦虑而是清楚地知道它在哪个环节可能出问题、在哪个环节可以优化。这种掌控感才是工程师在面对AI落地时真正的底气。后续如果有机会我再把强化学习部分单独拆开细讲。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。