flakeval 0.1.0__py3-none-any.whl
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.
- flakeval/__init__.py +5 -0
- flakeval/cli.py +99 -0
- flakeval/io.py +84 -0
- flakeval/models.py +68 -0
- flakeval/progress.py +101 -0
- flakeval/scoring.py +78 -0
- flakeval/stats.py +254 -0
- flakeval/study.py +311 -0
- flakeval/templates/my_eval.py +125 -0
- flakeval/templates/sample_data.csv +13 -0
- flakeval-0.1.0.dist-info/METADATA +559 -0
- flakeval-0.1.0.dist-info/RECORD +16 -0
- flakeval-0.1.0.dist-info/WHEEL +5 -0
- flakeval-0.1.0.dist-info/entry_points.txt +2 -0
- flakeval-0.1.0.dist-info/licenses/LICENSE +21 -0
- flakeval-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
flakeval settings file: compare YOUR models or prompts on YOUR data, with proper noise estimates.
|
|
4
|
+
|
|
5
|
+
HOW TO USE
|
|
6
|
+
1. Edit the settings below. Nothing else in this file needs changing (the engine lives in the flakeval package).
|
|
7
|
+
2. Check your setup on a couple of rows first (no files written): python my_eval.py --dry-run
|
|
8
|
+
3. Run it for real: python my_eval.py
|
|
9
|
+
Changed your scorer, or found it marking good answers wrong? python my_eval.py --rescore
|
|
10
|
+
That re-marks the saved answers without calling any model (needs SAVE_OUTPUTS = True).
|
|
11
|
+
A progress bar shows how far along it is (with an estimated time left). Result files go to OUT_DIR, and the
|
|
12
|
+
last thing printed is the verdict for each comparison.
|
|
13
|
+
(You got this file from `flakeval init`. Run that again in any folder to start a new evaluation.)
|
|
14
|
+
|
|
15
|
+
WHAT IT DOES
|
|
16
|
+
For every system in SYSTEMS it asks each question in your data RUNS times (with a different random seed each time),
|
|
17
|
+
scores every answer, and then uses flakeval to say whether the difference between the first system (the baseline)
|
|
18
|
+
and each other system is real or just noise. With RUN_A_A_TEST on, it also runs the baseline twice to show how
|
|
19
|
+
much two identical runs differ by chance.
|
|
20
|
+
|
|
21
|
+
PRIVACY
|
|
22
|
+
flakeval uploads nothing. Your rows are sent ONLY to the model endpoints you list in SYSTEMS. With a local model
|
|
23
|
+
(for example Ollama) nothing leaves your computer. Scores and raw model answers are written to OUT_DIR on your disk;
|
|
24
|
+
if your data is confidential, keep OUT_DIR out of git (add it to .gitignore).
|
|
25
|
+
API keys: put the key in an environment variable and name that variable in api_key_env. Never paste a key here.
|
|
26
|
+
|
|
27
|
+
COST
|
|
28
|
+
Total model calls = (number of questions) x RUNS x (number of systems, plus 1 for the A/A test). The script prints
|
|
29
|
+
this number and asks for confirmation before it starts. Try a small MAX_ITEMS first if you pay per call.
|
|
30
|
+
"""
|
|
31
|
+
from flakeval.study import run_cli
|
|
32
|
+
|
|
33
|
+
# =====================================================================================================================
|
|
34
|
+
# EDIT THE SETTINGS BELOW
|
|
35
|
+
# =====================================================================================================================
|
|
36
|
+
|
|
37
|
+
# ---- Your data: a .csv (with a header row) or a .jsonl file (one JSON object per line) ----
|
|
38
|
+
DATA_PATH = "sample_data.csv" # relative to the folder you run this file from
|
|
39
|
+
INPUT_COLUMN = "question" # column with the text sent to the model
|
|
40
|
+
EXPECTED_COLUMN = "answer" # column with the correct answer (set to None if your SCORER does not need one)
|
|
41
|
+
ID_COLUMN = "id" # column with a unique id per row (set to None to just use the row number)
|
|
42
|
+
MAX_ITEMS = None # test on a random subset of this many rows (None = all rows). Aim for 100+ if you can.
|
|
43
|
+
ITEM_SEED = 0 # fixes which subset is chosen, so every system sees the same questions
|
|
44
|
+
|
|
45
|
+
# ---- How to score an answer (1 = good, 0 = bad) ----
|
|
46
|
+
# "exact" the answer equals the expected text (ignores case, spaces and trailing punctuation)
|
|
47
|
+
# "contains" the expected text appears somewhere in the answer
|
|
48
|
+
# "number" the LAST number in the answer equals the expected number
|
|
49
|
+
# "choice_letter" multiple choice: the FIRST standalone capital letter A-H in the answer is the expected letter
|
|
50
|
+
# "answer_line" math, strict: the number after the LAST "Answer:" in the reply equals the expected number
|
|
51
|
+
# "final_number" math, lenient: like answer_line, but also accepts \boxed{...} and then the last number
|
|
52
|
+
# "custom" your own function (see custom_score below), for anything else
|
|
53
|
+
SCORER = "contains"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def custom_score(output: str, expected: str, row: dict) -> float:
|
|
57
|
+
"""Only used when SCORER = "custom". Return a number, usually 1.0 (good) or 0.0 (bad), or anything from 0 to 1.
|
|
58
|
+
`output` is the model's answer, `expected` is the value from EXPECTED_COLUMN, `row` is the whole data row."""
|
|
59
|
+
return 1.0 if output.strip() else 0.0
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# ---- The systems to compare. The FIRST one is the baseline; every other one is compared against it. ----
|
|
63
|
+
# Two models, or the same model with two different prompts, whatever you want to compare.
|
|
64
|
+
# name any short label (used for file names)
|
|
65
|
+
# model the model name your server expects
|
|
66
|
+
# base_url an OpenAI-compatible endpoint. Local examples: Ollama "http://localhost:11434/v1",
|
|
67
|
+
# LM Studio "http://localhost:1234/v1". Hosted: see your provider's docs for its base URL.
|
|
68
|
+
# api_key_env NAME of the environment variable holding the API key (None for local servers)
|
|
69
|
+
# temperature randomness of the answers (None = do not send the setting, for models that reject it)
|
|
70
|
+
# system_prompt optional instructions that go before every question
|
|
71
|
+
# prompt_template how each question is sent; {input} is replaced by the text of INPUT_COLUMN
|
|
72
|
+
# Optional per system: "send_seed": False (if a provider rejects the seed setting),
|
|
73
|
+
# "token_limit_param": "max_completion_tokens" (needed by some newer hosted models).
|
|
74
|
+
SYSTEMS = [
|
|
75
|
+
{
|
|
76
|
+
"name": "model_a",
|
|
77
|
+
"model": "qwen2.5:3b",
|
|
78
|
+
"base_url": "http://localhost:11434/v1",
|
|
79
|
+
"api_key_env": None,
|
|
80
|
+
"temperature": 0.7,
|
|
81
|
+
"system_prompt": "",
|
|
82
|
+
"prompt_template": "{input}",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "model_b",
|
|
86
|
+
"model": "llama3.2:3b",
|
|
87
|
+
"base_url": "http://localhost:11434/v1",
|
|
88
|
+
"api_key_env": None,
|
|
89
|
+
"temperature": 0.7,
|
|
90
|
+
"system_prompt": "",
|
|
91
|
+
"prompt_template": "{input}",
|
|
92
|
+
},
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
# ---- Using something that is not an OpenAI-compatible endpoint (another SDK, a local Python model, ...)? ----
|
|
96
|
+
# Write a function like the one below and give it to a system with "call": my_model (instead of model/base_url).
|
|
97
|
+
# It receives the prompt and must return the model's answer as plain text. Example for the Anthropic Python SDK:
|
|
98
|
+
#
|
|
99
|
+
# import anthropic
|
|
100
|
+
# client = anthropic.Anthropic() # reads the ANTHROPIC_API_KEY environment variable
|
|
101
|
+
# def my_model(prompt, system_prompt, temperature, seed, max_tokens):
|
|
102
|
+
# msg = client.messages.create(model="your-model-name", max_tokens=max_tokens, temperature=temperature,
|
|
103
|
+
# system=system_prompt or anthropic.NOT_GIVEN,
|
|
104
|
+
# messages=[{"role": "user", "content": prompt}])
|
|
105
|
+
# return msg.content[0].text
|
|
106
|
+
# SYSTEMS[1] = {"name": "my_api_model", "call": my_model, "temperature": 0.7,
|
|
107
|
+
# "system_prompt": "", "prompt_template": "{input}"}
|
|
108
|
+
#
|
|
109
|
+
# (That API has no seed setting. That is fine: its answers vary on their own. Just ignore `seed`.)
|
|
110
|
+
|
|
111
|
+
# ---- How many runs and how long answers can be ----
|
|
112
|
+
RUNS = 5 # times each question is asked per system (3 to 5 is a good range)
|
|
113
|
+
MAX_TOKENS = 300 # longest answer allowed; answers cut off here are scored as they are
|
|
114
|
+
WORKERS = 1 # parallel requests. Raise for hosted APIs (e.g. 8); keep 1 for a single local GPU
|
|
115
|
+
RUN_A_A_TEST = True # also run the baseline a second time, as a sanity check on how much chance alone moves scores
|
|
116
|
+
|
|
117
|
+
# ---- Output ----
|
|
118
|
+
OUT_DIR = "my_results" # score files, raw answers and report.txt go here
|
|
119
|
+
SAVE_OUTPUTS = True # keep the raw model answers (useful for checking your scorer; may contain your data)
|
|
120
|
+
|
|
121
|
+
# =====================================================================================================================
|
|
122
|
+
# Nothing below needs editing.
|
|
123
|
+
# =====================================================================================================================
|
|
124
|
+
if __name__ == "__main__":
|
|
125
|
+
run_cli(globals()) # reads the settings above and handles --dry-run, --yes and --rescore
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
id,question,answer
|
|
2
|
+
1,What is the capital of France? Answer in one word.,Paris
|
|
3
|
+
2,What is 7 times 8? Answer with just the number.,56
|
|
4
|
+
3,What is the capital of Australia? Answer in one word.,Canberra
|
|
5
|
+
4,What is the chemical formula of water?,H2O
|
|
6
|
+
5,How many days are there in a leap year? Answer with just the number.,366
|
|
7
|
+
6,What is 12 plus 15? Answer with just the number.,27
|
|
8
|
+
7,What colour do you get when you mix blue and yellow paint? Answer in one word.,green
|
|
9
|
+
8,What is the largest planet in our solar system? Answer in one word.,Jupiter
|
|
10
|
+
9,How many sides does a hexagon have? Answer with just the number.,6
|
|
11
|
+
10,Who wrote the play Romeo and Juliet? Answer with the last name only.,Shakespeare
|
|
12
|
+
11,At what temperature in degrees Celsius does water boil at sea level? Answer with just the number.,100
|
|
13
|
+
12,What is the capital of Japan? Answer in one word.,Tokyo
|