基于产品预期行为的状态转换数据审计

这个系列源自一次对多轮微调语料的数据审计。语料包含数千条已交付的训练样本,外加一套独立评估集。审计的核心思路是:沿着 "组织单元、地区、财期、分析维度、指标族、操作类型" 等字段,追踪模型在调用工具的多轮对话中,状态是如何变化的。
"状态转换" 本身不是新概念。一个有状态的产品,本该对 "哪些值能变、哪些组合合法、哪些转换在日常使用中重要" 有明确定义。而这次审计真正有价值的地方,在于把产品预期的行为和训练数据里实际写出来的对话做了一次对照。
训练数据在各状态字段上分布不均
单看取值范围,财期的所有可能值在训练数据里都出现过。但如果逐轮拆开看,在数千对符合条件的连续状态中,原子级的财期变更一次都没有发生过。
其他字段则完全不同:组织单元、指标族和操作类型,在观测值之间实现了完整的有向转换覆盖;地区覆盖了约三分之二;分析维度约 40%;财期则始终是零。

图:各字段的观测有向转换覆盖率。该图仅描述人工编写的语料,不代表所有数学上可能的转换都该出现在训练里,也不代表它们都存在。
脱离规范谈覆盖率,数字本身没有意义。一条缺失的转换,可能是因为它本来就无效,可能是有意留出来测泛化的,也可能是该有却漏掉了。不同的覆盖率层级,对应着不同的评估任务:
- 高覆盖率 → 测的是模型有没有学会(uptake)
- 部分覆盖率 → 测的是对留出样本的泛化能力
- 零覆盖率 → 需要先搞清楚:这个行为到底有没有被定义过?

先有规范,再谈审计
从数据里反推转换清单,有一个致命缺陷:如果一条有效转换从未在语料中出现,它就不会留下任何记录,你根本数不到它。因此,预期的转换空间必须独立于训练数据来定义—— 依据产品文档、工具接口契约或任务规范,而不是看训练里写了什么。
有了这份规范清单,审计就很直接了:标出哪些转换有效、哪些用于训练、哪些有意留出,再和实际编写的内容逐一比对。
覆盖率回答的是 "模型有没有见过",下面这个评估案例则回答:没见过的有效转换,模型表现会怎样。
评估集里的一个真实案例
有一道评估题是这样的:用户在一轮对话里要求按两个不同季度拆分展示某项指标。系统提示词规定,未指定时段时用固定的默认季度。正确做法显然是覆盖默认值,按用户说的两个季度返回结果。
但模型的做法是:因为前面没有可参考的轮次,它直接用了硬编码的默认季度作答,仿佛用户问的就是那个季度 ——用户要的两个季度全被丢了。
人工评审给这个回答打了 2/7 分,评语是:没有处理多个季度,也没有返回每个被请求季度的汇总。类似的情况在另一道题里又出现了一次:用户要求对比全年四个季度,模型再次忽略请求范围,只返回默认季度的结果,算出一个毫无意义的方差(因为它在拿同一个季度和自己比)。
这两道题都不涉及重复旧答案或编造数字,问题出在同一个根因上:模型从来没学会覆盖硬编码的默认值。
工具本身没有限制。它的 Time_Period 参数本来就支持传列表,一次调用同时指定两个季度完全可行。另一批训练样本也证明,当系统默认指向其他时段时,模型能在单次调用中正确切换到指定的单个季度。也就是说,请求就摆在面前,模型却选择了保留默认值,而不是替换它。
补充说明:这个案例是 "多季度请求"(Time_Period 传列表),和审计重点关注的 "原子级单值财期转换" 不完全是一回事。由于训练中零个原子级财期转换演示,模型在最接近的评估题里选择了保留硬编码默认值 —— 至少它没有重放旧财年或编造数字。但原子级转换本身到底表现如何,仍需单独运行并评分才能确认。

数据审计能告诉你 "某个行为在训练里有没有出现",但要判断泛化能力,必须看模型的实际输出。
评估集已经指明了下一步该查什么
在唯一转换边的层面上,组织单元、地区、指标族和操作类型,对评估集中用到的转换都有完整的训练支持;分析维度约有四分之三的案例有支持;而财期的支持率是 0%—— 评估集里有近十二条独特的财期转换边,这些事件在训练数据的转换记录中完全找不到。
这些财期案例是很好的泛化探针,目前已经产出了一个可落地的评估结论:上面那个多季度的案例表明,一个密切相关的未见财期请求会彻底失败,而且失败模式高度一致 —— 回退到硬编码默认值,而不是给出更合理的报错或处理。但这还不能说明模型在那十二条原子转换边上的表现。下一步应该直接运行这些确切的转换,用同一套标准给 "见过" 和 "未见" 的案例打分,而不是靠覆盖率数字去猜。
按覆盖率层级设计评估集
前面算出的训练覆盖率,其实为下一轮评估规划提供了现成的框架 —— 不需要等新数据写好,现在就能动手。每个字段已经落入三个层级,每个层级需要的评估思路不同:
换个角度看,财期不再是一个 "数据缺口",而是语料里现成的、最严苛的泛化测试题。下一轮评估可以主动围绕它来设计,而不是被动地等它暴露问题。
更强的转换泛化评估,可以这样设计
当前评估集已经包含了一些有用的未见转换,但如果想让对比更有说服力,可以专门构造一组配对案例:同一类状态变更,一部分在训练里演示过,另一部分性质相同却被有意留出。
一个小规模的针对性集合可以包括:
- 正反两个方向的财期切换
- 未见的分析维度转换
- 原始状态建立好几轮之后才发生的转换
- 两个字段同时变、其余状态必须保持不变的案例
- 嵌在错误恢复场景中的未见转换
- 配对的 "见过 / 未见" 转换对,方便直接对比性能
以财期切换为例,可以构造这样一对评估题:一题要求从 FY25 Q3 切到 FY25 Q4(训练中见过),另一题要求从 FY25 Q4 切到 FY26 Q1(同类变更但未见),然后直接比较两个结果。
配对设计的好处是,泛化不再是评估集的 "副产品",而是变成了可以直接测量的指标:无论某个具体转换有没有在训练里出现过,模型的性能是否保持稳定。
推荐做法
- 先定规范:从产品或任务规范出发,定义合法的状态值和转换。
- 再看数据:提取训练对话中实际出现了哪些转换。
- 标记评估集:把评估里用到的转换标为 "训练中见过" 或 "未见"。
- 最后比结果:拿到模型输出后,对比见过与未见的有效转换上的性能差异。
回到财期的例子:先按规范确认这个转换有效,再因为训练中从未出现而标记为 "未见",然后实际运行它 —— 而不是凭感觉下结论。多季度案例暗示硬编码默认值是一个可能的失败点,但它不能替代原子级转换本身的测试结果。只有跑了、评了,才能确定。
一句话总结: 转换覆盖率是 "训练暴露程度" 的证据,不是 "模型性能" 的结论。最有价值的下一步,是把见过和未见的有效转换,放到实际评估结果里去对比。

沪公网安备31011502401377号