Agentic Evaluations¶
Evaluate autonomous agents end-to-end: tasks, trajectories, trace-based criteria, and aggregate agent metrics.
Agentic evaluations extend elluminate beyond single-turn LLM outputs to cover agents that plan, call tools, and work against a task description over many steps. elluminate is runtime-agnostic: you run the agent wherever it already lives — your own code, a framework like LangChain, CrewAI, or AutoGen, or a harness like Harbor — translate its output to the ATIF trajectory format, and upload the trial results, including full trajectories, to elluminate. elluminate then rates each criterion against the trajectory, and the UI surfaces the trace, per-criterion ratings, and aggregate metrics.
What agentic evaluation is¶
When to use agentic evaluations¶
Use this workflow when:
- Your system makes multiple LLM calls per task (tool use, plan/act loops, sub-agents).
- Evaluation needs to look at what the agent did, not only at its final message.
- You already have (or want to keep) an external runner, e.g. Harbor, LangChain, CrewAI, AutoGen, or your own code.
For single-turn outputs, or tool-calling patterns where elluminate generates the responses itself, see the Tool Calling guide instead.
elluminate does not execute your agent
Agentic evaluations cover uploading and rating external agent runs. You run the agent yourself — with your own code, a framework, or a harness like Harbor — and elluminate stores the trial results, renders the Agent Trace, and (optionally) rates each criterion against the trajectory.
Core concepts¶
- Task — one unit of work for your agent, identified by a unique task name.
- Collection — your set of tasks: one row per task, with a
task(name) column and an optionalinstruction(input) column. - Trajectory (trace) — the full step-by-step record of one agent run: every message, tool call, and observation, in the ATIF format.
- Criterion — a binary YES/NO quality question. elluminate's LLM judge answers each criterion against the trajectory — the same judging used for a standard experiment. Criteria in a criterion set apply to every task; task-specific criteria apply to one task only.
- Overall Rating — a platform-managed binary YES/NO criterion included automatically in every Agentic experiment. It answers whether the agent succeeded at the task overall.
- Experiment — one evaluation run: it binds a collection and a criterion set, and holds the uploaded trajectories with their ratings and aggregate metrics.
The trajectory format¶
elluminate consumes one input from your runner: an agent trajectory in the ATIF format (Agent Trajectory Interchange Format), an open specification defined by Harbor. Whatever your runner is, you translate its output to ATIF and upload it — either in the browser or via the SDK. There is no native importer for LangChain, CrewAI, AutoGen, or other frameworks yet. The full schema and a minimal example are in the ATIF trajectory format section.
Not to be confused with UCE (elluminate.uce/1): UCE is a conversation input elluminate runs itself (see Conversations), while ATIF is the record of a run you already executed.
UI walkthrough¶
- Create an Agentic collection. In Collections → New collection, pick the Agentic type. It comes pre-configured with two columns, and keeping these conventional names is recommended:
task— a short, unique name for each task (one row per task) — andinstruction— the input the agent was given for that task (for a chat agent, the first user message). Write every instruction as complete, self-contained text.instructionis optional: when you upload a trajectory captured outside elluminate, the input is already part of the trajectory, so the column can be left empty. No prompt template is required, and Agentic experiments never auto-generate responses. - Create a criterion set. In Criteria Library → New Criterion Set, give it a name, then open the set and use Add New Criterion to add complete, self-contained binary YES/NO questions elluminate answers against the trajectory (e.g. "Did the agent edit the correct file?"). These apply to every task; for checks that only make sense for one task, add task-specific criteria.
- Create an Agentic experiment. On Experiments → New, choose the Agentic type, then select your collection and criterion set. No prompt template is needed — the wizard omits that step for Agentic experiments. The experiment name is auto-filled from the collection — rename it as you like.
- Run the agent externally (your own code, a framework, or a harness like Harbor) and collect one result per task, including an ATIF trajectory.
- Upload the results — either directly in the browser or via the SDK. When trajectories are present, elluminate automatically rates each criterion against the trajectory.
- Review the results in the UI (see below).
Automatic Overall Rating
elluminate includes Overall Rating in the frozen evaluation definition automatically. It does not add the criterion to or otherwise modify the criterion set you selected. Every evaluated response therefore has one more rating than the number of criteria in that set. If the selected set also contains a criterion labelled Overall Rating, both remain in the frozen definition as separate criterion IDs.
Task-specific criteria¶
A criterion set holds the checks that apply to every task. Checks that only make sense for one task — its concrete pass condition — belong on the task itself. Open your Agentic collection to reach the Tasks view: one card per task, showing its instruction and how many task-specific criteria it has.
Click the criteria button on a task card to open the task criteria sheet, then use Add criterion and Save:
- Labels are optional — omitted ones default to
Criterion 1,Criterion 2, … They must be unique within the task, andOverall Ratingis reserved. - Criteria can reference the task's own fields as
{{field_name}}; click a field chip below the criterion to insert one. Use Add Field in the Tasks view to add a field (such asexpected_outcome) to every task.
What an experiment evaluates for a given task is its criterion set, plus that task's own criteria, plus Overall Rating.
Criteria are frozen when the experiment is created
An Agentic experiment freezes its evaluation definition — the criterion set, every task's criteria, and their field values — when it is created. Later edits to a criterion set or to task criteria never change an existing experiment; create a new experiment to evaluate against the updated criteria.
Reviewing results in the UI¶
The experiment page has three tabs:
- Overview — aggregate metrics (overall score; plus cost per task, average duration, and tokens when your uploaded run includes them), a Criteria Performance chart (pass rate per criterion), and an AI Experiment Summary (an Executive Summary, plus sections such as Strengths, Weaknesses, Recommendations, and Notable Samples — each shown only when the summary has content for it). The chart includes Overall Rating, so the experiment's task-success rate is visible at a glance; it compares only criteria shared by all tasks, so task-specific criteria are shown on the individual responses instead. The summary is generated only after every trace is annotated, so it can take a few minutes to appear.
- Sample Navigator — per-sample detail: the Phase Timeline (a Gantt-style view of the agent's steps) and the Agent Trace (every message, tool call, and observation), alongside the per-criterion YES/NO ratings with reasoning. When a run delegates to sub-agents, each sub-agent trajectory renders nested and collapsible under the step that spawned it, so multi-agent runs stay fully inspectable.
- Responses Overview — all responses at a glance.
Upload results in the UI¶
Once your Agentic collection (the task rows) and Agentic experiment exist, you can upload results straight from the browser — no SDK required. Open the experiment and click Upload results (also offered from the empty state before any results exist).
In the dialog you:
- Drop a results file — a
.jsonfile containing an array of trial-result objects, or a.jsonlfile with one object per line. - Confirm the task name column — the experiment freezes this setting when it is created (usually
task). Uploads use that frozen column; choosing a different one is rejected. - Toggle "Evaluate after upload" (default on) — when enabled, elluminate rates each criterion against the uploaded trajectory after upload.
- Set the epoch (default
1) — bump it to upload another run of the same tasks into the same experiment.
Upload file format¶
Each object in the file mirrors the SDK AgentTrialResult:
task_name(required) — must exactly match a task name frozen when the experiment was created.trajectory— the ATIF trajectory dict (schema_versionmust matchATIF-v1.x, plusagent,steps, andfinal_metrics).- optional:
reward,cost_usd,steps,messages,criterion_ratings.
For precomputed ratings, first call experiment.get_agent_results_definition(). Each returned task lists the exact frozen criteria that apply to it. Include criterion_id in every criterion_ratings entry; labels are display text and may repeat. If you upload only a trajectory and let elluminate evaluate it, you do not need to fetch the definition.
Experiments created before frozen definitions still require task_name_column and retain a mutable live definition.
Label-only ratings remain supported when the label is unambiguous; supply criterion_id when display labels repeat.
This compatibility path does not provide the historical freeze guarantee of a new experiment.
A minimal single-trial .json file (an array with one object):
[
{
"task_name": "write-hello-world",
"reward": 1.0,
"cost_usd": 0.0042,
"trajectory": {
"schema_version": "ATIF-v1.0",
"session_id": "run-001/write-hello-world",
"agent": {
"name": "demo-agent",
"version": "0.1.0",
"model_name": "claude-sonnet-4-6"
},
"steps": [
{
"step_id": 1,
"source": "user",
"message": "Write a Python hello world script to hello.py"
},
{
"step_id": 2,
"source": "agent",
"message": "Writing hello.py.",
"tool_calls": [
{
"tool_call_id": "tc_1",
"function_name": "write_file",
"arguments": {"path": "hello.py", "content": "print('Hello, World!')"}
}
],
"observation": {
"results": [{"source_call_id": "tc_1", "content": "wrote 22 bytes"}]
},
"metrics": {"prompt_tokens": 420, "completion_tokens": 61, "cost_usd": 0.0042}
}
],
"final_metrics": {
"total_steps": 2,
"total_cost_usd": 0.0042,
"total_prompt_tokens": 420,
"total_completion_tokens": 61
}
}
}
]
For a .jsonl file, write the same objects one per line (no surrounding array, no commas).
Partial success and async evaluation
Trials are processed independently: a malformed trajectory is dropped for that trial only, and the upload reports per-trial errors so the rest still go through. When Evaluate after upload is on, rating runs asynchronously — results appear on the experiment page as they complete.
SDK walkthrough¶
The following script covers the full end-to-end flow: an Agentic collection, an Agentic experiment, conversion of runner output, and upload with elluminate's evaluation queued. The script is idempotent — collections, criterion sets, and experiments are reused across runs, and uploads are skipped when an experiment already contains responses.
Running the example¶
Set your API key (created in the elluminate UI under Project → Keys) either as an environment variable or in a .env file next to the script; the example calls load_dotenv():
# option 1: shell
export ELLUMINATE_API_KEY=<your-key>
# optionally, if you run elluminate on a non-default host:
# export ELLUMINATE_BASE_URL=https://your-instance.example.com
# option 2: .env in elluminate_sdk/examples/
echo "ELLUMINATE_API_KEY=<your-key>" > elluminate_sdk/examples/.env
# run
uv run --directory elluminate_sdk python examples/example_harbor_agentic_upload.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | |
- Initialize the SDK client (uses
ELLUMINATE_API_KEY) and pick anLLMConfigto associate with the experiment (metadata only; Agentic experiments never invoke it). - Stand-in for your runner's on-disk output. Replace with code that reads Harbor's
task_result.json+trajectory.jsonper task. - Translate one runner output into an
AgentTrialResult. This is the only integration-specific code you need;task_namemust match the value in the collection row's task column. - Create an Agentic collection with a single TEXT
taskcolumn, one row per task. No prompt template is required. - Create the criterion set that defines success. Labels are display text and may repeat; frozen criterion IDs identify ratings in uploads.
- Idempotent helper that returns an Agentic experiment and whether it already holds uploaded responses.
- Get-or-create the main experiment.
evaluation_mode="AGENTIC"disables auto-generation; responses are supplied via upload. - Convert every runner output into an
AgentTrialResult. - Upload with
evaluate=Trueso elluminate rates every criterion against the trajectory. Skipped on re-runs when the experiment is already populated. - Re-fetch the experiment and confirm trajectories are queryable from the SDK.
Growing the dev set (the eval flywheel)¶
Coverage grows over time: when your agent fails in production, feed that case back into the dev set so every future run is checked against it. To append new tasks to an existing collection, fetch the collection and call add_many() with one dict per task, keyed by the collection's task-name column (task):
# Grow an existing dev-set collection with newly discovered failure cases
collection = client.get_collection(name="my-agent-dev-set")
collection.add_many([
{"task": "New failing scenario discovered in prod ..."},
{"task": "Another regression case ..."},
])
# Re-run the agent on the (now larger) collection and upload the new trajectories.
This is different from bumping the epoch at upload time: the epoch re-runs the same tasks for another sample, whereas appending rows widens what you evaluate. Once the tasks exist, run your agent over the enlarged collection and upload the new trajectories as usual.
AgentTrialResult fields¶
Each trial your runner produces maps to one AgentTrialResult. Required and optional fields:
| Field | Required | Description |
|---|---|---|
task_name |
yes | Must exactly match a task name frozen when the experiment was created. |
messages |
no | Final OpenAI-format message list (shown on the response page). |
reward |
no | Primary reward score (0.0–1.0). |
steps |
no | Number of agent steps / LLM calls. |
cost_usd |
no | Total USD cost for the trial. |
duration_seconds |
no | Wall-clock duration. |
input_tokens |
no | Aggregate input tokens. |
output_tokens |
no | Aggregate output tokens. |
cached_tokens |
no | Aggregate cached input tokens. |
error |
no | Error message if the trial failed. |
metadata |
no | Free-form dict surfaced on the response page. |
trajectory |
no | Raw ATIF trajectory (validated by the backend; see ATIF format). |
criterion_ratings |
no | Precomputed YES/NO ratings. For frozen experiments, use criterion_id from get_agent_results_definition(); labels are display-only. |
ATIF trajectory format¶
Trajectories use the Agent Trajectory Interchange Format (ATIF), an open trajectory specification defined by Harbor.
A minimal ATIF v1 trajectory:
{
"schema_version": "ATIF-v1.0",
"session_id": "harbor-run-001/write-hello-world",
"agent": {
"name": "harbor-demo-agent",
"version": "0.1.0",
"model_name": "claude-sonnet-4-6"
},
"steps": [
{
"step_id": 1,
"source": "user",
"message": "Write a Python hello world script to hello.py"
},
{
"step_id": 2,
"source": "agent",
"message": "Writing hello.py.",
"tool_calls": [
{
"tool_call_id": "tc_1",
"function_name": "write_file",
"arguments": {"path": "hello.py", "content": "print('Hello, World!')"}
}
],
"observation": {
"results": [{"source_call_id": "tc_1", "content": "wrote 22 bytes"}]
},
"metrics": {"prompt_tokens": 420, "completion_tokens": 61, "cost_usd": 0.0042}
}
],
"final_metrics": {
"total_steps": 2,
"total_cost_usd": 0.0042,
"total_prompt_tokens": 420,
"total_completion_tokens": 61
}
}