资讯动态

从tokenizer到post training:中文大模型微调数据链路避坑指南

发布时间:2026/9/3 11:13:42 来源:尧图企业网站定制
如果你正在做开源大模型的后训练大概率遇到过这样的场景基座模型是从开源社区认真选出来的损失函数也在正常下降可生成结果就是不对劲。中文经常被拆成不完整的碎片同样的指令只要换一种表达输出就完全跑偏偶尔还会陷入同一句话的重复循环。很多人这时候会去调学习率、换更多的 SFT 数据、甚至怀疑模型结构却很少检查最容易被忽略的入口——tokenizer。模型并不是按“词”理解中文的它是按 token 序列理解中文的。Tokenizer 一旦不合适后训练阶段喂进去的数据可能从一开始就是错位的特殊标记被切碎、样本长度计数失真、回复内容被截断到半句话。所以post training 的下限来自数据入口在 tokenizer。这句话是本文的主线也是很多开源模型微调项目真正需要补上的一课。这篇文章不从“post training 的定义”平铺直叙而是从“从 tokenizer 开始”这个顺序来拆解整个链路先讲 tokenizer 为什么是中文 NLP 后训练最容易忽视的技术入口再讲 post training 到底解决了什么问题接着落到中文语料库的清洗与构建以及清洗后如何与 tokenizer 对齐最后给出一个最小可复现的数据准备示例并整理常见问题与工程建议。如果你正准备把开源基座模型应用到垂直领域这篇文章能帮你省掉不少试错环节。1. 为什么 post training 要从 tokenizer 讲起1.1 模型看到的语言是一串整数很多初学者会把神经网络想象成一个能直接“读中文”的系统其实任何 Transformer 模型都只认识离散的 token id。文本从字符串到整数张量中间必须经过 tokenizer。这个组件负责把“中文自然语言处理”切分成一个或多个 token再把 token 映射成整数 id。模型后续的注意力计算、损失计算、生成采样全部建立在这串 id 之上。如果 tokenizer 把一个中文常用词拆成了很多碎片模型不是“多花了几个 token”那么简单而是可能丢失了完整语义。比如一个模型把“自然语言处理”切成了“自”、“然”、“语”、“言”、“处”、“理”六个独立字虽然理论上模型仍能通过注意力机制学到组合关系但学习难度明显变大。更糟的情况是词表中根本没有某些字符文本中被替换成 [UNK]这些位置的语义信息直接丢失模型只能靠上下文猜测。从工程视角看tokenizer 的问题有很强的隐蔽性。它不像 loss 一样肉眼可见不像训练日志一样随时输出在微调阶段又很少被改动。于是当一个模型输出质量差时团队往往先怀疑数据量不够、超参不合理、指令模板不统一很少有人会去打印一条中文样本到底被切成了什么。但恰恰是这种“默认没问题”的假设会让很多后训练项目反复在同一类问题上踩坑。1.2 Tokenizer 在后训练链路中的位置post training 的完整链路可以概括为基座模型 高质量数据 后训练算法 对齐策略。数据生产者先决定语料从哪里来、怎么清洗、怎么组成对话然后通过 tokenizer 将样本转换成训练张量。模型训练过程中每一条指令、每一个回答都要经过 tokenizer 的切分。也就是说tokenizer 是数据与模型之间的“翻译官”它如果翻错了后续步骤很难救回来。这个入口在后训练阶段尤其重要因为后训练的数据通常不是长文本而是结构化的 prompt-response 片段。一个典型的 SFT 样本里包含 system 指令、用户问题、模型回答还可能包含各种特殊标记。特殊标记的 token id 是否稳定、是否能被正确保留、是否在长度截断时被切断都直接影响训练效果。我在前面提到的“隐形故障”主要有三种。第一种是特殊 token 被拆散比如某些分词器会把\s、im_start这类内容按符号切成多个普通 token模型无法识别这是指令边界。第二种是样本长度统计失真实际训练时 max_seq_length 按 tokenizer 统计可如果中文字符的 token 占比比预训练阶段更高同样长度的文本就更容易触发截断。第三种是词表覆盖不足垂直领域里出现大量新词、专业缩写、旧版词表没见过的字导致 [UNK] 频繁出现。理解这些问题后把 tokenizer 检查纳入后训练的第一道工序就是很自然的选择了。2. post training它是什么解决什么问题2.1 从预训练到后训练的分工大模型的完整生命周期可以粗略分成两个阶段预训练pre-training和后训练post training。预训练的目的是从海量文本中学习语言结构、世界知识和推理能力这个过程通常消耗巨大算力普通团队很难独立完成。post training 则是在预训练模型基础上用更小但更高质量的数据集通过指令微调、偏好优化等算法让模型学会遵循指令、按人类偏好回答、适配特定任务。很多人容易把 post training 理解成“再训练一下模型”这个说法不够准确。它更接近一种行为对齐基座模型本身已经有很强的续写能力但用户问“你是谁”时它可能不会像产品那样回答用户给出一个任务时它不一定会按步骤执行。后训练要解决的是让模型从“会说话”变成“懂规矩、会办事”。常见方法包括有监督微调SFT、奖励建模、基于人类反馈的强化学习RLHF/DPO以及针对特定能力的继续训练。SFT 负责教会模型输入输出格式RLHF/DPO 负责对齐人类偏好领域继续预训练则会把模型往特定知识方向再推一步。很多文章把它们统称为“对齐”或“指令微调”本文讨论的 post training更偏向 SFT 和偏好微调所依赖的数据组织方式。2.2 Post training 能让模型能力无中生有吗这是一个经常被误解的问题。从信息论角度看post training 很难为模型补充它在预训练阶段从未接触过的知识。它的主要作用是激活已有能力、调整输出分布、约束回答风格。如果模型在预训练语料里完全没有某个领域的细节知识仅在 SFT 阶段加入了 1 万条领域问答模型很可能只是把这些问答“背下来”遇到没见过的问法仍然答不出来。这个结论对做中文垂直领域项目的团队尤其重要。如果目标是让模型学会法律文书的固定格式post training 是有效的如果目标是让模型掌握某个小众行业的最新专业知识更稳妥的做法是补充领域语料做继续预训练或检索增强而不是指望 SFT 数据能覆盖一切。把 post training 定位成“适配与约束”就能避免在许多不切实际的预期上浪费精力。在实践中一个高质量 post training 项目的关键成功因素通常有三个一是基座模型本身在目标语言和任务上具备基础能力二是数据规模和覆盖面足够三是数据与 tokenizer 的适配工序完整。这三者中数据清洗和 tokenizer 适配反而是多数团队低估最深的部分。3. tokenizer 原理与中文场景下的关键差异3.1 Tokenizer 的四步工作流程一个现代 tokenizer 通常不是简单的“查词表”而是包含归一化、预分词、切分、后处理几个步骤。归一化负责把文本统一成标准形式比如全角转半角、大小写转换、去除不可见字符。对中文来说这一步还要处理全角标点、繁体简体混排、不同 Unicode 编码下的相似字符。预分词负责识别“候选词边界”英文可以根据空格和标点分但中文没有明显的空格边界很多分词器会退化成按单字或按字元序列处理。切分阶段才是真正决定 token 的地方常见算法包括 BPE、WordPiece、Unigram、SentencePiece它们使用不同的统计策略把文本切成词表内 token 的组合。最后的后处理阶段会补上 [CLS]、s、eos等特殊 token供模型使用。各算法对中文的影响差异很大。例如 BPE 和 WordPiece 通常依赖预分词结果对空格边界不敏感的语言支持较弱SentencePiece 把空格当作普通字符处理不依赖语言预先分词在日韩泰等语言里优势更明显字节级 BPE 则把文本映射到字节层覆盖所有 Unicode 字符不容易出现 [UNK]但代价是中文单字的 token 数可能变多压缩率偏低。下面用表格做一个比较。分词算法基本切分单位优点局限BPE字符或字节词表可控高频片段能合并依赖预分词中文需特殊处理WordPiece字符类似 BPE按似然增益选择合并多用于早期预训练模型定制成本稍高Unigram字符可输出概率适合子词正则化训练流程较复杂SentencePiece字符串空格也作为字符不依赖语言词边界适合中日韩参数配置需要调否则也会碎片化Byte-level BPE字节几乎不出现未知词覆盖所有字符中文 token 膨胀更明显序列更长在选择 tokenizer 时没有绝对最优方案关键看它是否和任务语言、模型训练阶段匹配。对中文项目首先应避免使用完全基于英文空格预分词设计的老化词表其次要实测中文文本的压缩率。3.2 中文场景为什么要单独关注中文文本没有类似英文的自然空格分隔词与词之间往往要靠语言知识判断中文单字的信息密度高常用字几千个就能覆盖绝大多数文本但专业词汇、人名地名、网络新词又层出不穷中文文本的标点、全半角、繁简混用问题也远比英文常见。这些特征叠加到一起对 tokenizer 提出了更高要求。还有一个容易忽略的指标压缩率即同样长度的中文文本最终会切成多少 token。压缩率越高意味着同样显存能放进去的样本信息越多训练和推理效率也更高。比如某个“字级别分词器”词表只有 8000 字中文确实不会出现太多 [UNK]但它很难把常见词组“自然语言处理”合并成一个 token导致序列特别长。而一个在高质量中文语料上训练出来的 BPE 词表可以把高频词、常见短语合并成较少的 token。读到这里你会发现后面讲中文语料库清洗和后训练数据格式时必须把 tokenizer 的特性考虑进去。因为同样的清洗规则对英文文本有效对中文不一定有效同样的截断逻辑在某个 tokenizer 下 OK换一个 tokenizer 后可能把回答尾巴截掉。4. 中文语料库post training 里最容易低估的工程4.1 高质量中文语料库不是“越多越好”构建高质量中文 NLP 语料库是 post training 项目的第一项大工程。很多人以为数据清洗就是把爬来的文本去个重、去掉广告实际上中文语料面临的问题比英文更杂网页文本里混杂大量脚本、版权导航、重复转载、繁简错乱内容新闻数据里可能包含时效性极强的旧信息垂直社区数据里往往有昵称、链接、签名档等噪声。如果把这些问题数据直接用于指令微调模型很可能学到错误的表达习惯。质量比数量更重要这句话在 post training 阶段尤其成立。预训练阶段可以用大规模数据让模型学习统计规律但后训练阶段人类期望的输入输出空间是有限的加入太多低质量样本反而会稀释高质量指令的权重。更合理的策略是先定义任务类型再围绕任务采集数据按一定比例混合通用指令、领域知识和安全负例。4.2 数据清洗的常规步骤与 Python 实现下面给出一段通用的中文语料清洗示例。这段代码适合从新闻、社区、网页等原始文本中提取干净正文同时也是“从数据清洗到模型训练全流程”中第一道工序的参考模板。需要注意数据清洗没有万能规则真实项目里要根据数据来源和下游任务不断调整。import re import unicodedata def clean_chinese_text(text: str) - str: if not isinstance(text, str): return # 1. 统一换行 text text.replace(\r\n, \n).replace(\r, \n) # 2. 全角转半角便于后续规则处理 text unicodedata.normalize(NFKC, text) # 3. 去除控制字符保留换行和制表符 text .join(ch for ch in text if ch or ch in \n\t) # 4. 去除 HTML 标签和脚本块 text re.sub(rscript.*?.*?/script, , text, flagsre.S | re.I) text re.sub(rstyle.*?.*?/style, , text, flagsre.S | re.I) text re.sub(r[^], , text) # 5. 去除链接、图片占位等噪声 text re.sub(rhttps?://\S, , text) text re.sub(rwww\.\S, , text) # 6. 压缩连续空白 text re.sub(r[ \t], , text) text re.sub(r\n{3,}, \n\n, text) return text.strip()代码逻辑并不复杂但每一步都有实际意义。第 2 步用 NFKC 归一化可以把全角英文、数字统一为半角避免同一个词因全半角差异被切分成不同 token。第 4 步处理 HTML 标签时特意先移除 script 和 style 内容防止文章中间夹杂的脚本被当成正文。第 5 步对 URL 的处理要谨慎如果任务是新闻标题分类链接本身就是噪声如果任务是信息抽取链接可能是值得保留的字段实际项目要按任务区分配置。清洗之后还要做去重。精确去重可以用哈希值判断适合处理完全重复的文本语义去重可以使用 MinHash、SimHash 等算法适合处理转载后略作改写的文章。对于一个真正的新闻语料库转载导致的长文本重复比例可能非常高如果不去掉这些重复模型容易在回答时反复复述某些固定段落。import hashlib def text_hash(text: str) - str: return hashlib.md5(text.encode(utf-8, errorsignore)).hexdigest() def dedup_exact(texts): seen set() result [] for text in texts: h text_hash(text) if h not in seen: seen.add(h) result.append(text) return result这个去重只适合验证流程真实项目通常还会对正文做“归一化后再哈希”忽略空白与标点差异。去重之后还需要根据任务手工抽检尤其是社区数据和领域数据必须检查是否存在拼写错误、敏感内容和版权风险。采集公开数据时要确认来源合法合规尊重目标网站的 robots 协议和版权声明涉及个人信息的文本一律过滤不能进入训练集。这是后训练数据构建中不可妥协的安全底线。4.3 数据配比后训练样本的“营养结构”清洗完原始文本之后还要把它们改造成后训练数据。最常犯的错误是只堆“问题-回答”比如收集几万条领域问答就拿来训练结果模型把所有回答都变成类似格式遇到不在语料里的问题时回答泛化极差。更合理的做法是参考一种分层配比通用指令数据占比不低于 20%保证模型基础的指令遵循能力不退化。领域任务数据根据垂直场景构造问答、摘要、改写、抽取等任务。对话多轮数据让模型理解上下文而不是只回答单轮问题。安全与拒答负例明确哪些输入不能执行避免模型无边界输出。这个比例不是固定公式却是一种工程经验post training 阶段的数据不是“越多越好”而是要让模型在通用能力与垂直能力之间取得平衡。如果在配比中发现领域数据占比过高建议优先补充通用指令而不是继续扩大领域数据因为灾难性遗忘通常发生在通用能力被领域语料稀释时。5. 清洗后还要与 tokenizer“对齐”不可跳过的细节检查5.1 指令模板与特殊 token 的稳定性当数据清洗完成准备把样本交给 tokenizer 之前有一道工序叫“tokenizer 对齐检查”。它是很多项目没有单独列出的步骤但非常重要。第一步是确认训练模板中的特殊 token 都存在于 tokenizer 词表中并且 token id 稳定。比如要构建如下格式的 SFT 样本system你是领域助手/system user什么是 tokenizer/user assistantTokenizer 是文本与模型之间的映射组件。/assistant在这里system、user、assistant这些标记必须作为独立的特殊 token 存在。如果 tokenizer 没有把它们注册进词表分词器会把尖括号、字母逐个切碎那么模型很难学到“从 assistant 标记开始生成回复”的规律。更隐蔽的问题是有些标记虽然以字符串形式出现在词表里但它同时匹配了普通文本中的相同内容导致训练时特殊 token 被误用。检查方法很简单加载 tokenizer 后打印这些特殊 token 的 id再把模板文本编码后解码回来看边界是否完整。不要省略这一步很多线上模型的指令遵循问题根因就是模板边界被 tokenizer 打乱了。5.2 长度预算与截断策略后训练样本通常需要设置一个最大长度。这个值既要能容纳尽量多的有效内容又不能超过显存上限和模型上下文窗口。如果把 max_length 设置得小于某些高压缩率样本的实际长度训练时可能出现一个现象样本里用户指令还没完整进入上下文模型的回答就已经被截断。这时候模型根本无法学会正确的指令输出。所以在真正跑训练之前应该先对清洗后的样本做一次 token 长度统计。用 tokenizer 把每一条 SFT 样本编码成 token id统计长度分布然后根据分布来决定 max_length 和截断策略。如果最大长度设成 2048但数据集中有 30% 的样本超过 2048那么这部分数据的尾部信息会全部丢失更合理的做法是把超长样本拆分、截断或过滤保证训练样本主体是完整的。5.3 用代码快速检查训练数据下面这段示例演示如何加载 tokenizer、统计单条样本长度并抽样检查 token 序列。这里不指定具体模型实际使用时把model_path替换成你的模型目录即可。from transformers import AutoTokenizer model_path /path/to/your/model tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue) sample system你是助手/systemuser什么是 tokenizer/userassistantTokenizer 是映射组件。/assistant encoded tokenizer.encode(sample, add_special_tokensTrue) print(token 数量:, len(encoded)) print(token 序列:, tokenizer.convert_ids_to_tokens(encoded)) print(解码还原:, tokenizer.decode(encoded))重点观察三件事第一特殊 token 是否以完整形态出现第二中文是否被切得过于零碎第三解码还原后是否能重新回到原始内容如果出现大量丢失内容或乱码说明 tokenizer 与文本之间存在兼容性问题。这段代码是整个后训练项目启动前的“体检单”每换一个新数据源、每换一个新模板都要跑一次。6. 一个最小的 post training 数据准备与训练配置示例6.1 构建标准化的 SFT JSONL 文件在数据清洗和 tokenizer 检查完成后第一步是把原始的问答对转成标准格式。业界最常见的做法是保存为 JSONL 文件每一行是一条完整样本。下面是一个参考格式{system: 你是一个熟悉自然语言处理的中文助手。, user: 请用一句话解释 post training。, assistant: Post training 是在预训练基础上用高质量指令数据让模型学会按人类期望方式回答的过程。} {system: 你是一个熟悉自然语言处理的中文助手。, user: 数据集清洗时发现大量重复文本应该怎么办, assistant: 先做归一化和精确去重再考虑用 MinHash 等方式处理近似重复。去重后建议人工抽样检查避免误删有效样本。}这种格式清晰后续可以很方便地把任意模板套上去。注意一点JSON 文件里的内容最好已经经过清洗和长度检查不要在训练代码里临时做复杂清洗那样既慢又难排查。6.2 用 Hugging Face 生态加载并 Tokenize 样本这里使用datasets库读取 JSONL并实现一个 tokenize 函数。由于涉及模板组装这个函数会同时完成特殊 token 拼接、截断和 padding 逻辑。from datasets import load_dataset from transformers import AutoTokenizer model_path /path/to/your/model tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue) tokenizer.pad_token tokenizer.eos_token # 若原词表没有 pad token按需设置 dataset load_dataset(json, data_filessft_data.jsonl, splittrain) def tokenize_sft(example, max_length2048): system example.get(system, ) user example.get(user, ) assistant example.get(assistant, ) # 按模板拼成一段文本 full_text ( fsystem{system}/system fuser{user}/user fassistant{assistant}/assistant ) # 为计算 loss 时区分“输入部分”和“输出部分”也记录回答的起始位置 prompt_text fsystem{system}/systemuser{user}/userassistant full_ids tokenizer.encode(full_text, add_special_tokensTrue, max_lengthmax_length, truncationTrue) prompt_ids tokenizer.encode(prompt_text, add_special_tokensTrue) labels full_ids.copy() # 输入部分不参与 loss 计算 labels[:len(prompt_ids)] [-100] * len(prompt_ids) return { input_ids: full_ids, labels: labels, length: len(full_ids), } processed_dataset dataset.map(tokenize_sft, remove_columnsdataset.column_names) print(processed_dataset[0])这段代码的关键是把“输入部分”的 labels 设置为 -100使模型只对 assistant 回答计算损失。实际项目中一些框架会自动处理这个问题但手动理解这个过程仍然很重要它能帮助你排查 loss 异常、过拟合回答模板等问题。6.3 后训练训练配置的参考项训练框架选择上不同项目的差异较大但从数据消费角度看核心配置通常包括以下内容。这里只列出参考思路具体数值要根据硬件、模型和数据集规模调整不能盲目照搬。model_name_or_path: /path/to/your/model train_file: sft_data.jsonl max_seq_length: 2048 learning_rate: 2.0e-5 per_device_train_batch_size: 8 gradient_accumulation_steps: 4 num_train_epochs: 1 logging_steps: 50 save_steps: 500 lr_scheduler_type: cosine warmup_ratio: 0.03值得特别说明的是后训练阶段通常不需要跑很多个 epoch。因为 SFT 数据量本身不大多次重复训练容易让模型死记硬背训练集中的回答方式损失函数虽然下降但泛化能力反而变差。在实践中1 到 3 个 epoch 是很常见的范围。如果训练到第 2 个 epoch 时验证集指标退化而训练集指标继续下降说明过拟合已经开始应该停止训练或重新增大数据量。7. 运行结果与效果验证7.1 训练前的数据验证很多项目在启动训练后才报错原因是数据 tokenize 过程没有提前验证。建议正式开始训练前先运行一段小脚本检查处理后的数据集统计 token 长度分布、打印若干条经过 tokenizer 解码后的文本、确认没有空样本、确认 labels 中回答部分仍保留有效 token。这一步至少能拦截掉一半以上的训练异常。import numpy as np lengths [len(item[input_ids]) for item in processed_dataset] print(样本数:, len(lengths)) print(平均长度:, int(np.mean(lengths))) print(最大长度:, max(lengths)) print(长度大于 1800 的样本占比:, round(float(np.mean([l 1800 for l in lengths])) * 100, 2), %)如果输出结果显示平均长度接近 max_length那么你应该重新检查截断逻辑看看大量样本是否被切断。尤其要观察被截断的样本是不是 assistant 部分超长。如果是可以考虑加长 max_length 或把超长回答拆分成多条训练样本。7.2 训练后的效果验证训练完成后不能只看训练集上的表现要用一批模型没见过的指令来测试。测试指令要覆盖不同难度简单定义、多轮对话、格式约束、拒绝回答等。下面是一个最简单的验证思路加载微调后的模型用固定前缀生成一段回答人工判断是否符合预期。from transformers import AutoModelForCausalLM, AutoTokenizer model_path /path/to/your/checkpoint tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue) model AutoModelForCausalLM.from_pretrained(model_path, trust_remote_codeTrue, device_mapauto) prompt system你是助手/systemuser请用一句话解释 tokenizer。/userassistant inputs tokenizer(prompt, return_tensorspt).to(model.device) output model.generate(**inputs, max_new_tokens256, do_sampleFalse) print(tokenizer.decode(output[0][inputs[input_ids].shape[1]:], skip_special_tokensTrue))检查生成结果时要注意几点回答是否完整结束是否包含不该出现的特殊 token对同一问题的多次回答是否稳定面对模型不了解的问题时是坦诚说明还是强行编造。如果只是 loss 下降但生成质量没有提升通常问题不在训练代码而在数据配比、模板格式或基座模型本身。8. 常见问题与排查思路下面把 post training 项目里最容易遇到的现象、原因和排查方式整理成一张表方便按图索骥。问题现象可能原因排查方式解决方案中文输出大量 [UNK] 或乱码词表对中文字符覆盖不足打印 tokenizer 对“中文测试”的编码结果更换更适合中文的 tokenizer或补充 special token 后重新训练训练 loss 降低但生成时出现重复句子SFT 数据重复度过高对数据做精确和近似去重增加数据多样性降低重复样本比例模型没有学会指令格式回复从 system 开始模板特殊 token 被切碎打印模板 encode/decode 结果把尖括号标记注册为 special token训练时 OOM单条样本 token 过长统计长度分布降低 max_length 或过滤超长样本回答总被截断max_length 设置过小查看样本中 assistant 部分长度增大 max_length或拆分长回答领域知识没有提升模型预训练阶段本身就缺该领域知识抽检模型对领域基础问题的回答补充领域继续预训练或使用 RAG灾难性遗忘通用能力变差领域数据占比过高用通用任务测试集评估增加通用指令数据比例验证集指标好实际使用差训练数据分布和线上分布不一致分析线上输入与训练样本差异补充更多线上真实分布数据排查顺序有一个基本建议如果生成结果怪异先回到 tokenizer 编码结果再检查样本模板然后看 loss 曲线最后才动模型结构或超参数。因为前两步是最便宜、最快的检查点也是很多人最容易跳过的。9. 工程建议与总结这几条经验是我在实际接触大量 post training 项目后最想提醒的内容。第一尽量沿用基座模型已有的 tokenizer不要轻易更换。凡是更换 tokenizer都需要重新扩充词表并做继续预训练否则模型学到的文本表示会被破坏。后训练阶段缺少足够算力去适配新词表因此最稳妥的做法是选择语言覆盖良好的基座模型然后继续使用它的原生 tokenizer。第二把 tokenizer 检查写进数据流水线而不是只做一次。每次新采集数据、每次修改指令模板都要重新统计长度分布、检查特殊 token、抽样看编码结果。这样能避免脏数据在模型训练阶段才爆发。第三数据配比要持续跟踪。建议给数据集里的每条样本打上来源标签比如 general、domain、safety、multi-turn训练时按比例采样。一旦发现模型回答风格单一或通用能力退化可以通过调整采样权重快速干预无需重新清洗全部数据。第四重视数据合规。采集任何中文语料前都要确认数据来源合法、内容可以用于模型训练。涉及个人信息、版权争议内容、未授权爬取的数据都应该从训练集中移除。构建高质量中文语料库听起来是技术问题但边界和安全问题优先级永远最高。回到开头的场景如果后训练效果不理想最先要问的不是学习率是不是设错了也不是模型是否还需要再调而是模型到底通过 tokenizer “看到”了什么。打印一段训练文本的 token 序列也许你会立刻发现所有异常都有了解释。对于想做更多实践的人来说下一步建议很具体先找一个开源中文模型用自己的领域数据构造 100 条 SFT 样本跑通从清洗、tokenizer 检查、训练、推理验证的完整链路再去追求更大规模的数据和更复杂的对齐算法。这条路径看起来朴素但它能帮你把每一个组件的边界摸清楚。后面等对基本功足够熟悉你会更容易理解 DPO、Long Context 扩展、继续预训练这些更深入的主题。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价