cosq 0.1.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.
- cosq-0.1.0/.env.example +5 -0
- cosq-0.1.0/.gitignore +19 -0
- cosq-0.1.0/LICENSE +21 -0
- cosq-0.1.0/PKG-INFO +254 -0
- cosq-0.1.0/README.md +193 -0
- cosq-0.1.0/configs/experiment/pilot_truthfulqa_open.yaml +22 -0
- cosq-0.1.0/configs/experiment/pilot_truthfulqa_open_openai.yaml +22 -0
- cosq-0.1.0/configs/experiment/smoke_mock.yaml +22 -0
- cosq-0.1.0/configs/model/hf_llama3_8b_instruct.yaml +13 -0
- cosq-0.1.0/configs/model/hf_mistral_7b_instruct.yaml +13 -0
- cosq-0.1.0/configs/model/mock.yaml +9 -0
- cosq-0.1.0/configs/model/openai_gpt4o_mini.yaml +11 -0
- cosq-0.1.0/configs/model/openai_template.yaml +14 -0
- cosq-0.1.0/data/.gitkeep +0 -0
- cosq-0.1.0/docs/methodology-notes.md +31 -0
- cosq-0.1.0/pyproject.toml +66 -0
- cosq-0.1.0/src/cosq/__init__.py +46 -0
- cosq-0.1.0/src/cosq/backends/__init__.py +25 -0
- cosq-0.1.0/src/cosq/backends/base.py +58 -0
- cosq-0.1.0/src/cosq/backends/hf_local.py +147 -0
- cosq-0.1.0/src/cosq/backends/mock.py +145 -0
- cosq-0.1.0/src/cosq/backends/openai.py +111 -0
- cosq-0.1.0/src/cosq/cli.py +295 -0
- cosq-0.1.0/src/cosq/config.py +198 -0
- cosq-0.1.0/src/cosq/data/__init__.py +14 -0
- cosq-0.1.0/src/cosq/data/base.py +43 -0
- cosq-0.1.0/src/cosq/data/jsonl.py +45 -0
- cosq-0.1.0/src/cosq/data/natural_questions.py +97 -0
- cosq-0.1.0/src/cosq/data/truthfulqa.py +101 -0
- cosq-0.1.0/src/cosq/decision/__init__.py +14 -0
- cosq-0.1.0/src/cosq/decision/base.py +37 -0
- cosq-0.1.0/src/cosq/decision/confidence.py +138 -0
- cosq-0.1.0/src/cosq/decision/threshold.py +61 -0
- cosq-0.1.0/src/cosq/dotenv.py +69 -0
- cosq-0.1.0/src/cosq/eval/__init__.py +27 -0
- cosq-0.1.0/src/cosq/eval/metrics.py +82 -0
- cosq-0.1.0/src/cosq/eval/scorer.py +57 -0
- cosq-0.1.0/src/cosq/eval/selective.py +115 -0
- cosq-0.1.0/src/cosq/parsing/__init__.py +25 -0
- cosq-0.1.0/src/cosq/parsing/answers.py +233 -0
- cosq-0.1.0/src/cosq/parsing/stages.py +124 -0
- cosq-0.1.0/src/cosq/prompts/__init__.py +42 -0
- cosq-0.1.0/src/cosq/prompts/en/cosq_abstain.v1.txt +1 -0
- cosq-0.1.0/src/cosq/prompts/en/cosq_answer.v1.txt +9 -0
- cosq-0.1.0/src/cosq/prompts/en/cosq_answer_open.v1.txt +9 -0
- cosq-0.1.0/src/cosq/prompts/en/cosq_certainty.v1.txt +9 -0
- cosq-0.1.0/src/cosq/prompts/en/cosq_confidence.v1.txt +10 -0
- cosq-0.1.0/src/cosq/prompts/en/cosq_needs.v1.txt +7 -0
- cosq-0.1.0/src/cosq/prompts/en/cot.v1.txt +5 -0
- cosq-0.1.0/src/cosq/prompts/en/cot_abstain.v1.txt +8 -0
- cosq-0.1.0/src/cosq/prompts/en/cot_abstain_open.v1.txt +8 -0
- cosq-0.1.0/src/cosq/prompts/en/cot_open.v1.txt +5 -0
- cosq-0.1.0/src/cosq/prompts/en/direct.v1.txt +4 -0
- cosq-0.1.0/src/cosq/prompts/en/direct_open.v1.txt +4 -0
- cosq-0.1.0/src/cosq/prompts/en/question.v1.txt +4 -0
- cosq-0.1.0/src/cosq/prompts/en/question_open.v1.txt +1 -0
- cosq-0.1.0/src/cosq/registry.py +49 -0
- cosq-0.1.0/src/cosq/report/__init__.py +17 -0
- cosq-0.1.0/src/cosq/report/analysis.py +293 -0
- cosq-0.1.0/src/cosq/report/tables.py +60 -0
- cosq-0.1.0/src/cosq/runner/__init__.py +7 -0
- cosq-0.1.0/src/cosq/runner/cache.py +139 -0
- cosq-0.1.0/src/cosq/runner/manifest.py +76 -0
- cosq-0.1.0/src/cosq/runner/runner.py +232 -0
- cosq-0.1.0/src/cosq/stats/__init__.py +44 -0
- cosq-0.1.0/src/cosq/stats/effects.py +81 -0
- cosq-0.1.0/src/cosq/stats/multiple.py +28 -0
- cosq-0.1.0/src/cosq/stats/power.py +79 -0
- cosq-0.1.0/src/cosq/stats/tests.py +123 -0
- cosq-0.1.0/src/cosq/strategies/__init__.py +19 -0
- cosq-0.1.0/src/cosq/strategies/base.py +75 -0
- cosq-0.1.0/src/cosq/strategies/baselines.py +74 -0
- cosq-0.1.0/src/cosq/strategies/cosq.py +122 -0
- cosq-0.1.0/src/cosq/strategies/cosq_gate.py +45 -0
- cosq-0.1.0/src/cosq/strategies/cosq_graded.py +122 -0
- cosq-0.1.0/src/cosq/strategies/cosq_graded_gate.py +20 -0
- cosq-0.1.0/src/cosq/types.py +167 -0
- cosq-0.1.0/tests/conftest.py +52 -0
- cosq-0.1.0/tests/fixtures/mini.jsonl +6 -0
- cosq-0.1.0/tests/test_backends.py +99 -0
- cosq-0.1.0/tests/test_cli.py +71 -0
- cosq-0.1.0/tests/test_condition_diagnostics.py +103 -0
- cosq-0.1.0/tests/test_config.py +107 -0
- cosq-0.1.0/tests/test_cosq_gate.py +155 -0
- cosq-0.1.0/tests/test_cosq_graded.py +272 -0
- cosq-0.1.0/tests/test_decision.py +45 -0
- cosq-0.1.0/tests/test_dotenv.py +60 -0
- cosq-0.1.0/tests/test_metrics.py +65 -0
- cosq-0.1.0/tests/test_open_ended.py +250 -0
- cosq-0.1.0/tests/test_openai_backend.py +55 -0
- cosq-0.1.0/tests/test_parsing.py +104 -0
- cosq-0.1.0/tests/test_runner.py +179 -0
- cosq-0.1.0/tests/test_selective.py +81 -0
- cosq-0.1.0/tests/test_stats.py +131 -0
- cosq-0.1.0/tests/test_strategies.py +121 -0
cosq-0.1.0/.env.example
ADDED
cosq-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
.coverage
|
|
7
|
+
.pytest_cache/
|
|
8
|
+
.ruff_cache/
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
.venv/
|
|
11
|
+
.env
|
|
12
|
+
.pypirc
|
|
13
|
+
|
|
14
|
+
# Local data and generated outputs
|
|
15
|
+
data/*
|
|
16
|
+
!data/.gitkeep
|
|
17
|
+
results/
|
|
18
|
+
*.sqlite
|
|
19
|
+
*.db
|
cosq-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ali Şenol
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cosq-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: cosq
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Chain-of-Self-Questioning for selective factual answering with LLMs
|
|
5
|
+
Project-URL: Homepage, https://github.com/senolali/cosq
|
|
6
|
+
Project-URL: Repository, https://github.com/senolali/cosq
|
|
7
|
+
Project-URL: Issues, https://github.com/senolali/cosq/issues
|
|
8
|
+
Author-email: Ali Senol <alisenol@tarsus.edu.tr>
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 Ali Şenol
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: abstention,hallucination,llm,question-answering,selective-prediction
|
|
32
|
+
Classifier: Development Status :: 3 - Alpha
|
|
33
|
+
Classifier: Intended Audience :: Science/Research
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
39
|
+
Requires-Python: >=3.10
|
|
40
|
+
Requires-Dist: numpy<2.4,>=1.24
|
|
41
|
+
Requires-Dist: pyyaml>=6.0
|
|
42
|
+
Requires-Dist: requests>=2.31
|
|
43
|
+
Requires-Dist: scipy>=1.10
|
|
44
|
+
Provides-Extra: dev
|
|
45
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
46
|
+
Requires-Dist: mypy<2,>=1.11; extra == 'dev'
|
|
47
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
48
|
+
Requires-Dist: pytest<9,>=8.0; extra == 'dev'
|
|
49
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
50
|
+
Requires-Dist: twine>=5.0; extra == 'dev'
|
|
51
|
+
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
52
|
+
Provides-Extra: hf
|
|
53
|
+
Requires-Dist: accelerate>=0.30; extra == 'hf'
|
|
54
|
+
Requires-Dist: bitsandbytes>=0.43; extra == 'hf'
|
|
55
|
+
Requires-Dist: datasets>=2.18; extra == 'hf'
|
|
56
|
+
Requires-Dist: torch>=2.0; extra == 'hf'
|
|
57
|
+
Requires-Dist: transformers>=4.40; extra == 'hf'
|
|
58
|
+
Provides-Extra: openai
|
|
59
|
+
Requires-Dist: openai>=1.0; extra == 'openai'
|
|
60
|
+
Description-Content-Type: text/markdown
|
|
61
|
+
|
|
62
|
+
# CoSQ: Chain-of-Self-Questioning
|
|
63
|
+
|
|
64
|
+
CoSQ is a Python framework for **selective factual answering** with large language models. Instead of forcing a model to answer every question, CoSQ asks the model to decompose the question into required knowledge items, assess whether those items are supported, and then either answer or abstain with `I don't know`.
|
|
65
|
+
|
|
66
|
+
The framework is designed for reproducible experiments on hallucination, abstention, answered accuracy, and risk-coverage trade-offs.
|
|
67
|
+
|
|
68
|
+
## Why CoSQ?
|
|
69
|
+
|
|
70
|
+
Standard accuracy rewards guessing: an abstention is usually scored the same as a wrong answer. That is a poor fit for settings where a wrong answer is more costly than saying "I don't know". CoSQ treats factual answering as a selective prediction problem and reports:
|
|
71
|
+
|
|
72
|
+
- **Answered accuracy**: accuracy among parseable committed answers.
|
|
73
|
+
- **Coverage**: the fraction of questions the model answers.
|
|
74
|
+
- **Hallucination rate**: wrong committed answers divided by all questions.
|
|
75
|
+
- **Abstention rate**: explicit `I don't know` responses.
|
|
76
|
+
- **Unparseable rate**: outputs that cannot be mapped to the benchmark answer space.
|
|
77
|
+
|
|
78
|
+
## Installation
|
|
79
|
+
|
|
80
|
+
From PyPI, after release:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install cosq
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
For local development:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
git clone https://github.com/senolali/cosq.git
|
|
90
|
+
cd cosq
|
|
91
|
+
python -m venv .venv
|
|
92
|
+
.venv\Scripts\activate
|
|
93
|
+
pip install -e ".[dev]"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Optional backends:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pip install -e ".[hf]" # local Hugging Face / transformers models
|
|
100
|
+
pip install -e ".[openai]" # OpenAI API backend
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Quick Start
|
|
104
|
+
|
|
105
|
+
Run a no-network smoke test with the deterministic mock backend:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
cosq run --config configs/experiment/smoke_mock.yaml --backend mock --allow-dirty
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The command writes a run directory under `results/runs/`. Then score and report it:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
cosq evaluate results/runs/<RUN_DIR>
|
|
115
|
+
cosq analyze results/runs/<RUN_DIR>
|
|
116
|
+
cosq report results/runs/<RUN_DIR>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Using OpenAI Models
|
|
120
|
+
|
|
121
|
+
Set your API key:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
set OPENAI_API_KEY=sk-... # Windows cmd
|
|
125
|
+
$env:OPENAI_API_KEY="sk-..." # PowerShell
|
|
126
|
+
export OPENAI_API_KEY=sk-... # macOS/Linux
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Probe the model:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
cosq probe --model configs/model/openai_gpt4o_mini.yaml
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Run a small open-ended TruthfulQA pilot:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
cosq run --config configs/experiment/pilot_truthfulqa_open_openai.yaml --allow-dirty
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
You can copy `configs/model/openai_template.yaml` and change `id` to another model available in your OpenAI account.
|
|
142
|
+
|
|
143
|
+
## Using Hugging Face Models
|
|
144
|
+
|
|
145
|
+
Install optional dependencies:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
pip install -e ".[hf]"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
For gated models, set `HF_TOKEN` and accept the model license on Hugging Face. Then copy one of the examples in `configs/model/`, replace `revision` with an immutable Hugging Face commit SHA, and run:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
cosq probe --model configs/model/hf_llama3_8b_instruct.yaml
|
|
155
|
+
cosq run --config configs/experiment/pilot_truthfulqa_open.yaml --allow-dirty
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Pinned revisions are required for local Hugging Face models so that a run refers to stable weights.
|
|
159
|
+
|
|
160
|
+
## Experiment Configuration
|
|
161
|
+
|
|
162
|
+
```yaml
|
|
163
|
+
name: smoke_mock
|
|
164
|
+
model: configs/model/mock.yaml
|
|
165
|
+
data:
|
|
166
|
+
name: jsonl
|
|
167
|
+
path: tests/fixtures/mini.jsonl
|
|
168
|
+
n: 3
|
|
169
|
+
seed: 1002
|
|
170
|
+
strategies:
|
|
171
|
+
- name: direct
|
|
172
|
+
- name: cot
|
|
173
|
+
- name: cot_abstain
|
|
174
|
+
- name: cosq
|
|
175
|
+
- name: cosq_graded_gate
|
|
176
|
+
label: cosq_graded_gate_mean060
|
|
177
|
+
threshold: 0.60
|
|
178
|
+
aggregator: mean
|
|
179
|
+
on_empty: abstain
|
|
180
|
+
repeats: 1
|
|
181
|
+
open_ended: false
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Built-in Strategies
|
|
185
|
+
|
|
186
|
+
- `direct`: answer directly.
|
|
187
|
+
- `cot`: reason step by step, then answer.
|
|
188
|
+
- `cot_abstain`: CoT with permission to answer `I don't know`.
|
|
189
|
+
- `cosq`: binary Chain-of-Self-Questioning with a strict conjunctive gate.
|
|
190
|
+
- `cosq_gate`: CoSQ gate followed by CoT-style answer generation.
|
|
191
|
+
- `cosq_graded`: item-level 0-100 confidence scores with thresholding.
|
|
192
|
+
- `cosq_graded_gate`: graded gate followed by CoT-style answer generation.
|
|
193
|
+
|
|
194
|
+
## Data
|
|
195
|
+
|
|
196
|
+
CoSQ ships with a tiny JSONL fixture for tests. Benchmark datasets are loaded at runtime or supplied as JSONL files. Local dataset payloads are ignored by git to keep the package lightweight.
|
|
197
|
+
|
|
198
|
+
A custom JSONL dataset should contain:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{"id":"q1","question":"What is the capital of France?","options":["Paris","Lyon"],"gold_index":0}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Caching and Re-scoring
|
|
205
|
+
|
|
206
|
+
Runs can use a SQLite cache:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
cosq run --config configs/experiment/pilot_truthfulqa_open_openai.yaml --cache results/cache.sqlite
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Raw model outputs are written before scoring. You can improve parsers or metrics and re-run `evaluate`, `analyze`, or `report` without making new model calls.
|
|
213
|
+
|
|
214
|
+
## Development and PyPI Release
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pip install -e ".[dev]"
|
|
218
|
+
pytest
|
|
219
|
+
ruff check .
|
|
220
|
+
python -m build
|
|
221
|
+
python -m twine check dist/*
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
To publish to PyPI:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
python -m build
|
|
228
|
+
python -m twine upload dist/*
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Repository Layout
|
|
232
|
+
|
|
233
|
+
```text
|
|
234
|
+
src/cosq/
|
|
235
|
+
backends/ # mock, local Hugging Face, OpenAI API
|
|
236
|
+
strategies/ # direct, CoT, CoSQ, graded CoSQ variants
|
|
237
|
+
decision/ # binary and confidence-based gates
|
|
238
|
+
data/ # dataset adapters
|
|
239
|
+
eval/ # offline scoring and metrics
|
|
240
|
+
report/ # tables and statistical summaries
|
|
241
|
+
prompts/ # versioned prompt templates
|
|
242
|
+
configs/
|
|
243
|
+
experiment/ # runnable experiment YAML files
|
|
244
|
+
model/ # model backend examples
|
|
245
|
+
tests/ # no-network test suite
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Citation
|
|
249
|
+
|
|
250
|
+
If you use CoSQ in academic work, please cite the accompanying paper once available. A BibTeX entry will be added after publication.
|
|
251
|
+
|
|
252
|
+
## License
|
|
253
|
+
|
|
254
|
+
MIT License.
|
cosq-0.1.0/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# CoSQ: Chain-of-Self-Questioning
|
|
2
|
+
|
|
3
|
+
CoSQ is a Python framework for **selective factual answering** with large language models. Instead of forcing a model to answer every question, CoSQ asks the model to decompose the question into required knowledge items, assess whether those items are supported, and then either answer or abstain with `I don't know`.
|
|
4
|
+
|
|
5
|
+
The framework is designed for reproducible experiments on hallucination, abstention, answered accuracy, and risk-coverage trade-offs.
|
|
6
|
+
|
|
7
|
+
## Why CoSQ?
|
|
8
|
+
|
|
9
|
+
Standard accuracy rewards guessing: an abstention is usually scored the same as a wrong answer. That is a poor fit for settings where a wrong answer is more costly than saying "I don't know". CoSQ treats factual answering as a selective prediction problem and reports:
|
|
10
|
+
|
|
11
|
+
- **Answered accuracy**: accuracy among parseable committed answers.
|
|
12
|
+
- **Coverage**: the fraction of questions the model answers.
|
|
13
|
+
- **Hallucination rate**: wrong committed answers divided by all questions.
|
|
14
|
+
- **Abstention rate**: explicit `I don't know` responses.
|
|
15
|
+
- **Unparseable rate**: outputs that cannot be mapped to the benchmark answer space.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
From PyPI, after release:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install cosq
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
For local development:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone https://github.com/senolali/cosq.git
|
|
29
|
+
cd cosq
|
|
30
|
+
python -m venv .venv
|
|
31
|
+
.venv\Scripts\activate
|
|
32
|
+
pip install -e ".[dev]"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Optional backends:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install -e ".[hf]" # local Hugging Face / transformers models
|
|
39
|
+
pip install -e ".[openai]" # OpenAI API backend
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
Run a no-network smoke test with the deterministic mock backend:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
cosq run --config configs/experiment/smoke_mock.yaml --backend mock --allow-dirty
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The command writes a run directory under `results/runs/`. Then score and report it:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
cosq evaluate results/runs/<RUN_DIR>
|
|
54
|
+
cosq analyze results/runs/<RUN_DIR>
|
|
55
|
+
cosq report results/runs/<RUN_DIR>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Using OpenAI Models
|
|
59
|
+
|
|
60
|
+
Set your API key:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
set OPENAI_API_KEY=sk-... # Windows cmd
|
|
64
|
+
$env:OPENAI_API_KEY="sk-..." # PowerShell
|
|
65
|
+
export OPENAI_API_KEY=sk-... # macOS/Linux
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Probe the model:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
cosq probe --model configs/model/openai_gpt4o_mini.yaml
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Run a small open-ended TruthfulQA pilot:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
cosq run --config configs/experiment/pilot_truthfulqa_open_openai.yaml --allow-dirty
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
You can copy `configs/model/openai_template.yaml` and change `id` to another model available in your OpenAI account.
|
|
81
|
+
|
|
82
|
+
## Using Hugging Face Models
|
|
83
|
+
|
|
84
|
+
Install optional dependencies:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pip install -e ".[hf]"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
For gated models, set `HF_TOKEN` and accept the model license on Hugging Face. Then copy one of the examples in `configs/model/`, replace `revision` with an immutable Hugging Face commit SHA, and run:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
cosq probe --model configs/model/hf_llama3_8b_instruct.yaml
|
|
94
|
+
cosq run --config configs/experiment/pilot_truthfulqa_open.yaml --allow-dirty
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Pinned revisions are required for local Hugging Face models so that a run refers to stable weights.
|
|
98
|
+
|
|
99
|
+
## Experiment Configuration
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
name: smoke_mock
|
|
103
|
+
model: configs/model/mock.yaml
|
|
104
|
+
data:
|
|
105
|
+
name: jsonl
|
|
106
|
+
path: tests/fixtures/mini.jsonl
|
|
107
|
+
n: 3
|
|
108
|
+
seed: 1002
|
|
109
|
+
strategies:
|
|
110
|
+
- name: direct
|
|
111
|
+
- name: cot
|
|
112
|
+
- name: cot_abstain
|
|
113
|
+
- name: cosq
|
|
114
|
+
- name: cosq_graded_gate
|
|
115
|
+
label: cosq_graded_gate_mean060
|
|
116
|
+
threshold: 0.60
|
|
117
|
+
aggregator: mean
|
|
118
|
+
on_empty: abstain
|
|
119
|
+
repeats: 1
|
|
120
|
+
open_ended: false
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Built-in Strategies
|
|
124
|
+
|
|
125
|
+
- `direct`: answer directly.
|
|
126
|
+
- `cot`: reason step by step, then answer.
|
|
127
|
+
- `cot_abstain`: CoT with permission to answer `I don't know`.
|
|
128
|
+
- `cosq`: binary Chain-of-Self-Questioning with a strict conjunctive gate.
|
|
129
|
+
- `cosq_gate`: CoSQ gate followed by CoT-style answer generation.
|
|
130
|
+
- `cosq_graded`: item-level 0-100 confidence scores with thresholding.
|
|
131
|
+
- `cosq_graded_gate`: graded gate followed by CoT-style answer generation.
|
|
132
|
+
|
|
133
|
+
## Data
|
|
134
|
+
|
|
135
|
+
CoSQ ships with a tiny JSONL fixture for tests. Benchmark datasets are loaded at runtime or supplied as JSONL files. Local dataset payloads are ignored by git to keep the package lightweight.
|
|
136
|
+
|
|
137
|
+
A custom JSONL dataset should contain:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{"id":"q1","question":"What is the capital of France?","options":["Paris","Lyon"],"gold_index":0}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Caching and Re-scoring
|
|
144
|
+
|
|
145
|
+
Runs can use a SQLite cache:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
cosq run --config configs/experiment/pilot_truthfulqa_open_openai.yaml --cache results/cache.sqlite
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Raw model outputs are written before scoring. You can improve parsers or metrics and re-run `evaluate`, `analyze`, or `report` without making new model calls.
|
|
152
|
+
|
|
153
|
+
## Development and PyPI Release
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
pip install -e ".[dev]"
|
|
157
|
+
pytest
|
|
158
|
+
ruff check .
|
|
159
|
+
python -m build
|
|
160
|
+
python -m twine check dist/*
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
To publish to PyPI:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
python -m build
|
|
167
|
+
python -m twine upload dist/*
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Repository Layout
|
|
171
|
+
|
|
172
|
+
```text
|
|
173
|
+
src/cosq/
|
|
174
|
+
backends/ # mock, local Hugging Face, OpenAI API
|
|
175
|
+
strategies/ # direct, CoT, CoSQ, graded CoSQ variants
|
|
176
|
+
decision/ # binary and confidence-based gates
|
|
177
|
+
data/ # dataset adapters
|
|
178
|
+
eval/ # offline scoring and metrics
|
|
179
|
+
report/ # tables and statistical summaries
|
|
180
|
+
prompts/ # versioned prompt templates
|
|
181
|
+
configs/
|
|
182
|
+
experiment/ # runnable experiment YAML files
|
|
183
|
+
model/ # model backend examples
|
|
184
|
+
tests/ # no-network test suite
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Citation
|
|
188
|
+
|
|
189
|
+
If you use CoSQ in academic work, please cite the accompanying paper once available. A BibTeX entry will be added after publication.
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
MIT License.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: pilot_truthfulqa_open
|
|
2
|
+
model: configs/model/hf_llama3_8b_instruct.yaml
|
|
3
|
+
data:
|
|
4
|
+
name: truthfulqa_mc1
|
|
5
|
+
n: 100
|
|
6
|
+
seed: 1002
|
|
7
|
+
strategies:
|
|
8
|
+
- name: direct
|
|
9
|
+
- name: cot
|
|
10
|
+
- name: cot_abstain
|
|
11
|
+
- name: cosq
|
|
12
|
+
tau: 0.0
|
|
13
|
+
on_empty: abstain
|
|
14
|
+
- name: cosq_graded_gate
|
|
15
|
+
label: cosq_graded_gate_mean060
|
|
16
|
+
threshold: 0.60
|
|
17
|
+
aggregator: mean
|
|
18
|
+
on_empty: abstain
|
|
19
|
+
repeats: 1
|
|
20
|
+
seed: 1002
|
|
21
|
+
lang: en
|
|
22
|
+
open_ended: true
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: pilot_truthfulqa_open_openai
|
|
2
|
+
model: configs/model/openai_gpt4o_mini.yaml
|
|
3
|
+
data:
|
|
4
|
+
name: truthfulqa_mc1
|
|
5
|
+
n: 100
|
|
6
|
+
seed: 1002
|
|
7
|
+
strategies:
|
|
8
|
+
- name: direct
|
|
9
|
+
- name: cot
|
|
10
|
+
- name: cot_abstain
|
|
11
|
+
- name: cosq
|
|
12
|
+
tau: 0.0
|
|
13
|
+
on_empty: abstain
|
|
14
|
+
- name: cosq_graded_gate
|
|
15
|
+
label: cosq_graded_gate_mean060
|
|
16
|
+
threshold: 0.60
|
|
17
|
+
aggregator: mean
|
|
18
|
+
on_empty: abstain
|
|
19
|
+
repeats: 1
|
|
20
|
+
seed: 1002
|
|
21
|
+
lang: en
|
|
22
|
+
open_ended: true
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# End-to-end smoke test: no GPU, no network. Numbers are not meaningful.
|
|
2
|
+
name: smoke_mock
|
|
3
|
+
model: configs/model/mock.yaml
|
|
4
|
+
data:
|
|
5
|
+
name: jsonl
|
|
6
|
+
path: tests/fixtures/mini.jsonl
|
|
7
|
+
n: 3
|
|
8
|
+
seed: 1002
|
|
9
|
+
strategies:
|
|
10
|
+
- name: direct
|
|
11
|
+
- name: cot
|
|
12
|
+
- name: cot_abstain
|
|
13
|
+
- name: cosq
|
|
14
|
+
- name: cosq_graded_gate
|
|
15
|
+
label: cosq_graded_gate_mean060
|
|
16
|
+
threshold: 0.60
|
|
17
|
+
aggregator: mean
|
|
18
|
+
on_empty: abstain
|
|
19
|
+
repeats: 1
|
|
20
|
+
seed: 1002
|
|
21
|
+
lang: en
|
|
22
|
+
open_ended: false
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
id: meta-llama/Meta-Llama-3-8B-Instruct
|
|
2
|
+
revision: "REPLACE-WITH-HUGGINGFACE-COMMIT-SHA"
|
|
3
|
+
backend: hf_local
|
|
4
|
+
quantization: nf4
|
|
5
|
+
compute_dtype: bfloat16
|
|
6
|
+
generation:
|
|
7
|
+
temperature: 0.0
|
|
8
|
+
top_p: 0.95
|
|
9
|
+
max_new_tokens: 256
|
|
10
|
+
seed: 1002
|
|
11
|
+
backend_params:
|
|
12
|
+
device_map: auto
|
|
13
|
+
trust_remote_code: false
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
id: mistralai/Mistral-7B-Instruct-v0.3
|
|
2
|
+
revision: "REPLACE-WITH-HUGGINGFACE-COMMIT-SHA"
|
|
3
|
+
backend: hf_local
|
|
4
|
+
quantization: nf4
|
|
5
|
+
compute_dtype: bfloat16
|
|
6
|
+
generation:
|
|
7
|
+
temperature: 0.0
|
|
8
|
+
top_p: 0.95
|
|
9
|
+
max_new_tokens: 256
|
|
10
|
+
seed: 1002
|
|
11
|
+
backend_params:
|
|
12
|
+
device_map: auto
|
|
13
|
+
trust_remote_code: false
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Copy this file and set id to any model available in your OpenAI account.
|
|
2
|
+
id: gpt-4o-mini
|
|
3
|
+
revision: hosted
|
|
4
|
+
backend: openai
|
|
5
|
+
quantization: null
|
|
6
|
+
generation:
|
|
7
|
+
temperature: 0.0
|
|
8
|
+
top_p: 0.95
|
|
9
|
+
max_new_tokens: 256
|
|
10
|
+
seed: 1002
|
|
11
|
+
backend_params:
|
|
12
|
+
token_env: OPENAI_API_KEY
|
|
13
|
+
# base_url: https://api.openai.com/v1
|
|
14
|
+
# system_prompt: You are a concise factual question-answering assistant.
|
cosq-0.1.0/data/.gitkeep
ADDED
|
File without changes
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# CoSQ Methodology Notes
|
|
2
|
+
|
|
3
|
+
CoSQ evaluates selective factual answering as a risk-coverage problem.
|
|
4
|
+
|
|
5
|
+
## Core protocol
|
|
6
|
+
|
|
7
|
+
1. A strategy receives the same benchmark question under the same model and decoding parameters.
|
|
8
|
+
2. The backend returns raw text only. It never parses, scores, or decides.
|
|
9
|
+
3. The runner writes every raw answer to `records.jsonl` before offline scoring.
|
|
10
|
+
4. Evaluation can be repeated from saved records without re-querying a model.
|
|
11
|
+
|
|
12
|
+
## Main metrics
|
|
13
|
+
|
|
14
|
+
- `answered_accuracy = correct / (correct + wrong)` for parseable committed answers.
|
|
15
|
+
- `coverage = (correct + wrong) / N`.
|
|
16
|
+
- `hallucination_rate = wrong / N`.
|
|
17
|
+
- `abstention_rate = idk / N`.
|
|
18
|
+
- `unparseable` is reported separately as measurement failure.
|
|
19
|
+
|
|
20
|
+
Answered accuracy must always be read together with coverage. A system can obtain high answered accuracy by answering only easy questions.
|
|
21
|
+
|
|
22
|
+
## CoSQ gates
|
|
23
|
+
|
|
24
|
+
Binary CoSQ uses a strict conjunctive gate: every required knowledge item must be judged `Certain`; otherwise the system abstains. Graded CoSQ replaces binary labels with 0-100 item-level confidence scores and compares an aggregate score, usually the mean, against a threshold.
|
|
25
|
+
|
|
26
|
+
## Reproducibility
|
|
27
|
+
|
|
28
|
+
- Prompt templates are versioned under `src/cosq/prompts/`.
|
|
29
|
+
- Config hashes include both experiment configuration and prompt templates.
|
|
30
|
+
- Model outputs are cached in SQLite when `--cache` is enabled.
|
|
31
|
+
- Hosted APIs are treated as unpinned model endpoints unless the provider exposes immutable revisions.
|