任务规格格式:评估契约的 JSONL 形状


文档摘要

任务规格格式:评估契约的 JSONL 形状 本节摘要:评估框架的好坏,取决于它的任务遵守什么契约。本节在写任何打分函数之前先冻结 JSONL 形状与指标词表。一份任务是一条单行 JSON 对象,固定字段( 、 、 、 、 、 )覆盖算术、多选、代码执行、分类、自由文本摘要五类任务;指标名是封闭词表,下游(7173 节)按单字段分派;few-shot 与后处理规则是任务的一部分而非运行器的,让同一提示跨模型产出同一目标。配套一个严格校验器,畸形记录在进运行器前就被拒,另附 10 条覆盖每条规则分支的固定集。读完本节,你能像对待数据库迁移一样对待规格——新增类别必须同时加指标、后处理规则与至少一条固定任务。 对应原课程:Phase 19 · Lesson 70 · (原英文 )。

任务规格格式:评估契约的 JSONL 形状

本节摘要:评估框架的好坏,取决于它的任务遵守什么契约。本节在写任何打分函数之前先冻结 JSONL 形状与指标词表。一份任务是一条单行 JSON 对象,固定字段(task_idcategoryprompttargetsmetric_namepost_process)覆盖算术、多选、代码执行、分类、自由文本摘要五类任务;指标名是封闭词表,下游(71~73 节)按单字段分派;few-shot 与后处理规则是任务的一部分而非运行器的,让同一提示跨模型产出同一目标。配套一个严格校验器,畸形记录在进运行器前就被拒,另附 10 条覆盖每条规则分支的固定集。读完本节,你能像对待数据库迁移一样对待规格——新增类别必须同时加指标、后处理规则与至少一条固定任务。

对应原课程:Phase 19 · Lesson 70 · task-spec-format(原英文 phases/19-capstone-projects/70-task-spec-format/docs/en.md)。本节属第 20 章「毕业项目」的评估赛道(Track G),是本赛道的地基。

学习目标

阅读完本节,你应当能够:

  1. 定义一个 JSONL 任务记录模式,用一种形状覆盖算术、多选、代码执行、分类、自由文本摘要
  2. 锁定一个封闭的指标名词表,让下游(71~73 节)按单字段分派。
  3. few-shot 示例与后处理规则写进任务而非运行器,使同一提示跨模型产出同一目标。
  4. 实现一个严格校验器,在畸形记录到达运行器前拒绝它。
  5. 交付一份 10 任务固定集,跑遍规格每条分支,让校验器有真东西可嚼。

一、问题与直觉

研究代码库积累评估脚本的速度比积累测试还快。半年后,每个 notebook 有自己的 JSON 形状,每个指标被实现两次,跨运行什么都比不了。解法很无聊:挑一个模式,写一个校验器,拒绝其余一切。这就是本节做的。

形状借鉴 BIG-bench、HELM、lm-eval 风格的框架,但字段名是我们自己的。每个字段有唯一主人:运行器读任务,指标读 targets,后处理步归一化生成,任何字段在流水线中途不可变

记录形状

任务是单行上的一个 JSON 对象。框架读 tasks.jsonl,逐行独立校验——坏行只中止该记录,不中止整次运行。

{ "task_id": "arith_001", "category": "arithmetic", "prompt": "计算结果。问题:17 + 24\n答案:", "targets": ["41"], "metric_name": "exact_match", "few_shot_examples": [ {"prompt": "问题:2 + 2\n答案:", "completion": "4"} ], "post_process": "strip_whitespace", "metadata": {"difficulty": "easy"} }

必填字段是 task_idcategoryprompttargetsmetric_namepost_process;few_shot_examplesmetadata 可选;未知顶层字段校验失败。

二、字段规则

  • task_id:无空白字符串,校验器在文件内强制唯一。
  • category:arithmeticmcqcode_execclassificationsummary 之一。类别约束哪个「指标 + 后处理」组合合法:code_exec 必须用 metric_name = code_exec,mcq 必须用 metric_name = exact_match 对单字母 target。
  • prompt:非空串,校验器禁止尾随空白,拒绝 prompt 体里已含 few-shot 块的记录——few-shot 渲染发生在运行器,不在作者。
  • targets:非空字符串列表。exact_match 任一元素匹配即算;f1rouge_l 取最高分 target;mcq 恰好一个元素。
  • metric_name:exact_matchf1bleu_4rouge_laccuracycode_exec 之一。词表封闭,新指标需要新课与新条目。
  • few_shot_examples:{prompt, completion} 对列表,校验器限 8 条以保持提示有界。
  • post_process:nonestrip_whitespacelowerextract_letterextract_code_blockextract_first_line 之一,每条规则单一确定行为,禁止组合

三、从零实现:校验器

校验器返回两个列表:已校验记录;错误记录(含出错行、违反的规则、出错字段)。除非显式 --allow-bad-tasks,错误列表非空时运行器拒绝启动。

Few-shot 渲染

运行器把 few-shot 示例以空行分隔拼在 prompt 前,同一代码路径对每个模型跑,所以方差唯一来源是模型本身;作者写一次示例,而非每个提供商写一次。

def render(task): parts = [] for ex in task.get("few_shot_examples", []): parts.append(ex["prompt"] + " " + ex["completion"]) parts.append(task["prompt"]) return "\n\n".join(parts)

后处理规则

后处理在生成之后、指标之前跑,确定且无状态:

  • none:原样返回。
  • strip_whitespace:去首尾空白。
  • lower:转小写。
  • extract_letter:返回匹配 [A-E] 的首字符,用于 MCQ。
  • extract_code_block:返回首个三反引号围栏块的体,用于代码执行。
  • extract_first_line:返回首个非空行,用于摘要分类。

需要此列表外规则的任务,属于新课。

四、框架对比

框架 任务形状 指标词表 后处理位置
BIG-bench JSON,任务自带 metric_fn 开放(任务定义) 任务内
HELM 严格模式,中央指标矩阵 封闭,中央定义 运行器
lm-eval-harness YAML/Py 类,每任务一个 Metric 半封闭 任务类内
本节 单行 JSONL,字段固定 封闭,单字段分派 任务声明,运行器执行

💡 本节的取舍:形状比 BIG-bench严、比 HELM 轻。封闭指标词表 + 任务声明后处理是关键——它让下游 71~73 节按 metric_name 单字段分派,运行器对指标名一无所知。业界(HELM、OpenCompass)也朝这个方向收敛:中央指标矩阵 + 任务声明配套。

五、可复用产物

  • TaskSpec + validate_file:本节的校验器是 71~73 节指标与 75 节运行器的共同入口——运行器只读已校验记录,指标只读 targets。
  • render + 后处理助手:与校验同模块,让 75 节运行器只 import 一个模块。
  • 10 任务固定集 + tasks_bad.jsonl:固定集覆盖算术 2、MCQ 2、代码执行 2、分类 2、摘要 2;坏集每条规则各踩一次,校验器恰好返回那么多错误。

main.py 定义 TaskSpecvalidate_taskvalidate_file 与 CLI 入口;固定加载器是 load_fixtures;渲染与后处理助手紧挨校验,让 75 节运行器只 import 单模块。从顶到底读 main.py,再读 code/tests/test_spec.py——测试钉死每条校验规则与每个后处理行为。

六、本节不做的事

本节不打分、不调模型、不跑代码——那些在 71、72、75 节。本节冻结的是它们共同遵守的契约。

⚠️ 真实评估套件增加类别就像数据库加列。清醒的做法是:拒绝增加类别,除非同时加一个指标、一条后处理规则、至少一条固定任务。把规格当数据库迁移,每次改动经评审、版本化、配测试。本节校验器就是那道门。

七、练习

  1. 加第六类:translation,定义其合法 metric_name(应指向 71 节的 BLEU-4)与后处理规则,扩校验器,加两条固定任务。
  2. --allow-bad-tasks 语义:让运行器在错误列表非空时仍启动,但把坏记录数与分类写进报告头。
  3. few-shot 上限可配:把 8 条上限改为 metadata 里可覆盖的字段,校验器读取并强制。
  4. 版本字段:给记录加 spec_version,校验器拒绝不匹配版本,演示一次破坏性升级。
  5. 跨文件唯一性:把 task_id 唯一性从单文件扩到多文件目录,校验器扫目录。

本节要点回顾

  1. 评估好坏取决于任务契约——先冻结 JSONL 形状与指标词表,再写打分函数。
  2. 单行 JSON 任务:固定字段(task_id/category/prompt/targets/metric_name/post_process),未知顶层字段即拒。
  3. 类别约束指标对:code_execcode_exec,mcqexact_match 对单字母。
  4. 指标词表封闭:exact_match/f1/bleu_4/rouge_l/accuracy/code_exec,新指标需新课。
  5. 后处理 6 条确定规则,禁止组合:none/strip/lower/extract_letter/extract_code_block/extract_first_line。
  6. few-shot 与后处理属任务而非运行器:同一提示跨模型同目标,作者写一次。
  7. 严格校验器:坏行只中止该记录;错误列表非空则运行器拒启(除非 --allow-bad-tasks)。
  8. 规格即迁移:新增类别必同加指标、后处理、固定任务,经评审版本化配测试。

下一节,我们将进入「经典指标」——从第一性原理实现 exact-match、F1、accuracy、BLEU-4、ROUGE-L,让本节 metric_name 字段指向的每个名字都有可审计的实现。


发布者: 作者: Rohit Gupta 转发
评论区 (0)
U