inspect-eval-execution

$npx mdskill add microsoft/ACESEvals/inspect-eval-execution

To run SABER inspect_ai evaluations locally, follow this process:

SKILL.md

.github/skills/inspect-eval-executionView on GitHub ↗
---
name: inspect-eval-execution
description: Guide for running SABER inspect_ai evaluations locally. Use this when asked to run, re-run, or configure an inspect eval for any SABER domain.
---

To run SABER inspect_ai evaluations locally, follow this process:

## 1. Understand the Domain Structure

Each domain lives in `domains/<domain>/` and follows this layout:

```
domains/<domain>/
  <domain>.py          # @task entry point — calls create_task()
  eval.yaml            # Domain metadata, Docker image definitions
  tasks/
    global.yaml        # Default prompts, tools, max_steps, aggregation
    <task_group>/
      <task>.yaml      # Individual task definitions
  compose/
    sandbox.compose.yml  # Docker Compose for sandbox containers
  scoring/             # Domain-specific scoring strategies
  tools/               # Domain-specific MCP tools
  prompts/             # Jinja2 prompt templates (instructions/, assistants/, etc.)
  docker/              # Dockerfiles for sandbox images
```

The `<domain>.py` file is minimal — it just calls `saber.task.create_task(**kwargs)` which wires up config loading, prompt rendering, scoring, tools, and the agent.

## 2. Build Docker Images First

Before running evals, ensure Docker images are built:

```bash
# Build all images for a domain
uv run saber build <domain>

# Or auto-build during eval (slower, builds missing images)
uv run inspect eval domains/<domain> --model <model> --display plain -T build=true

# Force rebuild all images
uv run inspect eval domains/<domain> --model <model> --display plain -T rebuild_all=true

# Rebuild specific images by prefix
uv run inspect eval domains/<domain> --model <model> --display plain -T rebuild=sandbox
```

## 3. Run an Evaluation

Always use `--display plain` to disable the Rich interactive progress display.
This outputs clean, parseable text instead of ANSI escape sequences and cursor
manipulation that pollute AI agent context windows.

```bash
# Basic evaluation (all tasks)
uv run inspect eval domains/<domain> --model <model> --display plain

# Common model formats (we own these endpoints):
#   openai/azure/gpt-4.1        (Azure OpenAI)
#   openai/azure/gpt-5.2        (Azure OpenAI)

# Run a single sample for quick iteration
uv run inspect eval domains/<domain> --model <model> --display plain --limit 1

# --limit <> is the BEST way to keep your evals small and contained for testing

# Filter to specific tasks
uv run inspect eval domains/<domain> --model <model> --display plain -T task_filter="sanity_*"
uv run inspect eval domains/<domain> --model <model> --display plain -T task_filter="incident_response_01"

# Multiple task patterns (comma-separated)
uv run inspect eval domains/<domain> --model <model> --display plain -T task_filter="sanity_*,advanced_*"
```

## 3.1 Permanent Environments

It is generally recommended if you expect to do multiround eval analysis to use "-T keep_permanent=true" in
your uv run inspect command. This keeps long to spin up resources like databases around for ease of use
on following evals.

If you do this, use

```bash
uv run saber teardown -y
```

To teardown any assets when you are finished

## 4. Key `-T` Parameters

| Parameter | Purpose | Example |
|-----------|---------|---------|
| `task_filter` | Glob pattern to select tasks | `-T task_filter="sanity_*"` |
| `build=true` | Build missing Docker images | `-T build=true` |
| `rebuild_all=true` | Rebuild ALL Docker images | `-T rebuild_all=true` |
| `rebuild=<prefix>` | Rebuild images matching prefix | `-T rebuild=sandbox` |
| `agent=<name>` | Agent implementation | `-T agent=react` |
| `run_preflight=true` | Health check before eval | `-T run_preflight=true` |
| `keep_permanent=true` | Keep permanent services alive | `-T keep_permanent=true` |

## 5. Control Concurrency and Limits

```bash
# Limit number of concurrent samples
uv run inspect eval domains/<domain> --model <model> --display plain --max-samples 4

# Limit concurrent model API connections
uv run inspect eval domains/<domain> --model <model> --display plain --max-connections 20

# Combine limits for stability
uv run inspect eval domains/<domain> --model <model> --display plain --limit 1 --max-samples 1
```

## 5b. Reasoning models — set `--reasoning-effort` explicitly (IMPORTANT)

Reasoning models (gpt-5.x, o1/o3, Claude Opus) do **NO reasoning by default** in these
runs: `reasoning_effort` is unset, the model emits **0 reasoning tokens**, and scores land
noticeably lower. Always pass it explicitly — especially for cross-run / cross-model
comparisons:

```bash
uv run inspect eval domains/<domain> --model <model> --reasoning-effort high --display plain
```

Verified impact (excytin, `gpt-5.4`, `latest_test_set`, 599 samples): `reasoning=high`
scored **0.886** vs **0.813** with reasoning unset — a **+0.073** aggregate swing, entirely
from reasoning, with the largest lift on intermediate checkpoints (the multi-step
investigation). The effort used is recorded in the eval-log header
(`model_generate_config.reasoning_effort`); `stats.model_usage.*.reasoning_tokens == 0`
means no reasoning happened. `--max-tokens` must be large enough to cover reasoning +
answer or completions get truncated.

## 6. Enable Verbose Logging

```bash
# Show info-level logs during eval
INSPECT_LOG_LEVEL=info uv run inspect eval domains/<domain> --model <model> --display plain

# Show debug-level logs (very verbose)
INSPECT_LOG_LEVEL=debug uv run inspect eval domains/<domain> --model <model> --display plain

# Write Python logger output to file
INSPECT_PY_LOGGER_FILE=/tmp/eval_debug.log uv run inspect eval domains/<domain> --model <model> --display plain
```

## 7. Iterative Development Workflow

When developing or debugging a domain:

1. **Start with `--limit 1`** to run a single sample quickly
2. **Use `task_filter`** to isolate the specific task you're working on
3. **Pipe output** to capture both stdout and stderr: `2>&1 | tee /tmp/eval_output.log`
4. **Check the eval log** — the path is printed at the end: `Log: logs/<timestamp>_<domain>_<id>.eval`
5. **Iterate on scoring/tools** — changes to domain code in `domains/<domain>/` take effect immediately (no reinstall needed)
6. **Changes to `saber` or `inspect_ai`** — if installed as editable, take effect immediately; if installed from git, you must edit the files in `.venv/lib/python3.11/site-packages/` directly and clear `__pycache__` dirs

## 8. Understand the Score Output

The eval summary shows scores organized by task and scorer:

```
saber_overall         task_name_1            task_name_2
mean           0.500  accuracy        1.000  accuracy        0.000
stderr         0.000  stderr          0.000  stderr          0.000
```

- `saber_overall` is the aggregate across all tasks
- Each task shows its `accuracy` (the final aggregated score)
- `nan` means the scorer did not produce a result (e.g., the agent didn't reach that evaluation point)
- Multiple scorers per task (e.g., `submission`, `crash_analysis`, `root_cause`) are aggregated per the task's `scoring_aggregation` config

## 9. Common Issues

- **"No tasks found"**: Check `task_filter` matches task YAML filenames (without `.yaml` extension)
- **Docker build failures**: Run `uv run saber build <domain>` separately to see full build output
- **Model API errors**: Verify environment variables (`AZURE_OPENAI_API_KEY`, `OPENAI_API_KEY`, etc.)
- **Stale saber version**: `uv.lock` pins an exact saber commit. If the ACES/SABER library repo has been updated but evals show missing features or unexpected errors, update the lock:
  ```bash
  uv lock --upgrade-package saber && uv sync --all-extras
  ```
  Then commit the updated `uv.lock`. Use `uv pip show saber` to verify the installed commit.

More from microsoft/ACESEvals