input/data 时用当前 Scope 自动取数),要么显式传入自己算好的数据——两种写法产出完全相同,选哪种只看你要不要在取数和渲染之间插入自己的 JavaScript。本页逐个列出官方组件:它展示哪一层数据、在报告里怎么调用、终端输出长什么样。
名称与用途
英文术语描述组件形态,API 名是代码里的导出名。默认组合件比较当前 Scope;范围摘要概括整批结果;实体列表逐项展示 experiment、评估用例或 Attempt;指标图形把指定维度聚合成值。Row、Col、Grid、Section、Stat、Text、Style、Table、Tabs 和 Tab 是十个排版原语,不计算结果,因此不算一种分析图。它们的中文统称依次是行、列、网格、分节、摘要项、文本、样式、表格、标签页和标签;代码里始终使用 API 名。
所有组件共守同一套契约,下面不再逐个重复:
- 诚实渲染。 缺数据渲染
—不补 0;覆盖不全的格子带12/15角标;截断如实标注剩余数量与原始 artifact 路径。 - 排序与方向随指标的
better。 higher 的指标降序、lower 的升序,「好」的一头恒在上、在右上。 - 深链到 Attempt 详情。 网页面的格子、点和条目深链到 Attempt 详情页;终端面用同一 Attempt 定位符交给
niceeval show @<id>。 - 终端输出形成反馈闭环。 每个 Attempt 有一个以
@开头的短定位符,例如@1k2m9qrs。它唯一指向 experiment、结果快照、评估用例和 Attempt。✓/✗/!/–是 passed / failed / errored / skipped。列表不用字母缩写编码证据可用性——定位符本身就是证据入口;打开 attempt(niceeval show @<定位符>)后再列出实际可用的证据命令。执行步骤统一包含消息、thinking、tool call/result 和 Skill load;OTel 只给这些步骤补时间,不另开一份输出。 - 两面同口径,网页面不依赖 JS 也完整。 排序在计算时由
sort定死,终端和网页看到同一份基准顺序;下钻是普通链接,展开折叠用<details>。网页面另有一层浏览操作:点表头就地重排、榜单行过滤、图表点位悬停看数值——只影响眼前的视图,不改数据口径,刷新即回基准顺序;浏览器禁用 JS 时这些操作消失,内容一样不少(悬停信息退化为图内提示)。
两种写法,同一份数据
每个组件的 props 分两种写法,选哪种都行:data 和取数选项会报错,两者二选一。所有计算函数的第一个参数都是 Scope(或手工挑的结果快照数组);产出的数据都是普通可序列化 JSON,可以先存下来、传给别的进程,或者原样喂给对应组件的 data prop。niceeval/report/react 入口的同名组件只收 data,不做取数——那一层是纯 React 渲染,见自定义报告。
evals 是数据获取阶段唯一的过滤选项:评估用例 id 前缀,与 CLI 位置参数同语义,在聚合之前收窄题集。实体列表(ExperimentList / EvalList / AttemptList)不设这个选项——它们逐实体成行,取数后用普通数组 .filter() 收窄,效果和任何专门选项完全一样。
排版原语
Row / Col / Section / Text 负责摆版面,一次摆放两个面各自成立:Col 纵向堆叠;Row 网页横排、终端字符分栏(宽度不够自动降级纵向);Section 是带标题的块;Text 是说明文字。另有 <Style>{css}</Style> 给自定义组件带样式:网页面吐 <style> 标签、终端面渲染为空——静态导出不打包用户代码,className 引用的 CSS 靠它随树走。
表格(Table)
第六个排版原语:官方组件摆不出的表,用它摆。它不计算任何东西——列由你定,格子是你算好的显示值,它只负责把两个面都排整齐。
align: "right" 让数字列右对齐,小数点自然对齐。格子是 null 就渲染 —,不补 0。行上带 locator 就多出一列 attempt:网页面链到 Attempt 详情,终端面列出定位符,直接喂给 niceeval show <定位符>。
表比终端宽时先压最宽的左对齐列(按显示宽度折行),右对齐列不折行——数字折行读不了;压到下限仍放不下,就从右侧丢列,并在表下如实报丢了几列,不静默截断。
某一列的格子只想显示前几行时,给这一列加 maxLines:超出的行丢弃,最后一行按显示宽度收口成 …;表头不受这个限制。网页面不消费这个字段——格子的高度由你自己的样式决定。
指标表、指标矩阵、成绩单和成对差异表的终端面就建在 Table 上,所以你的表和官方的表用的是同一把尺子。表格之外的形态要自己排字符时,用自定义报告「换形态」一节里那套文本排版函数。
摘要格(Grid / Stat)
一批 label-value 的速览数字(耗时、成本、参与率这类)用 Grid 摆格子、Stat 摆每格的内容,两面都自动排版,不用自己写 CSS 或对齐字符:
columns 是网页宽屏下最多摆几列,必须是正整数;容器变窄或终端变窄时两个面各自减列,不丢任何一格。variant="boxed" 给每一格描边,默认 "plain" 无框;density="compact" 收紧格内留白,字号也跟着降一档,不改变内容。
Stat.value 收 LocalizedText、number 或 null:null 显示 —,数字 0 照常显示成 0,不会被当成缺数据。detail 是主值下面的一行小字,省略就不留空行。tone(neutral / positive / negative / warning)是你对这个数字的语义判断,只给主值上色,组件不会替你从正负号或阈值猜。
Grid 只管排版,不读 Scope、不聚合指标——Stat.value 必须是你已经算好的显示值。需要保留覆盖率角标(12/15)和证据引用时,继续用指标表这类数据组件;只有真正自由的摘要卡片才用 Grid / Stat。一格里要放两个 Stat 时,用 Col 把它们包起来,Grid 仍然只把这个 Col 算作一格。
Section 也多一个可选的 meta:标题行右侧的短元信息,比如「6/6 完成」。网页面和标题同一行右对齐,终端面空间不够时换到下一行,缩进两格。
实验比较(ExperimentComparison)
niceeval show / view 不传 --report 时使用的默认组合件。它把同一份 Scope 显式传给 ScopeSummary、成本 × 端到端通过率的 MetricScatter 和 ExperimentList 三个组件,自己不产出数据,也不合并三者的结果:
selectedEvalIds。网页面与终端面都显示完整 Scope;需要子集时用 --exp 收窄,或在自定义报告里对 Scope 先 .filter() 再传给 input。
实验列表行的显示名不需要额外配置:experiment id 共享公共目录前缀时(比如都在 compare/ 下),行标签自动缩成各自的最短唯一后缀,不显示重复的前缀;末段撞名的 id 会自动加长到能互相区分为止。完整 id 始终是排序、过滤和折叠展开用的身份键,只是显示文字变短了。
组卡使用 Pass rate / 通过率、Experiments / 实验、Evals / Eval、Attempts / Attempt、Eval results / Eval 结果、Total cost / 总成本 这套字段标签,不在标签里重复“数”“次”或“计票”。时间显示为本地化到分钟的 Last run / 最近运行 或 Run range / 运行范围,不直接暴露 ISO 字符串;成本数据覆盖不全时写明“63/72 次有成本数据”,不显示没有上下文的 63/72。六项 KPI 在宽卡片保持同一行,空间不足时按三项或两项一组换行,避免总成本单独掉到下一行。
下面的 MetricScatter、ScopeSummary 和 ExperimentList 同样忠实消费调用方传入的数据,不推导隐藏范围。它等价于把三个组件按下面这样手工摆放——想自定义顺序或搭配其它组件时,照这个形状写:
范围摘要(ScopeSummary)
每张报告开头「这批数据是什么」:几个配置、几道题、通过分布、总成本、什么时候跑的。评估用例的身份键是 experimentId + evalId:同一个评估用例在不同 experiment 中运行时算两个独立评估用例,数量和判定计票都按这个身份算。
votes 只决定显示哪一级:
votes="eval"(默认):每个 experiment × 评估用例先按「任一轮 passed 即 passed,否则 failed > errored > skipped」折成最终判定后计票,回答「多少道题最终通过」。votes="attempt":Attempt 原始计票,不折叠,回答「实际跑的每一轮各是什么结果」。
ScopeWarnings 组件,同一份事实不在页面上出现两次。
收窄范围时在自定义组件里显式传 input:
实验列表(ExperimentList)
每项固定代表一个 experiment。主行显示 experiment id、agent、model、flags、评估用例判定构成、通过率、Tokens、成本和耗时。默认 ExperimentComparison 把当前 Scope 的全部条目交给它;组件本身不猜边界。
行标签默认缩成 experiment id 在当前列表里的最短唯一后缀——末段唯一就只显示末段,撞名的 id 各自向前多取一段直到能区分为止(与 MetricScatter 散点的点标签同一算法)。排序、过滤和折叠展开始终用完整 id,不受显示名影响。中文副行用“8 个 Eval”而不是“8 道题”。
.filter():
niceeval show 先输出 experiment 比较表,再按 experiment 展开评估用例 / Attempt 父子表。评估用例父行给题级平均值,Attempt 子行给这一轮的失败摘要和定位符:
experimentId + snapshot.startedAt + evalId + attempt 序号 的不可变身份确定,复制或发布结果后保持不变。宿主在当前结果根解析定位符;不存在或发生冲突时直接报错,不回退到“最新一次”。@ 前缀让它与评估用例 ID 前缀选择器无歧义。
experimentListData(scope) 返回普通的 ExperimentListItem[],顺序按 experiment id 稳定排列。要只看某个 agent、目录前缀或运行状态,直接过滤数组。组件不提供另一套查询语法。网页面的文本搜索只是临时浏览操作,不改变传入的条目;终端面始终输出完整的传入数组。
评估用例列表(EvalList)
每项固定代表一个 experimentId + evalId,因为同一个评估用例跑在两个 experiment 上是两条不同结果。主行显示判定、Attempt 数、聚合分数、平均成本和平均耗时;展开后显示这个评估用例的 Attempt 列表,由每个 Attempt 行显示该轮自己的失败原因。评估用例主行不挑某一轮的失败原因冒充题级结论。
niceeval show 每个 experiment × Eval 输出一项,Attempt 仍用同一套紧凑 ID 和证据位。每项只给一条模板:
evalListData(scope) 返回普通的 EvalListItem[]。按评估用例 id 前缀、experiment、判定或分数过滤都使用数组 .filter();组件只负责渲染传入的条目。
Attempt 列表(AttemptList)
每项固定代表一个 Attempt,显示 experiment、评估用例、Attempt 序号、判定、耗时、成本、失败断言、结构化 error 的一层摘要、Judge 评语和证据链接。diagnostics、cause 和 stack 留给定位符下钻详情,避免比较列表被基础设施日志撑开。它既能列失败证据,也能列通过样本,不把判定过滤写死在组件名里。
niceeval show 每项完整输出一个 Attempt,不折叠到评估用例汇总。这里已经是叶子层,只在末尾给一条与该 Attempt 可用证据对应的模板:
AttemptListItem[]。截断数量也由报告作者在数组上用 .slice(0, 20) 表达,截断时把原始数量交给组件的 total,组件据此显示“还有 n 项未展示”,不静默截断。
失败列表(FailureList)
「现在有哪些失败要处理」是每份报告都要的固定区块,工具箱直接提供成品组合件,不用每次都重写同一段取数过滤。它和上面 AttemptList 的手工写法完全等价,只是把最常见的一种过滤打包好了:收 verdict 为 failed 或 errored 的 Attempt,按开始时间倒序(最近的失败在前),截断到 limit(默认 20)。
AttemptList 的写法自己加工数组;FailureList 只覆盖这一种最常见的问题。
指标表(MetricTable)
一行一个维度值,一列一个指标,回答「谁整体更好」。行维度、指标列、排序全部可换,自定义指标(defineMetric)与内置指标同列。
sort 预排,基准顺序一致——要固定换一种排序,改一行重跑。12/15 角标表示该格 15 个 attempt 里只有 12 个测得了这个指标。sort 必须是 columns 中同一个 Metric 实例且声明了 better,否则报错;省略时按行 key 字典序,避免为方向不明的指标猜顺序。filter 只给网页面加行过滤框,不改变数据或终端输出。
rows: "experiment" 时每行自动带 agent 与 model 列——结果里现成的元信息,不用配置。MetricTable 不展开实体层级:要看 experiment、评估用例或 Attempt 的固定诊断字段,用上面三个实体列表;要自由换维度和指标列,用指标表。
指标矩阵(MetricMatrix)
行 × 列两个维度、格子里一个指标,回答「哪道题谁挂了」。稀疏渲染:没有样本的格子空着,不编数。
分组条形图(MetricBars)
同一份矩阵数据的另一种摆法:按组并排比大小,回答「每个科目上谁领先、差多少」。组维度一组条、系列维度一根条、条长是指标值——benchmark 发布图(Terminal-Bench、BrowseComp 各一组,每个 agent 一根柱)就是这个形状。
better)。better: "lower" 的指标(成本、耗时)条形反向填充,短条恒为「好」。MetricMatrix 和 MetricBars 写同一份取数选项时,两个组件不会重复计算——只要 input 与选项相同,底层数据只算一次。
成绩单(Scoreboard)
总分 + 分科小计,回答「这套题它能得几分」。逐题分值制:权重按评估用例 id 前缀配置,分母对所有被打分者恒定,没跑到的题挣 0 分并如实报 missing。
questions 是显式固定题集,不从已观测的 Attempt 并集猜——所有配置都没跑到的题仍然留在分母里按 0 分计。分数为 null(跑了但测不了)与完全没跑到的题分开计数(分别是 unscorable 和 unrun),成绩单能回答「这 0 分是没去考还是考了判不了」。score 默认是 examScore,每道题必须产出 [0, 1];总分是 fullMarks × earned / possible。
指标散点图(MetricScatter)
每个点一个配置、两个指标各占一轴,回答「又好又便宜的是谁」。series 把同 agent 不同档位的点连成线;better 驱动轴向——lower 的轴反向画,「好」的角落恒在右上。
MetricScatter 直接消费传入的 Scope,宿主渲染前替你算好数据;默认 ExperimentComparison 也把当前 Scope 原样交给它。要嵌预先算好的数据,改传 data。
samples/total,禁用 JS 时退化为图内提示)、同系列连线、点击深链下钻。终端面用字母标点,图例列在图下;x 或 y 缺数据的点两个面都不画,注脚如实报「n 个点缺数据」;点太密排不下时降级为坐标表,不硬挤。画得出来的点是 0 个时,两个面都明说这两个指标没有可用数据,不留一片空白;1 个点也照常出图。维度槽也收自定义维度和 flag()(experiment 声明的变量),怎么选见自定义报告的「换分组」一节。
指标趋势图(MetricLine)
x 是有序变量、每个系列一条线,回答「变量拧大,分数怎么走」——并行 agent 数 × 模拟延迟 × 得分这类 scaling 图就是它。与 MetricScatter 的分工:散点图的两轴都是测出来的指标(找优势前沿),趋势图的 x 是你配置的变量(看趋势)。变量在 experiment 的 flags 里声明,报告用 flag() 或数值型 flag 助手直接引用,不从 experiment 命名里解析。
成对差异表(DeltaTable)
每行一对配置、每列一个指标,格子里 A、B、Δ 三个值,回答「这个开关值不值」「这次修复翻转了什么」。涨跌好坏由 better 判定,任一侧缺数据 Δ 显示为缺,不硬算。
pairs 的 a / b 除 experiment id 外也收快照键 <experimentId> @ <startedAt>——手挑的快照数组(比如某个实验的最新一次和上一次)配这种写法。pairsByFlag(name) 按一个 flag 机械导出全部 A/B 对:实验矩阵是「同配置开关某个 flag」时,配对关系本来就是 experiment 配置的推论,手抄 id 字面量等于把配置复写进报告,加实验后报告会静默缺行。
官方组件之外
以上摆法都表达不了时,用defineComponent 写自己的双面组件——网页怎么渲染、终端字符怎么排,两个面你都说了算,写法见自定义报告的「换形态」一节。