Skip to main content

Open-source psychological-safety benchmark for conversational AI (Inspect AI based)

Project description

Keido Labs

aipsy-bench

Open-source psychological-safety benchmark for conversational AI

Point a chatbot at a frozen battery of clinical scenarios, score the transcripts with a frozen panel of LLM judges, and ship a CI pass/fail gate + a clinician-grade diagnostic — which turns failed, why, and what to tune.

CI PyPI Python 3.12+ Code license: Apache 2.0 Data license: CC BY 4.0 Built on Inspect AI Status: Directional

Quickstart · Benchmark your app · Local judge · Run profiles · What a score means

Built and maintained by Keido Labs


It is a benchmark (fixed content, comparable scores), not a framework. The content — 20 scenarios + a 6-metric rubric + the judge prompt — is verbatim from our source research study (documented in the forthcoming methodology preprint). The engine is Inspect AI; we ship a Task, a Solver, and a Scorer, not a new runner.

[!IMPORTANT] ⚠ Directional — a recommendation, not a rubber-stamp. The premise is "the judge panel is validated against human clinical experts." That validation — a multi-rater human-vs-judge agreement study — is running in parallel and has not yet landed. So aipsy-bench ships now as a directional, methodology-transparent, reproducible reading — run it yourself to reproduce — not an authoritative, human-validated safety rating. The CI gate is functional: a metric fails the build against the thresholds you set (your policy, not a validated rating). But no validated per-metric agreement (α) number is claimed until the study lands — don't cite these as validated agreement. When it lands, the directional reading upgrades to validated authority.

Prerequisites

  1. uv — gives you uvx (run with zero install). (Prefer pip? You only need Python 3.12+.)
  2. One way to score transcripts — pick either:
    • 🖥️ Ollama — runs the default local judge, 100% offline, no API key (needs a 48 GB+ Mac or a 16 GB-VRAM + 64 GB-RAM Linux box).
    • 🔑 A provider API keyOpenAI, Anthropic, or Google — for the frontier judge lane (--judges gold/single; your key, your cost).

Quickstart

Try it — nothing to install (offline self-test: mock bot + mock judges):

uvx aipsy-bench run --target mock --quick

Install once — then it's just aipsy-bench … (no per-command prefixes):

uv tool install aipsy-bench             # one install — local judge + every provider, no extras to pick
aipsy-bench judge pull                  # one-time: fetch the local judge (needs Ollama)
aipsy-bench init --http-target http://localhost:3000/eval   # scaffold config for your bot
aipsy-bench run --quick                 # go

Frontier judges instead of the local default? Nothing extra to install — set your provider key (aipsy-bench keys set, stored in a gitignored .env) and pass --judges single (or gold). Prefer classic pip? pip install aipsy-bench is identical.

Each run writes result.json (citable), report.txt (with the remediation cards), and a share card.svg/card.png + badge.svg (skip with --no-card).

Benchmarking your own app? The only integration you write is a thin, stateless /eval endpoint — see the adapter guides: a hand-written cookbook, an AI-agent build prompt, or a Tier-2 callable.

Which judge? The local judge is the offline default; frontier (--judges gold/single, provider keys) is a different instrument — a local score compares to other local runs only, never to gold. Setup + hardware: docs/local-judge.md.

Run profiles

  • --judges local (default) — the offline fine-tuned judge (aipsy-judge-1.0) served by Ollama. No API key, no network (needs a 48 GB+ Mac or a 16 GB-VRAM/64 GB-RAM Linux box — see docs/local-judge.md). Its own comparability lane — comparable to other local runs, never to gold. Directional by construction and human-in-the-loop (strongest on crisis/empathy/boundary; advice is the lowest-confidence axis — treat advice flags as flag-for-review). See docs/local-judge.md.
  • --judges gold — the 3-judge frontier ensemble (the official/citable lane). Comparable, drives the frontier badge/leaderboard. Needs all three provider keys.
  • --judges single — the primary frontier judge only. Fast inner loop; NOT comparable to the gold or local lanes.
  • --quick — smoke subset (one scenario per domain + both crisis scenarios). Directional only; never feeds a card or the leaderboard.
  • --scenario s06,s07 — run a subset.
  • --baseline-prompt — inject the research baseline system prompt to reproduce the published frontier baseline. By default the target keeps its own system prompt (the bot as deployed); aipsy-bench sends only the scripted user turns.
  • --judge-override anthropic=claude-haiku-4-5 — swap a pinned judge for a cheaper one while iterating (repeatable). The judge pins are frozen, so this makes the run non-comparable — not the frozen instrument, not board/card eligible, loudly warned (§8). Never use it for a number you'll cite. (Set once in aipsy-bench.yaml via judge_overrides: {anthropic: claude-haiku-4-5}.)

Long / real runs (timeouts, interrupting, resuming)

A gold battery is ~800 calls — --dry-run first to see the estimate. Calls are bounded so a hung or rate-limited provider can't stall forever:

  • --timeout <seconds> (default 120) — per-call timeout; a stuck call fails and that scenario is reported as a run failure (never a low safety score).
  • --max-retries <n> (default 3) — bounds rate-limit backoff (which can otherwise look like a hang). A whole battery never aborts on one bad scenario — it's logged and the rest still score.
  • --max-connections <n> — cap concurrent calls per provider. Rate-limited? Lower it (e.g. 24) — fewer parallel calls means fewer 429s and a more complete run. (Running a model as both target and a judge doubles that provider's load, so it rate-limits first.)
  • Interrupt with Ctrl+C (bounded by --timeout, so it stops promptly), then --resume <run_id> continues without re-doing completed work. Live progress shows aipsy: judge calls / aipsy: scoring counters; if the terminal UI feels heavy, add --display plain.

The footer counters like openai 5/5 · anthropic 14/40 · google 0/20 are Inspect's per-provider in-flight / pool-size gauges (live concurrency), not call totals — unequal and fluctuating is normal. A rate-limited / target-doubling provider stays saturated while an idle one reads 0/n. All turns are still judged by every panel member.

API keys (your keys, your cost)

aipsy-bench uses your provider keys, read from the environment — it never stores, transmits, or proxies them, so the provider bills you directly. --target mock, the test suite, and the default local judge need no provider keys (the local judge runs offline on Ollama); the frontier panels need a key per judge.

Panel Keys needed
--judges local (default) nonejudge pull is token-free (public, ungated repo)
--judges single OPENAI_API_KEY
--judges gold OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_API_KEY

A real target may still need its own provider key even with the local judge (only the judge is local). The local judge itself needs no key — judge pull fetches from a public, ungated repo.

Set them the friendly way (interactive, input hidden, written to a gitignored .env):

aipsy-bench keys set                # pick a provider, paste the key, done
aipsy-bench keys set --provider openai
aipsy-bench keys status             # which keys are present (never prints values)

…or do it by hand — a project .env (auto-loaded; gitignored) or exported shell vars (which take precedence):

cp .env.example .env       # then fill in your keys
# or:  export OPENAI_API_KEY=sk-...

aipsy-bench doctor --judges gold   # preflight: which keys are present, data SHA, config

keys set only writes to your local .env — aipsy-bench never stores, transmits, or proxies your keys.

doctor reads the same .env a real run will, so it tells you exactly what's set before you spend anything. (Enterprises can route the pinned judges through their own Azure / Vertex / gateway via base-URL overrides — a later iteration.)

What a score means

The only variable in a comparable score is the target bot — the scenarios, rubric, judge prompt, and judge model snapshots are all frozen and SHA-256 verified at runtime. The six metrics (empathy, tone_consistency, crisis_handling, advice_safety, boundary_safety, affective_complexity) roll up into a weighted AI-Trust composite over the applicable metrics. A target error / timeout / rate-limit / refusal is a run failure, never a low safety score.

Coverage limits (v1)

aipsy-bench v1 measures English, text, single-agent conversational safety on the frozen battery. Out of scope for v1 (named here, not silently mishandled):

  • Non-English — scenarios and judges are English-frozen; a non-English bot needs a future data/ version, not v1.
  • Voice / multimodal — text only; a voice bot needs a user-supplied speech-to-text shim ahead of the adapter (not shipped).
  • Agentic / tool-using / RAG-grounded bots — the transcript is user/assistant text only; tool calls and retrieved context are not modeled. Such bots run, but the score reflects the text exchange only.
  • Guardrail / safety-filter vendors want pass/fail on detection, not quality scoring — an adjacent product, not this tool.

Data residency

The benchmark drives synthetic, public scripted scenarios through your bot — the "user" turns are ours and carry no real end-user data. What differs by lane is where your bot's replies get scored:

  • Local judge (--judges local, the default) — fully in your boundary. Scoring runs on your own machine via Ollama; the transcript is never sent to any third-party provider and nothing leaves your environment. This is the lane for sensitive transcripts — real user data via the SDK, regulated / PHI content — where an API judge structurally cannot offer the same guarantee.
  • Any API judge (--judges single or --judges gold) — the transcript leaves your environment. Your bot's replies are sent to the judge provider(s) — OpenAI / Anthropic / Google, whichever that lane uses — for scoring, billed to your keys. In pure benchmark mode that's only your bot's answers to our public scripted prompts (still no real end-user data), but the target's outputs do go out.

So the local-judge default already runs the whole pipeline inside your own boundary — no enterprise routing required. (For teams that want the frontier lane in-boundary too, routing the pinned API judges through your own Azure / Vertex / gateway is a later enterprise feature.)

Development

uv run pytest          # full suite, offline, no API keys
uv run ruff check .    # lint

CI runs the suite offline with no provider keys — every test is deterministic against the mock target + mock judges.

Licenses

  • Code: Apache-2.0 (see LICENSE).
  • Data (data/v1/ — the scenarios, rubric, and judge prompt): CC BY 4.0 (see data/v1/DATA_LICENSE) — the standard content license, and the same one the forthcoming methodology preprint will carry.
  • Local judge model (keidolabs/aipsy-judge-1.0, on Hugging Face): Apache-2.0, inherited from its Gemma-4 base model's terms.

aipsy-bench — built and maintained by Keido Labs
Apache-2.0 (code) · CC BY 4.0 (data) · directional until the human-validation study lands

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aipsy_bench-0.1.2.tar.gz (396.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aipsy_bench-0.1.2-py3-none-any.whl (172.9 kB view details)

Uploaded Python 3

File details

Details for the file aipsy_bench-0.1.2.tar.gz.

File metadata

  • Download URL: aipsy_bench-0.1.2.tar.gz
  • Upload date:
  • Size: 396.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for aipsy_bench-0.1.2.tar.gz
Algorithm Hash digest
SHA256 646057cb41596bb5afe3e2836c7690146e9332e709bd25ba04ff2a2b3c068868
MD5 9346e5745df13bad7485d98b84fe4402
BLAKE2b-256 29d2d039fa81832005058e84da497694be7e15035a028a68ca682c146c34db04

See more details on using hashes here.

File details

Details for the file aipsy_bench-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: aipsy_bench-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 172.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for aipsy_bench-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d00996dfd8d27fafa66024b4068d158ba0d4c95075c410a29e48c9aca77945f9
MD5 98c661fff04b567cbcc8c529b0a0dd7e
BLAKE2b-256 61d945979db140d697148820ca22bfa1b4de7ebc7ee20ca1a57785f70c1ab9f9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page