Benchmark "auto" on your own data
A public benchmark tells you how model="auto" performs on someone else's data. It does not tell you how it performs on yours. This page shows how to take your own labeled rows, score "auto" against the frontier baselines it replaces, and read back a cost-annotated verdict, all in one evals.runs.create(...) call.
The shape is always the same:
- Say what you want done with each row — one sentence, like a prompt.
- Build an eval set from your rows.
- Run
"auto"againstfrontier="benchmarked". - Read the results and the dollar cost of the run.
Evals are metered: the org balance is debited for the compute you ran ("auto" and the frontier baselines). run.cost is the billed total in dollars; an empty balance raises InsufficientCreditsError. Top-up is browser-only.
Setup
Python
from pareta import Pareta
pa = Pareta.from_env() # reads PARETA_API_KEY (and optional PARETA_BASE_URL)
TypeScript
import { Pareta } from "pareta";
const pa = Pareta.fromEnv(); // reads PARETA_API_KEY (and optional PARETA_BASE_URL)
from_env() is the path you want; it keeps the key out of your source. See Authentication for the constructor form and key formats.
1. Your rows + what you want done
Each row of your data is an input and, when you have one, the answer you expect back. The only other thing Pareta needs is what you want done with each row — one sentence, written the way you'd prompt any model:
"extract the effective date and parties from each contract"
That's the whole setup. Pareta works out how to score the results from your words and your data, and if they don't line up — you asked for a summary but the rows look like classification labels — create refuses with suggestions instead of guessing.
Want to see how a set will be scored before creating anything? evals.propose_contract(items=..., prompt=...) returns the scoring plan without persisting a thing — and task= lets you pin a specific one (see the tasks reference). Most of the time you need neither.
2. Build an eval set from your rows
An eval set is your labeled data, stored server-side and reusable across runs. Each row is a dict; Pareta checks every row's shape at create time. The shape is always {"input": {...}, "expected_output": {...}} — both values JSON objects: the inputs the model sees and the gold answer the scorer compares against. The inner field names are task-specific.
Python
items = [
{
"input": {"contract_text": "This Agreement is made on 3 March 2026 between Acme Corp and Globex LLC..."},
"expected_output": {"effective_date": "2026-03-03", "parties": ["Acme Corp", "Globex LLC"]},
},
{
"input": {"contract_text": "Master Services Agreement, dated January 12, 2026, by and between Initech and Hooli..."},
"expected_output": {"effective_date": "2026-01-12", "parties": ["Initech", "Hooli"]},
},
# ... more rows. A few dozen labeled rows already give you a usable signal.
]
eval_set = pa.evals.sets.create(
items=items,
prompt="extract the effective date and parties from each contract",
) # refuses with suggestions if what you asked for doesn't match the data
print(eval_set.id) # use this in runs.create(eval_set=...)
print(eval_set.item_count) # 2
print(eval_set.scoring_strategy) # e.g. "extraction"
TypeScript
const items = [
{
input: { contract_text: "This Agreement is made on 3 March 2026 between Acme Corp and Globex LLC..." },
expected_output: { effective_date: "2026-03-03", parties: ["Acme Corp", "Globex LLC"] },
},
{
input: { contract_text: "Master Services Agreement, dated January 12, 2026, by and between Initech and Hooli..." },
expected_output: { effective_date: "2026-01-12", parties: ["Initech", "Hooli"] },
},
// ... more rows. A few dozen labeled rows already give you a usable signal.
];
const evalSet = await pa.evals.sets.create({
items,
prompt: "extract the effective date and parties from each contract",
}); // refuses with suggestions if what you asked for doesn't match the data
console.log(evalSet.id); // use this in runs.create({ evalSet: ... })
console.log(evalSet.itemCount); // 2
console.log(evalSet.scoringStrategy); // e.g. "extraction"
items must be non-empty (an empty list raises ValueError before any request goes out). If you omit name, the set is labeled "sdk eval set (N items)".
Reuse a set across many runs, or list and prune as you iterate:
Python
for s in pa.evals.sets.list():
print(s.id, s.task_id, s.item_count, s.name)
# pa.evals.sets.delete(eval_set.id) # when you are done with it
TypeScript
for (const s of await pa.evals.sets.list()) {
console.log(s.id, s.taskId, s.itemCount, s.name);
}
// await pa.evals.sets.delete(evalSet.id); // when you are done with it
2b. Document tasks: attach the file to each row
When task.has_blob_input is True, the row carries a binary document. Create the set with the row's text/label fields and a placeholder for the blob, then attach the file to that row by index:
Python
doc_task = "invoice-extraction" # a has_blob_input task
eval_set = pa.evals.sets.create(
task=doc_task,
items=[
{"expected_output": {"invoice_number": "INV-7781", "total": "1240.00"}},
{"expected_output": {"invoice_number": "INV-7782", "total": "98.50"}},
],
prompt="extract the invoice number and total from each invoice",
)
# Attach one PDF per row. idx is the 0-based row; field_name is the blob input
# field from the task schema. MIME is auto-detected from the filename.
pa.evals.sets.upload_document(eval_set.id, "invoices/7781.pdf", idx=0, field_name="document")
pa.evals.sets.upload_document(eval_set.id, "invoices/7782.pdf", idx=1, field_name="document")
TypeScript
const docTask = "invoice-extraction"; // a hasBlobInput task
const evalSet = await pa.evals.sets.create({
task: docTask,
items: [
{ expected_output: { invoice_number: "INV-7781", total: "1240.00" } },
{ expected_output: { invoice_number: "INV-7782", total: "98.50" } },
],
prompt: "extract the invoice number and total from each invoice",
});
// Attach one PDF per row. idx is the 0-based row; fieldName is the blob input
// field from the task schema. MIME is auto-detected from the filename.
await pa.evals.sets.uploadDocument(evalSet.id, "invoices/7781.pdf", { idx: 0, fieldName: "document" });
await pa.evals.sets.uploadDocument(evalSet.id, "invoices/7782.pdf", { idx: 1, fieldName: "document" });
upload_document accepts a path (str/Path), raw bytes, or any binary file-like object; anything else raises TypeError. Files under 5 MiB upload inline; larger ones go through a signed-URL direct-to-storage flow. Either way the call returns the completion response dict. Pass mime="application/pdf" to override detection.
3. Run "auto" against the frontier baselines
This is the core call. The contender is "auto" — Pareta's routing brain, run against every row exactly as it runs in production — and frontier="benchmarked" pulls the vendor baselines Pareta has already benchmarked on this task. The run scores everything on the same rows with the same scorer, so the numbers are directly comparable.
Python
run = pa.evals.runs.create(
eval_set=eval_set.id,
models=["auto"], # the contender: Pareta's routing brain
frontier="benchmarked", # vendor baselines benchmarked on this task
wait=True, # block until the run is terminal
)
print(run.status) # "completed"
TypeScript
const run = await pa.evals.runs.create({
evalSet: evalSet.id,
models: ["auto"], // the contender: Pareta's routing brain
frontier: "benchmarked", // vendor baselines benchmarked on this task
wait: true, // block until the run is terminal
});
console.log(run.status); // "completed"
models is required and is always ["auto"] — individual open-weights models are not part of the eval surface; they stay behind auto's routing. frontier controls the baselines:
frontier= | Evaluates against |
|---|---|
None or "none" | nothing ("auto" alone) |
"benchmarked" | frontier models Pareta has already benchmarked on this task (vision-filtered for document tasks) |
"all" | every frontier model in the eval pool for the task |
["gpt-5.5", "claude-sonnet-4-6"] | exactly these frontier ids |
The "benchmarked" and "all" keywords need to know the task. With eval_set=... the SDK looks it up from the set; if you pass an explicit list of ids it skips the lookup entirely.
GPUs and serving hardware never enter this call. There is no GPU, quantization, or run-mode knob — and no model to pick. You name a task and the baselines; Pareta resolves the rest. Frontier ids are the vendor names in the clear.
Inline create (skip step 2)
If you do not need a reusable set, hand the rows straight to the run. Pass items= and prompt= instead of eval_set=, and the SDK creates the set for you:
Python
run = pa.evals.runs.create(
items=items,
prompt="extract the effective date and parties from each contract",
models=["auto"],
frontier="benchmarked",
wait=True,
) # one call: builds the set and runs it
TypeScript
const run = await pa.evals.runs.create({
items,
prompt: "extract the effective date and parties from each contract",
models: ["auto"],
frontier: "benchmarked",
wait: true,
}); // one call: builds the set and runs it
You must pass either eval_set=<id> or items= plus prompt= (task= is optional); anything else raises ValueError.
Pinning the frontier roster
To see exactly which baselines a keyword resolves to — or to build an explicit frontier=[...] list — enumerate the roster first with evals.frontier_models; each entry exposes .id, .vendor, .vision, and .benchmarked:
Python
roster = pa.evals.frontier_models(task=eval_set.task_id) # resolved from your eval set
for m in roster:
print(m.id, m.vendor, "vision" if m.vision else "text", "benchmarked" if m.benchmarked else "-")
# Pin two of them explicitly
ids = [m.id for m in roster if m.benchmarked][:2]
run = pa.evals.runs.create(eval_set=eval_set.id, models=["auto"], frontier=ids, wait=True)
TypeScript
const roster = await pa.evals.frontierModels(evalSet.taskId!); // resolved from your eval set
for (const m of roster) {
console.log(m.id, m.vendor, m.vision ? "vision" : "text", m.benchmarked ? "benchmarked" : "-");
}
// Pin two of them explicitly
const ids = roster.filter((m) => m.benchmarked).map((m) => m.id).slice(0, 2);
const run = await pa.evals.runs.create({ evalSet: evalSet.id, models: ["auto"], frontier: ids, wait: true });
frontier_models() annotates benchmarked and applies the vision filter only when you pass task=. Without a task it returns the full roster, unannotated.
4. Read the ranked results
A terminal run carries one EvalResult per contender — "auto" plus each baseline. Sort by quality_mean to see where auto lands, and read run.cost to see what the run cost you:
Python
ranked = sorted(run.results, key=lambda r: r.quality_mean or 0, reverse=True)
for r in ranked:
cost_per_item = (r.mean_cost_micro_usd or 0) / 1_000_000 # micro-USD → dollars
print(
f"{r.model_id:24} "
f"quality={r.quality_mean:.3f} "
f"[{r.quality_ci_low:.3f}, {r.quality_ci_high:.3f}] "
f"${cost_per_item:.6f}/item "
f"ok={r.n_succeeded} err={r.error_count}"
)
print(f"\nrun cost: ${run.cost}") # Decimal dollars, floored to cents
print(f"raw micro-USD: {run.cost_micro_usd}")
TypeScript
const ranked = [...run.results].sort((a, b) => (b.qualityMean ?? 0) - (a.qualityMean ?? 0));
for (const r of ranked) {
const costPerItem = (r.meanCostMicroUsd ?? 0) / 1_000_000; // micro-USD → dollars
console.log(
`${(r.modelId ?? "").padEnd(24)} ` +
`quality=${r.qualityMean!.toFixed(3)} ` +
`[${r.qualityCiLow!.toFixed(3)}, ${r.qualityCiHigh!.toFixed(3)}] ` +
`$${costPerItem.toFixed(6)}/item ` +
`ok=${r.nSucceeded} err=${r.errorCount}`,
);
}
console.log(`\nrun cost: $${run.cost}`); // dollar string, floored to cents
console.log(`raw micro-USD: ${run.costMicroUsd}`);
What the fields mean:
quality_mean: the contender's mean score on the task's scorer, in[0, 1].quality_ci_low/quality_ci_high: the 95% confidence interval. If two contenders' intervals overlap heavily, your eval set is too small to separate them, so add rows.mean_cost_micro_usd: average cost per item, kept in micro-USD (not floored). This is where the auto-vs-frontier comparison lives, so sub-cent precision is preserved: auto matching frontier quality at a fraction of the cost is the whole point.n_succeeded/error_count: how many rows scored cleanly. Auto's failures count as errors, not skips — availability is part of what a benchmark should measure.model_id:"auto"for Pareta's row; the vendor id for each baseline.kindis"frontier"on the baseline rows, so you can filter the contender from what it is measured against.
Reading the verdict: auto's quality CI overlapping the frontier's at a lower per-item cost = frontier-grade on your data; a higher mean without overlap = ahead.
A note on money
run.cost is a Decimal of dollars, floored to whole cents, so the SDK never overstates a charge and a sub-cent run reads Decimal("0.00"). For the exact figure use run.cost_micro_usd (an integer, where 1_000_000 micro-USD is $1.00). The same convention is why per-item rates like mean_cost_micro_usd stay in micro-USD: flooring them to cents would erase the auto-vs-frontier difference you ran the eval to find.
Not blocking on the run
wait=True polls until the run reaches "completed" or "failed", then returns. For long sets, tune the cadence and ceiling:
Python
run = pa.evals.runs.create(
eval_set=eval_set.id,
models=["auto"],
frontier="benchmarked",
wait=True,
poll_interval=5.0, # seconds between polls (default 3.0)
timeout=1800.0, # give up after 30 min (default 900.0); raises ParetaError on timeout
)
TypeScript
const run = await pa.evals.runs.create({
evalSet: evalSet.id,
models: ["auto"],
frontier: "benchmarked",
wait: true,
pollInterval: 5, // seconds between polls (default 3)
timeout: 1800, // give up after 30 min (default 900); throws ParetaError on timeout
});
Or fire and poll yourself. wait=False returns immediately with a run you can retrieve later:
Python
run = pa.evals.runs.create(eval_set=eval_set.id,
models=["auto"], frontier="benchmarked")
run_id = run.id
# ... later, from anywhere ...
run = pa.evals.runs.retrieve(run_id)
if run.is_terminal:
print(run.status, run.results)
# equivalently, block on an already-started run:
run = pa.evals.runs.wait(run_id, timeout=1800.0)
TypeScript
let run = await pa.evals.runs.create({
evalSet: evalSet.id,
models: ["auto"],
frontier: "benchmarked",
});
const runId = run.id!;
// ... later, from anywhere ...
run = await pa.evals.runs.retrieve(runId);
if (run.isTerminal) {
console.log(run.status, run.results);
}
// equivalently, block on an already-started run:
run = await pa.evals.runs.wait(runId, { timeout: 1800 });
Handling an empty balance
Both auto's compute and the frontier baselines are metered. If the org balance cannot cover the run, create raises before any work is billed:
Python
from pareta import InsufficientCreditsError
try:
run = pa.evals.runs.create(eval_set=eval_set.id,
models=["auto"], frontier="benchmarked", wait=True)
except InsufficientCreditsError:
print("Out of credit. Top up in the dashboard (billing is browser-only).")
TypeScript
import { InsufficientCreditsError } from "pareta";
try {
const run = await pa.evals.runs.create({
evalSet: evalSet.id,
models: ["auto"],
frontier: "benchmarked",
wait: true,
});
} catch (e) {
if (e instanceof InsufficientCreditsError) {
console.log("Out of credit. Top up in the dashboard (billing is browser-only).");
} else {
throw e;
}
}
InsufficientCreditsError is a subclass of APIStatusError (status 402), so you can also catch the broader ParetaError if you want one handler for every SDK failure.
Full example
Python
from pareta import Pareta, InsufficientCreditsError
pa = Pareta.from_env()
# 1. Your rows + one sentence saying what you want done with each row.
prompt = "extract the effective date and parties from each contract"
# 2. Build the eval set from your rows.
items = [
{"input": {"contract_text": "This Agreement is made on 3 March 2026 between Acme Corp and Globex LLC..."},
"expected_output": {"effective_date": "2026-03-03", "parties": ["Acme Corp", "Globex LLC"]}},
{"input": {"contract_text": "Master Services Agreement, dated January 12, 2026, by and between Initech and Hooli..."},
"expected_output": {"effective_date": "2026-01-12", "parties": ["Initech", "Hooli"]}},
]
eval_set = pa.evals.sets.create(items=items, prompt=prompt,
name="contract fields v1")
print("scored as:", eval_set.scoring_strategy)
# 3. Run auto against the benchmarked frontier baselines.
try:
run = pa.evals.runs.create(
eval_set=eval_set.id,
models=["auto"],
frontier="benchmarked",
wait=True,
)
except InsufficientCreditsError:
raise SystemExit("Out of credit. Top up in the dashboard.")
# 4. Read the ranked results.
for r in sorted(run.results, key=lambda r: r.quality_mean or 0, reverse=True):
print(f"{r.model_id:24} {r.quality_mean:.3f} ${(r.mean_cost_micro_usd or 0)/1e6:.6f}/item")
print("run cost:", run.cost) # Decimal dollars, floored to cents
TypeScript
import { Pareta, InsufficientCreditsError } from "pareta";
const pa = Pareta.fromEnv();
// 1. Your rows + one sentence saying what you want done with each row.
const prompt = "extract the effective date and parties from each contract";
// 2. Build the eval set from your rows.
const items = [
{ input: { contract_text: "This Agreement is made on 3 March 2026 between Acme Corp and Globex LLC..." },
expected_output: { effective_date: "2026-03-03", parties: ["Acme Corp", "Globex LLC"] } },
{ input: { contract_text: "Master Services Agreement, dated January 12, 2026, by and between Initech and Hooli..." },
expected_output: { effective_date: "2026-01-12", parties: ["Initech", "Hooli"] } },
];
const evalSet = await pa.evals.sets.create({ items, prompt, name: "contract fields v1" });
console.log("scored as:", evalSet.scoringStrategy);
// 3. Run auto against the benchmarked frontier baselines.
let run;
try {
run = await pa.evals.runs.create({
evalSet: evalSet.id,
models: ["auto"],
frontier: "benchmarked",
wait: true,
});
} catch (e) {
if (e instanceof InsufficientCreditsError) {
throw new Error("Out of credit. Top up in the dashboard.");
}
throw e;
}
// 4. Read the ranked results.
for (const r of [...run.results].sort((a, b) => (b.qualityMean ?? 0) - (a.qualityMean ?? 0))) {
console.log(`${(r.modelId ?? "").padEnd(24)} ${r.qualityMean!.toFixed(3)} $${((r.meanCostMicroUsd ?? 0) / 1e6).toFixed(6)}/item`);
}
console.log("run cost:", run.cost); // dollar string, floored to cents
Async
Every call here has an async twin on AsyncPareta. The signatures match; the methods are coroutines (wait included).
Python
import asyncio
from pareta import AsyncPareta
async def main():
async with AsyncPareta.from_env() as pa:
eval_set = await pa.evals.sets.create(
task="contract-key-fields", items=items,
prompt="extract the effective date and parties from each contract")
run = await pa.evals.runs.create(
eval_set=eval_set.id,
models=["auto"],
frontier="benchmarked",
wait=True,
)
for r in run.results:
print(r.model_id, r.quality_mean)
print("run cost:", run.cost)
asyncio.run(main())
TypeScript
In TypeScript there is no separate AsyncPareta — the one Pareta client is already
async. Every I/O method returns a Promise, so you just await it; there is no sync/async
split to mirror and no context manager to close.
import { Pareta } from "pareta";
const pa = Pareta.fromEnv();
const evalSet = await pa.evals.sets.create({
task: "contract-key-fields", items,
prompt: "extract the effective date and parties from each contract",
});
const run = await pa.evals.runs.create({
evalSet: evalSet.id,
models: ["auto"],
frontier: "benchmarked",
wait: true,
});
for (const r of run.results) {
console.log(r.modelId, r.qualityMean);
}
console.log("run cost:", run.cost);
Next steps
- Run inference: send production traffic to the same
model="auto"your eval just measured; inference is metered the same way evals are. - Cost & quality monitoring: watch spend, success, and projected savings with
auto.metrics(). - Errors and retries: the full exception hierarchy behind
InsufficientCreditsErrorand friends.