这周最值得说的一件事:最值钱的训练数据不在 benchmark 里,在你生产日志的 before/after 字段里。但别急着开捞——那里面有个坑:人工修正过的 diff 确实是标注,可人会看漏。有团队跑了四万次游戏让人类审核 agent 的命令,漏了三分之一。修正日志是脏黄金,得淘。而且脱敏不是事后的清洗步骤,是埋点那天就要写进 schema 的事。
diff 才是标注,但信号是脏的
判断是:所有日志里,最值钱的字段是「模型输出了什么」和「用户最后接受了什么」这两列的差。用户把「已修改为」手动改成「已撤销」,这就是一条免费标注。同 session 里 agent 生成的路径和人类改完的路径之间的岔路口,就是模型认知出偏的地方。SFT 的时候 loss 应该算在这个 diff 上,而不是算在用户最终文本上——后者会把 agent 的废话也学进去。
但信号脏,脏在两处。第一,用户改你不一定是你错。可能是风格不合,可能只是手滑,也可能用户自己也没想好。第二,人看漏。scalex.dev 那篇热帖里,人类在 40k 次游戏运行中审核 agent 命令,漏掉了三分之一——是模拟环境里统计的,真实生产可能高可能低,我没更好的数字,但方向是对的:别把「人工改过」当成「人工改对了」。
过滤的办法,按我现在看有两招。看修改量级——把整段结果推倒重写,多半是风格冲突;只改了中间一句的事实描述,那才是内容错了。再看是否回滚——用户改完下一轮又改回去,说明第一次修正本身也是误操作。这两个信号做不了全自动,但能筛掉相当一部分噪声。
别把重试当作噪音丢掉,那是修正轨迹
重试日志是最容易被当成垃圾清掉的。但其实第一次失败 + 第二次成功这一对轨迹,比单独的成功案例信息量大得多。TRAJDEBUG 那篇讲的就是这个:agent 的最终失败往往不是最后一步的错,错误在轨迹前半段某个不起眼的位置,后面全是级联放大。
工程上的做法:每个 session 存 trace id,重试发生时保留两条完整轨迹。离线对齐两个事件序列——先归一化工具调用顺序,再找第一个行为分歧点。那个分歧点就是「修正发生的地方」,也是归因的位置。只存最终 success 标记是最亏的,因为结果不等于原因,你连模型在哪一步扭回来的都不知道。
反面说得对:成功案例会强化偏好
这个得正面接住。直接拿成功样本做 SFT,你只是在给模型已经会走的路加权重。日志里能被你捞到的成功样本,分布天然偏向模型舒适区——用户没打断、没重试、一路跑完,那些恰恰是它「本来就会」的任务。灌进这种数据,模型越训越自信,但边界一点没往外扩。
失败样本才是边界信息。它告诉你哪一步是模型认知和现实世界脱节的地方。但失败不能无脑当负例——工具报错可能是环境抖动,用户撤销可能是需求变了。所以归因得关联到 outcome:同 session 里失败后重试且成功了,这个「失败」才大概率是模型问题。单个成功是噪音,单个失败也是,失败加成功才是信号。
顺带说一句,捞完数据怎么验证有没有用,总有新东西——比如那篇讲任意时点停止评估的论文,能让「判断新数据是否带来提升」这件事跑得更省。但那是半个话题了。
脱敏得在埋点那一刻做,不是事后清洗
医疗领域那篇论文提了一个数字:EHR 特征工程占数据科学家工作量的四成。我信。从生产日志里捞训练数据,干的是一样的活——脱敏、字段对齐、清洗,大头全在这。
正确姿势是埋点时就做字段级分类。日志 schema 里直接声明哪些字段含 PII,写入前在采集层就 mask 掉,而不是存了原始数据、事后再跑一轮批量脱敏。后者必然漏,而且一旦漏了,你都不知道是哪批数据进了训练集。脱敏要进 CI,新字段上线没做脱敏标注不允许落库。这看起来慢,但比事后从模型里挖个人电话号码出来再去删干净,便宜得多。
这周 HN 热闹到 Cloudflare 说要出个「OS」、Qwen 刷榜什么的,跟捞数据这件事关系不大。回到操作层面,如果你手头刚好有 agent 在生产跑,明天先干一件事:去日志表里看有没有存 response_generated 和 response_accepted 两列。没有的话,先补上。其余的,等数据进去了再说。