demoparity
Counterfactual demographic auditing for LLM prompts. Swap protected attributes (sex, race, residency, or anything you define) into an otherwise identical prompt, send every variant to the same model, and test statistically whether the response changes with the attribute.
This work is a generalised, reusable version of the paired-prompt audit design from my Bachelor Thesis "Breaking the Bias: Addressing the Social Biases in Artificial Natural Language Models for Neuroscientific and Medical Implementation" (Steward, 2023; presented at the 3rd Connected Learning Symposium (2024), and the Black Scholar and Expert Conference (2023)). My original thesis built a "NeuroAnalyser" tool around a ChatGPT-3.5 use case.
demoparity keeps the same statistical design (descriptive stats, an enter-method OLS regression, Pearson's correlations with Fisher's z) but detaches it from one use case, so it works for multiple uses.
Motivation
Common design for LLM bias checks look at some example outputs or run a static benchmark dataset once. This design also wants to assess why a model's behaviour may differ, or whether different responses show a pattern that is distinguishable from noise.
Install
```bash
pip install demoparity
pip install demoparity[litellm] # call a model
How it works
build_designcrosses every scenario with every attribute-level combination.run_designsends each prompt through a model, concurrently, via litellm (OpenAI, Anthropic, Gemini, Bedrock, Ollama, 100+ providers, one model-string convention). Each provider's key comes from its standard environment variable (OPENAI_API_KEY,ANTHROPIC_API_KEY, ...).annotateextracts response length and attribute-mention counts.run_auditruns descriptive stats, an enter-method OLS regression, and Pearson correlations, and returns a report you can save to Markdown/CSV.
import demoparity as dp
design = dp.build_design(
[dp.Scenario("c1", "A {sex} patient reports a headache. Advise.")],
[dp.Attribute("sex", ["neutral", "male", "female"])],
)
results = dp.run_design(design, dp.litellm_generator(model="gpt-4o-mini"))
results = dp.annotate(results)
report = dp.run_audit(results, outcomes=["word_count"], predictors=["sex"])
print(report.to_markdown())
See examples/ for full worked audits with mention-tracking, checkpointing, and saved output.
Examples
Require a real API key (see Install above)
examples/hiring_screen_audit.pyis a resume screener, sex/name-origin/locationexamples/clinical_triage_audit.pymirrors clinical triage, sex/race/residency (my thesis study)
export OPENAI_API_KEY=sk-..
python examples/hiring_screen_audit.py --model gpt-4o-mini
Concurrency and checkpointing
run_design sends requests concurrently (concurrency=, default 5) and, with checkpoint_path=, writes each completed trial to a JSONL file as it finishes. Re-running with the same checkpoint path resumes and skips already-completed trials.
Saving output
from demoparity.persistence import save_results, save_report
save_results(results, "results.csv")
save_report(report, "report_dir") # report.md + descriptives.csv + correlations.csv + one CSV per regression
Command line
demoparity design spec.json --out design.csv
demoparity run design.csv --model gpt-4o-mini --checkpoint run.jsonl --out results.csv
demoparity report results.csv --outcomes word_count --predictors sex --save-dir report_dir
License
MIT. See LICENSE.
Metadata
Release files for demoparity 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| demoparity-0.2.0.tar.gz | 19.7 kB | Without provenance | Details for demoparity-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| demoparity-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for demoparity-0.2.0-py3-none-any.whl |
Total release size: 36.0 kB
Release files / demoparity-0.2.0.tar.gz
| Download URL | demoparity-0.2.0.tar.gz |
|---|---|
| Size | 19.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c16bd4b1460bf6ad2a4a6f45527cdb7c5555c2e224b91a085c38444e464dc0b6
|
|
BLAKE2b-256 checksum How to use checksums |
c1e5470c1f9c40aa29d44a67fce60b3b867832d3494b236d1bab16c74e59a5f3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.9
|
Release files / demoparity-0.2.0-py3-none-any.whl
| Download URL | demoparity-0.2.0-py3-none-any.whl |
|---|---|
| Size | 16.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1e7a91d5c8f83287f879de3ad60a670353986429e568cc34f6979b564038a661
|
|
BLAKE2b-256 checksum How to use checksums |
0f15da9b91b24162bc96a1bf812a802e9096dbd152f2c7a6d60e6e1140c5a395
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.9
|
Security for demoparity 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.