1. 首页
  2. 精选文章
  3. 经验分享!如何进行 Mid-train 以及 SFT 的 Query 筛选

经验分享!如何进行 Mid-train 以及 SFT 的 Query 筛选

  • 发布于 2026-05-08
  • 8 次阅读

作者:好奇的小逸
https://zhuanlan.zhihu.com/p/2035128896316756341

之前再做Mid-train和SFT时,积攒了一些经验,一直没有去写这方面的内容,这次就好好的总结一下相关的内容, 首先我们先有个认知就是:真正影响训练效果的,往往不是总量,而是样本的信息密度、覆盖面和分布是否合理

如果Query没筛好,常见的问题包括:

  • 大量重复样本让模型反复学习同一种表达
  • 某些高频任务占比过高,导致模型能力偏科
  • 指令形式过于单一,泛化到真实用户场景时效果差
  • 数据看起来很多,但真正带来增量的信息很少

因此,SFT数据筛选最好不要只靠人工“看着挑”,而应该按一套相对固定的流程来做。一个实用的顺序通常是:

先做去重,再做质量过滤,然后检查指令多样性,最后做类别配比和补齐。


1. 数据去重:先解决“重复学习”问题

去重是最基础的一步。因为如果重复样本太多,模型会把训练预算浪费在已经学过很多次的模式上。

在实际处理中,去重通常要分成三层。

1.1 精确去重

这一步处理的是完全重复或几乎完全重复的数据,常用方法包括:

文本标准化后做哈希去重

  • 统一全角/半角、大小写、空格、换行、标点形式
  • 去掉无意义前后缀,比如固定模板句、重复免责声明
  • 对标准化后的 queryquery + response 计算 MD5 / SHA1 / SimHash
  • 哈希相同则视为重复

这一步适合清理:

  • 完全重复爬取的数据
  • 不同来源但内容一样的数据
  • 仅换行、标点、空格不同的样本

1.2 近重复去重

很多数据不是完全一样,而是只改了少量词。 例如:

  • “帮我总结这篇文章”
  • “请帮我总结一下这篇文章内容”
  • “总结下面这篇文章”

这类数据如果大量存在,也会让训练信号过于集中。

常用方法:

n-gram Jaccard 相似度

  • 将 query 切成 2-gram 或 3-gram
  • 计算两个样本的 Jaccard 相似度
  • 相似度高于阈值(例如 0.85 / 0.9)时判为近重复

编辑距离 / 归一化编辑距离

  • 适合短文本 query
  • 对几十个字以内的指令效果较直观

SimHash + Hamming 距离

  • 适合大规模数据做快速近似去重
  • 可以先召回近邻,再做更精细判断

MinHash + LSH

  • 适合百万级以上文本集合
  • 能高效找出高相似候选对

实际工程里,一般不会直接全量两两比较,而是:

1.先标准化文本
2.用 SimHash / MinHash / LSH 做候选召回
3.再用 Jaccard 或编辑距离做精筛

这样速度和效果会比较平衡。

1.3 语义去重

语义去重处理的是“写法不同,但任务本质相同”的样本。

例如:

  • “把这段话换一种更正式的说法”
  • “请将下面内容改写得更书面一些”

字面上差异不小,但训练意义接近。如果这种数据占比过高,会挤压其他任务类型的训练空间。

常用方法:

Embedding 相似度去重

  • 使用文本向量模型将 query 编码成 embedding
  • 计算余弦相似度
  • 相似度高于阈值时判为语义近邻

聚类后簇内保留代表样本

  • 可用 KMeans、层次聚类、HDBSCAN
  • 每个簇只保留中心样本、最高质量样本或最具代表性的若干条

ANN 检索 + 阈值过滤

  • 用 Faiss / HNSW 建索引
  • 对每条样本搜索 top-k 相似邻居
  • 相似度过高时删除冗余样本

这里需要注意的是:

SFT 数据不应把所有语义相近样本都删光。

因为模型仍然需要学习“同一任务的不同表达方式”。所以更合理的做法不是“完全去掉语义相近样本”,而是:

  • 对高度冗余的簇做降采样
  • 每个语义簇保留 2~5 种不同表达风格
  • 保留不同语气、长短、约束条件下的变体

1.4 去重时保留哪条样本

当发现重复或相似样本后,不是随便删,而是要有保留规则。

常见保留策略:

  • 保留 response 更完整、更准确的一条
  • 保留约束更清晰的一条
  • 保留格式更规范的一条
  • 保留来自高质量来源的一条
  • 如果 query 类似但 answer 风格差异明显,可保留少量风格变体

2. 质量过滤:先把明显低质量样本剔掉

去重之后,紧接着就是质量过滤。

常见过滤规则包括:

2.1 格式质量

过滤掉以下样本:

  • query 或 response 为空
  • 文本截断、不完整
  • 大量乱码、HTML 残片、转义符污染
  • 多轮对话字段错位
  • system / user / assistant 角色混乱

2.2 内容质量

过滤掉以下样本:

  • answer 明显答非所问
  • 低信息量回复,如“好的”“收到”“不知道”
  • 大段重复句子
  • 强模板化、无实际任务信息的样本
  • 含明显事实错误或逻辑错误的样本

2.3 安全与合规

过滤或单独标记:

  • 泄露隐私信息的数据
  • 含违法违规、极端有害内容的数据
  • 敏感任务中未经审查的答案
  • 不适合当前模型目标的高风险样本

如果数据规模较大,质量过滤可以用“规则 + 小模型打分 + 人工抽检”结合的方式:

  • 规则先过滤明显脏数据
  • 分类器或 reward model 做质量打分
  • 人工抽检边界样本,防止误删

3. 指令多样性:不是多,而是结构化地多样

很多文档在说“要保证指令多样性”时,只停留在“问答、总结、分类都要有”这一层,这还不够。真正有效的多样性,至少要覆盖下面几个维度。

3.1 任务类型多样性

最基本的一层是任务意图覆盖。

常见类别包括:

  • 问答
  • 信息抽取
  • 总结
  • 改写
  • 分类
  • 翻译
  • 推理
  • 代码生成 / 代码解释
  • 创作
  • 结构化输出
  • 工具调用 / Agent 式指令

具体方法:

先定义任务 taxonomy

  • 不要先看数据量,而是先定义你希望模型具备哪些能力
  • 给每条 query 打上一级/二级任务标签

按标签统计占比

  • 看是否某几个类型过高

对头部类型做下采样,对缺失类型做补齐

如果没有现成标签,可以这样做:

  • 用规则关键词做初筛
  • 用 embedding 聚类找潜在任务簇
  • 再人工命名簇标签
  • 或用 LLM 对 query 做批量意图分类

3.2 表达方式多样性

即使任务类型一样,也要保留不同表达方式。

例如“总结”类指令,可以分成:

  • 直接命令式:总结下面内容
  • 请求式:请帮我概括这段话
  • 结果导向式:提炼成 3 个要点
  • 角色约束式:以产品经理视角总结
  • 风格约束式:用正式、简洁、口语化方式总结

具体方法:

句式模板聚类

  • 将 query 抽象成句式模板,例如“请帮我 + 动作 + 对象”
  • 统计模板分布,避免单一模板过多

基于 embedding 的表达聚类

  • 在同一任务标签内再做聚类
  • 每个簇保留若干不同表达

按语气标签采样

  • 命令式、礼貌式、口语式、专业式、模糊式、强约束式

3.3 输入长度与上下文形态多样性

真实用户不会总给一句简短指令。

还要覆盖:

  • 短 query vs 长 query
  • 有上下文 vs 无上下文
  • 单轮 vs 多轮
  • 非结构化文本 vs 表格 / 列表 / JSON
  • 干净输入 vs 含噪输入(错别字、口语、省略)

这里可以使用:

按 token 长度分桶采样,例如:

  • 0~32 tokens
  • 33~128 tokens
  • 129~512 tokens
  • 512+ tokens

按上下文类型打标签:

  • 单轮
  • 多轮
  • 文档问答
  • 表格理解
  • 代码上下文

对每个桶设置最小保留量

3.4 输出约束多样性

模型训练不只学“做什么”,还学“按什么要求做”。

所以要覆盖不同输出约束,例如:

  • 字数限制
  • 格式限制(JSON、Markdown、表格、列表)
  • 风格限制(正式、简洁、幽默、学术)
  • 角色限制(像老师、面试官、客服一样回答)
  • 步骤限制(先分析再回答、先列提纲再展开)

针对这些问题,这里可以使用:

  • 解析 query 中的约束字段
  • 将约束条件标准化为标签
  • 统计不同约束组合的频次
  • 对高频无约束样本降采样,保留更多有明确输出约束的样本

3.5 多样性不是平均分布

多样性不是把所有类别都做成完全一样多,而是要匹配模型目标。

例如:

  • 通用助手模型:任务面要广
  • 企业客服模型:问答、检索增强、多轮澄清占比可以更高
  • 代码模型:代码补全、debug、解释、重构的覆盖更关键

所以多样性控制的核心不是“均匀”,而是:

在符合目标任务分布的前提下,避免某一种模式过度垄断。


4. 类别覆盖与配比:解决“头部过多,长尾缺失”问题

实际数据分布常常是高度偏斜的,头部任务占了大多数。仅靠自然采样,最后得到的数据集往往不均衡。

4.1 先建立类别体系

常见做法:

一级标签:问答 / 总结 / 改写 / 分类 / 推理 / 代码 / 创作

二级标签:事实问答 / 开放问答 / 情感分类 / 摘要生成 / 风格改写等

领域标签:教育 / 法律 / 医疗 / 金融 / 通用办公 / 编程

交互标签:单轮 / 多轮 / 工具调用 / 长上下文

4.2 统计每个类别的样本量与质量

不要只看数量,还要同时看:

  • 样本数量
  • 平均长度
  • 平均质量分
  • 重复率
  • 失败率 / 脏样本率

有时候某个类别样本很多,但大量是低质量模板,实际有效占比并不高。

4.3 常用配比方法

方法一:固定配额采样

为每个类别设定目标样本数或比例。

适合:

  • 已知目标能力结构
  • 数据集规模可控
  • 希望结果稳定可解释

方法二:温度采样 / 平滑采样

对头部类别降权,对长尾类别升权,但不做到完全平均。

常见形式:

  • 按类别频次的 p_i^α 采样,其中 0 < α < 1
  • α 越小,分布越平
  • α = 1 接近原始分布

这种方法通常比强行平均更自然。

方法三:分层采样

先按大类分层,再在类内按质量、长度、表达方式进一步采样。

例如:

1.先保证总结、问答、改写、推理都有覆盖
2.再在“总结”类里保留短文本总结、长文总结、要点提炼、风格总结
3.最后按质量分排序保留前 N% 或分段采样

这是实践里比较推荐的方法,因为兼顾了覆盖和质量。


5. 如何用 NovelSelect 一类方法做“信息增量”筛选

如果完全靠人工筛选,很难同时兼顾去重、质量、多样性和配比,因此通常需要一种“样本价值评估”机制。

像 NovelSelect 这类方法,本质上是在回答一个问题:

这条样本相对于当前已选数据,是否还能提供新的训练信息?

5.1 NovelSelect 类方法通常关注什么

一般会综合考虑:

  • 与已选样本的相似度是否过高
  • 是否来自覆盖不足的任务簇
  • 是否提供新的表达方式或新的约束组合
  • 是否属于高质量、高信息密度样本

5.2 一种可执行的筛选思路

可以把每条样本的选择分数写成类似下面的形式:

score = 质量分 × 新颖性分 × 覆盖补偿分

其中:

  • 质量分:回答质量、格式完整性、人工偏好分
  • 新颖性分:与已选集合的最相似样本距离越大,分数越高
  • 覆盖补偿分:来自稀缺类别、稀缺长度桶、稀缺约束类型的样本加权更高

然后用贪心或分批迭代的方式选样本:

1.先选一批高质量种子样本
2.每轮计算候选样本与已选集合的相似度
3.优先加入高质量且与当前集合差异大的样本
4.对已经过饱和的类别降低权重
5.直到达到目标规模

5.3 它比简单随机采样好在哪里

随机采样的问题在于:

  • 容易重复抽到头部模式
  • 无法主动补足长尾能力
  • 很难控制信息冗余

而 NovelSelect 类方法更适合做:

  • 冗余压缩
  • 信息增量最大化
  • 类别覆盖补齐
  • 训练预算受限时的样本精选

6. 一个实用的数据筛选流水线

第一步:基础清洗

  • 去掉空样本、乱码、截断样本
  • 统一字段格式
  • 统一多轮对话结构

第二步:精确去重 + 近重复去重

  • 标准化文本后做哈希去重
  • 用 SimHash / MinHash / Jaccard 做近重复过滤

第三步:质量打分

  • 规则过滤
  • 小模型或 reward model 打分
  • 人工抽样校验阈值

第四步:任务与属性标注

给每条样本打标签:

  • 任务类型
  • 领域
  • 长度桶
  • 单轮 / 多轮
  • 输出约束
  • 风格 / 语气

第五步:语义聚类与多样性采样

  • 在 embedding 空间聚类
  • 每个簇保留代表样本 + 少量表达变体
  • 避免一个簇占比过高

第六步:类别配比

  • 对头部类别下采样
  • 对长尾类别补样或提权
  • 根据目标场景做最终分布调整

第七步:人工抽检

重点抽查:

  • 去重误杀率
  • 低质量漏网率
  • 类别标注准确率
  • 长尾类别是否真的保留住了

7. 实际执行时的几个经验

7.1 不要只对 query 去重

如果是SFT,对话质量往往由 query-response 对共同决定。

有些query 一样,但 response 一个好一个差,这种情况下不能只保留任意一条,而应优先保留高质量 answer。

7.2 不要把“多样性”理解成“随机性”

真正有用的多样性,是任务结构、表达方式、上下文形态和输出约束的系统性覆盖,而不是随便混入各种样本。

7.3 不要把长尾类别全部强行拉平

如果长尾类别质量低、标注噪声高,硬补太多反而会伤害训练。更好的做法是:

  • 先保证核心能力的高质量覆盖
  • 再逐步补长尾
  • 长尾类别不足时宁可少,也不要大量灌低质量数据

7.4 用小样本先验证筛选策略

不要一上来就在全量数据上跑复杂流程。可以先在一小部分样本上测试:

  • 阈值是否合理
  • 去重是否误删
  • 聚类是否把明显不同任务混在一起
  • 最终类别分布是否符合预期

先验证,再扩到全量,成本会低很多。