Experiments
NeMo Experiments is the comparison layer for agent optimization tasks, such as evaluating the impact of changes to a harness, infrastructure, tools, or agent code. It gives you one place to visualize and compare evaluation results from the runner of your choice — Harbor, the NeMo Optimizer, NeMo Evaluator, or your own — ranked on the metrics that matter, such as cost, latency, and evaluator scores.
Those metrics are derived from NeMo Intake observability data, the same traces and evaluator results your runs already produce, so any runner that lands telemetry in Intake feeds the same comparison.
Before You Start
Who This Is For
NeMo Experiments is for anyone running evaluations on their agent who needs a way to compare, analyze, and promote the results. For example: engineers iterating on prompts, models, tools, or routing; teams benchmarking many models or configurations at once; and reviewers who need a shared leaderboard to decide what to promote.
Requirements
- A NeMo Platform environment with the
intakeservice running. - The platform entity store (Postgres).
- A reachable ClickHouse database.
- A producer that creates Evaluations and sends their telemetry: the NeMo Optimizer, a benchmark or evaluation framework such as Harbor, or a direct API integration.
- (Recommended) NeMo Studio for the full UI — trace comparison views, a
customizable leaderboard, and Pareto charts. Everything is also available through the API, but
Studio is where the experience really lives. The Experiments UI is gated by the
VITE_FF_EXPERIMENTfeature flag, which is off by default.
How It Works
What It Does
Experiments computes comparable, always-current metrics for your evaluation runs. For each run it rolls up cost, latency, tokens, and per-evaluator scores from the underlying telemetry in ClickHouse and returns them as ranked rows. Rollups are computed at read time, so a leaderboard always reflects current telemetry, with no denormalized score table to maintain.
You group runs however makes sense — an insight to investigate, a model bake-off, a benchmark leaderboard, or the top runs promoted from several groups — and a single run can belong to more than one group. Sorting, filtering, and pinning within a group surface the runs that matter.
When to Use It
Use Experiments when you need to:
- Compare candidates from the optimizer, a prompt or model change, or a routing strategy against a baseline.
- Run a benchmark leaderboard: import many runs into one Experiment and rank them by the metric that matters.
- Track iteration over time: keep one Experiment per project so successive attempts stay side by side.
- Standardize comparison across a team: everyone reads the same metrics, in the same place, with the same vocabulary.
Experiments are most useful once real evaluation telemetry exists. A new group can start empty and fill in as runs land.
Core Concepts and Data Model
Experiments sit on top of Intake’s telemetry hierarchy (span → trace → session):
- An Experiment is a named container of Evaluations. It holds durable metadata (
description,summary, free-formmetadata, optionalinsight_id) and view configuration: adefault_sortand apareto(default X/Y metrics for the Pareto view). - An Evaluation is one run and one leaderboard row. It records producer-supplied fields
(
dataset_name,dataset_version,source_link,metadata,description,status,root_cause), theexperiment_idsit belongs to (at least one — an Evaluation can live in more than one Experiment), and an optionalparent_evaluation_idlinking a variant back to the run it was derived from. - A Session is one test-case execution within an Evaluation, a single ingested run made of spans. Sessions carry per-case status, latency, token and cost totals, and evaluator scores.
At read time, each Evaluation is enriched with rollups derived from its sessions in ClickHouse:
Metric aggregates expose these statistics: sum, mean, median, p90, p95, p99, count. A
metric path is therefore test_case_count, cost_usd.<stat>, latency_ms.<stat>,
tokens.<stat>, or evaluators.<name>.<stat> — the same grammar used for sorting and filtering below.
Two things about evaluator rollups specifically:
- Response shape.
evaluators.<name>.<stat>is the sort/filter query grammar. In the Evaluation JSON the same scores come back underaggregate_scores— a map keyed by evaluator name, each value carrying the stats above — alongside anevaluator_nameslist. There is noevaluatorsfield in the response;evaluators.<name>.<stat>(query) readsaggregate_scores[<name>].<stat>(response). - Missing-value semantics. Evaluator rollups are test-case-weighted: each stat is computed over
test_case_count, the full set of test cases, with a test case that didn’t report a given evaluator counted as0rather than dropped.
Two Experiment-level behaviors are worth knowing:
- Default sort. An Experiment stores a
default_sort(a sort-param string such as-evaluators.solved.mean) so its leaderboard opens ordered by the metric the team cares about. It defaults to-created_at(newest first). - Pinning. Any Evaluation can be pinned to the top of its Experiment — for example, the current baseline. Pins are workspace-shared: everyone with access sees the same pinned set, regardless of the active sort.
Get Started
Setup
Experiments are part of the intake service, so any running NeMo Platform already serves them. Point
at whatever you have, whether a deployed platform or a local one from nemo setup or
nemo quickstart up:
ClickHouse must be reachable either way, since the leaderboard rollups are computed from it at read time.
Running from source (local development)
If you are bringing the pieces up yourself from a repository checkout, start them in this order.
-
ClickHouse (required for the rollups):
-
Backend services:
intakeplus itsauthandentitiesdependencies.--portdefaults to8080; dropuv runif you installed thenemoCLI: -
Studio (optional, for the leaderboard and drill-down UI). From the
web/workspace, with the Experiments feature flag on and intake enabled for trace drill-down:
Confirm the Experiments read path is reachable:
A 200 with a (possibly empty) list is healthy. A 503 means the service is running but cannot reach
ClickHouse; reads that need metric rollups will fail until it recovers.
First Workflow
Create an Experiment, add an Evaluation, send it telemetry, then see it in Studio and through the API.
1. Create the Experiment (the leaderboard container):
Capture its id for the next step:
2. Add an Evaluation to it. experiment_ids is a list, so an Evaluation belongs to one or more
existing Experiments:
An Evaluation is a durable record on its own; its leaderboard metrics appear once evaluation telemetry for it lands in Intake.
3. Send it telemetry. Send the run’s telemetry to Intake just as you would for any agent run, whether it comes from the optimizer, a benchmark framework like Harbor, or your own code. Tag each session with the Evaluation’s identity:
- For ATIF and chat-completions, add a top-level
evaluation_contextobject to the ingest payload carryingevaluation_id(the Evaluation’s name) andtest_case_id. - For OTLP, set the
nemo.experiment.idandnemo.test_case.idroot-span attributes.
The per-evaluator scores on the leaderboard come from evaluator results captured on those
sessions, either automatically from ATIF verifier rewards or explicitly through the evaluator-results
endpoint. See
Capture Evaluator Results for both
paths, and Observe Agents for the ingestion paths themselves.
The nemo-experiments-upload skill walks this through end to end.
test_case_id is required for a populated leaderboard. A session tagged with only evaluation_id
still ingests and appears in the Evaluation’s session list, but it doesn’t count toward
test_case_count or any rollup — so the row reads as all zeros, with tokens, model, and agent blank
too. Always send test_case_id alongside evaluation_id.
Confirm It Worked
List the Experiment’s Evaluations and confirm the new row is present:
Then open Studio and navigate to /workspaces/default/experiment, then open
reranker-prompt-iteration.
What good looks like: the Experiment opens in Studio, your Evaluation appears as a row, and once
its sessions are ingested the row shows non-zero test_case_count, cost, latency, tokens, and
evaluator scores. Sorting by a metric reorders the table, and opening the Evaluation lists its
individual test cases.
Common Workflows
Add an Evaluation to an Existing Experiment
This is the everyday operation: an Experiment already exists and you want to record another run in it.
Create the Evaluation with the Experiment’s id in experiment_ids:
To move or re-scope an existing Evaluation’s membership, PATCH its experiment_ids, which must
stay non-empty:
An Evaluation can belong to several Experiments at once, which is useful when the same run should appear on both a per-project board and a cross-project benchmark.
Update an Evaluation
Use PATCH for partial updates: only the fields you send change. name, dataset_name, and
dataset_version are immutable:
PUT does a full replace of the mutable fields — omitted fields reset — so prefer PATCH for one-off
edits.
Rank an Experiment by the Metric That Matters
List an Experiment’s Evaluations sorted by a metric. Prefix the field with - for descending:
You can sort by an entity column (name, created_at) or any rollup metric (test_case_count,
cost_usd.<stat>, latency_ms.<stat>, tokens.<stat>, evaluators.<name>.<stat>). In Studio, click
a column header. If the Experiment has a default_sort, the leaderboard opens already ordered that
way.
Filter to the Evaluations You Care About
Filter by a metric range to narrow the leaderboard — for example, only Evaluations whose average cost is under $0.50:
Metric filters use the same grammar as sort, such as filter[test_case_count][\$gte]=5 or
filter[evaluators.groundedness.mean][\$gte]=0.8. You can also filter by
filter[metadata.<key>]=<value>, filter[status]=…, filter[is_pinned]=true, and
created_at/updated_at ranges. In Studio, use the column filters on cost, latency, test-case count,
and evaluator columns.
Set an Experiment’s Default Sort
Store the ordering the team should see first so no one has to re-sort each visit:
In Studio, set it from the Experiment’s Edit dialog.
Pin a Baseline to the Top
Keep the current baseline, or any reference run, at the top of the Experiment for everyone:
Pinned Evaluations float to the top of the leaderboard regardless of the active sort. List just the
pinned set with filter[is_pinned]=true.
Drill into an Evaluation’s Test Cases
Open one Evaluation’s sessions to see per-test-case behavior: status, latency, cost, and evaluator scores:
Use this to move from “this candidate scores lower” to “these specific cases regressed.” In Studio, open the Evaluation row to reach its sessions, then follow a session into its trace in Intake.
Configure the Pareto View
Each Experiment stores a pareto config: the default X/Y metrics for its Pareto (trade-off) chart in
Studio, defaulting to cost vs. latency. The axes are x_metric and y_metric, and each takes a base
metric id — cost_usd, latency_ms, or evaluators.<name>, with no .<stat> suffix. Set it on
create or update:
Delete an Experiment or Evaluation
Deleting an Experiment soft-deletes it and cascades to its Evaluations; deleting an Evaluation
soft-deletes just that row. Soft-deleted records are hidden from list and get operations unless
explicitly requested with filter[is_deleted]=true:
Where Evaluations Come From
You usually don’t create Evaluations by hand. Common producers:
- Optimizer: records each run as an Experiment and its candidates as Evaluations, so results land automatically. See Optimize Agents.
- Evaluation framework: a framework like Harbor sends complete trajectories through Intake’s ATIF ingest, and each run becomes an Evaluation with its final metrics as evaluator results. See Observe Agents.
- Direct API: create the Experiment and Evaluations, then ingest their sessions, for a custom evaluation pipeline.
Do It with an Agent
If you are working with a coding agent, the nemo-experiments-upload skill automates this whole path:
create an Experiment, add an Evaluation, log traces and scores to an ingest endpoint, and verify the
rollups. It ships with reference guides for the ATIF/Harbor, chat-completions, and OTLP ingest formats
and a troubleshooting matrix. Invoke it when you want to upload, log, ingest, or publish evaluation
runs to NeMo Experiments.
Operations
Limits
- An Experiment is sorted and filtered in memory over the full set of its Evaluations, bounded to
1,000 Evaluations per Experiment. A request that would select more is rejected with
413rather than returned partially sorted. Narrow it with filters. - Page size is capped at 1,000 records.
- Metric sorting and filtering require rollups. If ClickHouse is unavailable, a metric sort or filter
returns
503rather than a silently unsorted result. Sorting and filtering by entity columns (name,created_at) still works.
Security and Access Control
All Experiments endpoints are workspace-scoped under /apis/intake/v2/workspaces/{workspace}/, and
the service checks workspace access before reading or writing.
Evaluation metadata, source_link, and related fields are producer-supplied and surfaced to
reviewers, so treat them like any other telemetry payload. Do not store secrets, credentials, or
regulated data unless your deployment’s policy permits it.
Retention and Storage
Experiment and Evaluation metadata lives in the platform entity store and persists until you delete it; it does not expire on the telemetry TTL. Rollups are derived from ClickHouse at read time, so leaderboard metrics reflect whatever telemetry is still retained: span and trace-index data expire after 90 days, while evaluator results are retained without that span TTL. An Experiment older than the span window keeps its records and evaluator-based scores, but cost, latency, and run-count rollups reflect only the retained telemetry window.
Troubleshooting
Related Topics
- Observe Agents: the telemetry these leaderboards are computed from, and how to ingest it.
- Agent Evaluation: the task-driven evaluation model that produces these runs.
- Optimize Agents: the optimizer that creates Experiments and Evaluations automatically.