
大模型这玩意儿现在被聊得神乎其神但你要是问一个刚入行的朋友“这模型到底是怎么从一堆文字里长出来的”十有八九得到的回答是“喂数据、调参数、等它自己学会”。这话不能说错但就跟说“把大象放进冰箱分三步”一样正确但没用。我前后参与过几个不同规模的模型训练项目从早期几亿参数的小打小闹到后来百亿级别的正经训练踩过的坑比吃过的饭还多。今天就从最源头的数据准备聊起把“LLM 模型是怎么训练生成的”这件事拆开揉碎讲清楚。数据准备是整个训练流程里最不起眼但最要命的环节模型效果好不好八成在数据阶段就定下来了。这篇文章适合对 LLM 训练好奇的开发者、刚转行做大模型的朋友以及想搞清楚“为什么我的模型像个智障”的同行。我会把数据准备的核心逻辑、实操细节、避坑经验全盘托出让你看完就能上手操作。1. 数据准备的整体设计思路拆解1.1 为什么数据准备决定了模型的天花板很多人拿到一个训练任务第一反应是赶紧搭网络、写训练循环、调学习率。我早期也这样结果就是模型训到一半 loss 不降或者降下去了但生成的东西狗屁不通。后来才明白模型本质上是一面镜子它反射的是你喂给它的数据分布。你喂它一堆低质网页文本它就学会说车轱辘话你喂它代码和数学题它就能写函数解方程。数据准备不是“把文本收集起来丢进去”这么简单它包含采集、清洗、去重、过滤、配比、格式化等一系列工序每一步都在塑造模型最终的能力边界。打个比方训练 LLM 就像教一个小孩说话。数据准备就是你决定让他听什么、看什么、跟谁学。你天天让他听菜市场吵架他开口就是脏话你让他听新闻联播和科普节目他说话就条理清晰。模型没有判断力你给什么它学什么。所以我在任何项目里数据准备阶段投入的时间至少占总周期的百分之四十有时候甚至超过一半。这个比例听起来夸张但做过的人都知道数据没弄好后面全是白费功夫。1.2 数据来源的选型逻辑与取舍数据来源的选择直接决定了模型的“知识面”和“语言风格”。常见的来源包括网页文本、书籍、论文、代码仓库、问答社区、百科类站点等。每种来源都有它的价值和坑。网页文本量大、覆盖面广但噪声极高广告、导航栏、乱码混在一起书籍质量高、逻辑连贯但获取成本高且版权复杂代码数据能提升模型的推理和结构化输出能力但格式特殊需要单独处理问答社区口语化强、贴近真实对话但容易包含偏见和错误信息。我在实际项目中的配比经验是这样的通用网页文本占大头大概六成到七成保证知识广度高质量书籍和论文占一成五到两成提升语言质量和逻辑深度代码数据占一成左右增强推理能力剩余部分留给问答和百科类数据补充对话感和事实准确性。这个比例不是固定的要根据模型的目标用途调整。如果做代码助手代码比例要拉到三成以上如果做客服对话问答和对话数据的比例要大幅增加。选型的时候还要考虑数据获取的可持续性和合规性别训到一半数据源断了或者收到侵权通知那就尴尬了。1.3 数据管线的架构设计原则数据管线说白了就是一条流水线原始数据进来经过一道道工序变成干净的、格式统一的训练样本出去。设计这条管线的时候我遵循几个原则。第一是模块化采集、清洗、去重、过滤、配比各自独立方便单独调试和替换。第二是可复现每一步的输入输出都要有记录随机种子要固定不然出了问题根本查不到是哪一步歪了。第三是可扩展管线要能处理从几十 GB 到几十 TB 的数据量不能数据一多就崩。第四是可监控每个环节的通过率、丢弃率、处理速度都要有统计方便发现异常。我见过不少团队把管线写成一个巨大的脚本从头跑到尾中间某一步出错就得全部重来。这种设计在数据量小的时候还能忍数据一上规模就是灾难。我的做法是把每个环节拆成独立的服务或脚本用统一的中间格式比如 JSONL串联每一步的输出都落盘下一步从盘里读。这样即使某一步需要调整也只需要重跑那一步和它后面的步骤前面的不用动。这个设计思路在后来几次数据量翻倍的时候救了我很多次。2. 核心细节解析与实操要点2.1 数据采集从哪里搞到海量文本数据采集是第一步也是最容易出问题的一步。常见的采集方式有几种公开数据集下载、网页爬取、API 接口获取、自有数据整理。公开数据集是最省事的比如一些学术机构发布的大规模文本语料直接下载就能用。但公开数据集往往有滞后性而且大家都能拿到训练出来的模型同质化严重。网页爬取能拿到最新最广的数据但技术门槛高要处理反爬、去重、解析等问题。API 接口适合获取特定平台的数据但有调用频率限制和成本。自有数据质量最高但量往往不够。我一般会组合使用这几种方式。先用公开数据集打底保证基础量然后用网页爬取补充最新内容最后用自有数据做精调。网页爬取这块我踩过的坑最多。早期用简单的请求库去抓结果被封 IP、被验证码拦住、抓到一堆 JavaScript 渲染的空页面。后来改用无头浏览器效果好很多但速度慢、资源消耗大。再后来学会了分析网站的接口直接请求数据接口效率最高。这里要提醒一句采集的时候一定要遵守目标网站的 robots 协议和相关规定不要给人家服务器造成压力控制请求频率该停就停。这不是技术问题是基本的职业操守。采集到的原始数据通常是 HTML 格式里面混杂着标签、脚本、样式。需要先做解析提取出正文内容。常用的解析库有 BeautifulSoup、lxml 等也可以自己写规则。解析的时候要注意处理编码问题中文网页经常出现 GBK、UTF-8 混用的情况不处理好就是一堆乱码。我的经验是统一转成 UTF-8遇到无法解码的字符用替换策略别让一个坏字符卡住整个流程。2.2 数据清洗把垃圾从金子里筛出去清洗是数据准备里最繁琐但最重要的环节。原始文本里有什么广告、导航栏、版权声明、乱码、特殊符号、多余空白、HTML 残留标签、JavaScript 代码片段。这些东西不清理掉模型就会学到一堆没用的模式。清洗的步骤一般包括去除 HTML 标签、去除特殊字符、统一标点符号、去除多余空白、处理编码问题、去除重复段落。我具体说一下每一步的操作意图。去除 HTML 标签是因为标签本身没有语义价值留着只会干扰模型。去除特殊字符是指那些控制字符、零宽字符、表情符号等这些字符在训练时可能引发编码错误或者被模型当成噪声。统一标点符号是因为不同来源的文本标点用法不一致比如中文引号和英文引号混用统一之后模型学到的模式更一致。去除多余空白是为了减少无意义的 token 消耗连续多个空格或换行对模型没有额外信息。处理编码问题前面说过了这里不重复。有一个细节很多人忽略清洗的时候要保留文本的结构信息。比如段落之间的换行、列表的标记、标题的层级这些结构信息对模型理解文本很重要。我见过有人清洗完把换行全删了整篇文本变成一大坨模型学出来的东西完全没有段落概念。正确的做法是保留有意义的换行只删除多余的空白。另外清洗规则不要一刀切不同来源的数据用不同的规则。比如代码数据就不能随便删特殊符号那些符号在代码里是有意义的。2.3 数据去重别让模型把一句话学一万遍去重是数据准备里最容易被低估的环节。互联网上的文本重复率极高一篇文章被转载几十次是常事同一段话出现在不同网页里更是普遍。如果不去重模型就会对这些重复内容过度学习导致生成时反复说同一句话或者对某些表达产生极端偏好。去重分为精确去重和模糊去重。精确去重就是完全一样的文本只保留一份实现简单用哈希就行。模糊去重是识别内容相似但不完全相同的文本比如改了几个词的转载文章这个难度大很多。我常用的模糊去重方法是MinHash LSH。简单说就是把每篇文档转换成一组哈希签名然后通过局部敏感哈希快速找到相似的文档。这个方法的原理是如果两篇文档内容相似它们的哈希签名也会有很高的重合度。具体操作是先用 n-gram 把文档切分成片段对每个片段做哈希然后取最小的 k 个哈希值作为签名。两篇文档的签名重合度超过阈值就认为是重复的。阈值一般设在 0.8 左右太低会误删不同内容的文档太高会漏掉改头换面的重复。去重的时候还要注意粒度。文档级去重是最粗的整篇文档重复才删。段落级去重更细能删掉文档内部重复的段落。句子级去重最细但计算量大一般只在特定场景用。我的经验是文档级和段落级结合使用先做文档级去重再做段落级去重。这样既能删掉整篇重复的也能删掉文档内部反复出现的模板化内容。去重之后要统计一下删除比例如果删得太多说明数据源质量有问题得回头检查采集环节。2.4 数据过滤留下真正有价值的内容过滤是根据一定标准筛选数据把低质量的内容剔除。过滤的标准有很多维度文本长度、语言类型、困惑度、重复率、敏感内容、特殊符号比例等。文本长度过滤很简单太短的文本信息量不足太长的文本可能包含大量噪声。我一般设置最小长度 50 个字符最大长度根据模型上下文窗口来定通常不超过窗口的两倍。语言类型过滤是用语言检测工具判断文本的主要语言只保留目标语言的数据。困惑度过滤是用一个小的语言模型计算文本的困惑度困惑度太高的文本通常语法混乱或者内容无意义。敏感内容过滤是必须的但要注意方法。简单的关键词黑名单容易误伤比如“杀”字在“杀菌”“杀毒”里是正常用法。更好的做法是用分类模型判断文本是否包含不当内容或者用规则加人工抽检结合。特殊符号比例过滤是统计文本中非字母数字字符的比例比例过高说明文本可能是乱码或者代码片段混入。重复率过滤是统计文本内部 n-gram 的重复程度重复率过高说明文本可能是模板生成的或者灌水的。过滤这块我的经验是宁可保守一点不要过度过滤。早期我设了一堆严格的过滤规则结果把很多有价值的文本也删了模型训练出来知识面很窄。后来调整策略过滤规则放宽一些把更多精力放在后面的配比和精调上。过滤的目的是去掉明显没用的不是追求完美。而且过滤规则要根据数据源调整网页文本的过滤规则和书籍的过滤规则应该不一样。3. 实操过程与核心环节实现3.1 环境搭建与工具选型动手之前先把环境搭好。我用的技术栈是 Python 为主配合一些专门的库。数据处理用 pandas 和 numpy文本解析用 BeautifulSoup 和 lxml去重用 datasketch 库实现 MinHash语言检测用 fasttext 或者 langdetect分词用 jieba 或者 sentencepiece。存储方面原始数据用对象存储中间结果用 JSONL 格式落盘方便流式读取。计算资源方面数据量小的时候单机就行数据量大的时候用 Spark 或者 Ray 做分布式处理。工具选型的原则是成熟稳定优先不要追新。数据处理这块有很多新出的库但稳定性参差不齐踩坑成本高。我用的这几个库都是经过大量项目验证的文档齐全社区活跃遇到问题容易找到解决方案。另外要注意版本兼容性不同库之间可能有依赖冲突建议用虚拟环境隔离。我一般用 conda 创建独立环境把依赖版本固定下来避免不同项目之间互相干扰。3.2 完整数据管线的代码实现下面是我常用的数据管线核心代码框架。这个框架是模块化的每个环节可以单独运行也可以串联起来跑。import json import hashlib from datasketch import MinHash, MinHashLSH from bs4 import BeautifulSoup import re def load_raw_data(path): 加载原始数据支持 JSONL 和纯文本 with open(path, r, encodingutf-8) as f: for line in f: yield json.loads(line) def clean_html(text): 去除 HTML 标签提取正文 soup BeautifulSoup(text, lxml) for script in soup([script, style]): script.decompose() return soup.get_text(separator\n) def normalize_text(text): 标准化文本统一标点、去除多余空白 text re.sub(r\s, , text) text re.sub(r[\x00-\x1f\x7f-\x9f], , text) text text.replace(“, ).replace(”, ) text text.replace(‘, ).replace(’, ) return text.strip() def compute_minhash(text, num_perm128): 计算文本的 MinHash 签名 m MinHash(num_permnum_perm) for i in range(len(text) - 5): m.update(text[i:i5].encode(utf-8)) return m def deduplicate(docs, threshold0.8): 基于 MinHash LSH 的模糊去重 lsh MinHashLSH(thresholdthreshold, num_perm128) seen set() for idx, doc in enumerate(docs): m compute_minhash(doc[text]) if lsh.query(m): continue lsh.insert(str(idx), m) seen.add(idx) yield doc def filter_by_length(docs, min_len50, max_len10000): 按长度过滤 for doc in docs: if min_len len(doc[text]) max_len: yield doc def pipeline(raw_path, output_path): 完整管线 docs load_raw_data(raw_path) docs ({text: normalize_text(clean_html(d[raw]))} for d in docs) docs filter_by_length(docs) docs deduplicate(docs) with open(output_path, w, encodingutf-8) as f: for doc in docs: f.write(json.dumps(doc, ensure_asciiFalse) \n)这段代码是简化版实际项目中每个环节都会更复杂。比如清洗环节要根据数据源写不同的解析规则去重环节要处理内存限制过滤环节要加更多维度的判断。但核心逻辑就是这样加载、清洗、标准化、去重、过滤、输出。每一步的输出都落盘方便调试和复现。3.3 数据配比与格式化的具体操作数据清洗完之后要把不同来源的数据按比例混合。配比不是简单地把文件拼在一起而是要按照 token 数量来计算。比如目标是通用网页文本占 65%书籍占 20%代码占 10%问答占 5%那就要分别统计每类数据的 token 总数然后按比例采样。采样的时候要注意随机性不能只取每个文件的开头部分。我一般用 reservoir sampling 或者先打乱再取。格式化是把数据转换成模型训练需要的格式。常见的格式有纯文本、JSONL、TFRecord 等。纯文本最简单每行一个样本。JSONL 更灵活可以带元数据。TFRecord 适合 TensorFlow 生态。我一般用 JSONL因为可读性好调试方便。格式化的时候要注意 tokenizer 的兼容性确保文本编码后不会出现未知 token。另外要预留一部分数据作为验证集通常占总量的百分之一到五用来监控训练过程中的过拟合情况。配比这块有一个经验不要一次性把所有数据都混好而是分阶段配比。预训练阶段用大规模通用数据让模型学到基础语言能力继续训练阶段加入更多高质量领域数据提升特定能力微调阶段用少量精标数据对齐人类偏好。这种分阶段的方式比一锅炖效果好很多而且方便调整。我在一个项目里试过一锅炖和分阶段两种方式分阶段的模型在评测集上高了将近五个百分点效果差距很明显。4. 常见问题与排查技巧实录4.1 数据准备阶段的典型问题速查数据准备阶段的问题五花八门我整理了一个速查表覆盖最常见的几类。问题现象可能原因排查方法解决方案训练 loss 不降数据质量差、噪声多抽样检查清洗后的数据加强清洗和过滤提高数据质量模型生成重复内容数据重复率高统计去重前后的数据量加强去重尤其是段落级去重模型知识面窄数据来源单一检查各类数据的配比增加数据来源调整配比训练速度慢数据格式效率低检查数据读取和解析耗时改用二进制格式预 tokenize编码错误频发编码不统一检查原始数据编码统一转 UTF-8处理异常字符模型输出乱码特殊字符未清理检查清洗规则增加特殊字符过滤验证集效果差训练验证分布不一致对比训练集和验证集来源确保同分布采样这个表里的问题我基本都遇到过。最头疼的是“训练 loss 不降”排查了半天发现是数据里混了大量乱码模型根本学不到有效模式。还有一次是模型生成重复内容查了半天以为是模型结构问题最后发现是去重没做好同一段文本在数据里出现了几百次。这些教训告诉我数据问题一定要在训练之前解决训练中发现问题再回头改数据成本高十倍。4.2 独家避坑经验与实操心得说几个文档里不会写但实际很重要的经验。第一数据准备阶段一定要做小规模试验。不要一上来就处理全量数据先拿一万条样本跑通整个管线看看每一步的输出是否符合预期。我早期直接上全量结果跑到一半发现清洗规则写错了全部重来浪费了两天。后来养成习惯先小规模验证确认没问题再放大。第二保留原始数据的备份。清洗和过滤会丢失信息有时候后面发现某个过滤规则太严想找回被删的数据如果没有备份就麻烦了。我一般把原始数据、清洗后数据、去重后数据、最终数据分别存一份标注好版本和处理参数。这样即使中间某一步需要调整也能快速回滚。第三监控每个环节的通过率。清洗环节的通过率、去重环节的删除率、过滤环节的保留率这些指标要实时统计。如果某个环节的通过率突然大幅变化说明数据源或者规则出了问题。我在一个项目里发现去重环节的删除率从正常的百分之十五突然跳到百分之六十查下来是采集环节抓了一个内容农场全是重复的模板文章。及时发现之后调整了采集策略避免了数据质量下降。第四tokenizer 要和数据处理同步。很多人先处理数据再选 tokenizer结果发现 tokenizer 对某些字符处理不好又得回头改数据。正确的做法是数据处理阶段就用目标 tokenizer 做验证确保文本编码解码后没有异常。特别是中文数据不同 tokenizer 的分词效果差异很大选一个适合目标语言的 tokenizer 很重要。第五数据配比要动态调整。训练过程中要监控模型在不同类型数据上的表现如果发现某类能力弱就增加对应数据的比例。我在一个项目里发现模型代码能力差检查后发现代码数据只占了百分之五后来调到百分之十五代码生成质量明显提升。配比不是定死的要根据训练效果灵活调整。4.3 数据质量评估的实用方法数据准备完之后怎么评估质量我常用的方法有几种。人工抽检是最直接的随机抽几百条样本人工判断质量。这个方法费时但准确适合在关键节点做。统计指标分析是看数据的长度分布、词汇丰富度、重复率、语言分布等和预期对比。小模型验证是用一个小的语言模型在数据上训练几步看 loss 下降情况下降快说明数据质量好。下游任务测试是用准备好的数据训练一个小模型在具体任务上评测看效果如何。这几种方法我一般组合使用。人工抽检做一次确认没有系统性问题。统计指标每次数据处理完都跑一遍监控数据分布。小模型验证在数据量大的时候做快速判断质量。下游任务测试在最终数据确定前做确保数据能满足任务需求。这套组合拳下来数据质量基本能控制在可接受范围内。数据准备这件事说起来都是泪。我见过太多团队在模型结构上花大力气在数据上敷衍了事最后效果不行还找不到原因。其实 LLM 训练这件事数据是根基模型是枝叶根基不牢枝叶再茂盛也是虚的。把数据准备做扎实后面的训练会顺利很多。下一篇文章我会聊模型结构设计和训练策略那是另一个充满坑的领域。如果你正在准备自己的训练项目先把数据这关过了别急着搭网络。