niceeval 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INDEX.md +23 -23
- package/README.zh.md +6 -6
- package/dist/agents/types.d.ts +69 -7
- package/dist/context/types.d.ts +32 -12
- package/dist/i18n/en.d.ts +54 -0
- package/dist/i18n/zh-CN.d.ts +57 -3
- package/dist/o11y/types.d.ts +16 -2
- package/dist/report/aggregate.d.ts +32 -24
- package/dist/report/aggregate.js +158 -50
- package/dist/report/built-in/index.d.ts +2 -0
- package/dist/report/built-in/index.js +8 -0
- package/dist/report/components.d.ts +93 -160
- package/dist/report/components.js +377 -114
- package/dist/report/compute.d.ts +87 -81
- package/dist/report/compute.js +597 -417
- package/dist/report/flag.d.ts +32 -6
- package/dist/report/flag.js +92 -4
- package/dist/report/format.d.ts +19 -11
- package/dist/report/format.js +30 -13
- package/dist/report/index.d.ts +16 -16
- package/dist/report/index.js +20 -21
- package/dist/report/load.js +3 -2
- package/dist/report/locale.d.ts +57 -33
- package/dist/report/locale.js +122 -56
- package/dist/report/metrics.d.ts +23 -4
- package/dist/report/metrics.js +110 -25
- package/dist/report/primitives.d.ts +48 -15
- package/dist/report/primitives.js +135 -26
- package/dist/report/react/AttemptList.d.ts +9 -7
- package/dist/report/react/AttemptList.js +17 -10
- package/dist/report/react/DeltaTable.js +19 -18
- package/dist/report/react/EvalList.d.ts +4 -4
- package/dist/report/react/EvalList.js +0 -0
- package/dist/report/react/ExperimentComparison.d.ts +10 -0
- package/dist/report/react/ExperimentComparison.js +12 -0
- package/dist/report/react/ExperimentList.d.ts +4 -3
- package/dist/report/react/ExperimentList.js +17 -18
- package/dist/report/react/MetricBars.js +5 -4
- package/dist/report/react/MetricLine.js +12 -5
- package/dist/report/react/MetricMatrix.js +1 -1
- package/dist/report/react/MetricScatter.js +59 -28
- package/dist/report/react/MetricTable.js +2 -12
- package/dist/report/react/ScopeSummary.d.ts +10 -0
- package/dist/report/react/ScopeSummary.js +17 -0
- package/dist/report/react/Scoreboard.js +6 -6
- package/dist/report/react/cell.js +2 -2
- package/dist/report/react/chart-math.d.ts +23 -6
- package/dist/report/react/chart-math.js +71 -19
- package/dist/report/react/fixtures.d.ts +5 -9
- package/dist/report/react/fixtures.js +110 -147
- package/dist/report/react/index.d.ts +15 -5
- package/dist/report/react/index.js +18 -7
- package/dist/report/report.d.ts +137 -16
- package/dist/report/report.js +259 -28
- package/dist/report/text/faces.d.ts +17 -19
- package/dist/report/text/faces.js +253 -184
- package/dist/report/text/plot.js +1 -1
- package/dist/report/text/table.js +38 -7
- package/dist/report/tree.d.ts +90 -40
- package/dist/report/tree.js +252 -94
- package/dist/report/types.d.ts +247 -284
- package/dist/report/types.js +4 -3
- package/dist/report/web.d.ts +21 -5
- package/dist/report/web.js +42 -16
- package/dist/results/select.d.ts +38 -16
- package/dist/results/select.js +73 -25
- package/dist/results/types.d.ts +49 -14
- package/dist/runner/feedback/sink.d.ts +110 -0
- package/dist/runner/types.d.ts +513 -22
- package/dist/sandbox/docker.d.ts +23 -2
- package/dist/sandbox/e2b.d.ts +15 -1
- package/dist/sandbox/errors.d.ts +30 -3
- package/dist/sandbox/io-retry.d.ts +17 -0
- package/dist/sandbox/registry.d.ts +2 -0
- package/dist/sandbox/resolve.d.ts +18 -5
- package/dist/sandbox/retry.d.ts +11 -1
- package/dist/sandbox/types.d.ts +39 -5
- package/dist/sandbox/vercel.d.ts +7 -1
- package/dist/scoring/coverage.d.ts +30 -0
- package/dist/scoring/display.d.ts +21 -0
- package/dist/scoring/display.js +120 -0
- package/dist/scoring/types.d.ts +103 -20
- package/dist/shared/aggregate.d.ts +4 -2
- package/dist/shared/aggregate.js +8 -7
- package/dist/shared/types.d.ts +28 -0
- package/dist/tty-line.d.ts +0 -4
- package/dist/util.d.ts +23 -0
- package/docs-site/zh/README.md +44 -0
- package/docs-site/zh/examples/ai-agent-application.mdx +63 -0
- package/docs-site/zh/examples/coding-agent-extensions.mdx +57 -0
- package/docs-site/zh/examples/index.mdx +50 -0
- package/docs-site/zh/{concepts → explanation}/adapter.mdx +31 -13
- package/docs-site/zh/{concepts → explanation}/assert.mdx +7 -7
- package/docs-site/zh/{concepts → explanation}/drive.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/evals.mdx +4 -4
- package/docs-site/zh/{concepts → explanation}/experiment.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/hitl.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/judge.mdx +5 -5
- package/docs-site/zh/{concepts → explanation}/overview.mdx +11 -11
- package/docs-site/zh/{guides → explanation}/runner.mdx +18 -8
- package/docs-site/zh/{concepts → explanation}/tier.mdx +6 -6
- package/docs-site/zh/{guides → how-to}/agent-feedback-loop.mdx +35 -33
- package/docs-site/zh/{guides → how-to}/authoring.mdx +35 -2
- package/docs-site/zh/{guides → how-to}/ci-integration.mdx +23 -12
- package/docs-site/zh/{guides → how-to}/connect-otel.mdx +6 -6
- package/docs-site/zh/{guides → how-to}/connect-your-agent.mdx +47 -21
- package/docs-site/zh/{guides → how-to}/custom-reports.mdx +34 -39
- package/docs-site/zh/{guides → how-to}/dataset-fanout.mdx +25 -3
- package/docs-site/zh/{guides → how-to}/experiments.mdx +12 -5
- package/docs-site/zh/how-to/publish-report.mdx +105 -0
- package/docs-site/zh/{guides → how-to}/reporters.mdx +2 -2
- package/docs-site/zh/{guides → how-to}/sandbox-agent.mdx +56 -7
- package/docs-site/zh/how-to/sandbox-providers.mdx +350 -0
- package/docs-site/zh/{guides → how-to}/scoring-guide.mdx +4 -4
- package/docs-site/zh/{guides → how-to}/viewing-results.mdx +82 -39
- package/docs-site/zh/{guides → how-to}/write-experiment.mdx +6 -4
- package/docs-site/zh/{guides → how-to}/write-send.mdx +30 -14
- package/docs-site/zh/index.mdx +24 -26
- package/docs-site/zh/introduction.mdx +8 -8
- package/docs-site/zh/reference/builtin-agents.mdx +32 -5
- package/docs-site/zh/reference/capabilities.mdx +8 -8
- package/docs-site/zh/reference/cli.mdx +40 -12
- package/docs-site/zh/reference/define-agent.mdx +58 -5
- package/docs-site/zh/reference/define-config.mdx +1 -1
- package/docs-site/zh/reference/define-eval.mdx +42 -9
- package/docs-site/zh/reference/events.mdx +3 -3
- package/docs-site/zh/reference/expect.mdx +26 -1
- package/docs-site/zh/{guides → reference}/official-adapters.mdx +32 -8
- package/docs-site/zh/{guides → reference}/report-components.mdx +45 -33
- package/docs-site/zh/{guides → reference}/results-data.mdx +21 -13
- package/docs-site/zh/troubleshooting/debug-sandbox.mdx +57 -0
- package/docs-site/zh/troubleshooting/debugging.mdx +212 -0
- package/docs-site/zh/{quickstart.mdx → tutorials/quickstart.mdx} +5 -17
- package/package.json +10 -2
- package/src/agents/ai-sdk-otel.test.ts +1 -0
- package/src/agents/ai-sdk.test.ts +3 -0
- package/src/agents/ai-sdk.ts +3 -0
- package/src/agents/bub-install-spec.test.ts +34 -0
- package/src/agents/bub-install-spec.ts +32 -0
- package/src/agents/bub.ts +31 -32
- package/src/agents/claude-code.test.ts +130 -9
- package/src/agents/claude-code.ts +76 -4
- package/src/agents/codex.test.ts +189 -40
- package/src/agents/codex.ts +155 -14
- package/src/agents/coding-cli-versions.test.ts +15 -0
- package/src/agents/coding-cli-versions.ts +3 -0
- package/src/agents/index.ts +13 -2
- package/src/agents/langgraph.test.ts +204 -0
- package/src/agents/langgraph.ts +495 -0
- package/src/agents/marketplace.ts +85 -0
- package/src/agents/native-config.test.ts +179 -0
- package/src/agents/native-config.ts +267 -0
- package/src/agents/openai-compat.test.ts +1 -0
- package/src/agents/openai-compat.ts +1 -1
- package/src/agents/openclaw.test.ts +31 -0
- package/src/agents/openclaw.ts +171 -0
- package/src/agents/plugin-config.test.ts +1 -0
- package/src/agents/sdk-streams.test.ts +79 -0
- package/src/agents/sdk-streams.ts +55 -10
- package/src/agents/skills.test.ts +1 -0
- package/src/agents/streaming.test.ts +3 -9
- package/src/agents/streaming.ts +2 -2
- package/src/agents/types.ts +71 -8
- package/src/agents/ui-message-stream.test.ts +3 -0
- package/src/cli.ts +446 -124
- package/src/context/context.test.ts +51 -12
- package/src/context/context.ts +162 -30
- package/src/context/session.test.ts +2 -1
- package/src/context/session.ts +115 -7
- package/src/context/types.ts +30 -12
- package/src/define.test.ts +13 -8
- package/src/define.ts +25 -4
- package/src/expect/index.ts +53 -23
- package/src/i18n/en.ts +81 -17
- package/src/i18n/zh-CN.ts +80 -17
- package/src/o11y/cost.test.ts +1 -0
- package/src/o11y/execution-tree.test.ts +1 -20
- package/src/o11y/otlp/mappers/claude-code.test.ts +1 -0
- package/src/o11y/otlp/parse.test.ts +1 -0
- package/src/o11y/otlp/turn-otel.test.ts +1 -0
- package/src/o11y/parsers/bub.test.ts +1 -0
- package/src/o11y/parsers/claude-code.test.ts +1 -34
- package/src/o11y/parsers/openclaw.test.ts +154 -0
- package/src/o11y/parsers/openclaw.ts +310 -0
- package/src/o11y/prices.json +746 -311
- package/src/o11y/tool-names.test.ts +1 -0
- package/src/o11y/types.ts +16 -2
- package/src/report/aggregate.ts +178 -61
- package/src/report/built-in/index.tsx +9 -0
- package/src/report/components.tsx +625 -279
- package/src/report/compute.ts +723 -491
- package/src/report/dual-render.test.tsx +741 -1024
- package/src/report/flag.ts +104 -12
- package/src/report/format.ts +32 -12
- package/src/report/index.ts +119 -46
- package/src/report/load.ts +3 -2
- package/src/report/locale.ts +136 -65
- package/src/report/metrics.ts +108 -25
- package/src/report/primitives.tsx +196 -45
- package/src/report/react/AttemptList.tsx +30 -43
- package/src/report/react/DeltaTable.tsx +63 -45
- package/src/report/react/EvalList.tsx +0 -0
- package/src/report/react/ExperimentComparison.tsx +73 -0
- package/src/report/react/ExperimentList.tsx +50 -32
- package/src/report/react/MetricBars.tsx +5 -4
- package/src/report/react/MetricLine.tsx +13 -8
- package/src/report/react/MetricMatrix.tsx +2 -2
- package/src/report/react/MetricScatter.tsx +86 -34
- package/src/report/react/MetricTable.tsx +4 -76
- package/src/report/react/ScopeSummary.tsx +86 -0
- package/src/report/react/Scoreboard.tsx +28 -10
- package/src/report/react/cell.tsx +2 -2
- package/src/report/react/chart-math.test.ts +85 -0
- package/src/report/react/chart-math.ts +101 -22
- package/src/report/react/enhance.js +89 -5
- package/src/report/react/fixtures.ts +114 -154
- package/src/report/react/index.tsx +24 -39
- package/src/report/react/render.test.tsx +138 -158
- package/src/report/react/styles.css +243 -82
- package/src/report/report.test.ts +779 -841
- package/src/report/report.ts +423 -41
- package/src/report/text/faces.ts +290 -193
- package/src/report/text/plot.ts +1 -1
- package/src/report/text/table.ts +44 -7
- package/src/report/tree.ts +362 -104
- package/src/report/types.ts +261 -271
- package/src/report/web.ts +63 -20
- package/src/results/annotated-source.test.ts +62 -9
- package/src/results/annotated-source.ts +64 -6
- package/src/results/attempt-evidence.test.ts +13 -11
- package/src/results/attempt-evidence.ts +20 -13
- package/src/results/attempt-source.ts +6 -3
- package/src/results/copy.ts +150 -60
- package/src/results/host-equivalence.test.ts +34 -20
- package/src/results/index.ts +12 -4
- package/src/results/locator.test.ts +1 -22
- package/src/results/open.ts +15 -5
- package/src/results/publish.ts +149 -0
- package/src/results/results.test.ts +89 -54
- package/src/results/select.ts +104 -34
- package/src/results/truncate.ts +90 -0
- package/src/results/types.ts +43 -14
- package/src/results/writer.ts +31 -13
- package/src/runner/attempt.test.ts +138 -7
- package/src/runner/attempt.ts +603 -104
- package/src/runner/discover.test.ts +47 -0
- package/src/runner/discover.ts +36 -2
- package/src/runner/eval-source.test.ts +1 -27
- package/src/runner/feedback/agent.test.ts +504 -0
- package/src/runner/feedback/agent.ts +409 -0
- package/src/runner/feedback/ci.test.ts +562 -0
- package/src/runner/feedback/ci.ts +401 -0
- package/src/runner/feedback/coordinator.test.ts +317 -0
- package/src/runner/feedback/coordinator.ts +397 -0
- package/src/runner/feedback/failure.ts +40 -0
- package/src/runner/feedback/human.test.ts +616 -0
- package/src/runner/feedback/human.ts +535 -0
- package/src/runner/feedback/index.ts +66 -0
- package/src/runner/feedback/io.ts +78 -0
- package/src/runner/feedback/profile.test.ts +50 -0
- package/src/runner/feedback/profile.ts +58 -0
- package/src/runner/feedback/reducer.test.ts +395 -0
- package/src/runner/feedback/reducer.ts +260 -0
- package/src/runner/feedback/renderer.ts +82 -0
- package/src/runner/feedback/sink.ts +203 -0
- package/src/runner/feedback/testing.ts +106 -0
- package/src/runner/ledger.test.ts +230 -0
- package/src/runner/ledger.ts +329 -0
- package/src/runner/report.test.ts +128 -3
- package/src/runner/report.ts +33 -9
- package/src/runner/reporters/artifacts.ts +8 -2
- package/src/runner/reporters/braintrust.test.ts +8 -7
- package/src/runner/reporters/braintrust.ts +9 -2
- package/src/runner/reporters/index.ts +2 -2
- package/src/runner/reporters/json.test.ts +162 -0
- package/src/runner/reporters/json.ts +35 -8
- package/src/runner/reporters/shared.ts +1 -5
- package/src/runner/run.test.ts +760 -3
- package/src/runner/run.ts +243 -37
- package/src/runner/sandbox-prep.ts +3 -42
- package/src/runner/timing.ts +158 -0
- package/src/runner/types.ts +518 -22
- package/src/sandbox/checkpoint.test.ts +55 -0
- package/src/sandbox/checkpoint.ts +29 -8
- package/src/sandbox/cli-commands.ts +407 -0
- package/src/sandbox/docker.ts +115 -16
- package/src/sandbox/e2b-agent-template.test.ts +56 -0
- package/src/sandbox/e2b-agent-template.ts +94 -0
- package/src/sandbox/e2b.ts +74 -9
- package/src/sandbox/errors.ts +111 -4
- package/src/sandbox/index.ts +2 -0
- package/src/sandbox/io-retry.test.ts +58 -0
- package/src/sandbox/io-retry.ts +45 -0
- package/src/sandbox/keep-registry.test.ts +86 -0
- package/src/sandbox/keep-registry.ts +142 -0
- package/src/sandbox/keep.ts +178 -0
- package/src/sandbox/paths.test.ts +1 -0
- package/src/sandbox/paths.ts +19 -8
- package/src/sandbox/registry.ts +20 -3
- package/src/sandbox/resolve.ts +76 -11
- package/src/sandbox/retry.test.ts +70 -0
- package/src/sandbox/retry.ts +46 -4
- package/src/sandbox/types.ts +44 -6
- package/src/sandbox/vercel.ts +43 -20
- package/src/scoring/collector.ts +60 -17
- package/src/scoring/coverage.ts +95 -0
- package/src/scoring/diff.ts +81 -0
- package/src/scoring/display.test.ts +121 -0
- package/src/scoring/display.ts +133 -0
- package/src/scoring/evidence.test.ts +189 -0
- package/src/scoring/judge.test.ts +142 -0
- package/src/scoring/judge.ts +15 -18
- package/src/scoring/scoped.ts +217 -50
- package/src/scoring/types.ts +117 -20
- package/src/scoring/verdict.ts +16 -4
- package/src/shared/aggregate.ts +8 -6
- package/src/shared/types.ts +31 -0
- package/src/show/compose.ts +50 -67
- package/src/show/index.ts +127 -56
- package/src/show/render.ts +662 -131
- package/src/show/report-host.test.ts +188 -0
- package/src/show/report-host.ts +375 -0
- package/src/show/show.test.ts +320 -54
- package/src/tty-line.ts +8 -26
- package/src/util.test.ts +1 -0
- package/src/util.ts +41 -0
- package/src/view/app/App.test.tsx +69 -0
- package/src/view/app/App.tsx +144 -48
- package/src/view/app/components/AttemptModal.tsx +423 -11
- package/src/view/app/components/CodeView.tsx +41 -14
- package/src/view/app/components/CopyControls.tsx +2 -2
- package/src/view/app/i18n.ts +37 -17
- package/src/view/app/lib/attempt-route.test.ts +1 -0
- package/src/view/app/lib/verdict.ts +7 -9
- package/src/view/app/main.tsx +13 -8
- package/src/view/app/pages/{RunsPage.tsx → AttemptsPage.tsx} +6 -6
- package/src/view/app/types.ts +4 -1
- package/src/view/artifact-serving.test.ts +2 -1
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +17 -17
- package/src/view/data.test.ts +10 -3
- package/src/view/data.ts +155 -49
- package/src/view/index.ts +56 -41
- package/src/view/server.ts +37 -15
- package/src/view/shared/types.ts +34 -5
- package/src/view/styles.css +227 -0
- package/src/view/view-report.test.ts +167 -62
- package/dist/report/built-ins/experiment-comparison.d.ts +0 -1
- package/dist/report/built-ins/experiment-comparison.js +0 -13
- package/dist/report/built-ins/index.d.ts +0 -1
- package/dist/report/built-ins/index.js +0 -2
- package/dist/report/react/GroupSummary.d.ts +0 -8
- package/dist/report/react/GroupSummary.js +0 -8
- package/dist/report/react/RunOverview.d.ts +0 -8
- package/dist/report/react/RunOverview.js +0 -12
- package/docs-site/zh/example/ai-agent-application.mdx +0 -152
- package/docs-site/zh/example/claude-code-codex-plugin.mdx +0 -167
- package/docs-site/zh/example/claude-code-codex-skill.mdx +0 -152
- package/docs-site/zh/example/showcase.mdx +0 -39
- package/docs-site/zh/guides/publish-report.mdx +0 -91
- package/docs-site/zh/guides/sandbox-providers.mdx +0 -102
- package/src/report/built-in-user-parity.test.tsx +0 -640
- package/src/report/built-ins/experiment-comparison.tsx +0 -19
- package/src/report/built-ins/index.ts +0 -2
- package/src/report/react/GroupSummary.tsx +0 -66
- package/src/report/react/RunOverview.tsx +0 -109
- package/src/runner/reporters/console.ts +0 -70
- package/src/runner/reporters/live.test.ts +0 -56
- package/src/runner/reporters/live.ts +0 -247
- package/src/runner/reporters/quiet.test.ts +0 -66
- package/src/runner/reporters/quiet.ts +0 -49
- package/src/runner/reporters/table.ts +0 -277
- /package/docs-site/zh/{example/tier1-ai-sdk-v7.mdx → examples/integrations/ai-sdk-v7.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-claude-sdk.mdx → examples/integrations/claude-sdk.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-codex-sdk.mdx → examples/integrations/codex-sdk.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-langgraph.mdx → examples/integrations/langgraph.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-pi-sdk.mdx → examples/integrations/pi-sdk.mdx} +0 -0
- /package/docs-site/zh/{guides → how-to}/fixtures.mdx +0 -0
|
@@ -11,9 +11,15 @@ Evals 应该和测试一样进入 CI。它们能在 PR 阶段发现 agent 行为
|
|
|
11
11
|
默认情况下,只要存在失败的 gate,[NiceEval](https://niceeval.com/) 将以非零状态码退出。CI 中通常使用 `--strict`,让失败更明确。
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npx niceeval exp ci
|
|
14
|
+
NICEEVAL_LANG=en npx niceeval exp ci \
|
|
15
|
+
--output ci \
|
|
16
|
+
--strict \
|
|
17
|
+
--json .niceeval/ci-summary.json \
|
|
18
|
+
--junit .niceeval/junit.xml
|
|
15
19
|
```
|
|
16
20
|
|
|
21
|
+
CI profile 不输出 ANSI、spinner 或动态表格。日志使用单一有序 stdout 流,只追加 start、低频 heartbeat、失败/错误、diagnostic 和最终 result;通过的 Attempt 不逐条打印。
|
|
22
|
+
|
|
17
23
|
## GitHub Actions 示例
|
|
18
24
|
|
|
19
25
|
```yaml
|
|
@@ -32,8 +38,12 @@ jobs:
|
|
|
32
38
|
node-version: 22
|
|
33
39
|
cache: npm
|
|
34
40
|
- run: npm ci
|
|
35
|
-
- run:
|
|
41
|
+
- run: >-
|
|
42
|
+
npx niceeval exp ci --output ci --strict
|
|
43
|
+
--json .niceeval/ci-summary.json
|
|
44
|
+
--junit .niceeval/junit.xml
|
|
36
45
|
env:
|
|
46
|
+
NICEEVAL_LANG: en
|
|
37
47
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
38
48
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
39
49
|
```
|
|
@@ -52,18 +62,19 @@ jobs:
|
|
|
52
62
|
</Step>
|
|
53
63
|
</Steps>
|
|
54
64
|
|
|
55
|
-
## JUnit
|
|
56
|
-
|
|
57
|
-
```ts
|
|
58
|
-
import { defineConfig } from "niceeval";
|
|
59
|
-
import { Console, JUnit } from "niceeval/reporters";
|
|
65
|
+
## JSON、JUnit 和结构化错误
|
|
60
66
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
```text
|
|
68
|
+
niceeval: start total=24 configs=3 concurrency=10 reused=18
|
|
69
|
+
niceeval: errored locator=@12h8m4k1 eval=fixtures/button experiment=ci/codex phase=sandbox.create reason="E2B sandbox allocation failed after 5 attempts"
|
|
70
|
+
niceeval: result=failed passed=23 failed=0 errored=1 reused=18 duration=128s
|
|
71
|
+
niceeval: json=.niceeval/ci-summary.json
|
|
72
|
+
niceeval: junit=.niceeval/junit.xml
|
|
64
73
|
```
|
|
65
74
|
|
|
66
|
-
|
|
75
|
+
退出码是第一层红绿信号;JSON、JUnit 和结果快照是完整机器接口,日志行只用于搜索和 annotation。`errored` 行带 locator、eval/experiment 身份、已知时的正式 phase,以及一层 `reason` 摘要。详细 cause、stack 和 diagnostics 保存在 Attempt 的 `result.json`,可在保留 artifact 后运行 `niceeval show @<locator>` 回顾。
|
|
76
|
+
|
|
77
|
+
CLI 显式要求的 JSON/JUnit 和默认 results artifact 都是 required 输出:写入失败必须让 job 判红,不能只留 warning 后退出 0。想把结果同时上报到 Braintrust 这类实验平台,见 [Reporter 上报](./reporters)。
|
|
67
78
|
|
|
68
79
|
## 只检查发现
|
|
69
80
|
|
|
@@ -80,7 +91,7 @@ npx niceeval list
|
|
|
80
91
|
## 控制并发
|
|
81
92
|
|
|
82
93
|
```bash
|
|
83
|
-
npx niceeval exp ci --max-concurrency 2
|
|
94
|
+
npx niceeval exp ci --output ci --max-concurrency 2
|
|
84
95
|
```
|
|
85
96
|
|
|
86
97
|
标准 GitHub-hosted runner 上,sandbox eval 并发不宜过高。远程 HTTP eval 可以按服务限流能力调高。
|
|
@@ -4,11 +4,11 @@ sidebarTitle: "OTel 接入"
|
|
|
4
4
|
description: "把应用已经在发的 OTel span 也发给 NiceEval 一份,niceeval view 里就有每轮的调用瀑布图。断言不从这里来——接好 send 那一刻断言就齐了。"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
先说清这条接入**不**改变什么:断言。`t.calledTool`、`t.maxTokens`、耗时这些判定的依据,全部来自你的 adapter 在 `send` 里返回的 `Turn`(`events` + `usage`)——接好 send 的那一刻,全套断言就齐了,和 OTel 没有关系(见[接入你的 agent](/zh/
|
|
7
|
+
先说清这条接入**不**改变什么:断言。`t.calledTool`、`t.maxTokens`、耗时这些判定的依据,全部来自你的 adapter 在 `send` 里返回的 `Turn`(`events` + `usage`)——接好 send 的那一刻,全套断言就齐了,和 OTel 没有关系(见[接入你的 agent](/zh/how-to/connect-your-agent))。
|
|
8
8
|
|
|
9
9
|
OTel 接入买到的是另一样东西:**`niceeval view` 里的调用瀑布图**。应用内部每次模型调用、每次工具执行、各自的耗时和 token,按轮铺开成一条时间线——失败的 eval 为什么失败、慢的轮次慢在哪一步,经常一眼就在瀑布图里。
|
|
10
10
|
|
|
11
|
-
如果你的应用已经在发 OTel trace——AI SDK 的 telemetry、LangGraph 的 LangSmith 导出、OpenLLMetry / OpenInference 自动埋点,或自己按 GenAI 语义埋的点——那瀑布图的数据你已经在生产了:让应用把 span 也发给 [NiceEval](https://niceeval.com/) 一份即可,应用代码一行不改,仍是无侵入(见 [Tier](/zh/
|
|
11
|
+
如果你的应用已经在发 OTel trace——AI SDK 的 telemetry、LangGraph 的 LangSmith 导出、OpenLLMetry / OpenInference 自动埋点,或自己按 GenAI 语义埋的点——那瀑布图的数据你已经在生产了:让应用把 span 也发给 [NiceEval](https://niceeval.com/) 一份即可,应用代码一行不改,仍是无侵入(见 [Tier](/zh/explanation/tier))。
|
|
12
12
|
|
|
13
13
|
## 原理(一段话)
|
|
14
14
|
|
|
@@ -197,12 +197,12 @@ export default defineAgent({
|
|
|
197
197
|
|
|
198
198
|
## 边界
|
|
199
199
|
|
|
200
|
-
- **断言相关的一切都在 send**。想断工具调用,把它映射进 `events`(官方转换器或手写映射,见[写 send](/zh/
|
|
201
|
-
- **多轮会话、HITL 不归 span 管**。span 没有"等人输入"语义,会话续接也是应用协议的事——这两样照常在 `send` 里做(会话续接见[写 send](/zh/
|
|
200
|
+
- **断言相关的一切都在 send**。想断工具调用,把它映射进 `events`(官方转换器或手写映射,见[写 send](/zh/how-to/write-send));想断 usage,`send` 返回里带上。不存在"span 里有、events 里没有,于是断言看 span"的路径。
|
|
201
|
+
- **多轮会话、HITL 不归 span 管**。span 没有"等人输入"语义,会话续接也是应用协议的事——这两样照常在 `send` 里做(会话续接见[写 send](/zh/how-to/write-send),HITL 概念见 [HITL](/zh/explanation/hitl))。
|
|
202
202
|
- **收不到 span 会有提示**。整个 run 0 span 通常是端点没接上(env 没注入、服务没重启),[NiceEval](https://niceeval.com/) 会在日志里提示;瀑布图为空,断言照常判。
|
|
203
203
|
|
|
204
204
|
## 相关阅读
|
|
205
205
|
|
|
206
|
-
- [接入你的 agent](/zh/
|
|
207
|
-
- [写 send](/zh/
|
|
206
|
+
- [接入你的 agent](/zh/how-to/connect-your-agent) —— 断言从哪来:send 的事件映射。
|
|
207
|
+
- [写 send](/zh/how-to/write-send) —— 手写 adapter 的完整教程,第六步就是本页的 adapter 侧接法。
|
|
208
208
|
- [事件流参考](/zh/reference/events) —— 断言消费的事件长什么样。
|
|
@@ -14,11 +14,11 @@ description: "接入的全景:写一个 adapter、配一个 experiment、跑
|
|
|
14
14
|
<Card title="AI SDK 应用" icon="bolt" href="/zh/reference/builtin-agents">
|
|
15
15
|
用 Vercel AI SDK(`useChat` 后端)写的应用:内置 `uiMessageStreamAgent` 无侵入接它的 HTTP 接口,零映射、含 HITL,有完整的 before/after 示例。不用读本文。
|
|
16
16
|
</Card>
|
|
17
|
-
<Card title="Coding agent CLI" icon="terminal" href="/zh/
|
|
17
|
+
<Card title="Coding agent CLI" icon="terminal" href="/zh/how-to/sandbox-agent">
|
|
18
18
|
评 claude-code / codex / bub 这类改文件的 coding agent:用内置 sandbox agent。
|
|
19
19
|
</Card>
|
|
20
20
|
<Card title="其它 AI Agent" icon="plug">
|
|
21
|
-
自研 agent loop、LangGraph / OpenAI Agents SDK 应用、已部署 agent:手写 send(本文 + [写 send](/zh/
|
|
21
|
+
自研 agent loop、LangGraph / OpenAI Agents SDK 应用、已部署 agent:手写 send(本文 + [写 send](/zh/how-to/write-send))。应用已埋 OTel 的话顺手接上,`niceeval view` 多一张调用瀑布图([OTel 接入](/zh/how-to/connect-otel))。
|
|
22
22
|
</Card>
|
|
23
23
|
</CardGroup>
|
|
24
24
|
|
|
@@ -51,7 +51,7 @@ export default defineAgent({
|
|
|
51
51
|
});
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
URL 先写死没关系——怎么把它从 experiment 传进来,见下文[「参数怎么进」](#参数怎么进:experiment-声明,adapter-消费)。`send` 的完整契约(`TurnInput` / `AgentContext` / `Turn` 各字段)见 [Adapter](/zh/
|
|
54
|
+
URL 先写死没关系——怎么把它从 experiment 传进来,见下文[「参数怎么进」](#参数怎么进:experiment-声明,adapter-消费)。`send` 的完整契约(`TurnInput` / `AgentContext` / `Turn` 各字段)见 [Adapter](/zh/explanation/adapter)。
|
|
55
55
|
|
|
56
56
|
就算 agent runtime 和 eval 在同一个代码库里,也照样走 HTTP,不要把 `fetch` 换成进程内的函数直调:
|
|
57
57
|
|
|
@@ -101,12 +101,12 @@ npx niceeval exp my-bot refund # 只跑 ID 以 refund 开头的
|
|
|
101
101
|
npx niceeval view # 本地查看器里看结果
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
**跑通的样子**:人在终端运行时会看到一个动态 dashboard,完成和排队数量只在原位更新;失败、错误和 warning 会永久留在上方。结束时只打印摘要、失败 locator 和结果路径。`npx niceeval view` 里能看到每条 Eval 逐轮的输入、事件和评分明细。
|
|
105
105
|
|
|
106
106
|
没跑通时,按报错的位置分三类排查:
|
|
107
107
|
|
|
108
108
|
- **`fetch` 直接抛错**(连接被拒等):应用没起来,或 `send` 里的 URL 不对——先用 `curl` 对那个接口发一次同样的请求确认。
|
|
109
|
-
- **`t.succeeded()` 没过、本轮判定是 failed
|
|
109
|
+
- **`t.succeeded()` 没过、本轮判定是 failed**:请求发出去了,但应用返回的 Turn 是 `failed`。把协议中的失败映射到 `Turn.status` 或标准 `error` event;需要额外保留的有限上下文用 `ctx.diagnostic(...)`,不要打印完整响应体。
|
|
110
110
|
- **只有内容断言没过**:接入本身已经通了——在 `view` 里对照 `t.reply` 的实际值,调断言或调应用。
|
|
111
111
|
|
|
112
112
|
到这里接入已经完成:文本断言和 judge 评分都能用了。想要更多断言(工具、多轮、审批流),见文末的增量地图。
|
|
@@ -171,9 +171,35 @@ export default defineExperiment({
|
|
|
171
171
|
| `signal` | 运行器(超时与取消) | 挂到发出的每个请求上 |
|
|
172
172
|
| `model` | experiment 的 `model` | 应用接口收模型选择就随请求转发;不收就忽略 |
|
|
173
173
|
| `flags` | experiment 的 `flags` | 原样转发(请求体、header 都行),应用按参数切换变体 |
|
|
174
|
-
| `telemetry` | 配置了 OTel 接入时出现 | 只碰 `headers`:每轮新的 W3C `traceparent`,spread 进请求头。接收端点每次运行都一样,在 `defineConfig` 里固定、应用启动时指向它,不从 send 传——见 [OTel 接入](/zh/
|
|
175
|
-
| `session` | 运行器(每条会话线一份) | 会话续接与 HITL 停轮现场的存取器都在它上面:`history()`、`id` / `capture()`、`hold()` / `take()`,见[写 send](/zh/
|
|
176
|
-
| `
|
|
174
|
+
| `telemetry` | 配置了 OTel 接入时出现 | 只碰 `headers`:每轮新的 W3C `traceparent`,spread 进请求头。接收端点每次运行都一样,在 `defineConfig` 里固定、应用启动时指向它,不从 send 传——见 [OTel 接入](/zh/how-to/connect-otel) |
|
|
175
|
+
| `session` | 运行器(每条会话线一份) | 会话续接与 HITL 停轮现场的存取器都在它上面:`history()`、`id` / `capture()`、`hold()` / `take()`,见[写 send](/zh/how-to/write-send) |
|
|
176
|
+
| `progress(update)` | 运行器(绑定当前 `agent.run`) | 报告 Turn/tool 的短期状态;Human dashboard 可显示,结果不保存 |
|
|
177
|
+
| `diagnostic(input)` | 运行器(绑定当前 `agent.run`) | 保存协议退化、响应不完整等 warning/error;可由 locator 下钻回顾 |
|
|
178
|
+
|
|
179
|
+
### Adapter 里的进度、诊断和致命错误
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
async send(input, ctx) {
|
|
183
|
+
ctx.progress({ message: "等待上游模型" });
|
|
184
|
+
const response = await callAgent(input, { signal: ctx.signal });
|
|
185
|
+
|
|
186
|
+
if (response.eventsIncomplete) {
|
|
187
|
+
ctx.diagnostic({
|
|
188
|
+
code: "incomplete-event-stream",
|
|
189
|
+
level: "warning",
|
|
190
|
+
message: "上游响应缺少工具结果事件",
|
|
191
|
+
data: { requestId: response.requestId },
|
|
192
|
+
dedupeKey: `incomplete-event-stream:${response.requestId}`,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return toTurn(response);
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
`progress` 是可覆盖的短期状态;`diagnostic` 是运行结束后仍能回顾的有界记录。两者都不能指定 phase 或输出流,也不会自动改变 `Turn.status` 或 Attempt 判定。连接失败、解析无法继续等基础设施错误应抛出异常;正常收到的被测 Agent 失败通过 `Turn.status: "failed"` 表达。
|
|
201
|
+
|
|
202
|
+
终端只显示错误的一层摘要和 locator。完整 code、message、cause、stack 与 diagnostics 在 `result.json` 中,使用 `niceeval show @<locator>` 查看。OTel trace 只补充调用关系和耗时,不是错误记录的前提。
|
|
177
203
|
|
|
178
204
|
同一个 agent 对着本地和生产分别跑,就是两个 experiment 文件、两份工厂参数:
|
|
179
205
|
|
|
@@ -196,7 +222,7 @@ npx niceeval exp local
|
|
|
196
222
|
npx niceeval exp prod
|
|
197
223
|
```
|
|
198
224
|
|
|
199
|
-
不要把 URL 放进 CLI 位置参数——experiment 名之后的位置参数只用于过滤 eval ID。experiment 的完整字段(`runs`、`budget`、并发、`sandbox`)见[写实验](/zh/
|
|
225
|
+
不要把 URL 放进 CLI 位置参数——experiment 名之后的位置参数只用于过滤 eval ID。experiment 的完整字段(`runs`、`budget`、并发、`sandbox`)见[写实验](/zh/how-to/write-experiment)。
|
|
200
226
|
|
|
201
227
|
## 之后的增量:一张地图
|
|
202
228
|
|
|
@@ -204,13 +230,13 @@ npx niceeval exp prod
|
|
|
204
230
|
|
|
205
231
|
| 想解锁什么 | 给 adapter 加什么 | 去哪看 |
|
|
206
232
|
|---|---|---|
|
|
207
|
-
| 工具断言(`calledTool` / `toolOrder` / 负断言) | 把应用返回映射成标准事件流 | [写 send](/zh/
|
|
208
|
-
| 多轮对话、`t.newSession()` 隔离 | 接上 `ctx.session`:`history()` 或 `id` + `capture()` | [写 send](/zh/
|
|
209
|
-
| 审批流(HITL,人工介入) | 停轮返回 `waiting` + `input.requested`,回答轮续跑 | [HITL](/zh/
|
|
210
|
-
| `niceeval view` 的调用瀑布图 | 应用把 OTel span 发给 NiceEval(不影响断言) | [OTel 接入](/zh/
|
|
211
|
-
| feature A/B 对比 | 应用把变体暴露成 `flags` 可切换的配置 | [Tier](/zh/
|
|
233
|
+
| 工具断言(`calledTool` / `toolOrder` / 负断言) | 把应用返回映射成标准事件流 | [写 send](/zh/how-to/write-send)、[事件流参考](/zh/reference/events) |
|
|
234
|
+
| 多轮对话、`t.newSession()` 隔离 | 接上 `ctx.session`:`history()` 或 `id` + `capture()` | [写 send](/zh/how-to/write-send) |
|
|
235
|
+
| 审批流(HITL,人工介入) | 停轮返回 `waiting` + `input.requested`,回答轮续跑 | [HITL](/zh/explanation/hitl) |
|
|
236
|
+
| `niceeval view` 的调用瀑布图 | 应用把 OTel span 发给 NiceEval(不影响断言) | [OTel 接入](/zh/how-to/connect-otel) |
|
|
237
|
+
| feature A/B 对比 | 应用把变体暴露成 `flags` 可切换的配置 | [Tier](/zh/explanation/tier)、[写实验](/zh/how-to/write-experiment) |
|
|
212
238
|
|
|
213
|
-
这些增量落在哪一档、各档买到什么,见 [Tier](/zh/
|
|
239
|
+
这些增量落在哪一档、各档买到什么,见 [Tier](/zh/explanation/tier)。
|
|
214
240
|
|
|
215
241
|
## 参考实现
|
|
216
242
|
|
|
@@ -218,9 +244,9 @@ npx niceeval exp prod
|
|
|
218
244
|
|
|
219
245
|
## 相关阅读
|
|
220
246
|
|
|
221
|
-
- [官方适配器一览](/zh/
|
|
222
|
-
- [写 send](/zh/
|
|
223
|
-
- [Adapter](/zh/
|
|
224
|
-
- [OTel 接入](/zh/
|
|
225
|
-
- [Tier](/zh/
|
|
226
|
-
- [写实验](/zh/
|
|
247
|
+
- [官方适配器一览](/zh/reference/official-adapters) —— 被测对象能直接用官方 Adapter 时,Sandbox / 非 Sandbox 各有哪些、配置项怎么写。
|
|
248
|
+
- [写 send](/zh/how-to/write-send) —— 手写 Adapter 的完整教程:七步递进,从发一条消息到 HITL、OTel、flags。
|
|
249
|
+
- [Adapter](/zh/explanation/adapter) —— `send` 的契约:`TurnInput` / `AgentContext` / `Turn` 逐字段。
|
|
250
|
+
- [OTel 接入](/zh/how-to/connect-otel) —— 把应用的 span 也发给 [NiceEval](https://niceeval.com/),换 `niceeval view` 的调用瀑布图。
|
|
251
|
+
- [Tier](/zh/explanation/tier) —— 三档接入各投入什么、买到什么。
|
|
252
|
+
- [写实验](/zh/how-to/write-experiment) —— `defineExperiment` 的完整字段。
|
|
@@ -4,23 +4,23 @@ sidebarTitle: "自定义报告"
|
|
|
4
4
|
description: "一份报告就是一个报告文件:官方宿主打开结果、注入数据,双面组件让同一份自定义报告同时用于 niceeval show 与 niceeval view。"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
[查看结果](/zh/
|
|
7
|
+
[查看结果](/zh/how-to/viewing-results)讲「用」:官方两扇门 `niceeval show`(终端)和 `niceeval view`(网页)怎么看。本页讲「写」:官方摆法不够时,怎么写一份自己的报告——考试成绩单、代码行数榜、质量 × 成本 frontier。
|
|
8
8
|
|
|
9
9
|
一份报告就是一个报告文件。你不用打开结果目录、不用写渲染代码、不用起自己的应用:`niceeval show` / `niceeval view` 本体就是宿主——替你打开结果、把数据注入进来,你用官方组件和 `Row` / `Col` 摆版面,写完把文件路径递给 `--report`,终端和网页两扇门就都认它——官方的证据室深链、`--run` 历史切换、静态导出,自定义报告全部原样享有。
|
|
10
10
|
|
|
11
|
-
## view 的默认报告也是一份报告定义
|
|
11
|
+
## show / view 的默认报告也是一份报告定义
|
|
12
12
|
|
|
13
|
-
`niceeval view` 不传 `--report` 时渲染的默认报告不是私有实现,而是 `niceeval/report`
|
|
13
|
+
`niceeval show` / `view` 不传 `--report` 时渲染的默认报告不是私有实现,而是 `niceeval/report` 公开导出的一个值:
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
|
-
import {
|
|
16
|
+
import { ExperimentComparison } from "niceeval/report";
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
`
|
|
19
|
+
`ExperimentComparison` 先按 experiment id 的父目录切成可比组,再为每组分别计算成本 × 端到端成功率散点图和实验明细表。`compare/bub` 与 `compare/codex` 可以同图,`dev-e2b/bub` 必须在另一个组;顶层 experiment 各自成为单例组。网页持有全部组并一次聚焦一组;终端命中多组时只列索引和单组查看命令,命中单组时才展开详情。两面都不会生成跨组总榜。
|
|
20
20
|
|
|
21
21
|
| | 网页(人看) | 终端(agent 和你看) |
|
|
22
22
|
| --- | --- | --- |
|
|
23
|
-
| 官方默认 |
|
|
23
|
+
| 官方默认 | 分组比较报告(网页面) | 同一分组比较报告(文本面) |
|
|
24
24
|
| 自定义摆法 | `niceeval view --report reports/exam.tsx` | `niceeval show --report reports/exam.tsx` |
|
|
25
25
|
|
|
26
26
|
四个格子是同一个宿主。自定义只有三个层次,逐层深入:
|
|
@@ -39,16 +39,13 @@ import { CostPassRateComparison } from "niceeval/report";
|
|
|
39
39
|
// reports/exam.tsx —— 一份定义,两扇门共用
|
|
40
40
|
import {
|
|
41
41
|
defineReport, Col, Section,
|
|
42
|
-
|
|
43
|
-
costUSD, passRate,
|
|
42
|
+
ExperimentComparison, Scoreboard,
|
|
44
43
|
} from "niceeval/report";
|
|
45
44
|
|
|
46
45
|
export default defineReport(async ({ selection }) => {
|
|
47
|
-
const experiments = await ExperimentList.data(selection);
|
|
48
46
|
return (
|
|
49
47
|
<Col>
|
|
50
|
-
<
|
|
51
|
-
<ExperimentList items={experiments} />
|
|
48
|
+
<ExperimentComparison data={await ExperimentComparison.data(selection)} />
|
|
52
49
|
<Section title="考试成绩单">
|
|
53
50
|
<Scoreboard data={await Scoreboard.data(selection, { rows: "agent", subjects: "evalGroup" })} />
|
|
54
51
|
</Section>
|
|
@@ -62,7 +59,7 @@ niceeval show --report reports/exam.tsx # 终端:同一棵树走文本面
|
|
|
62
59
|
niceeval view --report reports/exam.tsx # 网页:同一棵树走网页面,attempt 深链直达证据室
|
|
63
60
|
```
|
|
64
61
|
|
|
65
|
-
注入的上下文只有两样,全部是[结果数据 API](/zh/
|
|
62
|
+
注入的上下文只有两样,全部是[结果数据 API](/zh/reference/results-data) 的原语,宿主没有私有通道:`results` 就是 `openResults(".niceeval")` 的返回(实验、历次快照、attempt 级 `diff()`、`trace()` 都在上面);`selection` 是宿主替你挑好的那份结果。挑选规则是:对每个实验、每道 eval,取该实验历史运行里最新的那次判定——只按前缀重跑了一部分 eval,其余 eval 的判定从更早的运行补齐,不会因为一次局部重跑就整体退回某一份残缺快照。默认报告吃的就是这份 `selection`,快照在 `selection.snapshots`,挑选提醒在 `selection.warnings`。默认挑法不合口径时,拿 `results` 自己挑,手工挑的 `Snapshot[]` 数组同样能喂给每个组件。
|
|
66
63
|
|
|
67
64
|
报告文件里有两种数据形态。实体列表的 `.data(selection)` 返回普通数组:`ExperimentListItem[]`、`EvalListItem[]`、`AttemptListItem[]`。报告作者用 JavaScript `.filter()` / `.slice()` 决定展示哪些实体,再把数组作为 `items` 传给列表;组件不藏另一套过滤 DSL。指标图形和汇总组件收算好的 `data`;其中 `MetricScatter` 也提供 `selection` 简写,由宿主在渲染前计算。计算后的组件只渲染传入数据,不碰结果目录。
|
|
68
65
|
|
|
@@ -70,9 +67,9 @@ niceeval view --report reports/exam.tsx # 网页:同一棵树走网页面
|
|
|
70
67
|
|
|
71
68
|
命令行的范围先作用在挑选上,报告拿到的就是收窄到这个范围后的 `selection`:位置参数的 eval id 前缀收窄 Selection 覆盖的 eval(覆盖提醒的分母同样收窄到范围内),`--run` 把结果根换成指定目录,`--experiment` 让 Selection 只留该实验。`--history` 与 `--report` 互斥——趋势在报告里用 `exp.snapshots` 自己摆;证据切面(`--eval` / `--execution` / `--diff`)只看证据,不渲染报告。
|
|
72
69
|
|
|
73
|
-
页面里的每个组件都是**双面**的:网页面是 React 渲染,终端面是字符渲染,两面吃同一份算好的数据。实体列表按 experiment → Eval → Attempt 展示事实;指标表、矩阵、条形图、成绩单、散点图、趋势图和差异表展示聚合值。完整清单见[报告组件](/zh/
|
|
70
|
+
页面里的每个组件都是**双面**的:网页面是 React 渲染,终端面是字符渲染,两面吃同一份算好的数据。实体列表按 experiment → Eval → Attempt 展示事实;指标表、矩阵、条形图、成绩单、散点图、趋势图和差异表展示聚合值。完整清单见[报告组件](/zh/reference/report-components)。网页面的实体、格子和点深链到 Attempt 详情,终端面印出对应的 `niceeval show <eval id>` 下钻命令。
|
|
74
71
|
|
|
75
|
-
|
|
72
|
+
默认报告没有特权:它就是上面导出的 `ExperimentComparison`。你的报告和它同级;需要同样的“按目录分组、组内比较”摆法就直接引用它,不需要就不摆。自己直接组合 `MetricScatter` / `ExperimentList` 时,通用组件只消费你传入的数据,不会自动分组;把跨组 Selection 传进去就表示你明确要做跨组分析。
|
|
76
73
|
|
|
77
74
|
## 排版:Row 与 Col 在两个面都成立
|
|
78
75
|
|
|
@@ -105,17 +102,17 @@ codex 78.0/100 40/50 38/50 │ codex 80% $0.51
|
|
|
105
102
|
|
|
106
103
|
想把实验按目录前缀分组、每组顶部摆一块紧凑统计(通过率、experiment/eval 数、failed/errored、总成本、最后运行时间),用官方组件 `GroupSummary`。它的计算函数 `GroupSummary.data` 只吃一份已经收窄好的 Selection——不管你怎么分组,把对应组的 Selection 传进去,就是同一套折叠口径(eval 级折叠计票、null-safe 总成本、组内最后运行时间的最大值),不是另一套近似公式。
|
|
107
104
|
|
|
108
|
-
常见的分法是按 experiment id 的目录前缀(`compare/bub-low` 属于组 `compare
|
|
105
|
+
常见的分法是按 experiment id 的目录前缀(`compare/bub-low` 属于组 `compare`,顶层实验以自己的完整 id 形成单例组);用 `Selection.filter` 收窄出每组的 Selection,就能一组摆一块:
|
|
109
106
|
|
|
110
107
|
```tsx
|
|
111
108
|
// reports/groups.tsx —— 按 experiment id 前缀分组,每组顶部摆一块统计
|
|
112
109
|
import { defineReport, Col, Section, GroupSummary } from "niceeval/report";
|
|
113
110
|
import type { Snapshot } from "niceeval/report";
|
|
114
111
|
|
|
115
|
-
// experiment id
|
|
116
|
-
function groupOf(snapshot: Snapshot): string
|
|
112
|
+
// experiment id 的完整父路径当组名;顶层 experiment 各自成为单例组。
|
|
113
|
+
function groupOf(snapshot: Snapshot): string {
|
|
117
114
|
const parts = snapshot.experimentId.split("/");
|
|
118
|
-
return parts.length > 1 ? parts.slice(0, -1).join("/") :
|
|
115
|
+
return parts.length > 1 ? parts.slice(0, -1).join("/") : snapshot.experimentId;
|
|
119
116
|
}
|
|
120
117
|
|
|
121
118
|
export default defineReport(async ({ selection }) => {
|
|
@@ -126,9 +123,7 @@ export default defineReport(async ({ selection }) => {
|
|
|
126
123
|
groups.map(async (key) => {
|
|
127
124
|
const scoped = selection.filter((s) => groupOf(s) === key);
|
|
128
125
|
const summary = <GroupSummary data={await GroupSummary.data(scoped)} />;
|
|
129
|
-
return key
|
|
130
|
-
<Section key={key} title={key}>{summary}</Section>
|
|
131
|
-
);
|
|
126
|
+
return <Section key={key} title={key}>{summary}</Section>;
|
|
132
127
|
}),
|
|
133
128
|
)}
|
|
134
129
|
</Col>
|
|
@@ -153,7 +148,7 @@ latest 2026-07-01T11:30:00Z
|
|
|
153
148
|
// reports/golf.tsx —— code-golf:谁写出能用的代码,谁写得短
|
|
154
149
|
import {
|
|
155
150
|
defineReport, Col, MetricTable,
|
|
156
|
-
defineMetric,
|
|
151
|
+
defineMetric, endToEndPassRate, costUSD,
|
|
157
152
|
} from "niceeval/report";
|
|
158
153
|
|
|
159
154
|
// 项目自己的口径:只比能用的代码的行数
|
|
@@ -166,8 +161,8 @@ const codeLines = defineMetric({
|
|
|
166
161
|
async value(attempt) {
|
|
167
162
|
const diff = await attempt.diff();
|
|
168
163
|
if (!diff) return null;
|
|
169
|
-
return Object.
|
|
170
|
-
.reduce((
|
|
164
|
+
return Object.keys(diff.files)
|
|
165
|
+
.reduce((sum, path) => sum + (diff.get(path) ?? "").split("\n").length, 0);
|
|
171
166
|
},
|
|
172
167
|
});
|
|
173
168
|
|
|
@@ -175,8 +170,8 @@ export default defineReport(async ({ selection }) => (
|
|
|
175
170
|
<Col>
|
|
176
171
|
<MetricTable data={await MetricTable.data(selection, {
|
|
177
172
|
rows: "agent",
|
|
178
|
-
columns: [
|
|
179
|
-
sort:
|
|
173
|
+
columns: [endToEndPassRate, codeLines, costUSD],
|
|
174
|
+
sort: endToEndPassRate,
|
|
180
175
|
})} />
|
|
181
176
|
</Col>
|
|
182
177
|
));
|
|
@@ -195,7 +190,7 @@ codex 80% 355 lines $0.51
|
|
|
195
190
|
|
|
196
191
|
`label` 可以是一份文案,也可以按语言给:`label: { en: "Code lines", "zh-CN": "代码行数" }`——查看器界面切语言时,按语言给的 label 跟着切;只给一份就两种语言都用它。指标算出来的数字本身不分语言。
|
|
197
192
|
|
|
198
|
-
内置指标里 `
|
|
193
|
+
内置指标里 `endToEndPassRate` / `taskPassRate` / `executionReliability` / `costUSD` / `durationMs` / `tokens` 只读 Attempt 自带的判定、用量这些字段,任何一份结果目录都算得出。没有限定词的“成功率”使用 `endToEndPassRate`:passed 记 1,failed 和 errored 都记 0。`taskPassRate` 只在形成可信判定的样本上衡量答题质量,errored 不参与;展示它时应明确写“可判定任务通过率”,不能简称成功率。要区分答题质量和执行问题,把 `endToEndPassRate`、`taskPassRate`、`executionReliability` 三列并排。`turns`(Agent 的总轮次)不一样,它读 `attempt.o11y()`——这份数据 `copySnapshots` 缺省会随行,但如果发布脚本显式给了 `artifacts` 列表又没把 `"o11y"` 写进去,它就不在发布根里(见[结果数据 API](/zh/reference/results-data)的「发布」一节),指标渲染成 `—`,不是 0。自己写的指标只要读了 `o11y()` / `diff()` 这类 artifact(就像上面 `codeLines` 读 `attempt.diff()`),发布前都要过一遍同样的检查。
|
|
199
194
|
|
|
200
195
|
## 换分组:三种维度
|
|
201
196
|
|
|
@@ -221,7 +216,7 @@ const vendor: Dimension = {
|
|
|
221
216
|
|
|
222
217
|
<MetricTable data={await MetricTable.data(selection, {
|
|
223
218
|
rows: vendor,
|
|
224
|
-
columns: [
|
|
219
|
+
columns: [endToEndPassRate, costUSD],
|
|
225
220
|
})} />
|
|
226
221
|
```
|
|
227
222
|
|
|
@@ -248,7 +243,7 @@ export default defineExperiment({
|
|
|
248
243
|
<MetricLine data={await MetricLine.data(selection, {
|
|
249
244
|
x: flag("latencyMs", { label: "Simulated latency", unit: "ms" }),
|
|
250
245
|
series: flag("agents", { label: (v) => `${v} agents` }),
|
|
251
|
-
y:
|
|
246
|
+
y: endToEndPassRate,
|
|
252
247
|
})} />
|
|
253
248
|
```
|
|
254
249
|
|
|
@@ -264,12 +259,12 @@ export default defineExperiment({
|
|
|
264
259
|
|
|
265
260
|
```tsx
|
|
266
261
|
// reports/cost-board.tsx
|
|
267
|
-
import { defineReport, Col, Table, MetricTable, costUSD,
|
|
262
|
+
import { defineReport, Col, Table, MetricTable, costUSD, endToEndPassRate } from "niceeval/report";
|
|
268
263
|
|
|
269
264
|
export default defineReport(async ({ selection }) => {
|
|
270
265
|
const board = await MetricTable.data(selection, {
|
|
271
266
|
rows: "agent",
|
|
272
|
-
columns: [
|
|
267
|
+
columns: [endToEndPassRate, costUSD],
|
|
273
268
|
});
|
|
274
269
|
return (
|
|
275
270
|
<Col>
|
|
@@ -283,7 +278,7 @@ export default defineReport(async ({ selection }) => {
|
|
|
283
278
|
key: r.key,
|
|
284
279
|
cells: {
|
|
285
280
|
agent: r.key,
|
|
286
|
-
pass: r.cells[
|
|
281
|
+
pass: r.cells[endToEndPassRate.name].display,
|
|
287
282
|
// 缺数据交 null,组件渲染成 —;不要自己填 0
|
|
288
283
|
cost: r.cells[costUSD.name].value === null ? null : r.cells[costUSD.name].display,
|
|
289
284
|
},
|
|
@@ -302,7 +297,7 @@ codex 80% $0.51
|
|
|
302
297
|
克劳德 — —
|
|
303
298
|
```
|
|
304
299
|
|
|
305
|
-
列宽按**终端显示宽度**算:一个汉字占 2 列,所以中文 agent 名、中文题目名都不会把表撕歪。`align: "right"` 让数字列右对齐。格子给 `null` 就渲染 `—`,不补 0。行上带 `locator` 就多出一列 attempt,网页面点进证据室、终端面把 locator 交给 `niceeval show`。完整字段见[报告组件](/zh/
|
|
300
|
+
列宽按**终端显示宽度**算:一个汉字占 2 列,所以中文 agent 名、中文题目名都不会把表撕歪。`align: "right"` 让数字列右对齐。格子给 `null` 就渲染 `—`,不补 0。行上带 `locator` 就多出一列 attempt,网页面点进证据室、终端面把 locator 交给 `niceeval show`。完整字段见[报告组件](/zh/reference/report-components)的「表格」一节。
|
|
306
301
|
|
|
307
302
|
### 不是表:`defineComponent` 加文本排版函数
|
|
308
303
|
|
|
@@ -324,7 +319,7 @@ codex 80% $0.51
|
|
|
324
319
|
// reports/passbars.tsx
|
|
325
320
|
import {
|
|
326
321
|
defineReport, defineComponent, Col, Style, MetricTable,
|
|
327
|
-
bar, padEnd, stringWidth,
|
|
322
|
+
bar, padEnd, stringWidth, endToEndPassRate,
|
|
328
323
|
} from "niceeval/report";
|
|
329
324
|
|
|
330
325
|
interface BarRow { key: string; ratio: number | null; display: string }
|
|
@@ -356,11 +351,11 @@ const PassBars = defineComponent<{ rows: BarRow[] }>({
|
|
|
356
351
|
});
|
|
357
352
|
|
|
358
353
|
export default defineReport(async ({ selection }) => {
|
|
359
|
-
const board = await MetricTable.data(selection, { rows: "agent", columns: [
|
|
354
|
+
const board = await MetricTable.data(selection, { rows: "agent", columns: [endToEndPassRate] });
|
|
360
355
|
const rows = board.rows.map((r) => ({
|
|
361
356
|
key: r.key,
|
|
362
|
-
ratio: r.cells[
|
|
363
|
-
display: r.cells[
|
|
357
|
+
ratio: r.cells[endToEndPassRate.name].value, // 格子键锚在指标对象上,不裸写字符串
|
|
358
|
+
display: r.cells[endToEndPassRate.name].display,
|
|
364
359
|
}));
|
|
365
360
|
return (
|
|
366
361
|
<Col>
|
|
@@ -394,10 +389,10 @@ codex ████████████████░░░░ 80%
|
|
|
394
389
|
niceeval view --report reports/exam.tsx --out site
|
|
395
390
|
```
|
|
396
391
|
|
|
397
|
-
产物是纯静态文件:你的报告页是首页,证据室(transcript、trace、代码视图)在同一站内,报告里的每个数字点进去就是证据。组件不 hydrate;页面内联一小段官方脚本,提供表头排序、行过滤、图表悬停这些浏览操作,浏览器禁用 JS 时页面仍完整可读。交给任何静态托管即可。CI 上没有 `.niceeval/` 时,先用 `copySnapshots` 把快照瘦身进仓库再导出,流程见[查看结果](/zh/
|
|
392
|
+
产物是纯静态文件:你的报告页是首页,证据室(transcript、trace、代码视图)在同一站内,报告里的每个数字点进去就是证据。组件不 hydrate;页面内联一小段官方脚本,提供表头排序、行过滤、图表悬停这些浏览操作,浏览器禁用 JS 时页面仍完整可读。交给任何静态托管即可。CI 上没有 `.niceeval/` 时,先用 `copySnapshots` 把快照瘦身进仓库再导出,流程见[查看结果](/zh/how-to/viewing-results#导出与静态托管)。
|
|
398
393
|
|
|
399
394
|
双面组件的网页面就是普通 React 组件,`data` 函数就是普通 TS 函数——想把某一块指标表嵌进已有的内部面板,import 组件喂数据就行。那是零件的复用,不是另一套报告系统:报告的家在官方宿主。算数据与渲染分离部署时(CI 落 JSON、另一个应用 fetch),两侧锁同一个 niceeval 版本是硬要求——组件数据不带版本戳,兼容性跟随包版本。
|
|
400
395
|
|
|
401
396
|
## 界线:内置命令不长配置
|
|
402
397
|
|
|
403
|
-
一次只渲染一份报告,`--report` 收显式文件路径——没有 `reports/` 目录自动发现、没有插件注册表、没有配置文件。自定义指标和自定义组件都住在你的报告文件里,随文件一起递入,宿主不为它们长任何注册面。不传 `--report` 时渲染的就是内置的 `
|
|
398
|
+
一次只渲染一份报告,`--report` 收显式文件路径——没有 `reports/` 目录自动发现、没有插件注册表、没有配置文件。自定义指标和自定义组件都住在你的报告文件里,随文件一起递入,宿主不为它们长任何注册面。不传 `--report` 时渲染的就是内置的 `ExperimentComparison`,你的报告和它是同级实现。
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "数据驱动测试(dataset fan-out):用多份数据运行同一套 eval"
|
|
3
3
|
sidebarTitle: "数据驱动测试"
|
|
4
|
-
description: "从 .eval.ts
|
|
4
|
+
description: "从 .eval.ts 文件导出数组或 keyed record,将一套 eval 逻辑展开为多个 case。用 loadYaml 或 loadJson 读取外部数据集,并获得稳定 ID。"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
数据驱动测试(dataset fan-out)适合大量结构相同、输入不同的测试。例如 SQL 生成、意图分类、检索问答和工具选择。
|
|
8
8
|
|
|
9
9
|
## 工作原理
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
没有外部业务 ID 时,一个 `.eval.ts` 文件默认导出数组:
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
14
|
import { defineEval } from "niceeval";
|
|
@@ -41,6 +41,25 @@ sql/0001
|
|
|
41
41
|
|
|
42
42
|
序号零填充,便于稳定引用和过滤。
|
|
43
43
|
|
|
44
|
+
数据源已经带稳定 case、issue 或 benchmark ID 时,默认导出 keyed record:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
export default Object.fromEntries(
|
|
48
|
+
rows.map((row) => [
|
|
49
|
+
row.issueId,
|
|
50
|
+
defineEval({
|
|
51
|
+
description: row.title,
|
|
52
|
+
async test(t) {
|
|
53
|
+
await t.send(row.prompt);
|
|
54
|
+
t.succeeded();
|
|
55
|
+
},
|
|
56
|
+
}),
|
|
57
|
+
]),
|
|
58
|
+
);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
文件是 `evals/swelancer.eval.ts`、key 是 `15193` 时,ID 就是 `swelancer/15193`。key 必须是一个非空路径片段:不能是 `.` / `..`,不能含 `/`、`\\` 或控制字符。NiceEval 按 key 字典序发现,数据源返回顺序变化不会改变运行顺序。
|
|
62
|
+
|
|
44
63
|
## 从 YAML / JSON 加载
|
|
45
64
|
|
|
46
65
|
```ts
|
|
@@ -63,8 +82,11 @@ cases:
|
|
|
63
82
|
# 运行整个数据集
|
|
64
83
|
npx niceeval exp local sql
|
|
65
84
|
|
|
66
|
-
#
|
|
85
|
+
# 只运行第一个数组 case
|
|
67
86
|
npx niceeval exp local sql/0000
|
|
87
|
+
|
|
88
|
+
# 运行一个 keyed case
|
|
89
|
+
npx niceeval exp local swelancer/15193
|
|
68
90
|
```
|
|
69
91
|
|
|
70
92
|
## 数据集 vs 独立文件
|
|
@@ -35,7 +35,7 @@ export default defineExperiment({
|
|
|
35
35
|
npx niceeval exp compare-models # 把同组各 model 并排出报告
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
这样每个配置独立成文件:可命名、可 diff、可单独 review,"这一组就是对照"
|
|
38
|
+
这样每个配置独立成文件:可命名、可 diff、可单独 review,"这一组就是对照"在文件结构上就讲清楚了。默认 `niceeval show` / `view` 也沿用这条边界:只把同一文件夹下的 experiment 放进同一张成本 × 端到端成功率图和实验表,不同文件夹分别显示。
|
|
39
39
|
|
|
40
40
|
某一格结果反常、需要单独复现时,用该配置的完整 id(`组/文件名`)精确只跑这一格,不用先跑完整组:
|
|
41
41
|
|
|
@@ -43,18 +43,18 @@ npx niceeval exp compare-models # 把同组各 model 并排出报告
|
|
|
43
43
|
npx niceeval exp compare-models/gpt-5.4
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
`defineExperiment` 的字段怎么写、`flags` 怎么透传到 adapter,见[写实验](/zh/
|
|
46
|
+
`defineExperiment` 的字段怎么写、`flags` 怎么透传到 adapter,见[写实验](/zh/how-to/write-experiment)。
|
|
47
47
|
|
|
48
48
|
## 适合比较什么
|
|
49
49
|
|
|
50
50
|
- 不同 Adapters。
|
|
51
51
|
- 不同模型(Tier 1 接入即可:应用接口暴露模型选择,`model` 经 `ctx.model` 透传)。
|
|
52
52
|
- 不同 prompts 或 feature flags(要求 Tier 3 接入:变体在应用内部,需要应用把它暴露成 experiment 可选的 flag,经 `flags` → `ctx.flags` 透传)。
|
|
53
|
-
- 不同 sandbox
|
|
54
|
-
- 不同运行环境条件(比如装不装某个记忆工具的二进制、有没有预置状态):环境差异写在 `sandbox` spec 的 `.setup()` / `.teardown()` 钩子里,一个变体一个 experiment 文件,见 [
|
|
53
|
+
- 不同 sandbox provider。
|
|
54
|
+
- 不同运行环境条件(比如装不装某个记忆工具的二进制、有没有预置状态):环境差异写在 `sandbox` spec 的 `.setup()` / `.teardown()` 钩子里,一个变体一个 experiment 文件,见 [沙箱 provider · 环境钩子](/zh/how-to/sandbox-providers#环境钩子)。
|
|
55
55
|
- 同一任务的 pass@N。
|
|
56
56
|
|
|
57
|
-
Tier 1 / Tier 2 / Tier 3 的定义见 [Tier](/zh/
|
|
57
|
+
Tier 1 / Tier 2 / Tier 3 的定义见 [Tier](/zh/explanation/tier)。
|
|
58
58
|
|
|
59
59
|
## 查看结果
|
|
60
60
|
|
|
@@ -67,6 +67,13 @@ api-validation claude-code pass@3 = 1/3 (33%) mean 41s
|
|
|
67
67
|
|
|
68
68
|
除了 pass rate,还应该看平均耗时、token、成本和失败类型。
|
|
69
69
|
|
|
70
|
+
```bash
|
|
71
|
+
npx niceeval show --experiment compare-models
|
|
72
|
+
npx niceeval view
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`show --experiment` 按路径段匹配 id 前缀,所以组名会选中组内所有配置,但不会误中名字只是在字符串上相似的另一个组。`view` 默认加载完整结果,直接在页面里选组;`--experiment` 对它只是可选的启动时收窄。
|
|
76
|
+
|
|
70
77
|
## 设计 experiment 的建议
|
|
71
78
|
|
|
72
79
|
- 保持 eval 集合稳定,避免比较时混入新变量。
|