Skip to content

Build a dataset

A dataset is a sample of your own captured traffic for one route, optionally expanded with synthetic examples, graded by a judge model, and exported as JSONL. It is how you get from “we have production traffic” to “we have an eval set” without hand-picking examples.

Datasets live on the Datasets page in the dashboard.

A dataset can only be built from calls whose content was captured. The route needs at least two calls with both a request and a response stored, or the API answers 409 route has fewer than two consented examples. If the route runs with capture_text=False, no amount of traffic will make it eligible. See Keep content private.

The route picker in the dashboard only offers routes that already clear this bar, and shows how many eligible examples each one has.

  1. The task description is the instruction the judge and the generator both work from, so write it as a specification, not a label. Say what a correct answer looks like and what a wrong one looks like. Up to 10,000 characters.

  2. target_size is how many examples you want, from 2 to 1,000. synthetic_target is how many of those may be generated rather than sampled from production, from 0 up to the smaller of 500 and target_size. Production failures seed the synthetic expansion, so it fills gaps around the errors you actually had rather than inventing unrelated cases.

  3. coverage_gap scores each candidate on relevance to the task, novelty against what is already selected, and variability, weighting failures more heavily, then collapses near-duplicates. metadata_stratified spreads the sample across metadata strata instead.

  4. 0 builds once. Otherwise 24 to 2,160 hours creates a schedule, and each run only covers production since the last successful export. A sparse route accumulates rather than losing the window.

  5. The job is queued immediately and moves through sampling, expanding, judging and exporting to completed. stopped, failed and canceled are the terminal alternatives. A job that finds nothing that meets the confidence policy stops with that as its reason rather than exporting an empty file.

Create a dataset job
curl -X POST https://app.metergraph.dev/v1/datasets \
-H "Content-Type: application/json" \
-H "Cookie: metergraph_session=..." \
-d '{
"route": "ticket-classifier",
"name": "Q3 escalation eval",
"task_description": "Classify an inbound ticket into one of five queues...",
"target_size": 100,
"synthetic_target": 25,
"sampling_method": "coverage_gap",
"cadence_hours": 168,
"budget_usd": 5
}'

Every control, with its bounds:

FieldDefaultRange
route, name, task_descriptionRequired. Name up to 200 characters, description up to 10,000
target_size502 to 1,000
synthetic_target100 to the smaller of 500 and target_size
cadence_hours1680, or 24 to 2,160
sampling_methodcoverage_gapcoverage_gap or metadata_stratified
dimensionsintent, error_type, complexityUp to 20 strings
variabilityoutcome, cost_band, template_hashStrings
failure_weight31 to 20
near_duplicate_distance0.080 to 1
judge_sample_rate0.250.01 to 1
confidence_floor0.700 to 1
judge_routejudgeA configured judge route
budget_usd5Above 0, up to 1,000

An unrecognised field is a 422 rather than being ignored, so a typo fails loudly. The dashboard form sends the defaults above and exposes the route, name, task, size, synthetic share, sampling method, judge route and cadence.

  • Cancel a job that has not reached a terminal state. Reserved budget is released back.
  • Pause and resume a schedule without touching the jobs it has already produced.
  • Each job reports accepted items against total, how many came from production against synthetic, the propagated confidence, and spend against budget.

Owners and members can create, cancel, pause and resume. A viewer can read.

Exports appear once the job’s items clear the confidence policy. Both are newline-delimited JSON, one item per line, downloaded from GET /v1/datasets/{id}/exports/{format}. Any other format name is a 404.

For an eval harness. Carries the input, the expected output, and the metadata you need to slice results.

evals_code_jsonl (one line, formatted here)
{
"schema_version": 1,
"id": "8f3c...",
"input": { "messages": [{ "role": "user", "content": "..." }] },
"expected": { "output": "..." },
"metadata": {
"origin": "production",
"dimensions": { "intent": "...", "error_type": "...", "complexity": "..." },
"variability": { "outcome": "...", "cost_band": "...", "template_hash": "..." },
"confidence": 0.82,
"confidence_source": "sampled_judge"
}
}

The shape a provider fine-tuning endpoint expects: a user turn and the assistant turn it should have produced, plus enough metadata to trace a line back to the item it came from.

fine_tuning_jsonl (one line, formatted here)
{
"messages": [
{ "role": "user", "content": "..." },
{ "role": "assistant", "content": "..." }
],
"metadata": {
"metergraph_item_id": "8f3c...",
"origin": "production",
"confidence": 0.82
}
}

origin is production or synthetic. confidence_source is one of production, human_reference, sampled_judge or propagated_judge, which tells you whether that line was judged directly or inherited its confidence. dimensions and variability are objects keyed by the dimension names the job was created with.

Both files contain the same items in the same order. Pick by what you are feeding, not by what the dataset is.

A completed dataset can also be delivered as a pull request, and the Datasets page shows the link when there is one. Like alert delivery, that repository is a server-level setting rather than a per-workspace one, so on the hosted service the file you want is the one you download. See Set up alerts.