Skip to main content
Eval options control what a run records, how it runs, and how you recover when it stops: run settings, concurrency, async code, pinned context, and resuming. Configure them once your eval works and you need runs you can compare, debug, and finish after a crash. For a first run, start with Run your first eval; the Eval options and errors lists every option.

Before you begin

Before you start, make sure you have:
  • Working eval: An Eval call that runs, as in Run your first eval.
  • Client: An AtlanClient for reading results back, set up as in the quickstart’s verify step.
1

Set run options

These are the options to decide on for every run:
  • Name: Keep it the same across branches and runs. Auto-registered scorers are named after it, and the CI action finds baselines by it.
  • config: Everything that distinguishes this run: model, prompt revision, commit, temperature. It is stored on the experiment, and you can filter on it with GET /eval/v1/experiments?config=model:example-model. Keep secrets out of it.
  • Concurrency: Python runs max_concurrency cases at a time, which speeds up only async tasks. TypeScript runs cases one at a time.
2

Verify run evidence

Read the run back before you trust a mean. A failure is handled like this:A run where no scorer produces a usable value finalizes as completed, then raises with the experiment ID. This includes runs where every task errored. Pass require_scores=False (requireScores: false) only when an empty score set is an expected outcome. Read the stored experiment’s summary.metrics.failed_cases (failedCases in TypeScript) and each result’s error to find the cause. The CI action treats an error rate above 20% as a broken run. In TypeScript, summary.scores is typed unknown; cast it before reading, for example run.summary.scores as Record<string, { mean: number; count: number }>.
Results list 50 per page by default and at most 500; page with offset. input and output are stored as objects, so a string or number your task returned reads back as {"value": x}. The span read returns core,io fields by default; add attributes, usage, cost, or error to fields for more.To check a finished run’s evidence, for example after a crash or in a CI job that did not run Eval itself, call verify_experiment (verifyExperiment). It confirms the experiment is terminal and every result has a distinct, queryable trace, and checks a sample of traces for their score spans and span nesting. A content-policy check is reported as MANUAL: review it yourself.
Before uploading a result, Eval waits up to 30 seconds for each case trace to be queryable, so no result points to a missing trace. The wait covers a trace that is not there yet and a trace plane that is down or slow: a trace read that fails with traces_unavailable (503) or request_timeout (504) is retried inside the window, respecting the server’s Retry-After when one is sent, until the window is spent and its error fails the run. Any other trace-read error fails the run immediately. If your trace export is slow, raise the wait with trace_verification_timeout_s (traceVerificationTimeoutMs). Turn verification off only for tests against a stub.
3

Pin context that changed (optional)

config records settings. A context manifest records the version and SHA-256 digest of each input you identify, such as instructions, prompts, skills, tool schemas, or a retrieval snapshot. The SDK writes the manifest, and one digest over it, into the experiment config. Two runs with the same digest recorded the same manifest. Your runner must load and use the content it records; the digest alone does not verify that execution used it.
The manifest is stored, but the referenced content is not fetched or checked, so point each entry at something you can still retrieve. Then compare runs by what you held constant:
4

Use async_eval in event loops (optional)

Python Eval starts its own event loop, so it fails inside an existing one, such as Jupyter, FastAPI, or an async test, with Eval() cannot run inside an event loop. Await async_eval there instead; it takes the same arguments.
The task and scorers can be sync or async in both SDKs.
5

Pass case details to task (optional)

A task that declares a second parameter receives hooks: the case’s expected, metadata, and tags, and the span the task runs in. Use the span to attach details to the trace.
6

Resume stopped run (optional)

Save the experiment ID as soon as the run starts, then resume with the same arguments. Eval skips the case IDs already stored and finishes the rest.
Resume requires the experiment to still be running, in the same workspace, with the same dataset or inline cases, and the same config and context manifest. case_id on a record-backed run is the dataset record’s ID. Run one writer per experiment.
If your task has side effects, such as sending email or writing records, make it idempotent before you resume: cases without a stored result run again.
To close a run you will not resume, mark it failed with the ID from the error message. An experiment left running stays in the list and never becomes a baseline. A failed experiment is frozen like a completed one.
client.experiments.list(experiment_status="running") lists the open runs. Close only runs you own: another job’s run may still be in progress.

Troubleshooting

Run failures include an Eval call inside an event loop, a run left running after a trace timed out or a trace read failed, and a 409 on a duplicate experiment name. See Eval errors.

Next steps

See also