refactor(evaluator)!: collapse the dataset entrypoints into evaluate_dataset - #1202
Conversation
📝 WalkthroughWalkthroughThe SDK now requires metric sequences for ChangesUnified evaluation API
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/nemo_evaluator_sdk/examples/high_level_evaluate_walkthrough.ipynb`:
- Line 463: Update the directory_result call in high_level_evaluate_walkthrough
so evaluator.run_sync uses only its supported arguments; remove the unsupported
pattern keyword and pass the dataset directory through the accepted dataset path
or glob representation.
In
`@packages/nemo_platform_ext/src/nemo_platform_ext/skills/nemo-evaluator/references/sdk-execution.md`:
- Line 84: Update the Evaluator API documentation around the metrics=[metric]
example and the descriptions of Evaluator.run and Evaluator.run_sync to require
a metric sequence, not a bare metric, and state that both methods return
BenchmarkEvaluationResult. Remove references to the deprecated single-metric
overload and alternate result types while preserving the existing usage example
structure.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: a3d12cfb-6c1e-400e-a288-05b7eee51c09
⛔ Files ignored due to path filters (5)
sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/execution/backends/base.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/execution/backends/local/backend.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/execution/evaluator.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/values/multi_metric_results.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/skills/nemo-evaluator/references/sdk-execution.mdis excluded by!sdk/**
📒 Files selected for processing (23)
packages/nemo_evaluator_sdk/examples/examples.pypackages/nemo_evaluator_sdk/examples/high_level_evaluate_walkthrough.ipynbpackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/execution/README.mdpackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/execution/backends/base.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/execution/backends/local/backend.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/execution/evaluator.pypackages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/values/multi_metric_results.pypackages/nemo_evaluator_sdk/tests/execution/backends/local/test_backend.pypackages/nemo_evaluator_sdk/tests/execution/test_evaluator.pypackages/nemo_evaluator_sdk/tests/execution/test_metric_execution.pypackages/nemo_evaluator_sdk/tests/execution/test_resolvers.pypackages/nemo_evaluator_sdk/tests/metrics/test_bleu.pypackages/nemo_evaluator_sdk/tests/metrics/test_f1.pypackages/nemo_evaluator_sdk/tests/metrics/test_number_check.pypackages/nemo_evaluator_sdk/tests/metrics/test_rouge.pypackages/nemo_evaluator_sdk/tests/metrics/test_string_check.pypackages/nemo_evaluator_sdk/tests/metrics/test_tool_calling.pypackages/nemo_evaluator_sdk/tests/test_api.pypackages/nemo_platform_ext/src/nemo_platform_ext/skills/nemo-evaluator/references/sdk-execution.mdplugins/nemo-evaluator/src/nemo_evaluator/jobs/evaluate.pyplugins/nemo-evaluator/tests/test_evaluate_job.pyskills/nemo-evaluator-plugin/assets/examples/plugin_sdk_examples.pyskills/nemo-evaluator-plugin/references/execution.md
|
…dataset The backend contract carried two dataset entrypoints that differed only in metric arity and return type: `evaluate` took one metric and returned an `EvaluationResult`, `evaluate_benchmark` took a list and returned a `BenchmarkEvaluationResult`. One metric is the degenerate case of several, so the two collapse into a single `evaluate_dataset(metrics=[...])`. `Evaluator.run`/`run_sync` lose their single-metric overloads — three each — leaving the three that discriminate on config and target, where the choice actually matters. Callers pass a list. `BenchmarkEvaluationResult` gains the `__str__` that `EvaluationResult` already had. Without it, collapsing to one result type would have quietly regressed `print(result)` to a pydantic dump for every caller. Two smaller things fall out of having one destination rather than two. The plugin's evaluate job no longer unwraps a one-metric list to hit the singular overload. And a backend's flavour is now decided by a single method, so the async/sync/mixed three-way collapses to two: a lone method is either a coroutine function or it is not, and there is no mixed client left to reject. This frees the name `evaluate` for the taskset entrypoint, which follows separately; nothing claims it here. BREAKING CHANGE: `EvaluationBackend.evaluate` and `evaluate_benchmark` are replaced by `evaluate_dataset`, which takes a metric list and returns a `BenchmarkEvaluationResult`. `Evaluator.run` and `run_sync` no longer accept a bare metric. Signed-off-by: Sandy Chapman <schapman@nvidia.com>
…eft behind The collapse removed the single-metric overloads but left seven `run_sync` calls in the high-level walkthrough passing a bare metric. They fail as `AttributeError: 'tuple' object has no attribute 'output_spec'`, which says nothing about the real problem. The earlier sweep matched `metrics=[` and these pass named variables, so none of them matched. `BenchmarkEvaluationResult` is now what every dataset run returns, but it was only reachable from `nemo_evaluator_sdk.values.multi_metric_results` — callers could not name the type they are handed. It is exported from the package root and from `values` alongside `EvaluationResult`. The walkthrough's directory example passed `pattern=`, which no `Evaluator` method has ever accepted, on this branch or before it. The loader already handles a glob path when no pattern is given, so the example points `dataset` at `part-*.jsonl` and keeps excluding the file it is meant to exclude. The skill reference still promised a bare metric and one of two result types. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Sandy Chapman <schapman@nvidia.com>
|
/nvskills-ci |
fb45f3f to
acfad8e
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
|
/nvskills-ci |
Signed-off-by: nvskills-svc-account <svc-nvskills-signing@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@skills/nemo-evaluator-plugin/skill-card.md`:
- Line 2: Update the generator or Sphinx substitution configuration that
produces the skill-card description so the NeMo Evaluator product name comes
from a defined substitution rather than hardcoded text, then regenerate the
affected skill-card files, including the referenced 12-12 variant. Do not edit
the generated markdown manually.
- Around line 38-39: Update the generator or its markdownlint configuration so
generated skill cards include blank lines after the headings corresponding to
lines 38, 53, and 81, plus before the table at line 72; then regenerate
skills/nemo-evaluator-plugin/skill-card.md and verify the markdownlint warnings
are resolved without manually editing the generated file.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: a4da49de-df7d-4d41-b38a-656c17421c5d
📒 Files selected for processing (3)
skills/nemo-evaluator-plugin/BENCHMARK.mdskills/nemo-evaluator-plugin/skill-card.mdskills/nemo-evaluator-plugin/skill.oms.sig
Summary
The backend contract carried two dataset entrypoints that differed only in metric arity and return type —
evaluatetook one metric and returned anEvaluationResult,evaluate_benchmarktook a list and returned aBenchmarkEvaluationResult. One metric is the degenerate case of several, so this collapses them into a singleevaluate_dataset(metrics=[...]).This is deliberately a subtraction: 210 insertions against 781 deletions. It also frees the name
evaluate, which a follow-up will use for the taskset entrypoint — nothing claims it here, soevaluate_datasetis the only method on the contract after this lands.Related Issue
None.
Changes
EvaluationBackend/SyncEvaluationBackend:evaluateandevaluate_benchmarkreplaced byevaluate_dataset. Same forLocalBackendand the sync adapter.Evaluator.run/run_sync: the three single-metric overloads on each are gone, leaving the three that discriminate on config and target. Return type narrows toBenchmarkEvaluationResult.BenchmarkEvaluationResult.__str__, matchingEvaluationResult. Without it, collapsing to one result type would have quietly regressedprint(result)to a pydantic dump for every caller.metrics if len(metrics) > 1 else metrics[0], which existed only to reach the singular overload._MixedBackendand its test go with it.metrics=[...]across tests, examples, skill references and the walkthrough notebook.Type of Change
Quality Gates
Existing tests were retargeted rather than duplicated: the backend fakes now carry one dataset result instead of two, and
test_api.pyasserts the multi-metric shape, whose row columns are metric-qualified (output.exact-match.exact-match) and whose preview is per-metric. Two tests were removed because their subjects no longer exist — the single-vs-sequence dispatch fallthrough, and the mixed sync/async client.Verification
Signed-off-by:traileruv run pre-commit run -apasses, or any blocked checks are identified belowuv run --frozen pytest packages/nemo_evaluator_sdk/tests plugins/nemo-evaluator/tests docs/evaluator -quv run --frozen pytest e2e -quv run ruff check/ruff format --checkbash tools/lint/run-ty-check.shmake vendoruv run pre-commit run -aTwo hooks fail on this machine only, neither related to the diff:
Run uv lock with platform uvrequires uv 0.9.14 exactly and exits on the version check before reading a file.Check for uv.lock driftpasses and nopyproject.tomlchanged.Run UI lint-stagedfails withmise ERROR No version is set for shim: pnpmin a fresh worktree. This PR changes nothing underweb/.Notes for reviewers
Two things surfaced only once this was split out of a larger branch:
is_metric/is_metric_sequenceare not dead yet. The plugin'sbundle_metrics_for_specstill dispatches on single-vs-sequence, so they survive until the plugin's own API goes plural._is_sync_backendcost theTypeGuardnarrowing on the final branch, so it stays, with an unreachableelsethat exists so the checker can narrow.Summary by CodeRabbit