数据管道会加数据,不会删数据

配比、过滤、检索三层都在往管道里加东西,却没人能说清某个坏行为来自哪一批数据。三篇新论文各给出一个可复算的定位单位:域归因系数、百万级梯度对齐分、语句级血缘多项式。

工程实践 已修订 数据管道 数据工程 数据配比 数据过滤 数据溯源 数据定位 arXiv

加数据的人很多,删数据的人很少

一次线上行为退化的标准处理流程长这样:先加一道内容过滤器,再补一批干净数据冲淡,重新训一遍看指标有没有回去。这套动作里没有一步回答三个问题——出问题的那批数据在管道第几步进来的,它影响了哪些能力,把它拿掉要付多大代价。

管道每一层都在做加法。去重在加规则,过滤在加模型,合成在加样本,配比在加搜索。做减法的能力几乎为零,因为做减法之前必须先能定位,而定位是这套流程里唯一没人负责的环节。

10 月 27 日 arXiv 上的几篇论文给的也不是更强的过滤器,而是三个可复算的定位单位:配比层的域归因系数、样本层的梯度对齐分、答案层的语句级血缘多项式。三层的共同点是,原来那个搜出来、试出来的量被换成了能从账上读出来的量。

配比不是搜出来的,是回归系数

配数据配比的主流做法很直白:训一大批小 proxy 模型,每个用随机抽出来的一组域权重,再拿这些「配比—得分」对拟合一个回归,用回归去预测哪组配比最好。LinMix(arXiv:2610.37390)指出这里有个被忽略的身份转换——这套流程本质上是一个域归因问题,回归测的是每个域对目标指标的贡献。用这个视角一照,通行的 Dirichlet 采样就成了一种很差的回归设计:它要调 concentration 超参,采样出来的配比还都挤在先验配比附近,把归因误差放大,到了几百个域的规模根本撑不住线性拟合。

改法是把采样点挪到 capped simplex 的顶点上:每个域要么取到上限,要么完全缺席。这个采样没有超参,还能把域效应解耦开,于是线性模型的系数直接就是域归因。最优配比也就不用搜了——留下正系数的域,归一化,完事。作者还证明了顶点采样在这种设计下是最优的,并证明 Dirichlet 采样在配比集中时会抬高归因误差。

数字:1B 的 OLMo2 与 4B 的 Qwen3.5 上,LinMix 在推理、代码、数学三类基准上都超过基于 Dirichlet 的配比,MBPP 相对增益 46%、GSM8K 14%。在 288 个细粒度域的设置下,只有顶点采样还能撑住线性拟合,LinMix 相对最强非线性基线平均提升 11%。论文挂在 NeurIPS 2026 的 Attributing Model Behavior at Scale 工作坊上。

读这组数字要带两条限定。第一,46% 与 14% 是相对增益,不是绝对准确率的百分点,拿它去对账线上指标会差一个量级。第二,验证只做到 1B(OLMo2)与 4B(Qwen3.5)两档,288 域那组也是在 proxy 规模上做的;proxy 上归因出来的系数迁移到目标规模的稳定性,论文没有给出证据,所以「留正系数域、归一化」这一步在生产配比方仍然需要先小批量验证再全量推开。第三条限定藏在 cap 里:顶点是「取到 cap」或「缺席」,所以归因系数是在这个 cap 之下的域贡献;cap 变了,同一个域的系数可以变号。cap 不只影响方差,它定义了你问的那个问题。

工程上值得抄的是采样设计,不是回归本身:

import numpy as np

def vertex_mixes(n_domains, cap, n_mixes, rng):
    """capped simplex 顶点采样:每个域要么取到 cap,要么完全缺席。"""
    M = rng.integers(0, 2, size=(n_mixes, n_domains)).astype(float)
    empty = M.sum(axis=1) == 0
    if empty.any():                      # 全零行没有意义,补一个域进去
        M[empty, rng.integers(0, n_domains)] = 1.0
    M *= cap
    return M / M.sum(axis=1, keepdims=True)   # 每行和为 1
from sklearn.linear_model import LinearRegression
import pandas as pd

# X: 上面的配比矩阵,y: 对应 proxy 模型在目标指标上的得分
reg = LinearRegression().fit(X, y)
attribution = pd.Series(reg.coef_, index=domains).sort_values(ascending=False)
keep = attribution[attribution > 0]        # 只留正归因的域
best_mix = keep / keep.sum()               # 最优配比直接读出,不需要在候选里搜

三个踩坑点。第一,cap 别设得太小,域普遍顶到上限时方差会塌掉,系数分不开。第二,每个域都必须在若干次 mix 里既出现过也缺席过,否则共线性会把系数拉飞——顶点采样默认满足,但你手动加进来的「保底配比」会破坏它。第三,目标指标必须是你真正要优化的那个;归因是在给目标分配功劳,目标选错,归因就成了一份精确的错账。

一百万条数据里,哪一条在拖安全性的后腿

比配比更难定位的是样本。指令微调会悄悄侵蚀安全性,哪怕没有一条训练样本看起来有害——内容过滤器对这类数据无能为力,因为它判的是「这个样本像不像坏样本」,而问题出在「这个样本的梯度往哪个方向推」。

SimpleLoRIF(arXiv:2610.37481)的做法是把梯度归因从分析工具拉成可用的过滤器:简化一个低秩归因方法,并把反向传播限制在最后四个 transformer block 之内。这两刀把成本压下来之后,百万量级的数据集可以被整个嵌入一遍。它在 emergent misalignment 上先做了验证——梯度能把「不安全代码」的训练数据和微调之后出现的广泛有害行为连起来,在 misaligned 模型的梯度空间里 AUC 高达 0.865。

接着作者用它造了 SafeTulu:把 Tulu 3 里与不安全回答梯度最对齐的 20% 样本删掉。在 Qwen、Llama、Olmo 三个系列上训出来的模型,GCG 攻击成功率最多降 22%,优于 LLM-as-judge 与先前的梯度过滤方法,能力大体保持甚至略有提升。被删掉的那批数据还被翻出来做了归因分析,挑出两个此前少被研究的退化来源:工具执行失败,以及叙事里的算术。

作者一并放出了 SafeTulu 本体和一个 Hugging Face Space,允许按自己的需要改删除比例、或只对某个子集过滤后重建版本。这一点比 20% 这个数本身更重要:论文给的是一条可重算的排序,不是一个固定的配方,20% 只是在 Tulu 3 上跑出来的一个取值。

还有一个口径要分清:AUC 0.865 是在 emergent misalignment 场景里、在已经表现为 misaligned 的模型的梯度空间中测出来的。它证明的是「梯度能从训练数据连到事后出现的有害行为」这条链路存在,不等于任意一次安全性退化都能用同一条 unsafe 方向复现出同等区分度。上线前应当先在自己那批数据上复算一遍 AUC,再决定删多少。

可运行的骨架大致是这样:

import torch

LAST_K = 4   # 只回传最后 4 个 block,这是成本能降到百万级的关键

def grad_embed(model, batch):
    blocks = model.model.layers
    for b in blocks[:-LAST_K]:
        for p in b.parameters():
            p.requires_grad_(False)        # 前层不建图,省显存也省时间
    loss = model(**batch).loss
    loss.backward()
    grads = [p.grad for b in blocks[-LAST_K:] for p in b.parameters() if p.grad is not None]
    flat = torch.cat([g.flatten() for g in grads])
    model.zero_grad(set_to_none=True)
    return flat                            # 落盘,后续做低秩投影与检索

打分与删除:

import torch.nn.functional as F

# unsafe_dir: 用一小批已知有害回答的梯度嵌入取均值得到的方向
score = F.cosine_similarity(embeds, unsafe_dir.unsqueeze(0), dim=-1)
drop_idx = score.topk(int(0.20 * len(score))).indices

落地时有四条要守住。不安全方向必须用一小批已知有害回答的梯度构造,不要用关键词表——关键词表判的正是它判不了的那个东西。冻结层数是一个精度换成本的旋钮,上线前先在小子集上比对冻结与不冻结的分数排序是否同序,不同序就说明你砍掉了有信息的层。20% 是这篇论文的取值不是普适阈值,删除比例必须配能力回归兜底,否则你只是把安全性问题换成了能力问题。被删的那批数据一定要留档——它就是下一次出事时唯一的反查线索,删完不留痕等于把定位能力也一起删了。

答案对,不代表过程对

检索这一层的定位难度又高一级:GraphRAG 先建知识图谱再让 LLM 出答案,答案变得更难解释。GraphRAGProv(arXiv:2610.37237)的改法是绕过生成——在 source-grounded 的 RDF 图上直接跑 SPARQL 查询,把答案和它的 how-provenance 多项式一起算出来。

这个多项式记录的是「用了哪些 statement occurrence、它们是怎么被组合起来的」。每一处 occurrence 都链回源文本,于是用户可以顺着链接检查两件事:抽取出来的 statement 到底忠不忠于原文,查询有没有把它们正确地组合起来。查询本身成了一种审计 text-to-graph 变换的手段。作者的交互式 demo 检查了来自两个多跳 QA 基准的 400 个案例,结果是在最终答案正确的情况下,依然能查出抽取错误和查询错误。

对 RAG 管道来说,这条结论指向一个很具体的工程动作:把血缘记到 occurrence 级,而不是记到文档级。

{
  "answer": "...",
  "used_statements": [
    {"id": "s:0042", "subject": "...", "object": "...",
     "source_doc": "doc-17", "source_span": [1203, 1288],
     "extracted_by": "extractor@v3", "confidence": 0.71},
    {"id": "s:0088", "subject": "...", "object": "...",
     "source_doc": "doc-31", "source_span": [540, 602],
     "extracted_by": "extractor@v3", "confidence": 0.64}
  ],
  "combination": "join(s:0042, s:0088) -> filter(year > 2019)",
  "provenance_poly": "(s:0042 \u2297 s:0088) \u2295 (s:0042 \u2297 s:0113)"
}

有了这份记录,抽查的策略要跟着改:优先抽答案对的那批。错误的过程藏在正确答案后面,抽错了的那批只会重复你已经知道的事。

上游的披露不会自己继承

还有一层定位问题不在自己的管道里,而在管道的上游。一份针对预训练披露的文档审计(arXiv:2610.37465)用 2025 Foundation Model Transparency Index 的 24 个预训练相关指标,审计了 17 个家族的 41 个模型条目,做 24 组相邻版本比较。结果:11 组分数下降、6 组上升、7 组不变,合计 38 次指标丢失、28 次增益。

更麻烦的是总分会掩盖内部变化。OLMo-2 与 OLMo-3 总分完全相同,内部却是三增三减;Llama-3.1 相对 Llama-2 总分提升,却丢掉了两个数据相关指标的得分。语料构成与训练算力这两处的缺口一直在。结论很直接:新版本并不一致地保留旧版本的披露。

工程上的对应动作是别把「来源」存成一个名字。每个数据源应当存一份采集时点的披露快照:谁发布的、什么时候抓的、拿到了哪些字段、明确缺哪些字段。继承上游数据时默认新版覆盖旧版,是这类管道里最常见的一个无声假设。

语料构建这一侧还有个配套的坑。Lipi-Ghor(arXiv:2610.36184)是一份弱监督孟加拉语语音语料:885 小时音频,来自 596 个频道下的 998 个 YouTube 视频,覆盖有声书、戏剧、宗教布道、新闻、方言等 17 个域,每条录音按 SSTT 格式(Speaker、Speech、Transcription、Timestamp)标注,把自动 diarization 与 YouTube 字幕轨拼在一起。四个主流 ASR 模型在 zero-shot 与微调两种条件下,一致地在情感、方言、长音频上退化。

关键的是它的下一步处理:字幕目标本身带噪声,所以作者另发了一份人工标注的 gold 评测集——17 名志愿者、30 小时人在环路校正、按全部 17 个域分层。弱监督语料的目标不能跟评测集用同一份,这不只是一个语音项目的问题:凡是「用自动管线生成的目标训、又用同一份目标评」的管道,评测分数里就混进了目标噪声,而这部分噪声永远不会在你自己的指标里显形。

同一份语料还给出了一条容易被漏掉的披露信息:它的授权是分层的——视频 ID 列表、diarization 输出、管线代码与 gold 标注按 CC-BY-4.0 放行,字幕衍生转写仅限研究用途,原始音频完全不重新分发。这意味着「来源 = Lipi-Ghor」这个字符串里至少含三种不同的再分发条件,写进披露快照时必须分开记。上游审计那篇论文统计的 38 次指标丢失里,语料构成与训练算力是长期缺口;这一类授权分层通常连指标都没有,属于缺口之外的盲区。

定位能力才是管道的下一段工程

层位原来的量可复算的定位单位论文给出的刻度排查成本
配比搜出来的域权重线性回归的域归因系数MBPP +46%、GSM8K +14%、288 域 +11%小时
样本内容过滤器判有害梯度对齐分(可排序、可删)AUC 0.865、删 20% 后 GCG −22%天
答案最终答案对错语句级血缘多项式400 案例、答案正确仍有抽取与查询错天
上游来源名称采集时点的披露快照24 组比较中 11 降、38 次指标丢失周

这四层合起来指向同一件事:管道的下一段工程不是把数据洗得更干净,而是让问题能被定位。判据可以写成一句话——一次数据事故,能不能在不重跑整个管道的前提下,被指认到具体的域、具体的样本批次、具体的语句。

能指认到,做减法才有依据;指认不到,加再多过滤器也只是把下一次事故的发生时间往后推。

三个定位单位共有的一个前提

「可复算」不等于「可重算」。梯度对齐分依赖的是当时那个模型的参数与最后四层的结构,换一次基座、改一次层数,同一批样本的分值就得重算,历史分数不能直接跨版本比。语句级血缘依赖抽取器版本——上面那份 JSON 里 extractor@v3 这个字段不是装饰,抽取器升级后同一段源文本会产出不同的 statement,血缘链就断了。域归因系数依赖 cap 与目标指标的版本,两者任一变化,系数序列都要重起一条。

所以这四层落地时都要配一件配套的、不起眼的工程:把定位单位连同它的生成条件一起存。至少记模型版本与冻结层数、抽取器版本、cap 与目标指标口径、以及计算日期。少了这一份元数据,你存的就不是定位线索,而是一批无法复现的数字——下次出事时它和反查不了没有区别。

参考来源