flakeval 0.1.0__tar.gz → 0.1.2__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.
Files changed (30) hide show
  1. flakeval-0.1.2/PKG-INFO +249 -0
  2. flakeval-0.1.2/README.md +223 -0
  3. {flakeval-0.1.0 → flakeval-0.1.2}/pyproject.toml +15 -2
  4. flakeval-0.1.2/src/flakeval/__init__.py +20 -0
  5. flakeval-0.1.2/src/flakeval.egg-info/PKG-INFO +249 -0
  6. flakeval-0.1.0/PKG-INFO +0 -559
  7. flakeval-0.1.0/README.md +0 -542
  8. flakeval-0.1.0/src/flakeval/__init__.py +0 -5
  9. flakeval-0.1.0/src/flakeval.egg-info/PKG-INFO +0 -559
  10. {flakeval-0.1.0 → flakeval-0.1.2}/LICENSE +0 -0
  11. {flakeval-0.1.0 → flakeval-0.1.2}/setup.cfg +0 -0
  12. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval/cli.py +0 -0
  13. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval/io.py +0 -0
  14. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval/models.py +0 -0
  15. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval/progress.py +0 -0
  16. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval/scoring.py +0 -0
  17. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval/stats.py +0 -0
  18. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval/study.py +0 -0
  19. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval/templates/my_eval.py +0 -0
  20. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval/templates/sample_data.csv +0 -0
  21. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval.egg-info/SOURCES.txt +0 -0
  22. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval.egg-info/dependency_links.txt +0 -0
  23. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval.egg-info/entry_points.txt +0 -0
  24. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval.egg-info/requires.txt +0 -0
  25. {flakeval-0.1.0 → flakeval-0.1.2}/src/flakeval.egg-info/top_level.txt +0 -0
  26. {flakeval-0.1.0 → flakeval-0.1.2}/tests/test_flakeval.py +0 -0
  27. {flakeval-0.1.0 → flakeval-0.1.2}/tests/test_init_and_template.py +0 -0
  28. {flakeval-0.1.0 → flakeval-0.1.2}/tests/test_noise_diagnostics.py +0 -0
  29. {flakeval-0.1.0 → flakeval-0.1.2}/tests/test_study.py +0 -0
  30. {flakeval-0.1.0 → flakeval-0.1.2}/tests/test_template_case_studies.py +0 -0
@@ -0,0 +1,249 @@
1
+ Metadata-Version: 2.4
2
+ Name: flakeval
3
+ Version: 0.1.2
4
+ Summary: Is your LLM eval improvement real, or just noise? Repeat evals, measure variance, get a verdict.
5
+ Author: Anchit Gupta
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://anchitgupta22.github.io/flakeval/
8
+ Project-URL: Repository, https://github.com/AnchitGupta22/flakeval
9
+ Project-URL: Issues, https://github.com/AnchitGupta22/flakeval/issues
10
+ Keywords: llm,evaluation,statistics,machine-learning
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Operating System :: OS Independent
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: numpy>=1.22
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest; extra == "dev"
23
+ Provides-Extra: examples
24
+ Requires-Dist: datasets>=2.19; extra == "examples"
25
+ Dynamic: license-file
26
+
27
+ <p align="center">
28
+ <img src="assets/flakeval_logo.png" alt="Logo" width="240" />
29
+ <br/>
30
+ <br/>
31
+ <a href="LICENSE"><img alt="MIT License" src="https://img.shields.io/badge/License-MIT-yellow.svg" /></a>
32
+ <a href="https://pypi.org/project/flakeval/"><img alt="PyPI Version" src="https://img.shields.io/pypi/v/flakeval" /></a>
33
+ <a href="https://pypi.org/project/flakeval/"><img alt="Python Versions" src="https://img.shields.io/pypi/pyversions/flakeval" /></a>
34
+ <a href="https://github.com/AnchitGupta22/flakeval/actions"><img alt="Tests"
35
+ src="https://github.com/AnchitGupta22/flakeval/actions/workflows/tests.yml/badge.svg"/></a>
36
+ <a href="https://anchitgupta22.github.io/flakeval/"><img alt="Documentation" src="https://img.shields.io/badge/Documentation-Read%20the%20docs-red" /></a>
37
+ </p>
38
+
39
+ ---
40
+
41
+ **Is your AI improvement real, or just luck?**
42
+
43
+ *(Say it "flake-eval": flaky + evaluation.)*
44
+
45
+ You change a prompt, a model or a setting, and your test score goes from 72% to 74%. Did it really get better, or would you get 74% just by running the same test again? `flakeval` answers that with a plain verdict.
46
+
47
+ - Works on results you already have (a simple JSONL file), or runs your evaluation for you.
48
+ - Gives a verdict, a range for the true difference, and the **smallest difference your test can reliably detect**.
49
+ - Tells you whether you need **more runs** or **more test questions**.
50
+ - Exits with an error on a real regression, so it works as a CI check.
51
+ - One dependency (numpy). Runs on a laptop.
52
+
53
+ **Full documentation, case studies and FAQ: https://anchitgupta22.github.io/flakeval/**
54
+
55
+ ---
56
+
57
+ ## Contents
58
+
59
+ 1. [The idea in plain English](#the-idea-in-plain-english)
60
+ 2. [Quick start](#quick-start)
61
+ 3. [Case studies (summary)](#case-studies-summary)
62
+ 4. [FAQ](#faq)
63
+ 5. [How it works](#how-it-works)
64
+ 6. [Limitations](#limitations)
65
+ 7. [Repository layout](#repository-layout)
66
+ 8. [Roadmap](#roadmap)
67
+
68
+ ---
69
+
70
+ ## The idea in plain English
71
+
72
+ Language models answer with some randomness, and your test only has a limited number of questions. Together this wobble is called **noise**. A 2-point change in score could be a real improvement or just noise. `flakeval` measures the noise so you know which.
73
+
74
+ | Verdict | Meaning | What to do |
75
+ |---|---|---|
76
+ | **REAL IMPROVEMENT** | B scored higher; chance is an unlikely explanation. | Trust it. |
77
+ | **REAL REGRESSION** | B scored lower; chance is an unlikely explanation. | Investigate before shipping B. |
78
+ | **WITHIN NOISE** | The test cannot tell (this does **not** mean "equal"). | Add more **runs** or more **questions**, as the advice line says. |
79
+ | **IDENTICAL RESULTS** | A and B scored the same on every item. | Check your change actually reached the model. |
80
+
81
+ Example (simulated: B is truly ~2 points better, 200 items, 5 runs each):
82
+
83
+ ```
84
+ $ flakeval compare a.jsonl b.jsonl
85
+ A: 0.6800 (5 runs) B: 0.6860 (5 runs) items: 200
86
+ delta (B - A): +0.0060 95% CI: [-0.0310, +0.0430] p = 0.7955
87
+ smallest reliably detectable difference: ~0.0535
88
+ VERDICT: WITHIN NOISE
89
+ ```
90
+
91
+ The true difference could be anywhere from 3.1 points worse to 4.3 points better, and this test can only reliably spot gaps of about 5 points, so a 2-point improvement is invisible to it.
92
+
93
+ ---
94
+
95
+ ## Quick start
96
+
97
+ Requires Python 3.10+.
98
+
99
+ ```bash
100
+ pip install flakeval
101
+ ```
102
+
103
+ ### Option A: you already have scores
104
+
105
+ Write one JSON line per item per run (use at least 3 runs per item, and the same ids in both files):
106
+
107
+ ```json
108
+ {"item_id": "q17", "run": 2, "score": 1.0}
109
+ ```
110
+
111
+ ```bash
112
+ flakeval report a.jsonl # how noisy is one system?
113
+ flakeval compare a.jsonl b.jsonl # is B really different from A?
114
+ flakeval compare a.jsonl b.jsonl --json # machine-readable
115
+ ```
116
+
117
+ `flakeval compare` exits with code 1 only on a statistically real regression, so it works as a **CI gate**.
118
+
119
+ From Python:
120
+
121
+ ```python
122
+ from flakeval import repeat, compare
123
+
124
+ a = repeat(eval_model_a, items, runs=5, workers=8, save="a.jsonl")
125
+ b = repeat(eval_model_b, items, runs=5, workers=8, save="b.jsonl")
126
+ print(compare(a, b))
127
+ ```
128
+
129
+ If your function uses a sampling seed, make it **different for every run** (`repeat(..., with_run=True)` passes the run number). A fixed seed hides the noise this tool measures.
130
+
131
+ ### Option B: let flakeval run your models
132
+
133
+ ```bash
134
+ flakeval init # creates my_eval.py (settings) and sample_data.csv
135
+ python my_eval.py --dry-run # 2 questions per system, prints answers and scores; saves nothing
136
+ python my_eval.py # the real run (shows the number of calls and asks first)
137
+ ```
138
+
139
+ Put your questions in a CSV or JSONL (`id, input text, expected answer`), then edit the settings at the top of `my_eval.py`. Example: does a new prompt beat the current one on the same model? The first system is the baseline.
140
+
141
+ ```python
142
+ DATA_PATH = "tickets.csv"
143
+ INPUT_COLUMN = "ticket"
144
+ EXPECTED_COLUMN = "label"
145
+ ID_COLUMN = "id"
146
+ SCORER = "exact"
147
+
148
+ SYSTEMS = [
149
+ {"name": "current_prompt", "model": "qwen2.5:3b", "base_url": "http://localhost:11434/v1",
150
+ "api_key_env": None, "temperature": 0.7, "system_prompt": "",
151
+ "prompt_template": "Classify this ticket as billing, bug or question.\n\nTicket: {input}"},
152
+ {"name": "new_prompt", "model": "qwen2.5:3b", "base_url": "http://localhost:11434/v1",
153
+ "api_key_env": None, "temperature": 0.7, "system_prompt": "",
154
+ "prompt_template": "Reply with exactly one label: billing, bug or question.\n\nTicket: {input}"},
155
+ ]
156
+
157
+ RUNS = 5 # 3 to 5 is a good range
158
+ MAX_TOKENS = 20
159
+ ```
160
+
161
+ - **Models:** anything with an OpenAI-compatible endpoint (Ollama, LM Studio, vLLM, hosted APIs). Put the *name* of the environment variable holding your key in `api_key_env`, never the key itself. For anything else, pass your own function as `"call": my_function`.
162
+ - **Built-in scorers:** `exact`, `contains`, `number`, `choice_letter`, `answer_line`, `final_number`, or `"custom"` (your own `custom_score(output, expected, row)` returning 0 to 1).
163
+ - **Overrides:** `--max-items 10`, `--runs 2`, `--workers 4`, `--out-dir DIR`, `--scorer NAME`. Try `--max-items 10 --runs 2 --out-dir trial` for a cheap rehearsal.
164
+ - **Output:** a printed report plus `my_results/` with scores, raw answers (`<system>.outputs.jsonl`) and `report.txt`. The baseline is run twice (A/A check) by default, showing how much two identical runs differ by chance.
165
+ - **Safe to rerun:** finished systems are skipped, and a server failure stops the run instead of recording fake zeros.
166
+ - **Fixed your scorer?** `python my_eval.py --rescore` re-marks saved answers without calling any model.
167
+ - **Pure Python, no settings file:** use `default_config()` and `run_study(cfg)` from `flakeval.study`.
168
+
169
+ **Read some raw answers that scored 0 before trusting the numbers.** A scorer that wrongly marks good answers down looks exactly like model noise.
170
+
171
+ **Privacy:** nothing is uploaded. Rows go only to the endpoints you list. If your data is confidential, add `my_results/` to `.gitignore`.
172
+
173
+ ### Option C: clone the repo (tests, demo, case studies)
174
+
175
+ ```bash
176
+ git clone https://github.com/AnchitGupta22/flakeval && cd flakeval
177
+ pip install -e ".[dev,examples]"
178
+ python -m pytest
179
+ cd examples && python make_demo.py && flakeval compare a.jsonl b.jsonl
180
+ ```
181
+
182
+ If `flakeval` is not found, use `python -m flakeval.cli compare a.jsonl b.jsonl`.
183
+
184
+ ---
185
+
186
+ ## Case studies (summary)
187
+
188
+ Two worked examples live in `examples/template_case_studies/` (`arc_eval.py`, `gsm8k_eval.py`), run on `qwen2.5:3b` and `llama3.2:3b` with Ollama. Full tables, methodology and diagnostics are in the [documentation](https://anchitgupta22.github.io/flakeval/).
189
+
190
+ - **ARC (science multiple choice, 200 items x 5 runs):** the same model twice scored 82.6% and 82.9% (within noise). `llama3.2:3b` scored 11.7 points lower than `qwen2.5:3b` (p < 0.001), flagged as real.
191
+ - **GSM8K (math reasoning, 200 items x 3 runs):** under strict scoring, the same system twice differed by 4.8 points (p = 0.024). Five extra repeats ranged from 69.7% to 74.5%, so this was chance. A "double-check" prompt result of -4.7 points fell inside that natural spread, so no conclusion could be drawn.
192
+
193
+ Takeaways:
194
+
195
+ 1. Always include the "same system twice" check; it shows how big a gap chance alone can produce.
196
+ 2. Reasoning tasks are far noisier than single-letter answers (32.5% of GSM8K items changed score across 3 runs vs 0.5% on ARC).
197
+ 3. Check the "smallest detectable difference" **before** you start. If it is bigger than the improvement you hope for, your test is too small.
198
+ 4. Treat borderline p-values (about 0.01 to 0.05) with caution, and always report how you scored the answers.
199
+
200
+ ---
201
+
202
+ ## FAQ
203
+
204
+ **Isn't it all just chance?** Yes, partly, and `flakeval` cannot remove that. It **measures how much chance is in your result**, like a margin of error in a poll, and tells you whether more runs or more questions would shrink it. Halving the smallest detectable difference takes about four times the data.
205
+
206
+ **Why not just set temperature to 0?** That removes most model randomness but not the sampling of your questions, and real users do not run at temperature 0.
207
+
208
+ **How many questions and runs do I need?** Look at the "smallest detectable difference" in the report. A reasonable start is 100 or more questions and 3 to 5 runs.
209
+
210
+ ---
211
+
212
+ ## How it works
213
+
214
+ Scores form an items x runs matrix, and comparisons are paired by item id. The 95% interval comes from a bootstrap that resamples **items** (run noise is already inside each item's mean). The p-value comes from a paired sign-flip permutation test. A verdict of "real" requires the interval to exclude zero **and** p < 0.05. The smallest detectable difference is about 2.8 x the standard error (80% power, alpha 0.05).
215
+
216
+ In simulation (60 items, 5 runs), two identical systems were called "different" 5.3% of the time (target 5%), and a true 10-point gap was detected 71% of the time.
217
+
218
+ **Pitfall guarded against:** many servers use a fixed default seed (Ollama's is 0), so "repeated" runs are identical and show zero noise. The template sends a different seed per question and run, and `flakeval` warns when no item changes score across runs.
219
+
220
+ ## Limitations
221
+
222
+ - Assumes your items are a random sample of the questions you care about.
223
+ - Compares two systems at a time; no multiple-comparison correction yet.
224
+ - Scores are treated as plain numbers; an LLM judge's own randomness is not modeled separately.
225
+ - p-values assume runs of one configuration are interchangeable.
226
+ - The case studies use one benchmark each, two small models and one machine. They illustrate the method; they are not a model ranking.
227
+
228
+ ## Repository layout
229
+
230
+ ```
231
+ src/flakeval/ the installable package (stats, io, cli, study, scoring, models, progress, templates)
232
+ examples/ demo data and the two case studies (not part of the installed package)
233
+ tests/ pytest suite
234
+ ```
235
+
236
+ ## Roadmap
237
+
238
+ - [ ] Importers for lm-evaluation-harness, Inspect, and promptfoo outputs
239
+ - [ ] HTML report
240
+ - [ ] Adaptive mode: keep sampling until the verdict is decided
241
+ - [ ] LLM-judge variance and multi-system comparisons with correction
242
+
243
+ ## License
244
+
245
+ MIT. See [LICENSE](LICENSE).
246
+
247
+ ## Citation
248
+
249
+ If `flakeval` is useful in your work, please cite it (see [`CITATION.cff`](CITATION.cff)). **Author:** Anchit Gupta
@@ -0,0 +1,223 @@
1
+ <p align="center">
2
+ <img src="assets/flakeval_logo.png" alt="Logo" width="240" />
3
+ <br/>
4
+ <br/>
5
+ <a href="LICENSE"><img alt="MIT License" src="https://img.shields.io/badge/License-MIT-yellow.svg" /></a>
6
+ <a href="https://pypi.org/project/flakeval/"><img alt="PyPI Version" src="https://img.shields.io/pypi/v/flakeval" /></a>
7
+ <a href="https://pypi.org/project/flakeval/"><img alt="Python Versions" src="https://img.shields.io/pypi/pyversions/flakeval" /></a>
8
+ <a href="https://github.com/AnchitGupta22/flakeval/actions"><img alt="Tests"
9
+ src="https://github.com/AnchitGupta22/flakeval/actions/workflows/tests.yml/badge.svg"/></a>
10
+ <a href="https://anchitgupta22.github.io/flakeval/"><img alt="Documentation" src="https://img.shields.io/badge/Documentation-Read%20the%20docs-red" /></a>
11
+ </p>
12
+
13
+ ---
14
+
15
+ **Is your AI improvement real, or just luck?**
16
+
17
+ *(Say it "flake-eval": flaky + evaluation.)*
18
+
19
+ You change a prompt, a model or a setting, and your test score goes from 72% to 74%. Did it really get better, or would you get 74% just by running the same test again? `flakeval` answers that with a plain verdict.
20
+
21
+ - Works on results you already have (a simple JSONL file), or runs your evaluation for you.
22
+ - Gives a verdict, a range for the true difference, and the **smallest difference your test can reliably detect**.
23
+ - Tells you whether you need **more runs** or **more test questions**.
24
+ - Exits with an error on a real regression, so it works as a CI check.
25
+ - One dependency (numpy). Runs on a laptop.
26
+
27
+ **Full documentation, case studies and FAQ: https://anchitgupta22.github.io/flakeval/**
28
+
29
+ ---
30
+
31
+ ## Contents
32
+
33
+ 1. [The idea in plain English](#the-idea-in-plain-english)
34
+ 2. [Quick start](#quick-start)
35
+ 3. [Case studies (summary)](#case-studies-summary)
36
+ 4. [FAQ](#faq)
37
+ 5. [How it works](#how-it-works)
38
+ 6. [Limitations](#limitations)
39
+ 7. [Repository layout](#repository-layout)
40
+ 8. [Roadmap](#roadmap)
41
+
42
+ ---
43
+
44
+ ## The idea in plain English
45
+
46
+ Language models answer with some randomness, and your test only has a limited number of questions. Together this wobble is called **noise**. A 2-point change in score could be a real improvement or just noise. `flakeval` measures the noise so you know which.
47
+
48
+ | Verdict | Meaning | What to do |
49
+ |---|---|---|
50
+ | **REAL IMPROVEMENT** | B scored higher; chance is an unlikely explanation. | Trust it. |
51
+ | **REAL REGRESSION** | B scored lower; chance is an unlikely explanation. | Investigate before shipping B. |
52
+ | **WITHIN NOISE** | The test cannot tell (this does **not** mean "equal"). | Add more **runs** or more **questions**, as the advice line says. |
53
+ | **IDENTICAL RESULTS** | A and B scored the same on every item. | Check your change actually reached the model. |
54
+
55
+ Example (simulated: B is truly ~2 points better, 200 items, 5 runs each):
56
+
57
+ ```
58
+ $ flakeval compare a.jsonl b.jsonl
59
+ A: 0.6800 (5 runs) B: 0.6860 (5 runs) items: 200
60
+ delta (B - A): +0.0060 95% CI: [-0.0310, +0.0430] p = 0.7955
61
+ smallest reliably detectable difference: ~0.0535
62
+ VERDICT: WITHIN NOISE
63
+ ```
64
+
65
+ The true difference could be anywhere from 3.1 points worse to 4.3 points better, and this test can only reliably spot gaps of about 5 points, so a 2-point improvement is invisible to it.
66
+
67
+ ---
68
+
69
+ ## Quick start
70
+
71
+ Requires Python 3.10+.
72
+
73
+ ```bash
74
+ pip install flakeval
75
+ ```
76
+
77
+ ### Option A: you already have scores
78
+
79
+ Write one JSON line per item per run (use at least 3 runs per item, and the same ids in both files):
80
+
81
+ ```json
82
+ {"item_id": "q17", "run": 2, "score": 1.0}
83
+ ```
84
+
85
+ ```bash
86
+ flakeval report a.jsonl # how noisy is one system?
87
+ flakeval compare a.jsonl b.jsonl # is B really different from A?
88
+ flakeval compare a.jsonl b.jsonl --json # machine-readable
89
+ ```
90
+
91
+ `flakeval compare` exits with code 1 only on a statistically real regression, so it works as a **CI gate**.
92
+
93
+ From Python:
94
+
95
+ ```python
96
+ from flakeval import repeat, compare
97
+
98
+ a = repeat(eval_model_a, items, runs=5, workers=8, save="a.jsonl")
99
+ b = repeat(eval_model_b, items, runs=5, workers=8, save="b.jsonl")
100
+ print(compare(a, b))
101
+ ```
102
+
103
+ If your function uses a sampling seed, make it **different for every run** (`repeat(..., with_run=True)` passes the run number). A fixed seed hides the noise this tool measures.
104
+
105
+ ### Option B: let flakeval run your models
106
+
107
+ ```bash
108
+ flakeval init # creates my_eval.py (settings) and sample_data.csv
109
+ python my_eval.py --dry-run # 2 questions per system, prints answers and scores; saves nothing
110
+ python my_eval.py # the real run (shows the number of calls and asks first)
111
+ ```
112
+
113
+ Put your questions in a CSV or JSONL (`id, input text, expected answer`), then edit the settings at the top of `my_eval.py`. Example: does a new prompt beat the current one on the same model? The first system is the baseline.
114
+
115
+ ```python
116
+ DATA_PATH = "tickets.csv"
117
+ INPUT_COLUMN = "ticket"
118
+ EXPECTED_COLUMN = "label"
119
+ ID_COLUMN = "id"
120
+ SCORER = "exact"
121
+
122
+ SYSTEMS = [
123
+ {"name": "current_prompt", "model": "qwen2.5:3b", "base_url": "http://localhost:11434/v1",
124
+ "api_key_env": None, "temperature": 0.7, "system_prompt": "",
125
+ "prompt_template": "Classify this ticket as billing, bug or question.\n\nTicket: {input}"},
126
+ {"name": "new_prompt", "model": "qwen2.5:3b", "base_url": "http://localhost:11434/v1",
127
+ "api_key_env": None, "temperature": 0.7, "system_prompt": "",
128
+ "prompt_template": "Reply with exactly one label: billing, bug or question.\n\nTicket: {input}"},
129
+ ]
130
+
131
+ RUNS = 5 # 3 to 5 is a good range
132
+ MAX_TOKENS = 20
133
+ ```
134
+
135
+ - **Models:** anything with an OpenAI-compatible endpoint (Ollama, LM Studio, vLLM, hosted APIs). Put the *name* of the environment variable holding your key in `api_key_env`, never the key itself. For anything else, pass your own function as `"call": my_function`.
136
+ - **Built-in scorers:** `exact`, `contains`, `number`, `choice_letter`, `answer_line`, `final_number`, or `"custom"` (your own `custom_score(output, expected, row)` returning 0 to 1).
137
+ - **Overrides:** `--max-items 10`, `--runs 2`, `--workers 4`, `--out-dir DIR`, `--scorer NAME`. Try `--max-items 10 --runs 2 --out-dir trial` for a cheap rehearsal.
138
+ - **Output:** a printed report plus `my_results/` with scores, raw answers (`<system>.outputs.jsonl`) and `report.txt`. The baseline is run twice (A/A check) by default, showing how much two identical runs differ by chance.
139
+ - **Safe to rerun:** finished systems are skipped, and a server failure stops the run instead of recording fake zeros.
140
+ - **Fixed your scorer?** `python my_eval.py --rescore` re-marks saved answers without calling any model.
141
+ - **Pure Python, no settings file:** use `default_config()` and `run_study(cfg)` from `flakeval.study`.
142
+
143
+ **Read some raw answers that scored 0 before trusting the numbers.** A scorer that wrongly marks good answers down looks exactly like model noise.
144
+
145
+ **Privacy:** nothing is uploaded. Rows go only to the endpoints you list. If your data is confidential, add `my_results/` to `.gitignore`.
146
+
147
+ ### Option C: clone the repo (tests, demo, case studies)
148
+
149
+ ```bash
150
+ git clone https://github.com/AnchitGupta22/flakeval && cd flakeval
151
+ pip install -e ".[dev,examples]"
152
+ python -m pytest
153
+ cd examples && python make_demo.py && flakeval compare a.jsonl b.jsonl
154
+ ```
155
+
156
+ If `flakeval` is not found, use `python -m flakeval.cli compare a.jsonl b.jsonl`.
157
+
158
+ ---
159
+
160
+ ## Case studies (summary)
161
+
162
+ Two worked examples live in `examples/template_case_studies/` (`arc_eval.py`, `gsm8k_eval.py`), run on `qwen2.5:3b` and `llama3.2:3b` with Ollama. Full tables, methodology and diagnostics are in the [documentation](https://anchitgupta22.github.io/flakeval/).
163
+
164
+ - **ARC (science multiple choice, 200 items x 5 runs):** the same model twice scored 82.6% and 82.9% (within noise). `llama3.2:3b` scored 11.7 points lower than `qwen2.5:3b` (p < 0.001), flagged as real.
165
+ - **GSM8K (math reasoning, 200 items x 3 runs):** under strict scoring, the same system twice differed by 4.8 points (p = 0.024). Five extra repeats ranged from 69.7% to 74.5%, so this was chance. A "double-check" prompt result of -4.7 points fell inside that natural spread, so no conclusion could be drawn.
166
+
167
+ Takeaways:
168
+
169
+ 1. Always include the "same system twice" check; it shows how big a gap chance alone can produce.
170
+ 2. Reasoning tasks are far noisier than single-letter answers (32.5% of GSM8K items changed score across 3 runs vs 0.5% on ARC).
171
+ 3. Check the "smallest detectable difference" **before** you start. If it is bigger than the improvement you hope for, your test is too small.
172
+ 4. Treat borderline p-values (about 0.01 to 0.05) with caution, and always report how you scored the answers.
173
+
174
+ ---
175
+
176
+ ## FAQ
177
+
178
+ **Isn't it all just chance?** Yes, partly, and `flakeval` cannot remove that. It **measures how much chance is in your result**, like a margin of error in a poll, and tells you whether more runs or more questions would shrink it. Halving the smallest detectable difference takes about four times the data.
179
+
180
+ **Why not just set temperature to 0?** That removes most model randomness but not the sampling of your questions, and real users do not run at temperature 0.
181
+
182
+ **How many questions and runs do I need?** Look at the "smallest detectable difference" in the report. A reasonable start is 100 or more questions and 3 to 5 runs.
183
+
184
+ ---
185
+
186
+ ## How it works
187
+
188
+ Scores form an items x runs matrix, and comparisons are paired by item id. The 95% interval comes from a bootstrap that resamples **items** (run noise is already inside each item's mean). The p-value comes from a paired sign-flip permutation test. A verdict of "real" requires the interval to exclude zero **and** p < 0.05. The smallest detectable difference is about 2.8 x the standard error (80% power, alpha 0.05).
189
+
190
+ In simulation (60 items, 5 runs), two identical systems were called "different" 5.3% of the time (target 5%), and a true 10-point gap was detected 71% of the time.
191
+
192
+ **Pitfall guarded against:** many servers use a fixed default seed (Ollama's is 0), so "repeated" runs are identical and show zero noise. The template sends a different seed per question and run, and `flakeval` warns when no item changes score across runs.
193
+
194
+ ## Limitations
195
+
196
+ - Assumes your items are a random sample of the questions you care about.
197
+ - Compares two systems at a time; no multiple-comparison correction yet.
198
+ - Scores are treated as plain numbers; an LLM judge's own randomness is not modeled separately.
199
+ - p-values assume runs of one configuration are interchangeable.
200
+ - The case studies use one benchmark each, two small models and one machine. They illustrate the method; they are not a model ranking.
201
+
202
+ ## Repository layout
203
+
204
+ ```
205
+ src/flakeval/ the installable package (stats, io, cli, study, scoring, models, progress, templates)
206
+ examples/ demo data and the two case studies (not part of the installed package)
207
+ tests/ pytest suite
208
+ ```
209
+
210
+ ## Roadmap
211
+
212
+ - [ ] Importers for lm-evaluation-harness, Inspect, and promptfoo outputs
213
+ - [ ] HTML report
214
+ - [ ] Adaptive mode: keep sampling until the verdict is decided
215
+ - [ ] LLM-judge variance and multi-system comparisons with correction
216
+
217
+ ## License
218
+
219
+ MIT. See [LICENSE](LICENSE).
220
+
221
+ ## Citation
222
+
223
+ If `flakeval` is useful in your work, please cite it (see [`CITATION.cff`](CITATION.cff)). **Author:** Anchit Gupta
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "flakeval"
7
- version = "0.1.0"
7
+ version = "0.1.2"
8
8
  description = "Is your LLM eval improvement real, or just noise? Repeat evals, measure variance, get a verdict."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -20,6 +20,19 @@ keywords = [
20
20
  "statistics",
21
21
  "machine-learning"
22
22
  ]
23
+ classifiers = [
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Programming Language :: Python :: 3.13",
29
+ "Operating System :: OS Independent"
30
+ ]
31
+
32
+ [project.urls]
33
+ Homepage = "https://anchitgupta22.github.io/flakeval/"
34
+ Repository = "https://github.com/AnchitGupta22/flakeval"
35
+ Issues = "https://github.com/AnchitGupta22/flakeval/issues"
23
36
 
24
37
  [project.optional-dependencies]
25
38
  dev = ["pytest"]
@@ -32,4 +45,4 @@ flakeval = "flakeval.cli:main"
32
45
  where = ["src"]
33
46
 
34
47
  [tool.setuptools.package-data]
35
- flakeval = ["templates/*"]
48
+ flakeval = ["templates/*"]
@@ -0,0 +1,20 @@
1
+ from importlib.metadata import version, PackageNotFoundError
2
+
3
+ from .io import load_jsonl, repeat, save_jsonl
4
+ from .stats import Comparison, Scores, Summary, compare, summarize
5
+
6
+ __all__ = [
7
+ "Scores",
8
+ "Summary",
9
+ "Comparison",
10
+ "summarize",
11
+ "compare",
12
+ "repeat",
13
+ "load_jsonl",
14
+ "save_jsonl",
15
+ ]
16
+
17
+ try:
18
+ __version__ = version("flakeval")
19
+ except PackageNotFoundError:
20
+ __version__ = "0.0.0"