
如果你和当年的我一样天真地以为把开源 LLM 代码拉下来、找几个 TB 的语料、丢进显卡里跑起来就算完成了预训练——那这篇内容就是来帮你清醒的。我真正下场做 LLM 预训练再到把模型适配到垂直领域完整流程走下来最大的感受是预训练本身没什么玄学真正卡时间和精力的是数据和工程领域适配也不是临时抱佛脚它是一套从数据流转到评估闭环的方法论。这篇文章就是我从预训练到领域适配的完整实践记录涵盖算力预算、数据清洗、架构选型、训练监控、继续预训练、指令微调、评测和部署。适合准备真正下场的个人开发者和小团队参考至少能帮你把弯路缩短一半。1. 先算账再动手个人开发者做预训练的真实成本和三条可行路线1.1 一张 A100 也不够预训练的算力账怎么算很多人对训练大模型的难度没有体感我先给一个可以自己复算的公式。7B 模型从零训练 1T token理论计算量大约是6ND 6 × 7e9 × 1e12 ≈ 4.2e22 FLOPs一张 A100 80GB 在 BF16 下的峰值算力约 312 TFLOPS实际预训练场景因为数据加载、通信、空转利用率能到 50% 就算非常不错了。按 50% 算一张卡一小时干活 1.56e14 FLOPs。4.2e22 ÷ 1.56e14 ≈ 2.7e8 秒也就是单卡需要约 75000 个小时。8 卡 A100 要跑将近 390 天100 卡要跑 31 天。这个数字一出大多数个人开发者应该能清醒从零训练一个 7B 模型不是靠几张卡慢慢跑能解决的电费和卡折旧都受不了。但这不代表预训练不能碰。把目标降到 1.4B 模型、100B token6 × 1.4e9 × 1e11 8.4e20 FLOPs同样的算法8 卡 A100 大概需要 187 个小时也就是8 个白天黑夜的连续运行如果是 8 卡 4090大约要多跑一倍时间两周到一个月能出结果。所以个人开发者能碰的区域是小参数 百亿级 token 的预训练实验或者干脆不要从零训走下面的路线。1.2 个人开发者真正应该走的三条路线我实践下来性价比最高的不是从零预训练而是这三条路线核心做法典型资源产出可用性A. 基于开源底座继续预训练用领域语料对已有模型做全参或 LoRA 式 Continue Pretraining1-2 张 24GB 显卡起步高直接可用于领域适配B. 中小模型从零预训练1B 以下参数百亿级 token跑通完整数据流水线8 卡可跑单卡能跑极小模型主要用于学习和验证流程C. 外挂知识不训练RAG / GraphRAG 注入语料用提示词做领域适配无显卡也能做很多场景下效果比微调稳定路线 A 是绝大部分场景的正确起点。你现在能拿到的开源底座已经在大规模通用语料上花了几百万卡时你花几十万卡时未必追得上。继承底座学到的通用能力只把领域知识补进去才是个人开发者该干的事。路线 B 的价值在于理解原理而不是产出产品。我自己通过跑 1B 以下的实验才真正搞懂了 tokenizer、数据配比、学习率和 loss 曲线之间的关系。路线 C 最容易被忽视。我见过太多人花两周微调一个模型最后效果还不如直接把语料做成检索增强因为高频变化的私有知识本来就该放在外部索引里。领域适配的第一原则是能不训练就不训练。1.3 预算别忘了算上失败成本这里有个多数新手会踩的坑只算了理想情况下训练 10 天的费用没算失败重跑的成本。超参没调好要重跑数据清洗不过关要重跑训练中途 loss 爆炸也要重跑。按我的经验从零预训练项目预算至少按理想时间乘 2继续预训练和微调项目乘 1.3 就够。把评估和命令行测试的卡时也打进去别等要评测的时候发现卡被训练占用。2. 数据工程预训练和领域适配的真正分水岭2.1 语料清洗不是去掉 HTML 标签这么简单我最初做数据处理时以为清理语料就是去个 HTML、去个空白字符。实际跑起来才发现数据工程占整个项目的时间经常超过 60%而且数据的质量直接决定预训练曲线的平滑度和最终能力上限。我现在的清洗流程是原始语料统一编码去掉乱码和 BOM。启发式规则过滤超短行、重复符号、无意义字符比例过高的段落。文档级去重用 MinHash 做近似去重而不是简单按行去重否则代码、模板类文本会被误杀。质量打分用困惑度过滤低质文本也可以部署一个小型的 RoBERTa 类中文预训练模型做分类打分把低质段落筛掉。抽样人工检查规则永远有盲区每 10 万条抽样 100 条人工看一遍。这里要特别说去重。LLM 训练里重复数据会导致两个问题一个是浪费算力模型反复看同样的内容另一个是导致生成阶段出现复读机现象。MinHash 的具体参数我用的是 5-gram 分片、128 个哈希桶字段相似度阈值压到 0.7 以上才判重。2.2 tokenizer领域新词要不要扩展词表领域适配效果不佳很多时候不是模型不够大而是tokenizer 把领域专有词拆得稀碎。比如医疗术语、工程名词、行业黑话在底座词表里可能被拆成 4-5 个 token模型很难建立稳定的词级表示。做法是在领域语料上用 BPE 训练一个新词表和底座词表做合并把新词初始化成随机 embedding然后跟着继续预训练一起更新。注意词表别扩得太大增量控制在 5k 到 20k 比较合理否则 embedding 矩阵撑大的显存开销会挤占模型容量。图像领域有 ResNet 预训练权重语言领域有预训练底座思路是相通的通用特征要继承领域特征靠增量学习。DEIM 这类检测模型用 COCO 预训练权重也是同一个逻辑能继承通用视觉特征就没必要从零训。2.3 数据配比通用语料和领域语料怎么混配比直接决定模型会不会偏科或失忆。我常用的一套领域继续预训练配比参考数据来源占比说明通用文本30% - 50%保留底座通用能力防止灾难性遗忘领域语料20% - 50%核心知识注入来源要权威代码 / 结构化数据10% - 20%提升逻辑能力和格式遵循能力数学 / 推理5% - 10%少量即可太多容易改变风格不要用 100% 领域语料做继续预训练。我试过纯领域数据训太久通用问答能力明显下降最后只能回滚到混合配比。2.4 训练数据要做元信息管理每条数据从哪来、经过了哪个清洗版本、质量分多少、用在预训练还是微调都要能追溯。我吃过一次亏线上模型出问题往回翻数据发现某批数据的来源标注错了根本不知道它是网页还是爬虫导致定位问题多花了两天。简单做法是每批数据生成一个 JSON 清单文件记录来源 URL、抓取时间、清洗脚本版本、质量分区间。数据流水线做得越规范后面排查问题的成本越低。3. 架构与框架选型别急着抄 Llama先搞懂这几个模块3.1 主流结构的几个关键点要说人话现在开源底座基本都跑不出三类组件RMSNorm 做层归一化、RoPE 做位置编码、GQA 做分组注意力前馈层用 SwiGLU。你不要自己设计架构直接继承但要理解为什么。注意力里最常见的困惑就是 Key / Query / Value 到底在做什么。我的理解是Key 是我是谁、我有什么内容Query 是我在找什么、我关心什么Value 是我能提供什么。Attention 的过程就是让每个 query 去和所有 key 算相关性再按相关性把对应 value 加权求和。理解了这三者的分工后面排查长度外推、上下文污染、推理显存问题时都会清晰很多。GQA 的设计是为了省 KV Cache——推理时显存大头之一就是历史 token 的 K 和 V。如果你用的是 24GB 显卡部署模型GQA 的有无差别很大选底座时值得专门看一眼。3.2 框架选型个人开发者别背太重的轮子我第一版从零训练流程用的是纯手写训练循环结果被一堆分布式问题绊住。后来重新分工底层模型结构和训练循环HF Transformers 生态方便继承底座、加载权重。多卡并行DeepSpeed用 ZeRO 系列策略个人开发者不需要碰 Megatron-LM 那一套重工程。微调和继续预训练可以直接用 LLaMA-Factory 或 Axolotl 这类封装但前提是你理解底层在干什么否则出了问题没法定位。如果你是想读懂全流程我强烈建议先用一个几十万参数的玩具模型把训练循环跑通一遍再上真模型。这个步骤会帮你节省后面排查问题的大量时间。3.3 从开源模型继续训练时先确认架构一致性从已有底座继续训练时最容易踩的坑是架构参数对不上。位置编码最大长度、特殊 token 数量、attention mask 类型、嵌入层的 padding 规则都要和底座完全一致。需要扩展上下文长度时也没有直接改 max_position_embeddings这么简单。RoPE 要配合频率缩放如 NTK 缩放否则长文本位置编码会失真。我建议先用已有社区验证过的扩展方案不要自己改位置编码公式。4. 训练实战单机多卡并行、损失曲线与常见翻车点4.1 单机多卡的并行配置建议个人开发者最常见的是单机 2-8 卡。我的起步配置是BF16 混合精度 DeepSpeed ZeRO Stage 2 梯度检查点。ZeRO Stage 2 会把优化器状态分到各卡上对 7B 全参继续预训练来说8 卡 A100 比较稳如果只有 24GB 显存要么 ZeRO Stage 3 CPU offload很慢要么退一步用 LoRA 而不是全参。一个训练的启动命令大概长这样torchrun --nproc_per_node8 train.py \ --model_name_or_path Qwen/Qwen2.5-7B \ --per_device_train_batch_size 1 \ --gradient_accumulation_steps 32 \ --bf16 True \ --gradient_checkpointing True \ --learning_rate 2e-5 \ --num_train_epochs 2 \ --deepspeed ds_config_z2.json梯度累积到等效 batch size 越大训练越稳定但显存小的卡只能靠步数堆。个人实践下来等效 batch token 数在 0.5M 到 1M 之间比较合适太小 loss 波动大太大收敛太慢。4.2 超参从零预训练和继续预训练要分开看从零预训练学习率一般取 1e-4 到 3e-4warmup 需要 2000 步左右让模型先稳定下来。继续预训练就不一样了——底座已经是一个成熟模型学习率过大会把已有能力冲掉。我一般取 1e-5 到 3e-5warmup 500 步以内就够。AdamW 的 beta2 从默认的 0.999 调到 0.95在梯度噪声大的场景下会更稳定。很多人问继续预训练到底训多少步。我的答案是没有固定步数以评测为准。每隔 500 或 1000 步保存一个 checkpoint然后在领域评测集上对比选领域能力提升最大且通用能力下降幅度可接受的节点。4.3 训练不收敛先查数据别先改模型loss 不降或 NaN第一反应不是调学习率而是查数据。下面是我排查时的对照表现象大概率原因第一步操作训练爆 NaN数据里有异常值、embedding 溢出抽样检查当前 batch查数值范围loss 突然 spike某个低质量 batch 拉高了梯度定位到具体数据源去掉后再试loss 整体不降数据配比失衡、labels 错位先验证 100 条样本的 loss 是否在下降曲线平滑但效果差任务和语料不匹配或量不够重做数据别折腾模型结构验证 loss 回升过拟合 / 领域语料占比过高降低领域占比或提前停止如果你的 loss 经常在训练中段出现尖刺可以加 z-loss 这类稳定性辅助损失这在开源预训练里是常见手段。但根子上还是要先把数据洗干净。4.4 训练日志和断点恢复要养成习惯训练日志不是给老师看的是给自己将来排查用的。我每条实验中至少记录global step、当前 tokens 数、train loss、grad norm、当前学习率、每秒 token 吞吐、MFU模型利用率。checkpoint 不要只存最新的。我会每 500 步存一个至少保留最近 2 个和最优的一个防止中途崩溃后只能从头跑。lmsys 社区有个说法是训练事故发生概率和你 checkpoint 存储频率成反比话糙理不糙。还要提前做好断点恢复命令行里保留 resume 参数训练脚本支持 load 权重和优化器状态。真等机器断电再来补就晚了。5. 领域适配的分岔口继续预训练、指令微调还是外挂 RAG5.1 先给结论三种手段解决的问题完全不同这是领域适配里最容易被误解的地方。很多人觉得模型不懂我的业务那就微调一下吧但微调根本解决不了模型没见过某份私密文档的问题。手段本质适合解决什么继续预训练把领域知识写进权重是知识内化长期稳定的领域术语、行业逻辑、概念关系指令微调教模型按格式做任务是行为对齐总结、抽取、问答、格式输出等能力RAG / GraphRAG把相关知识放到外部索引是事实外挂频繁更新的私有文档、需要引用来源的问题偏好对齐调整回答偏好和价值观让输出风格、优先级更符合用户习惯一个常见误区和反面教材是把一些包含具体人名、金额、日期的高频变化信息放进训练数据里。等这个季度数据更新了模型还答着上个季度的错误事实又没法重新训练最后只能紧急上个 RAG 补救。动态事实别喂权重静态知识才值得训练。5.2 继续预训练的具体做法和防遗忘策略如果确定要走继续预训练路线步骤如下领域语料清洗到干净、权威、低重复。和通用语料按前面说的比例混合。学习率设为 1e-5 量级分块长度 2048-4096训练 1-3 个 epoch 以内。每次保存 checkpoint 后用领域评测集加通用能力抽测集做回归。防灾难性遗忘是最关键的。我的一套组合拳是通用语料保留 30%-50% 混入训练同时在每个 checkpoint 上跑一遍通用能力抽测比如 MMLU 的子集、简单的常识问答一旦掉点明显就降低领域语料占比或提前停止。结构化知识源对继续预训练特别友好。比如把本体ontology和图谱如 LLM wiki 这类结构化语料转成自然语言句子再喂给模型模型学概念间关系会比从纯爬虫文本里学快很多。GraphRAG 的思路也是类似的图结构本身是在帮模型压缩知识减少需要的训练量。5.3 什么时候应该选 RAG 而不是训练我现在的判断标准很简单信息更新频率高政策、价格、岗位、库存——RAG。需要回答有据可查必须给出来源——RAG。涉及私有文档和大量长尾问题——RAG。领域术语、推理逻辑、表达风格是长期稳定痛点——继续预训练或 SFT。混合方案是最常用的用指令微调把模型的抽取、总结、引用、拒答能力教好用 RAG 提供事实上下文。这样模型既知道怎么回答也知道用哪里的事实回答。6. 指令数据构造与高效微调把领域能力真正教会模型6.1 SFT 数据的质比量重要指令微调是领域适配的最后一公里。我最开始做 SFT 时堆了好几万条指令模型反而变傻。后来才明白对于已经具备通用能力的底座来说1k-5k 条高质量指令往往就够了50k 条弱数据的副作用可能比收益更大。高质量指令的核心不是多而是像任务类型多样总结、抽取、改写、多轮问答、工具调用都要覆盖。格式一致每条指令的训练格式和推理时保持一致。有依据涉及事实的问题必须基于给定文档作答不能编。有难度梯度既有简单抽取也要有需要多步推理的复杂问题。如果想用更大的模型蒸馏生成 SFT 数据可以但一定要人工抽检。AI 生成的数据有一个毛病表面通顺细节错误。作为领域开发者的你才是质量的最后把关人。6.2 LoRA / QLoRA 实操要点LoRA 的原理是冻结原权重插入低秩矩阵去学增量。我的常用参数参考参数推荐值说明rank16 / 32rank 太小学不进去太大会破坏底座alpha2 × rank控制增量缩放比例target modulesq_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj全注意力加 MLP 效果稳定学习率1e-4 到 3e-4LoRA 层新参数可以用稍大的 lrQLoRA 量化位宽4bit NF424GB 卡也能微调 14B用 LLaMA-Factory 或 PEFT 都可以。一个关键提醒如果你的继续预训练阶段扩展了新 token微调时 embedding 层必须一起放开训练否则新 token 的表示在 SFT 阶段学不到语义。训练一段时间后把 LoRA 权重和底座合并再转成你需要的推理格式。合并后的模型一定要重新评估一遍因为合并过程偶尔会带来精度损失尤其是量化底座上叠加 LoRA 时。6.3 指令模板和 chat template 的一致性这个坑看着小杀伤力极大。训练时如果用的是带系统提示词的模板推理时也得用一模一样的模板。很多人模型产出乱码不是模型问题是训练和推理模板不一致。HF 的 AutoTokenizer 自带 chat template我建议训练和推理都统一走它。不要自己拼字符串因为特殊 tokenBOS、EOS、think 标记等一旦错位模型的生成习惯就全乱了。6.4 偏好对齐小团队用 DPO 比 PPO 现实SFT 之后如果发现模型能力有但回答习惯不对——比如总把不相关的内容也长篇大论或者在多个可能答案里选了用户不想要的那个——可以做偏好对齐。DPO 是比 PPO 简单得多的方案不需要奖励模型只要构造偏好对数据。做法是针对同一个问题让当前模型生成多个回答再由人工或规则排序挑出一个偏好答案和一个次偏好答案形成训练对。个人开发者起步 500-2000 对就够了。注意偏好数据不要只挑正确 vs 错误更多要体现哪种表达方式更符合你的用户群这才是 DPO 的本职。7. 评测闭环从公开榜单到领域验收的可行路线7.1 公开榜单只能筛下限Open LLM Leaderboard 这类公开榜单可以帮你判断模型的基础能力有没有掉点但不要用它来验收领域模型。榜单上的题目是通用的你的领域可能根本不涉及这些任务而且榜单上的分数容易被刷高不代表真实业务里好用。我会把公开榜单当作回归测试来用每次继续预训练或微调前后都跑一遍保证通用能力没有退化到不可接受。真正决定模型能不能上线靠的是你自己的领域评测集。7.2 构建领域评测集50-100 条足够起步领域评测集不需要多到几百条50-100 条覆盖主要任务类型就够。关键是从真实业务里来。我见过很多人拿着自己写的高大上和奇葩问题做评测结果和线上用户问法完全两样。构造时注意覆盖单轮问答和基础抽取。多轮对话和指代理解。需要引用来源的事实题。敏感或越权问题的拒答能力。边界情况超长输入、混乱格式、空上下文。每次评测输出一定要人工看一眼不能只看一个指标。模型生成的答案可能语义正确但格式不对这时候你要判断是评测太严格还是模型确实没学好。7.3 LLM as Judge 的用法和三个偏差当评测集到上百条规模后一条条人工打分会很累。我现在的做法是先用强模型当裁判打分人工复核失败样例。LLM as Judge 有三个已知偏差要防位置偏差裁判容易偏向排在前面的结果——评测时随机交换两个答案顺序多跑几次。长度偏差裁判觉得越长越好——给裁判设定字数和要点约束。自恋偏差裁判更认可和自己风格接近的答案——如果是统一裁判至少保证它对符合规范的定义是你认可的。不要完全自动化。高风险、涉及真实用户利益的问题永远留一个人工复审环节。顺带提一句基于 LLM 的单元测试是个被低估的思路。把典型问题写成断言式用例模型的输出经过规则或小模型判断后自动通过/失败。这样每次迭代训练完直接跑一套自动用例比肉眼扫输出高效得多。你可以把这个逻辑接入 CI模型演进过程中只要用例挂了就拦下来。7.4 评测失败样本本身就是最好的训练数据评测不是为了打分是为了找问题。每次评测后把失败 case 分类是缺少领域实体知识是格式遵循不到位还是多步推理能力不够这个分析结果直接决定你下一轮动什么手段。比如大量报错都说错了术语那可能是继续预训练的领域语料不够或清洗不干净如果内容引用的来源错了那多半要检查 RAG 链路而不是训练。8. 部署上线与迭代量化、推理服务化、数据回流8.1 量化选型按部署场景选工具领域适配完成后模型要落地还得过量化这一关。我的选择逻辑方案适用场景备注GGUFllama.cpp本地单机、CPU 推理、边缘设备Q4_K_M 是性价比甜点AWQ / GPTQGPU 服务端需要高吞吐高质量量化后损失比动态量化小ONNX需要跨框架、配合现有推理管线onnx 部署 llm 是主流生产选择之一适合不想绑定单一推理引擎的团队操作上注意三点LoRA 权重先合并到底座再量化不要在量化后的模型上再叠 LoRA量化之后必须跑一遍领域评测集看损失能不能接受如果量化后明显掉点先检查是不是校准集选得不对而不是直接放弃量化。8.2 服务化从单卡推理到网关路由部署阶段如果用 vLLM吞吐量会比原生 HF 推理高出一个量级核心原因是它做了 Continuous Batching。个人部署我的建议是 vLLM OpenAI 兼容 API 起步。如果你手上有多个模型——一个通用底座、一个领域微调版本、甚至一个 RAG 增强版本——可以考虑前面加一层 LLM 网关做模型路由、API Key 管理和限流对外统一暴露一个地址。这样切流量和灰度发布都方便不必每换一个模型就改一次客户端。遇到过工具调用场景报错provider rejected the request schema or tool payload这多半不是网关问题而是模型 prompt 里 functions 的 schema 格式和推理服务不兼容先把 tools 参数格式对齐再查别的。8.3 线上数据回流让模型越用越顺模型上线只是开始。真正让领域模型越用越顺的是线上反馈数据回流。我会把用户行为里点赞 / 点踩 / 复制 / 追问记下来定期把坏案例抽出来做脱敏、去重、人工修正变成下一轮的 SFT 数据或继续预训练语料。这里提醒一个铁律不要直接把用户原始输入当训练数据。用户输入里有隐私、脏话、乱码直接灌进去迟早出事。正确路径是用户反馈 - 人工筛选 - 改写改写改写 - 进清洗管线 - 进数据集。迭代节奏建议每周跑一次 badcase review每月产出一版新微调模型。每次只改动一个变量——这轮只加数据下轮只调 LoRA 参数再下轮只换配比——否则出了问题你根本不知道是谁引起的。8.4 算力预算和迭代的配合训练和部署资源要分开规划。训练用高规格机器短租跑完就释放部署用小显存量化模型常驻。中间用网关做切换线上始终跑稳定版本新模型先在评测集上过关再灰度切一部分流量。个人开发者最怕的不是没资源是一次冲动把算力全砸在训练上结果没有预算迭代。如果只是做垂直领域问答先确认是不是一定要训练说不准一个 RAG 就解决了如果真的要训先把数据管好再上模型。最后说个我自己的教训我第一版领域模型在评测集上表现不错上线后才发现用户问法跟评测集相差太远。后来我把评测集改成从真实用户会话里抽样每次迭代都先过这 100 条效果判断才靠谱起来。训练 LLM 这件事技术方案从来不是瓶颈数据闭环才是。希望这篇记录能让你少走点弯路。