Files
2026-07-13 13:30:30 +08:00

171 lines
5.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# gemini-hallcheck
Confidence-targeted, abstention-aware hallucination evaluator for Gemini via `google-genai`.
- Implements the Kalai et al. idea in practice: **"Answer only if you're > t confident; otherwise say `IDK`."**
- Scores with an abstention-aware loss: **correct = +1, wrong = t/(1t), IDK = 0**.
- Produces a **riskcoverage curve** (conditional accuracy vs. coverage) with **labeled t-points**.
- Works from **CSV** or directly from **MMLU** (Hugging Face), with **random sampling** and an **`--idk-frac`** mixer to create **IDK-only** items (tests true abstention).
- **LLM semantic judge** (Gemini 2.5 Flash-Lite) or **exact** judge.
- **Async** with progress bar, **quota-aware retries** (honors server `RetryInfo`) and optional **client-side RPM throttle**.
- Runs on **Gemini API** or **Vertex AI** (env-based switch).
> ️ We do **not** implement MMLU-Pro here.
---
## Install
```bash
python -m venv .venv && source .venv/bin/activate
pip install -e .
```
### Auth options
**Gemini API (Developer API):**
```bash
export GOOGLE_API_KEY=YOUR_KEY # or GEMINI_API_KEY
```
**Vertex AI:**
```bash
export GOOGLE_GENAI_USE_VERTEXAI=true
export GOOGLE_CLOUD_PROJECT=your-gcp-project
export GOOGLE_CLOUD_LOCATION=us-central1 # or europe-west1, etc.
# Do NOT set GOOGLE_API_KEY when using Vertex AI mode.
```
---
## Quickstart
### CSV mode
```bash
gemhall run --data examples/toy.csv --thresholds 0.5 0.75 0.9 --model gemini-2.5-flash-lite --progress --out outputs
```
### MMLU (direct from HF Datasets)
```bash
gemhall mmlu --thresholds 0.5 0.75 0.9 --model gemini-2.5-flash-lite --split test --subjects all --limit 200 --judge llm --async --concurrency 16 --progress --out outputs/mmlu
```
**Mix in "IDK-only" items** (turns a fraction of sampled items into unanswerables so the only correct behavior is `IDK`):
```bash
--idk-frac 0.3
```
---
## What you get
- `results.csv` one row per (item × t): prediction, abstained flag, correctness, score
- `metrics.json` coverage, conditional accuracy (on answers), hallucination rate among answers, avg expected score
- `behavior.json` simple behavior checks (e.g., monotonic coverage as t increases)
- `rc_curve.png` **riskcoverage curve** with **"t=…"** labels on each point
- `report.md` short summary plus the chart embedded
---
## Interpreting the curve
- **Coverage** (x-axis): fraction of items the model answered (didn't say `IDK`).
- **Conditional accuracy** (y-axis): how often it was correct **when it did answer**.
- As **t** rises ⇒ coverage falls, conditional accuracy should rise.
- If **accuracy at t** is **well below t**, the model is **over-confident or non-compliant** → raise t, harden prompts, add retrieval/handoffs, or re-calibrate.
---
## CLI reference
Shared flags (both `run` and `mmlu`):
```sh
--thresholds FLOAT... Confidence thresholds (e.g., 0.5 0.75 0.9) [required]
--model TEXT Gemini model id (default: gemini-2.5-flash)
--temperature FLOAT Sampling temperature (default: 0.0)
--thinking-budget INT Optional thinking budget (default: 0)
--seed INT RNG seed for sampling (default: 1234)
--judge {exact,llm} Validity judge (exact or LLM; default: exact)
--async Use async client for parallel requests
--concurrency INT Max concurrent requests in async mode (default: 8)
--progress Show a progress bar
--out PATH Output directory (default: outputs)
--rpm-limit INT Client-side requests-per-minute cap (optional)
--max-retries INT Max retries on 429 with backoff (default: 6)
```
`run` (CSV):
```sh
--data PATH CSV with columns: id, question, gold, unknown_ok
```
`mmlu` (Hugging Face "cais/mmlu"):
```sh
--split TEXT Split (e.g., test, dev) [default: test]
--subjects STR... Subject names or 'all' [default: all]
--limit INT Randomly sample N items after filtering subjects
--idk-frac FLOAT Fraction [0..1] to convert to IDK-only items (default: 0.0)
```
**MMLU loader notes:**
We first try the unified `"all"` config and fall back to stitching per-subject configs if needed. No `trust_remote_code` required. We also ensure a `subject` column exists.
---
## Judges
- **exact** strict match for MCQ (letters A/B/C/D), or numerical/text equality for free-form.
- **llm** Gemini 2.5 Flash-Lite "YES/NO" grader; for `unknown_ok=1`, only `IDK` is considered correct (no LLM call).
---
## IDK detection & scoring
- We normalize model outputs; `IDK` is recognized case-insensitively with common variants.
- Score per item at threshold **t**:
- answered & correct: **+1**
- answered & wrong: **t/(1t)**
- abstained (`IDK`): **0**
---
## Rate limits & retries
- If you omit `--rpm-limit`, we still **auto-retry** on `429 RESOURCE_EXHAUSTED`, honoring server **`RetryInfo`** with jittered exponential backoff.
- Set `--rpm-limit` to smooth out bursts and avoid 429s when running with high `--concurrency`.
- Typical stable settings: `--async --concurrency 12 --rpm-limit 180 --max-retries 8`.
---
## Business mapping
- **t≈0.5: Drafting & triage** high coverage, human-in-the-loop
- **t≈0.75: Assistive answers** support suggestions, FAQ with citations
- **t≈0.9: Self-serve replies** public answers in non-regulated flows
- **t≈0.95: High-stakes** regulated/brand-critical, else handoff
---
## Troubleshooting
- **MMLU config error**: we now request `"all"` and fall back per-subject; ensure `datasets>=2.18.0`.
- **Curly-brace crash in prompts**: fixed by using f-strings (brace-safe).
- **429 quota**: use `--rpm-limit`, and/or lower `--concurrency`.
- **Vertex AI vs API key**: set `GOOGLE_GENAI_USE_VERTEXAI=true` (+ project/location) to use Vertex AI; don't set an API key at the same time.
---
## Citation
This project is based on the following paper.
[arXiv:2509.04664](https://arxiv.org/abs/2509.04664)