如果你是抱着"去哪里找 50 条评测数据"的问题点开这篇文章,我建议先换一个问题。

真正困难的,从来不是凑出 50 个 query,而是让每一个 query 都成为一条可以稳定判分的 case:它测试什么,什么算成功,依赖哪个时间点和数据状态,哪些过程不可省略,失败之后又该如何进入下一轮回归。

一条 query 还不是一个 case。只有当成功标准、上下文状态和必要约束都明确时,它才真正可以用于评测。

一条能被判分的 case,大概长这样:

case = {
  query,               # 输入:问题、任务指令
  judgment,            # 成功标准:statements / rubric,而非一条"标准答案"
  trajectory_anchors,  # 中间轨迹锚点:expect-tools、关键中间状态、forbidden 项
  world_state,         # 世界状态:reference_time、数据快照标识
  metadata             # 来源、能力维度、难度、版本
}

schema 就是本文的目录:

  • query 从哪来 —— 来源与反推合成

  • judgment 怎么写 —— 标准怎么写

  • trajectory_anchors 和 world_state 为什么不能省 —— 一条 case 还要带上什么

  • metadata 怎么支撑覆盖与迭代 —— 多少条才够,以及数据飞轮

query 从哪来

按项目阶段的可得性排序。

Dogfooding。 开发过程中,团队自己使用系统时亲眼所见的失败,成功标准往往当场就能说出来,都是一条条现成的 case。当然,也有陷阱:熟悉系统的人会不自觉绕开它不擅长的问法,这批 case 会偏向 happy path,多样性指望不上。

需求与验收标准。 PRD 里的每一条功能描述、验收清单里的每一个检查项,天然就是一条 case 的雏形。缺陷也明显:需求文档里的语言是产品经理的语言,不是用户的语言。

已上线的真实生产日志和系统。不论是已上线的 chatbot 应用,还是现成的 SaaS 系统。这里并非直接随机抽日志,而是从业务角度上,去挖掘高频的访问(需求)。

合成数据。 用 LLM 生成、补充、扩展。它排在最后不是因为不重要,而是因为它不该独立存在。好的合成永远以前三种真实数据为种子。

反推与合成

正着想问题,多半是想不出来的;但答案和原料往往就躺在现成的资源里——从它们倒推问题。

RAG 场景。 一条 testset 是 (query, judgment, references)。凭空想 query 很难,但 references 是现成的。选一段文档,让 LLM 基于它生成"这段内容能够回答的问题",QA 对就有了,而且 answer 有据可查。但这也面临着一个问题:直接合成的 query 往往不像人会问出的问题。

Text2SQL 场景。 一条 case 是 (query, golden-sql, expect-tools, expect-data, …)。缺的是自然语言 query?但 SaaS 系统里高频执行的 SQL 是现成的,带注释的报表代码也是现成的。把这些交给 LLM,反推"业务方会怎么用一句话问出这条 SQL"——golden-sql 甚至不用写。

合成 pipeline。不少评估框架支持基于已有文档合成测试集(比如 DeepEval 的 synthesizer),但结果往往生硬。自建 pipeline 并不复杂,一是从真实种子变异,而不是凭空生成;二是引入 persona,合成数据不像人话,很大程度上是因为缺少"提问的人"——给 LLM 一组用户画像(角色、意图、表达习惯,可以基于业务本体 ontology 来构建)。

Filter。 合成结果先过一遍自动化检查:去重、去低质(长度、格式等)、去越界。机器筛完再进人工。

HITL。 人工检查这一步不能跳过。但人工很贵,所以有一条会在本文反复出现的原则:能做判断题就不做选择题,能做选择题就不做问答题——尽可能降低标注的摩擦。

judgment 怎么写

怎么定义"答对"?

最直觉的做法:评测集长成 (query, golden-answer),然后让 LLM-as-a-Judge 比较系统输出与 golden-answer"是否一致"。judge 会立刻陷入两难——“一致"到什么程度算一致?评分随机性极大,而且分数不可解释。

尽可能把"标准答案"拆成可核对的判定点:statements(回答必须包含 / 不得包含的事实陈述),或者 rubric(得分点与扣分点清单)。

还顺带解决了一个成本问题。请行业专家写标准答案,又贵又没用:写一条"完美答案"要半小时,并且也难以用于评估。

  • 专家不写答案,只标得分点和扣分点——他们对"什么最关键、什么绝不能错"的判断,才是真正稀缺的东西

  • 由 rubric 反推一版参考 answer,交给 LLM 来写,成本趋近于零

(依旧是把问答题变成判断题。降低标注摩擦这个原则)

一条 case 还要带上什么

query 和 judgment 齐了,还不够。

world_state:case 所依赖的世界状态

这是一个真正踩过的坑。评估 Text2SQL 时,有一批 case 的问法是时间相对的——“上个月华东区销售怎么样”。golden-sql 是按写 case 那天的"上个月"生成的;几周后跑回归,同一条 case,系统理解的"上个月"已经是另一个月。从那以后,schema 里多了两个字段:reference_time 和数据快照标识。不论是 mock 系统时间,还是上下文注入,都能用上。

trajectory_anchors:中间轨迹的锚点

对 chatbot,测最终回答也许够了;对 agent,只测 E2E 结果会漏掉大量信息。

锚点包括但不限于:expect-tools(该调哪些工具)、关键的中间状态、以及 forbidden 项(绝不能出现的调用或状态)。至于"哪条轨迹更好”,轮次越少越好、token 消耗越低越好这类粗指标只能兜底,锚点命中率的信息量大得多。

标注中间过程还有一个好处:大量判定可以从 judge-LLM 降级为代码比对,又快、又便宜、还没有随机性。

多少条才够

重要的不是总数,是分布。

一个覆盖矩阵:一个轴是能力维度(系统应当覆盖的任务类型),一个轴是难度或场景变体(简单直问 / 多约束 / 多跳……)

metadata 字段在这里派上用场:每条 case 标上它所属的能力维度、难度、来源,覆盖矩阵才能自动统计,而不是靠人肉盘点。

数据飞轮

第一版评测集是静态的,而系统会不断测出新的问题,评测集是不断更新的。

来源自然是生产环境。上线之后(怎么采样、怎么 tracing,第五篇细讲),每一条线上失败,都是一条候选 case。“失败回流"的管道一旦打通,评测集就从一份需要你维护的负担,变成一份随系统一起增值的资产。

然后,将评测集版本化管理。

系列导航

附录:工具推荐

LLMOps + 评估框架

数据合成框架|数据合成 pipeline

数据标注