Article

AI Harness 实战 02:评测样本工程(从手工案例到可持续数据飞轮)

在第 01 篇里,我们搭好了 Harness 基线:

  • 样本可执行
  • 结果可对比
  • 回归可追溯

但团队很快会遇到第二个瓶颈:

  • 样本集越来越“过拟合旧问题”,新问题测不出来
  • 每次补样本都靠人肉,维护成本持续上升
  • 通过率看起来在涨,但线上事故并没有减少

这篇只回答一个问题:如何把“样本”从一次性资产,变成可持续演进的数据系统。

一、为什么评测会失真:不是模型退化,而是样本老化

很多团队把回归率波动归因给模型,但根因常在样本工程:

  1. 覆盖结构失衡
  • 黄金样本占比过高,长尾失败场景占比过低。
  1. 输入分布漂移
  • 线上真实请求变化了,离线样本还停留在两个月前。
  1. 断言粒度过粗
  • 只判断“看起来像对的”,没有验证关键约束是否满足。
  1. 样本生命周期缺失
  • 旧样本没人清理,失效样本持续污染结论。

所以第 02 步的重点不是“多加样本”,而是建立样本生命周期治理。

二、样本工程目标:四个可持续能力

你需要的不是大样本库,而是四项稳定能力:

  1. 可分层
  • 明确知道每条样本属于哪类风险与业务路径。
  1. 可演进
  • 样本可新增、可降级、可归档,不会越堆越乱。
  1. 可追因
  • 一次失败能快速定位到场景、规则、版本。
  1. 可闭环
  • 线上失败可低成本回流为离线可测样本。

三、样本分层模型:从“按来源”改为“按风险”

建议把样本集切成四层,而不是只分黄金/失败回放:

  1. L1-Contract(契约层)
  • 验证固定接口约束与输出格式,防止基础破坏。
  1. L2-Task(任务层)
  • 验证核心业务任务是否达标,是日常优化主战场。
  1. L3-Risk(风险层)
  • 聚焦高风险失败:越权、幻觉、错误执行建议、敏感操作。
  1. L4-Drift(漂移层)
  • 采样近期线上流量,监控输入分布与性能漂移。

这四层对应不同发布门禁强度:

  • L1/L3 失败可直接阻断
  • L2 失败按阈值告警或阻断
  • L4 主要用于趋势观察与提前预警

四、样本元数据:没有元数据,就没有治理

每条样本至少要带以下字段:

{
  "id": "risk_authz_20260416_001",
  "layer": "L3-Risk",
  "domain": "repo_write",
  "source": "production_incident",
  "created_at": "2026-04-16T09:30:00Z",
  "owner": "ai-platform",
  "severity": "high",
  "freshness_days": 14,
  "ttl_days": 90,
  "version": "v1",
  "expected": {
    "must_include": ["需要审批", "只读替代方案"],
    "must_not_include": ["直接执行删除", "绕过权限"]
  }
}

核心点只有两个:

  • freshness_days:多久必须复核一次
  • ttl_days:超过多久必须重写或归档

这样可以直接解决“样本永生”导致的失真问题。

五、自动补样本流水线:把事故变资产

建议建立最小闭环:

线上失败事件 -> 事件清洗 -> 脱敏 -> 归因打标 -> 生成候选样本
-> 人审(轻量) -> 入库(L2/L3/L4) -> 下次回归执行

关键原则:

  1. 自动提取上下文,不手工复制粘贴
  2. 默认脱敏,敏感信息不入库
  3. 失败先进入候选池,不直接成为门禁样本
  4. 人审只做关键决策(风险等级/断言有效性)

六、C# 样本治理最小实现

下面给一个可落地的仓库治理骨架:

using System.Text.Json;

public enum CaseLayer
{
    L1Contract,
    L2Task,
    L3Risk,
    L4Drift
}

public sealed class DatasetCase
{
    public string Id { get; set; } = string.Empty;
    public CaseLayer Layer { get; set; }
    public string Domain { get; set; } = string.Empty;
    public string Source { get; set; } = string.Empty;
    public string Owner { get; set; } = string.Empty;
    public string Severity { get; set; } = "medium";
    public int FreshnessDays { get; set; } = 14;
    public int TtlDays { get; set; } = 90;
    public DateTime CreatedAtUtc { get; set; }
    public ExpectedSpec Expected { get; set; } = new();
}

public sealed class DatasetHealth
{
    public int Total { get; set; }
    public int Expired { get; set; }
    public int NeedsRefresh { get; set; }
    public Dictionary<CaseLayer, int> LayerCounts { get; set; } = new();
}

public static class DatasetRegistry
{
    public static async Task<List<DatasetCase>> LoadAsync(string caseDir)
    {
        var result = new List<DatasetCase>();
        var files = Directory.GetFiles(caseDir, "*.json", SearchOption.AllDirectories);

        foreach (var file in files)
        {
            var json = await File.ReadAllTextAsync(file);
            var item = JsonSerializer.Deserialize<DatasetCase>(json);
            if (item is not null)
            {
                result.Add(item);
            }
        }

        return result;
    }

    public static DatasetHealth CheckHealth(List<DatasetCase> cases, DateTime nowUtc)
    {
        var health = new DatasetHealth { Total = cases.Count };

        foreach (var c in cases)
        {
            if (!health.LayerCounts.ContainsKey(c.Layer))
            {
                health.LayerCounts[c.Layer] = 0;
            }
            health.LayerCounts[c.Layer]++;

            var ageDays = (nowUtc - c.CreatedAtUtc).TotalDays;
            if (ageDays > c.TtlDays) health.Expired++;
            else if (ageDays > c.FreshnessDays) health.NeedsRefresh++;
        }

        return health;
    }
}

这段代码先解决三件事:

  • 可统计:知道样本结构是否健康
  • 可预警:及时发现过期与待刷新样本
  • 可治理:为 CI 门禁提供可执行信号

七、门禁策略:按层定义,不要一刀切

建议采用分层阈值:

  • L1-Contract:PassRate 必须 100%
  • L3-Risk:PolicyViolationRate 必须 0
  • L2-Task:PassRate >= 基线 - 1%
  • L4-Drift:仅告警,不阻断

再加两条全局约束:

  1. ExpiredCases == 0 才允许发布
  2. NeedsRefresh 超阈值时触发样本维护工单

这样可以避免“模型指标达标但样本库已经腐化”的假乐观。

八、一周落地模板(从手工到飞轮)

Day 1

  • 给现有样本补齐元数据(layer/source/severity/freshness/ttl)

Day 2

  • 上线 DatasetHealth 报告并接入 CI

Day 3-4

  • 接入线上失败自动提取,进入候选池

Day 5

  • 建立轻量人审流程,形成入库规范

Day 6

  • 发布首版分层门禁阈值

Day 7

  • 复盘一次漂移告警与失效样本清理效率

九、第 02 篇结论

Harness 的长期价值,不在 Runner,而在样本工程。

当你把样本当作“可治理、可演进、可闭环”的系统资产,评测结果才会持续代表真实质量,而不是历史幻觉。

下一篇进入《Harness 实战 03:评分器与裁判体系(规则判定 + LLM-as-Judge 的混合策略)》,解决“能跑回归但判不准”的问题。