qinghuan
← 用数据改进可靠性 / 全部笔记

单元 27 / 用数据改进可靠性

P0 · 必会主线L2 · 进阶

建立不会自我欺骗的 Agent 评测集

把真实任务、正确行为和失败类型整理成固定测试数据,让每次改进都有同一把尺子。

本篇目录 · 按需要跳转

这篇重点学什么

本篇重点:写清系统允许和禁止做什么,把同一原始案例的变体归为一组,记录失败类型,并固定回归测试的版本与通过条件。

开始读正文 ↓
学过相近内容?查看哪些可以跳过

两条路线有些基础相同。已经学会的部分可以跳过,另一条路线只用来补你当前需要的内容。

数据划分与评测集

共同基础这组原则只学一次:先确定以后要处理哪些新数据,再据此给相关样本分组;同组不跨数据集,测试集不用来调参,并划清时间先后,避免测试内容的相同或近似版本提前进入训练。

另一条路线补充什么?

只用训练部分学习预处理参数,再复用参数处理其他数据(fit / transform);交叉验证时每折都在训练部分重新拟合。检查新实体上的效果,保存数据及处理结果的版本,并说明评测时哪些任务计入总数。

读完这篇,你能做什么

能建立三十例、五类任务的评测集,保留测试数据并对失败给出可核对证据。

学习理由、准备要求与知识点

为什么学它

没有固定样例和标注规则,就难以判断提示或框架升级是否有效。把同一案例族放在一组、提前留出测试数据,可以减少相似案例泄漏和反复按测试结果改方案的影响。

先读这些内容

知识点清单

  • 任务类型覆盖
  • 输入、资料和预期行为
  • 禁止行为约束
  • 开发验证测试用途
  • 按案例族分组
  • 数据泄漏
  • 标注版本及分歧
  • 失败分类与回归样例

运行前先确认完整算法使用 Java 17 标准库;JDK 源码基线为 OpenJDK 17 GA。示例是内存中的机制模型,外部服务接入需要另外配置和验证。

01先弄懂它是什么

评测集要代表真实工作,而不只是凑一批容易回答的题。每个用例至少写清输入、允许使用的资料、应该怎样做、哪些行为不允许。开放问题可以有多种正确表述,但权限、格式、来源和停止条件仍可明确规定。只有这些条件稳定,后面的分数才有可比较的含义。

可以让不同数据承担不同工作:开发集用来发现问题,验证集用来比较配置,测试集留作最终评价。同一案例的改写、从同一文档生成的问题,或共享答案模板的样本,彼此关联很强,应作为案例族一起管理。如果随机按行拆开,让近重复同时进入开发和测试,就容易得到偏乐观的成绩。

错误分类连接测量与修复。资料缺失、检索漏召回、引用不支持、Schema失败、工具越权、恢复重复执行和超时是不同问题。一个笼统失败率可以描述总体,但不能指导下一步,应保存首个决定性失败和必要的后续症状。

文中这几个词,先认一认

案例族
来自同一事实、文档或生成模板,彼此高度相关的一组测试用例,划分数据时应一起考虑。
数据泄漏
本该只用于最终评价的信息提前影响了开发或训练,让测试成绩显得比真实能力更好。
错误分类
用稳定的标签记录失败发生在哪、可能因为什么,方便修复后重测并安排处理顺序。

还有陌生词?到术语小抄里看一个具体例子 ↗

02看看它怎么工作

本题把案例族ID稳定散列到固定数量分组,族内所有行使用相同fold。输入顺序变化不会改变分组,同族新样本仍进入原组,适合建立可复现划分基线。不同族可能落在同一组,这不是碰撞错误,而是分组本来允许多个族共存。

用散列分组,只能提供一种稳定划分方式,不能保证各组样本数、类别和难度都平衡。例如一个很大的案例族就可能占去测试集大部分位置,所以划分后还要检查每组有多少族、多少行、分别是什么类型。若实际业务会随时间变化,应优先按时间或真实部署场景分组,不能一律套用随机散列。

使用SHA-256读取固定字节作为分组依据,避免依赖进程随机化的哈希实现。算法不需要散列的保密性质,它只需要稳定映射;族ID规范化政策也要固定,否则大小写或空白变化会把同族拆开。数据隐私仍需独立脱敏与访问控制。

正在加载流程图…

图中状态只描述本篇可执行机制;业务调用仍需由外层应用负责。
查看流程图源码(Mermaid)
flowchart LR
  T["任务与禁止行为"] --> C["用例和资料版本"]
  C --> F["识别案例族"]
  F --> S["按族或时间划分"]
  S --> D["检查分布与泄漏"]
  D --> E["评价与错误分类"]
  E --> R["脱敏回归样本"]

按顺序看,每一步做了什么

  1. 定义任务范围、允许资料和硬性禁止行为。
  2. 标注案例族、来源版本、难度及预期结果。
  3. 按族或时间划分集合,检查分布与泄漏。
  4. 建立稳定错误分类并保留标注分歧。
  5. 把真实失败缩成回归样本,测试集保持隔离。

03对照实现代码

OpenJDK 17 MessageDigest 源码 (新标签页)↗

OpenJDK 17 GA,jdk-17+35 · MessageDigest.getInstance / digest

下方为原创 Java 教学片段,调用已核验的 JDK API 说明局部机制;不是该类原样源码,也不实现神经网络。完整程序见算法模块。

核心机制代码 · java
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] bytes = digest.digest(familyId.getBytes(StandardCharsets.UTF_8)); // 固定编码,映射才稳定。
int hashPrefix = ByteBuffer.wrap(bytes).getInt();
int fold = Math.floorMod(hashPrefix, foldCount); // 处理负整数,结果始终在合法组范围。
// 分组散列不等于数据匿名化,原案例仍需脱敏与权限控制。

MessageDigest通过算法名称选择摘要实现,digest产生字节摘要并结束当前摘要计算。固定SHA-256和UTF-8让同一族ID在相同规则下得到稳定结果。

取摘要前四字节只用于分组,不用于唯一身份或安全验证。不同族映射到同组完全正常,不能把fold当成无碰撞标识。

MessageDigest对象有可变计算状态,不应在多个线程中未经协调共享。完整算法为每次族计算新实例,避免把线程安全问题混进划分演示。

散列只固定分组,不证明族定义正确、分布均衡或没有泄漏。相同文档的两个不同族ID仍可能被分到两侧,数据治理需要在算法之前完成。

代码先调用谁,再调用谁

  1. 确认稳定案例族ID
  2. UTF-8编码
  3. MessageDigest.digest计算摘要
  4. 转换固定前缀并floorMod
  5. 按fold检查分布及泄漏

04动手写一个例子

案例族稳定分组

输入唯一用例ID及非空案例族ID,给定组数k>=2,返回每行所属组;同族同组且与输入顺序无关。Java17程序使用SHA-256,不保证组大小均衡。

输入 1
id1与id2属于同family
输出 1
分到相同fold
输入 2
相同列表反向输入
输出 2
各ID的fold不变

每行分组只由案例族和固定组数决定,不使用行索引或处理顺序,因此同族在任何输入排列下保持相同分组。

用floorMod把可能为负的摘要前缀整数映射到零至k-1。Math.abs不能安全处理Integer.MIN_VALUE,直接取余又可能得到负数。

拒绝重复用例ID,避免结果映射覆盖导致样本丢失。空输入返回空映射,组数改变会改变划分,应作为数据集版本变更记录而不是静默调整。

为什么这样写是对的每个已处理ID唯一对应由其family和k决定的fold,范围在[0,k),同family永远同fold;不承诺不同family分到不同组。

时间 O(C+n)额外空间 O(n)

C为族ID总UTF-8字节数,摘要扫描输入,n为用例数;返回映射O(n)。本程序不缓存重复族摘要,缓存可减少重复工作但增加族表。

保存为 Main.java,运行 javac --release 17 -encoding UTF-8 Main.java,再运行 java Main。程序包含固定输入自测,断言失败时会抛出错误。

Main.java · 完整可运行程序 · Java
import java.util.*;
import java.security.*;
import java.nio.*;
import java.nio.charset.StandardCharsets;
public class Main {
    record Case(String id,String family){}
    static int fold(String family,int k){
        try{byte[] hash=MessageDigest.getInstance("SHA-256").digest(family.getBytes(StandardCharsets.UTF_8));
            return Math.floorMod(ByteBuffer.wrap(hash).getInt(),k); // 负前缀也映射到合法组。
        }catch(NoSuchAlgorithmException e){throw new IllegalStateException(e);}
    }
    static Map<String,Integer> split(List<Case> cases,int k){
        if(k<2)throw new IllegalArgumentException("fold count");Map<String,Integer> out=new HashMap<>();
        for(Case c:cases){
            if(c.id()==null||c.id().isBlank()||c.family()==null||c.family().isBlank())throw new IllegalArgumentException("case");
            if(out.putIfAbsent(c.id(),fold(c.family(),k))!=null)throw new IllegalArgumentException("duplicate case"); // 不覆盖同ID。
        }
        return out; // 映射只依赖族ID,不依赖行顺序。
    }
    static void eq(Object e,Object a){if(!e.equals(a))throw new AssertionError(a);}
    public static void main(String[] args){
        List<Case> x=List.of(new Case("1","familyA"),new Case("2","familyA"),new Case("3","familyB"));
        var a=split(x,3);eq(a.get("1"),a.get("2"));
        eq(a,split(List.of(x.get(2),x.get(1),x.get(0)),3));
        eq(Map.of(),split(List.of(),3));
        for(int v:a.values())if(v<0||v>=3)throw new AssertionError(v);
        try{split(List.of(x.get(0),x.get(0)),3);throw new AssertionError();}catch(IllegalArgumentException expected){}
        try{split(x,1);throw new AssertionError();}catch(IllegalArgumentException expected){}
        System.out.println("PASS 6 tests");
    }
}

这些特殊情况也要试一试

  • 同族分组一致不等于各组数量均衡。
  • 改变k或族ID规范会改变划分,需版本化。
  • 散列后的分组号不构成资料匿名化。
进阶选读 · 后续再读:分层分组与时间外推评估

场景案例族大小悬殊,关键类别在测试组中太少,或部署数据随时间变化。

做法按族保留约束的同时优化类别比例,可用贪心分配并检查偏差;时间问题使用前后时间切分,避免未来资料泄漏到开发。

复杂度精确平衡分组可以包含分区类组合优化,一般可能NP-hard;启发式更快但需报告残余不均衡。

好处与代价更均衡提高比较稳定性,但不能拆族换取漂亮比例;真实部署边界优先于形式上的平均分组。

05项目里怎么用

每个样本不只保存一段参考答案,还要写清使用哪版资料、允许读哪些内容、应该怎样做、哪些行为不允许。开放回答可以用评分量表(Rubric)评价,例如分别检查结论、依据和表达是否达标;不同措辞也可以合格。越权等硬失败则要单独判定,不能靠文风分补回来。两位标注者判断不一致时,应记录分歧并修订规则,不能悄悄挑对当前系统更有利的那一份。

失败归因先分层再细化,例如数据缺失、检索、生成、工具执行、状态恢复和外部依赖。一个错误可能有多重症状,优先记录最早决定性原因,并保留安全轨迹定位后续影响。分类名称和规则版本化,避免不同评测批次统计口径漂移。

新增回归样本来自实际故障时,先脱敏并确认资料授权,再缩成最小输入。开发人员可以使用回归集修复,保留测试集不能因每次看到失败就立刻调参;需要更新测试集时明确标记旧集已经参与开发。

容易踩的坑

  • 同一案例改写按行随机分散到训练和测试。
  • 只保存参考答案,没有禁止行为和授权范围。
  • 哈希分组被误解为均衡或匿名保证。
  • 反复用测试集调参后仍称独立测试。

几种做法,怎么选

表格有四列,窄屏可左右滑动查看代价和适用条件。

方案优势代价与限制适用条件
按案例族划分减少近重复泄漏组大小可能不均衡改写和同源资料样本
按时间划分接近未来部署变化分布差异可能较大持续更新知识与行为
分层分组保留类别覆盖需要额外优化和人工检查类别稀少且族关系明确

06检验是否读懂了

先自己想、自己写,再展开答案核对。场景题是假设的练习情境;遇到还没学过的内容,可以做完基础后再回来。

先用自己的话解释

01为什么按行随机切分可能泄漏?

展开参考答案与推导

同一事实或模板的近重复样本可能分到两侧,系统已经从开发样本获得测试信息,分数偏乐观。

02错误分类有什么实际作用?

展开参考答案与推导

把失败映射到可修复层,帮助决定补资料、改检索、收紧契约或修恢复,而非盲目更换模型。

03稳定哈希能证明没有泄漏吗?

展开参考答案与推导

不能,族ID必须先正确识别关联;不同ID仍可能同源,算法只执行既定分组规则。

换个情况,还会处理吗

01测试分数很高但新文档很差,查什么?

展开参考答案与推导

检查资料族或时间泄漏、训练测试分布差异及新版本覆盖,再建立真正独立的时间或文档族评估。

02一个大案例族占大半测试集怎么办?

展开参考答案与推导

保留族完整性,报告分布并采用分层分组或按族加权,不能拆族只为让数量好看。

03标注者对正确答案分歧很大,如何处理?

展开参考答案与推导

修订任务定义与Rubric,保留分歧及不确定标签,必要时排除无法稳定评价的项但报告原因和数量。

写代码试一试

01输入反转为何fold不变?

输入 / 条件
同一ID与family换行序
输出 / 预期
映射相同

提示 不使用索引。

展开参考答案与推导

分组只由family的稳定摘要和k决定,行位置不参与计算,因此置换输入不改变每个ID结果。

02为什么不用abs(hash)%k?

输入 / 条件
hash=Integer.MIN_VALUE
输出 / 预期
abs仍可能为负

提示 整数极值边界。

展开参考答案与推导

最小负整数绝对值无法用int表示,使用floorMod保证结果在合法非负范围。

03如何检查族泄漏?

输入 / 条件
同family在两个已划分集合
输出 / 预期
报告冲突族

提示 先按family聚合集合名。

展开参考答案与推导

为每个族收集出现的分组,数量大于一即违反约定;这个检查应在导出后再次运行。

读完之后,独立完成

课后作业:自己做一遍

本篇共 12 道作业,先完成 9 道基础与综合任务,再按前置知识挑战进阶题。其中包含 2 道思维拓展,试着换个条件,看看原来的办法是否还管用。不附参考答案。

这次练什么

能建立三十例、五类任务的评测集,保留测试数据并对失败给出可核对证据。

本篇重点加练

案例族与标注版本影响评测独立性和可比性,需要检查数据更新后的连带变化。

  • 按案例族分组
  • 标注版本及分歧

重点内容会多练几次。先说清楚怎么做,再试试空数据、出错或条件改变时会发生什么。

先自己做,卡住时记下问题,再回来查。问答题写清“为什么、什么时候适用”;动手题留下输入、输出和运行步骤,方便下次重做。

基础必做

  1. 作业 01原理问答

    为学习助手建立任务覆盖矩阵,至少包含问答、计划和工具执行,分别写输入资料、允许结果与需要保存的验证证据。

    提交内容
    一份独立书面回答或标注图,包含自造例子、概念边界及判断依据。
    怎样算完成
    • 逐项回应题目要求,区分事实、假设与个人判断。
    • 能用自己的例子解释适用条件,记录尚未弄懂的点。

    练到的知识点任务类型覆盖 · 输入、资料和预期行为

  2. 作业 02代码推演

    为同一任务构造一个表面成功但违反禁止行为的案例,说明开发、验证和测试集分别如何使用该样本并记录版本。

    提交内容
    手工推演记录,写明输入约定、中间状态、最终判断;可运行时附程序对照记录。
    怎样算完成
    • 推演包含中间过程,数据形状、单位、顺序或状态前后一致。
    • 主动检查至少一个边界或异常条件,能解释手算与运行差异。

    练到的知识点禁止行为约束 · 开发验证测试用途

  3. 作业 03原理问答

    为新增样本定义所属来源组的标识与标注版本,说明同一原始案例的改写、修订和分歧标签各应保留什么关联记录。

    提交内容
    概念或合同说明、关系图与自造案例,明确事实、假设和适用条件。
    怎样算完成
    • 关键概念有明确边界,能用案例检验声明。
    • 未获证据支持的假设单独标注。

    练到的知识点按案例族分组 · 标注版本及分歧

综合应用

  1. 作业 04面试场景

    五条问题改写自同一原始笔记,另有三条独立问题。设计案例族划分和泄漏审查,解释你希望评估的部署泛化目标。

    提交内容
    场景分析与决策记录,包含信息缺口、约束、备选方案和验证计划。
    怎样算完成
    • 方案回应给定约束,列出至少一种替代方案及代价。
    • 每项关键结论说明所需证据,不能核实的部分明确标注。

    练到的知识点按案例族分组 · 数据泄漏

  2. 作业 05编程实践

    编写小型评测集检查器,发现缺标注、版本冲突与分类缺失;将一条真实或自造失败转成可回放回归案例,保留来源和分歧记录。

    提交内容
    可复现的最小程序或实验材料、自写测试、环境说明与运行记录;题目允许纸面实验时提交完整案例表。
    怎样算完成
    • 提交物按说明可以重现;测试覆盖正常、边界与失败场景。
    • 运行证据与断言能核验声明的行为,注明模拟与真实执行范围。

    练到的知识点标注版本及分歧 · 失败分类与回归样例

  3. 作业 06排错实验

    故意把近重复样本分散到开发与测试两侧,检查现有检测流程能否发现,记录检测条件与无法自动判定的情况。

    提交内容
    最小故障输入、复现步骤、观测记录、定位依据及回归用例。
    怎样算完成
    • 其他人可按记录复现故障,并区分现象与已验证原因。
    • 定位过程有观测依据,回归用例可以再次暴露原问题。

    练到的知识点任务类型覆盖 · 按案例族分组 · 数据泄漏

  4. 作业 07编程实践

    实现本地评测集差异审计器,对两版样本清单检查族分组、标签变更和遗漏来源,生成需要人工复核的清单而非直接覆盖旧标签。

    提交内容
    可复现的小程序或题目允许的离线实验、自写测试、输入和运行记录。
    怎样算完成
    • 输入、环境和运行过程可重现,测试覆盖声明的重点条件。
    • 验证目标由合同确定,模拟结果不冒充真实服务证据。

    练到的知识点按案例族分组 · 标注版本及分歧

  5. 作业 08排错实验

    将原本不同的两个案例族发现为同源后合并,检查既有划分和历史报告中哪些记录受到影响,并保留追溯证据。

    提交内容
    最小故障序列、观测记录、原因核对与可再次触发原问题的测试。
    怎样算完成
    • 故障可以稳定重现,现象与已验证原因分开。
    • 观测记录足以判断声明的合同是否被违反。

    练到的知识点按案例族分组 · 标注版本及分歧

  6. 作业 09面试场景

    标注政策升级后系统得分提高,但模型没有变化。制定重算、并行报告与不可比较项的处理协议,区分能力变化与口径变化。

    提交内容
    场景评审记录,包含约束、备选方案、未决信息和验证计划。
    怎样算完成
    • 方案回应题目约束,取舍能对应到可核验的事实。
    • 给出失败或条件变化时的检查方式。

    练到的知识点按案例族分组 · 标注版本及分歧

进阶挑战 · 掌握前置后选做

  1. 作业 10设计评审

    设计测试集更新政策,处理新功能、暴露过的测试题和标注修订,给出版本间可比性声明及人工审查计划。

    提交内容
    设计评审文档或对照实验报告,包含前置条件、方案取舍、验收证据与尚未验证的范围。
    怎样算完成
    • 比较使用一致条件与事先声明的标准,记录失败与未知结果。
    • 说明方案的适用前提、未覆盖风险及后续验证方法。

    练到的知识点输入、资料和预期行为 · 开发验证测试用途 · 标注版本及分歧

思维拓展

先写出你的猜想,再用例子或实验验证。答案可以不同,但要说清依据、适用情况,以及还有什么没弄懂。

  1. 作业 11思维拓展 · 反例构造

    构造“测试集条目ID没变,所以两次评测严格可比”的反例,要求只改变案例族关系或标注版本,并说明如何检测。

    提交内容
    具体反例、原主张的适用前提、复现或逻辑证明及结论边界。
    怎样算完成
    • 反例满足原主张所声称的前提,确实针对其结论。
    • 说明一个反例能推翻什么、不能进一步证明什么。

    练到的知识点按案例族分组 · 标注版本及分歧

  2. 作业 12思维拓展 · 开放探究

    设计标注不确定性的敏感性分析:对存在分歧的样本采用两套事先声明的政策,观察系统排名是否稳定,并报告无法下定论的情况。

    提交内容
    可证伪假设、预先声明的比较协议、小规模证据与限制说明。
    怎样算完成
    • 假设存在可被否定的条件,协议在观察结果前声明。
    • 包含不支持假设的可能结果及不确定性说明。

    练到的知识点按案例族分组 · 标注版本及分歧

完成后,再检验一次

给每题标记“独立完成 / 查阅后完成 / 尚未完成”。查过资料或没做出的题,记下卡在哪里。隔一天换一组输入再试,能解释结果和出错原因,再把这个知识点标为掌握。

继续阅读

先看能帮你完成当前练习的部分。例子跑通后,再读更深入的解释。

  • 必读实践指南英文

    scikit-learn:数据泄漏与常见陷阱 (新标签页)↗

    阅读数据泄漏、先划分数据及随机性管理;把相同原则用于提示选择和保留测试集。

  • 实践实践指南英文

    Spring AI:Evaluation Testing (新标签页)↗

    阅读 EvaluationRequest、相关性与事实评估接口,理解模型评分的输入并配合独立人工标注。

  • 深入参考文档英文

    Sentence Transformers:Evaluation (新标签页)↗

    查阅 InformationRetrievalEvaluator 的 queries、corpus、相关标注与指标,建立可重跑的检索评测。

  • 实践实践指南中文

    OpenCompass 中文:分数前面还经过了哪些处理 (新标签页)↗

    先看“已支持评估指标”和“如何配置”,标出 evaluator、pred_postprocessor、dataset_postprocessor。自拟三组答案,分别按原样比较和你明写的整理规则比较,记录差异;不要把自拟规则说成框架默认。首轮跳过代码执行评测、外部评分 API 和榜单排名。 正文公开可读,无需登录。阅读和手工练习无需模型;完整框架评测另需安装依赖、数据与可用模型,本轮未运行。

  • 实践实践指南英文

    Cleanlab:把可疑标签找出来,再由人核对 (新标签页)↗

    先看 Workflow 1 的问题表,再看 Workflow 3 的圈点图。挑三条疑似错标,写出还需哪份原始材料才能确认。留意预测概率须来自未用该样本训练的模型;低分也可能表示样本含糊。首轮跳过自动改标签、重新训练和总体健康分,不因模型不同意就删数据。 页面与结果表公开可读。完整运行需要 cleanlab、scikit-learn 等依赖;本轮未安装或训练。图上结果属于作者的合成数据,不能作为自有数据的效果承诺。

  • 深入参考文档英文

    OpenJDK 17 MessageDigest 源码 (新标签页)↗

    按指定版本定位 MessageDigest.getInstance / digest;对照源码分析理解实际调用边界。

打开资料库,找下一份学习材料 ↗