simpleaudit 0.3.2__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {simpleaudit-0.3.2/simpleaudit.egg-info → simpleaudit-0.4.0}/PKG-INFO +119 -62
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/README.md +117 -57
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/pyproject.toml +2 -8
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/__init__.py +4 -1
- simpleaudit-0.4.0/simpleaudit/cli.py +32 -0
- simpleaudit-0.4.0/simpleaudit/decision.py +138 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/judges/__init__.py +13 -0
- simpleaudit-0.4.0/simpleaudit/judges/choice_match.py +181 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/judges/compose.py +5 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/model_auditor.py +171 -24
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/reframing.py +16 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/targets/__init__.py +3 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/targets/base.py +5 -0
- simpleaudit-0.4.0/simpleaudit/targets/decision.py +211 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/tracing/__init__.py +6 -0
- simpleaudit-0.4.0/simpleaudit/tracing/auth.py +332 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/tracing/otlp.py +43 -13
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/tracing/provider.py +11 -2
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/tracing/selection.py +29 -3
- {simpleaudit-0.3.2 → simpleaudit-0.4.0/simpleaudit.egg-info}/PKG-INFO +119 -62
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit.egg-info/SOURCES.txt +7 -4
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit.egg-info/requires.txt +1 -5
- simpleaudit-0.4.0/tests/test_choice_match_judge.py +300 -0
- simpleaudit-0.4.0/tests/test_decision.py +275 -0
- simpleaudit-0.4.0/tests/test_decision_target.py +345 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_file_uri.py +0 -211
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_judge_output_contract.py +1 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_judge_registry.py +1 -0
- simpleaudit-0.4.0/tests/test_otlp_auth.py +401 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_tracing.py +2 -1
- simpleaudit-0.3.2/simpleaudit/cli.py +0 -113
- simpleaudit-0.3.2/simpleaudit/tracing/auth.py +0 -175
- simpleaudit-0.3.2/simpleaudit/visualization/scenario_viewer.html +0 -1107
- simpleaudit-0.3.2/simpleaudit/visualization/server.py +0 -408
- simpleaudit-0.3.2/simpleaudit/visualization/thumbnail.png +0 -0
- simpleaudit-0.3.2/simpleaudit/visualization/visualizer.html +0 -2134
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/LICENSE +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/setup.cfg +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/auditor.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/checklist.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/context_marks.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/cross_judge.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/experiment.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/judges/abstention.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/judges/binary_abstention.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/judges/checklist.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/judges/default.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/judges/factuality.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/judges/harm.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/judges/helpfulness.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/judges/helsedir_sexhealth_no.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/judges/helsedir_sexhealth_no_rag.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/judges/safety.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/perturbations.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/repeated_results.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/results.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/__init__.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/arbeidstilsynet_arbeidstid.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/bullshitbench_health.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/bullshitbench_v1_v2.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/health.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/hei_refusal.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/helfo.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/helpmed.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/human_rights_education.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/human_rights_fair_trial.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/human_rights_water.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/images/blank_chart.png +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/images/illegible_label.png +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/images/injection.png +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/images/make_images.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/images/product_a.png +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/images/product_b.png +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/images/quarterly_revenue.png +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/images/truncated_axis.png +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/lanekassen.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/nav_aap.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/nb_kryss_ordning.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/rag.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/safety.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/skatteetaten.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/skatteetaten_legitimasjon.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/system_prompt.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/toll_reisegodskvote.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/ung.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/scenarios/vision_integrity.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/spans.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/stats.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/targets/callable.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/targets/http.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/targets/model.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/tracing/context.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/tracing/shared.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/tracing/store.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit/utils.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit.egg-info/dependency_links.txt +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit.egg-info/entry_points.txt +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/simpleaudit.egg-info/top_level.txt +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_anthropic_judge_default_path.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_audit_flow.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_basic.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_checklist.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_checklist_judge.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_checklist_pipeline.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_checklist_reframing.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_cross_judge.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_custom_prompts.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_document_expansion.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_experiment_streaming.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_fakes.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_fragility.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_generation_params.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_json_format.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_judge_compose.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_judge_notes.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_judge_postprocess.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_judge_response_schema.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_judge_robustness_pipeline.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_model_auditor.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_perturbations.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_reframing.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_rejudge.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_repeated_experiments.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_resumable_experiments.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_scenario_data.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_scenario_pack_conventions.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_spans.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_stats.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_strip_thinking.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_target_api_key.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_targets.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_token_counting.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_tracing_auth.py +0 -0
- {simpleaudit-0.3.2 → simpleaudit-0.4.0}/tests/test_vision_integrity_pack.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simpleaudit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Lightweight AI Safety Auditing Framework
|
|
5
5
|
Author: SimpleAudit Contributors
|
|
6
6
|
License: MIT
|
|
@@ -31,9 +31,6 @@ Requires-Dist: grpcio>=1.60; extra == "tracing"
|
|
|
31
31
|
Requires-Dist: opentelemetry-proto>=1.20; extra == "tracing"
|
|
32
32
|
Provides-Extra: plot
|
|
33
33
|
Requires-Dist: matplotlib>=3.5.0; extra == "plot"
|
|
34
|
-
Provides-Extra: visualize
|
|
35
|
-
Requires-Dist: fastapi>=0.104.0; extra == "visualize"
|
|
36
|
-
Requires-Dist: uvicorn[standard]>=0.24.0; extra == "visualize"
|
|
37
34
|
Provides-Extra: dev
|
|
38
35
|
Requires-Dist: pytest<9,>=8; extra == "dev"
|
|
39
36
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
@@ -43,7 +40,7 @@ Requires-Dist: pytest-testmon<3,>=2; extra == "dev"
|
|
|
43
40
|
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
44
41
|
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
45
42
|
Provides-Extra: all
|
|
46
|
-
Requires-Dist: simpleaudit[dev,plot
|
|
43
|
+
Requires-Dist: simpleaudit[dev,plot]; extra == "all"
|
|
47
44
|
Dynamic: license-file
|
|
48
45
|
|
|
49
46
|
<div align="center">
|
|
@@ -68,44 +65,6 @@ See the [standards and best practices for creating custom test scenarios](https:
|
|
|
68
65
|
|
|
69
66
|
<img alt="simpleaudit_example_gemma_model" src="https://github.com/user-attachments/assets/05c45a62-74e7-4aa3-a3cd-41bad0cc8233" />
|
|
70
67
|
|
|
71
|
-
|
|
72
|
-
## Why SimpleAudit?
|
|
73
|
-
|
|
74
|
-
<div style="overflow-x: auto;">
|
|
75
|
-
|
|
76
|
-
| Tool | Complexity | Dependencies | Token cost | Use case |
|
|
77
|
-
|------|------------|--------------|------------|----------|
|
|
78
|
-
| **SimpleAudit** | ⭐ Simple | 2 packages | $ Low | Comparative scoring |
|
|
79
|
-
| Petri | ⭐⭐⭐ Complex | Inspect framework | $$ ~1.7× higher | Discovery-oriented auditing |
|
|
80
|
-
| PyRIT | ⭐⭐⭐ Complex | Many | $$ Variable | Multi-turn attack campaigns |
|
|
81
|
-
| Garak | ⭐⭐ Medium | Plugin system | $ Variable | Static vulnerability scanning |
|
|
82
|
-
| Custom | ⭐⭐⭐ Complex | Varies | Varies | Build from scratch |
|
|
83
|
-
|
|
84
|
-
</div>
|
|
85
|
-
|
|
86
|
-
### Methodology & Validation
|
|
87
|
-
|
|
88
|
-
SimpleAudit is built around an **instrumental-validity chain** — when no labelled benchmark exists for your language or domain, you need a substitute for ground-truth agreement. The chain has three requirements, each empirically validated ([paper](https://arxiv.org/abs/2605.06652)):
|
|
89
|
-
|
|
90
|
-
| Requirement | What it means | Result |
|
|
91
|
-
|---|---|---|
|
|
92
|
-
| **Responsiveness** | Safe vs. unsafe targets must separate | AUROC 0.89–1.00 across reliable judge–auditor cells |
|
|
93
|
-
| **Target sensitivity** | Score variance must come from the target, not the apparatus | Target-dominant (η² ≈ 0.52); judge variance largely cancels under deltas |
|
|
94
|
-
| **Reproducibility** | Scores must stabilise across reruns | Within ~1 point on the 0–100 scale by n=10 |
|
|
95
|
-
|
|
96
|
-
The reproducibility leg operates at two levels. At the **aggregate** level, the overall score stabilises within ~1 point by n=10. At the **per-scenario** level, the fragility signal (normalised entropy, ordinal spread, modal agreement) identifies individual verdicts that are unstable across runs — a direct application of the *Jagged Judges* finding ([Zhao et al., 2026](https://arxiv.org/abs/2608.12645)) that baseline jury majority strength is the best single-shot predictor of which items flip under perturbation. The reframing check extends this to prompt-wording invariance, isolating apparatus artifacts from genuine target behaviour.
|
|
97
|
-
|
|
98
|
-
We apply the same chain to [Petri](https://github.com/safety-research/petri) — both tools pass, so the differences live upstream of the chain. SimpleAudit's choice is to **commit to a fixed scenario pack, rubric, auditor, judge, sampling configuration, and rerun count** by default, so every rerun is comparable. Petri's design point is discovery over a 38-dimension rubric where the user picks the construct and aggregation; that flexibility is the right call for discovery and moves work to the user when the goal is a single comparable score.
|
|
99
|
-
|
|
100
|
-
Practical consequences:
|
|
101
|
-
|
|
102
|
-
- **Default `J = A`** (judge matches auditor capability) is empirically grounded — judge variance largely cancels under matched-target deltas while auditor variance does not. ~1.7× lower per-run token cost than Petri under matched protocols.
|
|
103
|
-
- **Auditor capability should match the target range.** An auditor that is too strong floors safe-target scores and erases the deltas the instrument exists to report — don't reach for the strongest available model by default.
|
|
104
|
-
- **Report the bundle, not a leaderboard.** Score, matched deltas, critical-rate differences, uncertainty, and the judge/auditor used — together, never collapsed to a single rank.
|
|
105
|
-
|
|
106
|
-
See the paper for the full validation protocol, variance decomposition, and a Norwegian public-sector procurement case comparing Borealis and Gemma 3.
|
|
107
|
-
|
|
108
|
-
|
|
109
68
|
## Installation
|
|
110
69
|
|
|
111
70
|
**Install from PyPI (recommended):**
|
|
@@ -166,29 +125,16 @@ results.save("./my_audit_results/audit_results.json")
|
|
|
166
125
|
```
|
|
167
126
|
|
|
168
127
|
**💡 View results interactively:**
|
|
169
|
-
```bash
|
|
170
|
-
# Option 1: Run directly with uvx (no installation needed, requires uv)
|
|
171
|
-
uvx 'simpleaudit[visualize]' serve --results_dir ./my_audit_results
|
|
172
128
|
|
|
173
|
-
|
|
174
|
-
pip install 'simpleaudit[visualize]'
|
|
175
|
-
simpleaudit serve --results_dir ./my_audit_results
|
|
176
|
-
```
|
|
177
|
-
This will spin-up a local web server to explore results with scenario details. 👉 [Check for live demo.](https://simulamet-simpleauditvisualization.hf.space)
|
|
178
|
-
See [visualization/README.md](https://github.com/simulamet/simpleaudit/blob/main/simpleaudit/visualization/README.md) for more options and features.
|
|
179
|
-
|
|
180
|
-
To share results as a single self-contained HTML file (no server, no JSON upload), use `simpleaudit export-html ./audit_results.json` or the **Download HTML** button in the visualizer.
|
|
129
|
+
The web visualizer now lives in [SimpleAudit Studio](https://github.com/SimulaMet/SimpleAuditStudio). To browse a folder of results in a local web server (no audit worker), run:
|
|
181
130
|
|
|
182
|
-
|
|
131
|
+
```bash
|
|
132
|
+
uvx simpleaudit-studio --visualize-only --results_dir ./my_audit_results
|
|
133
|
+
```
|
|
183
134
|
|
|
184
|
-
|
|
185
|
-
If the command fails:
|
|
186
|
-
- **`Address already in use`** — port 8000 is taken. Use `--port 8080` or stop the other process.
|
|
187
|
-
- **`uvx: command not found`** — install `uv` first (`curl -LsSf https://astral.sh/uv/install.sh | sh`).
|
|
188
|
-
- **Weird import/module error** — stale cache. Run `uv cache clean` and retry.
|
|
189
|
-
</Troubleshooting>
|
|
135
|
+
This opens a file-tree viewer with scenario details, fragility metrics, PDF export, and a **Download HTML** button that produces a self-contained HTML file (no server, no JSON upload). For a full Studio instance (audits, experiments, comparison), run `uvx simpleaudit-studio`.
|
|
190
136
|
|
|
191
|
-
[
|
|
137
|
+
> **Note:** [`uvx`](https://docs.astral.sh/uv/) is used to run Studio without installing it. Install `uv` first if you don't have it (`curl -LsSf https://astral.sh/uv/install.sh | sh`).
|
|
192
138
|
|
|
193
139
|
### Running Experiments
|
|
194
140
|
|
|
@@ -540,6 +486,41 @@ auditor = ModelAuditor(
|
|
|
540
486
|
| `max_retries` | Retries per API call for transient failures | No (default: 2) |
|
|
541
487
|
| `retry_backoff` | Initial retry delay in seconds, doubled per attempt (exponential backoff) | No (default: 0.5) |
|
|
542
488
|
|
|
489
|
+
## Why SimpleAudit?
|
|
490
|
+
|
|
491
|
+
<div style="overflow-x: auto;">
|
|
492
|
+
|
|
493
|
+
| Tool | Complexity | Dependencies | Token cost | Use case |
|
|
494
|
+
|------|------------|--------------|------------|----------|
|
|
495
|
+
| **SimpleAudit** | ⭐ Simple | 2 packages | $ Low | Comparative scoring |
|
|
496
|
+
| Petri | ⭐⭐⭐ Complex | Inspect framework | $$ ~1.7× higher | Discovery-oriented auditing |
|
|
497
|
+
| PyRIT | ⭐⭐⭐ Complex | Many | $$ Variable | Multi-turn attack campaigns |
|
|
498
|
+
| Garak | ⭐⭐ Medium | Plugin system | $ Variable | Static vulnerability scanning |
|
|
499
|
+
| Custom | ⭐⭐⭐ Complex | Varies | Varies | Build from scratch |
|
|
500
|
+
|
|
501
|
+
</div>
|
|
502
|
+
|
|
503
|
+
### Methodology & Validation
|
|
504
|
+
|
|
505
|
+
SimpleAudit is built around an **instrumental-validity chain** — when no labelled benchmark exists for your language or domain, you need a substitute for ground-truth agreement. The chain has three requirements, each empirically validated ([paper](https://arxiv.org/abs/2605.06652)):
|
|
506
|
+
|
|
507
|
+
| Requirement | What it means | Result |
|
|
508
|
+
|---|---|---|
|
|
509
|
+
| **Responsiveness** | Safe vs. unsafe targets must separate | AUROC 0.89–1.00 across reliable judge–auditor cells |
|
|
510
|
+
| **Target sensitivity** | Score variance must come from the target, not the apparatus | Target-dominant (η² ≈ 0.52); judge variance largely cancels under deltas |
|
|
511
|
+
| **Reproducibility** | Scores must stabilise across reruns | Within ~1 point on the 0–100 scale by n=10 |
|
|
512
|
+
|
|
513
|
+
The reproducibility leg operates at two levels. At the **aggregate** level, the overall score stabilises within ~1 point by n=10. At the **per-scenario** level, the fragility signal (normalised entropy, ordinal spread, modal agreement) identifies individual verdicts that are unstable across runs — a direct application of the *Jagged Judges* finding ([Zhao et al., 2026](https://arxiv.org/abs/2608.12645)) that baseline jury majority strength is the best single-shot predictor of which items flip under perturbation. The reframing check extends this to prompt-wording invariance, isolating apparatus artifacts from genuine target behaviour.
|
|
514
|
+
|
|
515
|
+
We apply the same chain to [Petri](https://github.com/safety-research/petri) — both tools pass, so the differences live upstream of the chain. SimpleAudit's choice is to **commit to a fixed scenario pack, rubric, auditor, judge, sampling configuration, and rerun count** by default, so every rerun is comparable. Petri's design point is discovery over a 38-dimension rubric where the user picks the construct and aggregation; that flexibility is the right call for discovery and moves work to the user when the goal is a single comparable score.
|
|
516
|
+
|
|
517
|
+
Practical consequences:
|
|
518
|
+
|
|
519
|
+
- **Default `J = A`** (judge matches auditor capability) is empirically grounded — judge variance largely cancels under matched-target deltas while auditor variance does not. ~1.7× lower per-run token cost than Petri under matched protocols.
|
|
520
|
+
- **Auditor capability should match the target range.** An auditor that is too strong floors safe-target scores and erases the deltas the instrument exists to report — don't reach for the strongest available model by default.
|
|
521
|
+
- **Report the bundle, not a leaderboard.** Score, matched deltas, critical-rate differences, uncertainty, and the judge/auditor used — together, never collapsed to a single rank.
|
|
522
|
+
|
|
523
|
+
See the paper for the full validation protocol, variance decomposition, and a Norwegian public-sector procurement case comparing Borealis and Gemma 3.
|
|
543
524
|
|
|
544
525
|
## Scenario Packs
|
|
545
526
|
|
|
@@ -681,6 +662,7 @@ SimpleAudit includes pre-built judge configurations grounded in published evalua
|
|
|
681
662
|
| `harm` | HELM Safety — Liang et al., 2022 | `harmful`, `category`, `severity`, `explanation` |
|
|
682
663
|
| `binary_abstention` | Substance-vs-words binary classifier (language-agnostic) | `abstained` (bool), `reasoning` |
|
|
683
664
|
| `checklist` | Evidence-anchored checklist — RULERS (Hong et al., 2026), TICK (Cook et al., 2024), GuidedBench (Huang et al., 2025) | judge returns `checklist` (per-expectation `status`, `evidence_kind`, `quote`) and `notes`; code derives `severity`, `issues_found`, `positive_behaviors`, `summary`, `recommendations` — see [below](#evidence-anchored-checklist-judge) |
|
|
665
|
+
| `choice_match` | Exact-match scoring of a scenario's [decision question](#decision-models), in code — no judge model | `choice`, `choice_source`, `accepted`, `correct`, and for decision models `confidence`, `probabilities`; `severity` is `pass`, the designed severity, or `ungraded` |
|
|
684
666
|
|
|
685
667
|
</div>
|
|
686
668
|
|
|
@@ -863,6 +845,81 @@ results = auditor.run(
|
|
|
863
845
|
|
|
864
846
|
The `language` parameter is substituted into the probe generator's system prompt: the built-in red-team persona and all named judge configs include a literal `{language}` placeholder, and a custom `probe_prompt` can opt in by including its own `{language}` placeholder (replaced verbatim, so JSON braces elsewhere in the prompt are untouched).
|
|
865
847
|
|
|
848
|
+
## Decision Models
|
|
849
|
+
|
|
850
|
+
Some models do not write prose: a **decision model** reads a document and a question with fixed options, and returns the chosen option with a probability for every option. Examples are [Clef](https://ollama.com/library/clef), served by Ollama at `/v1/systemone`, and [Jev](https://openrouter.ai/typesafe/jev-1.13) on OpenRouter's Decisions API. SimpleAudit can audit them, and can ask chat models the same questions so both kinds are compared on the same scenarios.
|
|
851
|
+
|
|
852
|
+
### The `decision` field
|
|
853
|
+
|
|
854
|
+
A scenario states its question as a `decision` block: the question, the options, and the accepted answer.
|
|
855
|
+
|
|
856
|
+
```python
|
|
857
|
+
scenario = {
|
|
858
|
+
"name": "Verdict - Guilty",
|
|
859
|
+
"description": "Asks whether the court found the defendant guilty.",
|
|
860
|
+
"documents": ["The court finds the defendant A.B. guilty of domestic violence ..."],
|
|
861
|
+
"severity": "medium",
|
|
862
|
+
"decision": {
|
|
863
|
+
"id": "verdict",
|
|
864
|
+
"instructions": "Did the court find the defendant guilty?",
|
|
865
|
+
"criteria": {"yes": "Found guilty", "no": "Not found guilty"},
|
|
866
|
+
"accepted": ["yes"],
|
|
867
|
+
},
|
|
868
|
+
}
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
- `accepted` never reaches the model under test.
|
|
872
|
+
- A chat model gets the question as text: the scenario's `test_prompt`, or, when it has none, the question with its options and a request for the chosen key on the first line.
|
|
873
|
+
- A decision model gets the structured question, with the scenario's `documents` as its input.
|
|
874
|
+
|
|
875
|
+
See the [scenario guidelines](simpleaudit/scenarios/simpleaudit_scenario_guidelines_v1.0.md) ("Decision Field") for every key.
|
|
876
|
+
|
|
877
|
+
### Auditing a decision model
|
|
878
|
+
|
|
879
|
+
`DecisionTarget` sends the question to a System One endpoint, and the `choice_match` judge grades the answer in code:
|
|
880
|
+
|
|
881
|
+
```python
|
|
882
|
+
from simpleaudit import Auditor, DecisionTarget
|
|
883
|
+
|
|
884
|
+
auditor = Auditor(
|
|
885
|
+
target=DecisionTarget.ollama("clef", base_url="http://localhost:11434"),
|
|
886
|
+
judge="choice_match", # no judge model, no API key
|
|
887
|
+
max_turns=1,
|
|
888
|
+
)
|
|
889
|
+
results = auditor.run([scenario])
|
|
890
|
+
results.summary()
|
|
891
|
+
|
|
892
|
+
r = results[0]
|
|
893
|
+
r.judgment["choice"], r.judgment["confidence"], r.judgment["probabilities"]
|
|
894
|
+
```
|
|
895
|
+
|
|
896
|
+
For Jev on OpenRouter, use `DecisionTarget.openrouter("typesafe/jev-1.13")`, with the key in `OPENROUTER_API_KEY`. Provider routing, for example `{"provider": {"zdr": True}}`, goes in `extra_body`.
|
|
897
|
+
|
|
898
|
+
`DecisionTarget`:
|
|
899
|
+
- checks the endpoint's limits before sending: 2–26 options per question, and 64 KiB per request for Ollama. A scenario over a limit is recorded as an error; its documents are never shortened.
|
|
900
|
+
- answers one turn only, so the auditor runs a single turn and warns when more were requested.
|
|
901
|
+
- stores the full answer (choice, probabilities, confidence) beside the reply in the transcript.
|
|
902
|
+
|
|
903
|
+
### Asking chat models the same questions
|
|
904
|
+
|
|
905
|
+
The same scenarios run with any chat model. With `judge="choice_match"`, the option key on the first line of the reply is compared with the accepted answer:
|
|
906
|
+
|
|
907
|
+
```python
|
|
908
|
+
from simpleaudit import ModelAuditor
|
|
909
|
+
|
|
910
|
+
auditor = ModelAuditor(
|
|
911
|
+
model="llama3.2", provider="ollama",
|
|
912
|
+
judge_model="unused", judge_provider="ollama", # no judge model is called
|
|
913
|
+
judge="choice_match",
|
|
914
|
+
max_turns=1,
|
|
915
|
+
)
|
|
916
|
+
results = auditor.run([scenario])
|
|
917
|
+
```
|
|
918
|
+
|
|
919
|
+
Use `max_turns=1` with `choice_match`. Follow-up turns need an `auditor_model` of their own, and then the last reply is graded. To grade grounding and reasoning as well as the choice, use another judge, such as `checklist`, and state the accepted answer in `expected_behavior` too: LLM judges do not see `accepted`.
|
|
920
|
+
|
|
921
|
+
[`examples/decision_models_ollama.py`](examples/decision_models_ollama.py) runs a decision model and a chat model on the same scenarios.
|
|
922
|
+
|
|
866
923
|
## Custom Judge
|
|
867
924
|
|
|
868
925
|
By default the judge uses a built-in safety evaluation schema (severity: `critical / high / medium / low / pass`). You can use a [named judge config](#judge-configs) for a different evaluation goal, or define fully custom prompts and output schemas.
|
|
@@ -20,44 +20,6 @@ See the [standards and best practices for creating custom test scenarios](https:
|
|
|
20
20
|
|
|
21
21
|
<img alt="simpleaudit_example_gemma_model" src="https://github.com/user-attachments/assets/05c45a62-74e7-4aa3-a3cd-41bad0cc8233" />
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
## Why SimpleAudit?
|
|
25
|
-
|
|
26
|
-
<div style="overflow-x: auto;">
|
|
27
|
-
|
|
28
|
-
| Tool | Complexity | Dependencies | Token cost | Use case |
|
|
29
|
-
|------|------------|--------------|------------|----------|
|
|
30
|
-
| **SimpleAudit** | ⭐ Simple | 2 packages | $ Low | Comparative scoring |
|
|
31
|
-
| Petri | ⭐⭐⭐ Complex | Inspect framework | $$ ~1.7× higher | Discovery-oriented auditing |
|
|
32
|
-
| PyRIT | ⭐⭐⭐ Complex | Many | $$ Variable | Multi-turn attack campaigns |
|
|
33
|
-
| Garak | ⭐⭐ Medium | Plugin system | $ Variable | Static vulnerability scanning |
|
|
34
|
-
| Custom | ⭐⭐⭐ Complex | Varies | Varies | Build from scratch |
|
|
35
|
-
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
### Methodology & Validation
|
|
39
|
-
|
|
40
|
-
SimpleAudit is built around an **instrumental-validity chain** — when no labelled benchmark exists for your language or domain, you need a substitute for ground-truth agreement. The chain has three requirements, each empirically validated ([paper](https://arxiv.org/abs/2605.06652)):
|
|
41
|
-
|
|
42
|
-
| Requirement | What it means | Result |
|
|
43
|
-
|---|---|---|
|
|
44
|
-
| **Responsiveness** | Safe vs. unsafe targets must separate | AUROC 0.89–1.00 across reliable judge–auditor cells |
|
|
45
|
-
| **Target sensitivity** | Score variance must come from the target, not the apparatus | Target-dominant (η² ≈ 0.52); judge variance largely cancels under deltas |
|
|
46
|
-
| **Reproducibility** | Scores must stabilise across reruns | Within ~1 point on the 0–100 scale by n=10 |
|
|
47
|
-
|
|
48
|
-
The reproducibility leg operates at two levels. At the **aggregate** level, the overall score stabilises within ~1 point by n=10. At the **per-scenario** level, the fragility signal (normalised entropy, ordinal spread, modal agreement) identifies individual verdicts that are unstable across runs — a direct application of the *Jagged Judges* finding ([Zhao et al., 2026](https://arxiv.org/abs/2608.12645)) that baseline jury majority strength is the best single-shot predictor of which items flip under perturbation. The reframing check extends this to prompt-wording invariance, isolating apparatus artifacts from genuine target behaviour.
|
|
49
|
-
|
|
50
|
-
We apply the same chain to [Petri](https://github.com/safety-research/petri) — both tools pass, so the differences live upstream of the chain. SimpleAudit's choice is to **commit to a fixed scenario pack, rubric, auditor, judge, sampling configuration, and rerun count** by default, so every rerun is comparable. Petri's design point is discovery over a 38-dimension rubric where the user picks the construct and aggregation; that flexibility is the right call for discovery and moves work to the user when the goal is a single comparable score.
|
|
51
|
-
|
|
52
|
-
Practical consequences:
|
|
53
|
-
|
|
54
|
-
- **Default `J = A`** (judge matches auditor capability) is empirically grounded — judge variance largely cancels under matched-target deltas while auditor variance does not. ~1.7× lower per-run token cost than Petri under matched protocols.
|
|
55
|
-
- **Auditor capability should match the target range.** An auditor that is too strong floors safe-target scores and erases the deltas the instrument exists to report — don't reach for the strongest available model by default.
|
|
56
|
-
- **Report the bundle, not a leaderboard.** Score, matched deltas, critical-rate differences, uncertainty, and the judge/auditor used — together, never collapsed to a single rank.
|
|
57
|
-
|
|
58
|
-
See the paper for the full validation protocol, variance decomposition, and a Norwegian public-sector procurement case comparing Borealis and Gemma 3.
|
|
59
|
-
|
|
60
|
-
|
|
61
23
|
## Installation
|
|
62
24
|
|
|
63
25
|
**Install from PyPI (recommended):**
|
|
@@ -118,29 +80,16 @@ results.save("./my_audit_results/audit_results.json")
|
|
|
118
80
|
```
|
|
119
81
|
|
|
120
82
|
**💡 View results interactively:**
|
|
121
|
-
```bash
|
|
122
|
-
# Option 1: Run directly with uvx (no installation needed, requires uv)
|
|
123
|
-
uvx 'simpleaudit[visualize]' serve --results_dir ./my_audit_results
|
|
124
83
|
|
|
125
|
-
|
|
126
|
-
pip install 'simpleaudit[visualize]'
|
|
127
|
-
simpleaudit serve --results_dir ./my_audit_results
|
|
128
|
-
```
|
|
129
|
-
This will spin-up a local web server to explore results with scenario details. 👉 [Check for live demo.](https://simulamet-simpleauditvisualization.hf.space)
|
|
130
|
-
See [visualization/README.md](https://github.com/simulamet/simpleaudit/blob/main/simpleaudit/visualization/README.md) for more options and features.
|
|
131
|
-
|
|
132
|
-
To share results as a single self-contained HTML file (no server, no JSON upload), use `simpleaudit export-html ./audit_results.json` or the **Download HTML** button in the visualizer.
|
|
84
|
+
The web visualizer now lives in [SimpleAudit Studio](https://github.com/SimulaMet/SimpleAuditStudio). To browse a folder of results in a local web server (no audit worker), run:
|
|
133
85
|
|
|
134
|
-
|
|
86
|
+
```bash
|
|
87
|
+
uvx simpleaudit-studio --visualize-only --results_dir ./my_audit_results
|
|
88
|
+
```
|
|
135
89
|
|
|
136
|
-
|
|
137
|
-
If the command fails:
|
|
138
|
-
- **`Address already in use`** — port 8000 is taken. Use `--port 8080` or stop the other process.
|
|
139
|
-
- **`uvx: command not found`** — install `uv` first (`curl -LsSf https://astral.sh/uv/install.sh | sh`).
|
|
140
|
-
- **Weird import/module error** — stale cache. Run `uv cache clean` and retry.
|
|
141
|
-
</Troubleshooting>
|
|
90
|
+
This opens a file-tree viewer with scenario details, fragility metrics, PDF export, and a **Download HTML** button that produces a self-contained HTML file (no server, no JSON upload). For a full Studio instance (audits, experiments, comparison), run `uvx simpleaudit-studio`.
|
|
142
91
|
|
|
143
|
-
[
|
|
92
|
+
> **Note:** [`uvx`](https://docs.astral.sh/uv/) is used to run Studio without installing it. Install `uv` first if you don't have it (`curl -LsSf https://astral.sh/uv/install.sh | sh`).
|
|
144
93
|
|
|
145
94
|
### Running Experiments
|
|
146
95
|
|
|
@@ -492,6 +441,41 @@ auditor = ModelAuditor(
|
|
|
492
441
|
| `max_retries` | Retries per API call for transient failures | No (default: 2) |
|
|
493
442
|
| `retry_backoff` | Initial retry delay in seconds, doubled per attempt (exponential backoff) | No (default: 0.5) |
|
|
494
443
|
|
|
444
|
+
## Why SimpleAudit?
|
|
445
|
+
|
|
446
|
+
<div style="overflow-x: auto;">
|
|
447
|
+
|
|
448
|
+
| Tool | Complexity | Dependencies | Token cost | Use case |
|
|
449
|
+
|------|------------|--------------|------------|----------|
|
|
450
|
+
| **SimpleAudit** | ⭐ Simple | 2 packages | $ Low | Comparative scoring |
|
|
451
|
+
| Petri | ⭐⭐⭐ Complex | Inspect framework | $$ ~1.7× higher | Discovery-oriented auditing |
|
|
452
|
+
| PyRIT | ⭐⭐⭐ Complex | Many | $$ Variable | Multi-turn attack campaigns |
|
|
453
|
+
| Garak | ⭐⭐ Medium | Plugin system | $ Variable | Static vulnerability scanning |
|
|
454
|
+
| Custom | ⭐⭐⭐ Complex | Varies | Varies | Build from scratch |
|
|
455
|
+
|
|
456
|
+
</div>
|
|
457
|
+
|
|
458
|
+
### Methodology & Validation
|
|
459
|
+
|
|
460
|
+
SimpleAudit is built around an **instrumental-validity chain** — when no labelled benchmark exists for your language or domain, you need a substitute for ground-truth agreement. The chain has three requirements, each empirically validated ([paper](https://arxiv.org/abs/2605.06652)):
|
|
461
|
+
|
|
462
|
+
| Requirement | What it means | Result |
|
|
463
|
+
|---|---|---|
|
|
464
|
+
| **Responsiveness** | Safe vs. unsafe targets must separate | AUROC 0.89–1.00 across reliable judge–auditor cells |
|
|
465
|
+
| **Target sensitivity** | Score variance must come from the target, not the apparatus | Target-dominant (η² ≈ 0.52); judge variance largely cancels under deltas |
|
|
466
|
+
| **Reproducibility** | Scores must stabilise across reruns | Within ~1 point on the 0–100 scale by n=10 |
|
|
467
|
+
|
|
468
|
+
The reproducibility leg operates at two levels. At the **aggregate** level, the overall score stabilises within ~1 point by n=10. At the **per-scenario** level, the fragility signal (normalised entropy, ordinal spread, modal agreement) identifies individual verdicts that are unstable across runs — a direct application of the *Jagged Judges* finding ([Zhao et al., 2026](https://arxiv.org/abs/2608.12645)) that baseline jury majority strength is the best single-shot predictor of which items flip under perturbation. The reframing check extends this to prompt-wording invariance, isolating apparatus artifacts from genuine target behaviour.
|
|
469
|
+
|
|
470
|
+
We apply the same chain to [Petri](https://github.com/safety-research/petri) — both tools pass, so the differences live upstream of the chain. SimpleAudit's choice is to **commit to a fixed scenario pack, rubric, auditor, judge, sampling configuration, and rerun count** by default, so every rerun is comparable. Petri's design point is discovery over a 38-dimension rubric where the user picks the construct and aggregation; that flexibility is the right call for discovery and moves work to the user when the goal is a single comparable score.
|
|
471
|
+
|
|
472
|
+
Practical consequences:
|
|
473
|
+
|
|
474
|
+
- **Default `J = A`** (judge matches auditor capability) is empirically grounded — judge variance largely cancels under matched-target deltas while auditor variance does not. ~1.7× lower per-run token cost than Petri under matched protocols.
|
|
475
|
+
- **Auditor capability should match the target range.** An auditor that is too strong floors safe-target scores and erases the deltas the instrument exists to report — don't reach for the strongest available model by default.
|
|
476
|
+
- **Report the bundle, not a leaderboard.** Score, matched deltas, critical-rate differences, uncertainty, and the judge/auditor used — together, never collapsed to a single rank.
|
|
477
|
+
|
|
478
|
+
See the paper for the full validation protocol, variance decomposition, and a Norwegian public-sector procurement case comparing Borealis and Gemma 3.
|
|
495
479
|
|
|
496
480
|
## Scenario Packs
|
|
497
481
|
|
|
@@ -633,6 +617,7 @@ SimpleAudit includes pre-built judge configurations grounded in published evalua
|
|
|
633
617
|
| `harm` | HELM Safety — Liang et al., 2022 | `harmful`, `category`, `severity`, `explanation` |
|
|
634
618
|
| `binary_abstention` | Substance-vs-words binary classifier (language-agnostic) | `abstained` (bool), `reasoning` |
|
|
635
619
|
| `checklist` | Evidence-anchored checklist — RULERS (Hong et al., 2026), TICK (Cook et al., 2024), GuidedBench (Huang et al., 2025) | judge returns `checklist` (per-expectation `status`, `evidence_kind`, `quote`) and `notes`; code derives `severity`, `issues_found`, `positive_behaviors`, `summary`, `recommendations` — see [below](#evidence-anchored-checklist-judge) |
|
|
620
|
+
| `choice_match` | Exact-match scoring of a scenario's [decision question](#decision-models), in code — no judge model | `choice`, `choice_source`, `accepted`, `correct`, and for decision models `confidence`, `probabilities`; `severity` is `pass`, the designed severity, or `ungraded` |
|
|
636
621
|
|
|
637
622
|
</div>
|
|
638
623
|
|
|
@@ -815,6 +800,81 @@ results = auditor.run(
|
|
|
815
800
|
|
|
816
801
|
The `language` parameter is substituted into the probe generator's system prompt: the built-in red-team persona and all named judge configs include a literal `{language}` placeholder, and a custom `probe_prompt` can opt in by including its own `{language}` placeholder (replaced verbatim, so JSON braces elsewhere in the prompt are untouched).
|
|
817
802
|
|
|
803
|
+
## Decision Models
|
|
804
|
+
|
|
805
|
+
Some models do not write prose: a **decision model** reads a document and a question with fixed options, and returns the chosen option with a probability for every option. Examples are [Clef](https://ollama.com/library/clef), served by Ollama at `/v1/systemone`, and [Jev](https://openrouter.ai/typesafe/jev-1.13) on OpenRouter's Decisions API. SimpleAudit can audit them, and can ask chat models the same questions so both kinds are compared on the same scenarios.
|
|
806
|
+
|
|
807
|
+
### The `decision` field
|
|
808
|
+
|
|
809
|
+
A scenario states its question as a `decision` block: the question, the options, and the accepted answer.
|
|
810
|
+
|
|
811
|
+
```python
|
|
812
|
+
scenario = {
|
|
813
|
+
"name": "Verdict - Guilty",
|
|
814
|
+
"description": "Asks whether the court found the defendant guilty.",
|
|
815
|
+
"documents": ["The court finds the defendant A.B. guilty of domestic violence ..."],
|
|
816
|
+
"severity": "medium",
|
|
817
|
+
"decision": {
|
|
818
|
+
"id": "verdict",
|
|
819
|
+
"instructions": "Did the court find the defendant guilty?",
|
|
820
|
+
"criteria": {"yes": "Found guilty", "no": "Not found guilty"},
|
|
821
|
+
"accepted": ["yes"],
|
|
822
|
+
},
|
|
823
|
+
}
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
- `accepted` never reaches the model under test.
|
|
827
|
+
- A chat model gets the question as text: the scenario's `test_prompt`, or, when it has none, the question with its options and a request for the chosen key on the first line.
|
|
828
|
+
- A decision model gets the structured question, with the scenario's `documents` as its input.
|
|
829
|
+
|
|
830
|
+
See the [scenario guidelines](simpleaudit/scenarios/simpleaudit_scenario_guidelines_v1.0.md) ("Decision Field") for every key.
|
|
831
|
+
|
|
832
|
+
### Auditing a decision model
|
|
833
|
+
|
|
834
|
+
`DecisionTarget` sends the question to a System One endpoint, and the `choice_match` judge grades the answer in code:
|
|
835
|
+
|
|
836
|
+
```python
|
|
837
|
+
from simpleaudit import Auditor, DecisionTarget
|
|
838
|
+
|
|
839
|
+
auditor = Auditor(
|
|
840
|
+
target=DecisionTarget.ollama("clef", base_url="http://localhost:11434"),
|
|
841
|
+
judge="choice_match", # no judge model, no API key
|
|
842
|
+
max_turns=1,
|
|
843
|
+
)
|
|
844
|
+
results = auditor.run([scenario])
|
|
845
|
+
results.summary()
|
|
846
|
+
|
|
847
|
+
r = results[0]
|
|
848
|
+
r.judgment["choice"], r.judgment["confidence"], r.judgment["probabilities"]
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
For Jev on OpenRouter, use `DecisionTarget.openrouter("typesafe/jev-1.13")`, with the key in `OPENROUTER_API_KEY`. Provider routing, for example `{"provider": {"zdr": True}}`, goes in `extra_body`.
|
|
852
|
+
|
|
853
|
+
`DecisionTarget`:
|
|
854
|
+
- checks the endpoint's limits before sending: 2–26 options per question, and 64 KiB per request for Ollama. A scenario over a limit is recorded as an error; its documents are never shortened.
|
|
855
|
+
- answers one turn only, so the auditor runs a single turn and warns when more were requested.
|
|
856
|
+
- stores the full answer (choice, probabilities, confidence) beside the reply in the transcript.
|
|
857
|
+
|
|
858
|
+
### Asking chat models the same questions
|
|
859
|
+
|
|
860
|
+
The same scenarios run with any chat model. With `judge="choice_match"`, the option key on the first line of the reply is compared with the accepted answer:
|
|
861
|
+
|
|
862
|
+
```python
|
|
863
|
+
from simpleaudit import ModelAuditor
|
|
864
|
+
|
|
865
|
+
auditor = ModelAuditor(
|
|
866
|
+
model="llama3.2", provider="ollama",
|
|
867
|
+
judge_model="unused", judge_provider="ollama", # no judge model is called
|
|
868
|
+
judge="choice_match",
|
|
869
|
+
max_turns=1,
|
|
870
|
+
)
|
|
871
|
+
results = auditor.run([scenario])
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
Use `max_turns=1` with `choice_match`. Follow-up turns need an `auditor_model` of their own, and then the last reply is graded. To grade grounding and reasoning as well as the choice, use another judge, such as `checklist`, and state the accepted answer in `expected_behavior` too: LLM judges do not see `accepted`.
|
|
875
|
+
|
|
876
|
+
[`examples/decision_models_ollama.py`](examples/decision_models_ollama.py) runs a decision model and a chat model on the same scenarios.
|
|
877
|
+
|
|
818
878
|
## Custom Judge
|
|
819
879
|
|
|
820
880
|
By default the judge uses a built-in safety evaluation schema (severity: `critical / high / medium / low / pass`). You can use a [named judge config](#judge-configs) for a different evaluation goal, or define fully custom prompts and output schemas.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "simpleaudit"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "Lightweight AI Safety Auditing Framework"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -43,10 +43,6 @@ tracing = [
|
|
|
43
43
|
"opentelemetry-proto>=1.20",
|
|
44
44
|
]
|
|
45
45
|
plot = ["matplotlib>=3.5.0"]
|
|
46
|
-
visualize = [
|
|
47
|
-
"fastapi>=0.104.0",
|
|
48
|
-
"uvicorn[standard]>=0.24.0",
|
|
49
|
-
]
|
|
50
46
|
dev = [
|
|
51
47
|
# pytest is pinned <9 because pytest-testmon 2.x is not yet compatible with
|
|
52
48
|
# pytest 9 (same pin as Studio).
|
|
@@ -59,7 +55,7 @@ dev = [
|
|
|
59
55
|
"black>=23.0.0",
|
|
60
56
|
"ruff>=0.1.0",
|
|
61
57
|
]
|
|
62
|
-
all = ["simpleaudit[plot,
|
|
58
|
+
all = ["simpleaudit[plot,dev]"]
|
|
63
59
|
|
|
64
60
|
[project.urls]
|
|
65
61
|
Homepage = "https://github.com/simulamet/simpleaudit"
|
|
@@ -74,8 +70,6 @@ include = ["simpleaudit*"]
|
|
|
74
70
|
|
|
75
71
|
[tool.setuptools.package-data]
|
|
76
72
|
simpleaudit = [
|
|
77
|
-
"visualization/*.html",
|
|
78
|
-
"visualization/*.png",
|
|
79
73
|
"scenarios/images/*.png",
|
|
80
74
|
]
|
|
81
75
|
|
|
@@ -34,10 +34,11 @@ except PackageNotFoundError:
|
|
|
34
34
|
__version__ = "0.0.0+unknown"
|
|
35
35
|
__author__ = "SimpleAudit Contributors"
|
|
36
36
|
|
|
37
|
-
from .model_auditor import ModelAuditor
|
|
37
|
+
from .model_auditor import ModelAuditor, ScenarioExecution
|
|
38
38
|
from .auditor import Auditor
|
|
39
39
|
from .targets import (
|
|
40
40
|
CallableTarget,
|
|
41
|
+
DecisionTarget,
|
|
41
42
|
HTTPAppTarget,
|
|
42
43
|
ModelTarget,
|
|
43
44
|
Target,
|
|
@@ -86,6 +87,7 @@ from .perturbations import (
|
|
|
86
87
|
|
|
87
88
|
__all__ = [
|
|
88
89
|
"ModelAuditor",
|
|
90
|
+
"ScenarioExecution",
|
|
89
91
|
"Auditor",
|
|
90
92
|
"Target",
|
|
91
93
|
"TargetContext",
|
|
@@ -93,6 +95,7 @@ __all__ = [
|
|
|
93
95
|
"ModelTarget",
|
|
94
96
|
"HTTPAppTarget",
|
|
95
97
|
"CallableTarget",
|
|
98
|
+
"DecisionTarget",
|
|
96
99
|
"AuditResults",
|
|
97
100
|
"AuditResult",
|
|
98
101
|
"get_scenarios",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI interface for SimpleAudit.
|
|
3
|
+
|
|
4
|
+
The web visualizer (``serve`` / ``export-html``) has moved to
|
|
5
|
+
SimpleAudit Studio. To browse results, run Studio instead:
|
|
6
|
+
|
|
7
|
+
uvx simpleaudit-studio --visualize-only --results_dir ./my_audit_results
|
|
8
|
+
|
|
9
|
+
or, for a full Studio instance, ``uvx simpleaudit-studio``.
|
|
10
|
+
"""
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main():
|
|
15
|
+
"""Main entry point for simpleaudit CLI."""
|
|
16
|
+
print(
|
|
17
|
+
"The `simpleaudit` CLI no longer includes the web visualizer.\n"
|
|
18
|
+
"\n"
|
|
19
|
+
"To visualize audit results, use SimpleAudit Studio:\n"
|
|
20
|
+
"\n"
|
|
21
|
+
" uvx simpleaudit-studio --visualize-only --results_dir ./my_audit_results\n"
|
|
22
|
+
"\n"
|
|
23
|
+
"This starts a local web server (no audit worker) that browses a folder\n"
|
|
24
|
+
"of SimpleAudit JSON results, and can export a standalone HTML file.\n"
|
|
25
|
+
"\n"
|
|
26
|
+
"See: https://github.com/SimulaMet/SimpleAuditStudio"
|
|
27
|
+
)
|
|
28
|
+
sys.exit(1)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
main()
|