worthir-eval 1.2.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.
- worthir_eval-1.2.0/LICENSE +21 -0
- worthir_eval-1.2.0/PKG-INFO +105 -0
- worthir_eval-1.2.0/README.md +92 -0
- worthir_eval-1.2.0/contracts/README.md +11 -0
- worthir_eval-1.2.0/contracts/__init__.py +1 -0
- worthir_eval-1.2.0/contracts/quickstart_contract.json +40 -0
- worthir_eval-1.2.0/contracts/route_registry.json +29 -0
- worthir_eval-1.2.0/examples/__init__.py +1 -0
- worthir_eval-1.2.0/examples/custom_router/README.md +36 -0
- worthir_eval-1.2.0/examples/custom_router/__init__.py +1 -0
- worthir_eval-1.2.0/examples/custom_router/router.py +92 -0
- worthir_eval-1.2.0/examples/custom_router/run.py +57 -0
- worthir_eval-1.2.0/examples/custom_task/README.md +32 -0
- worthir_eval-1.2.0/examples/custom_task/__init__.py +1 -0
- worthir_eval-1.2.0/examples/custom_task/source/outcomes.csv +13 -0
- worthir_eval-1.2.0/examples/custom_task/source/queries.csv +5 -0
- worthir_eval-1.2.0/examples/custom_task/source/routes.csv +4 -0
- worthir_eval-1.2.0/examples/custom_task/source/task.json +16 -0
- worthir_eval-1.2.0/examples/trec_walkthrough/README.md +28 -0
- worthir_eval-1.2.0/examples/trec_walkthrough/__init__.py +1 -0
- worthir_eval-1.2.0/examples/trec_walkthrough/source/alternative_choices.csv +5 -0
- worthir_eval-1.2.0/examples/trec_walkthrough/source/policy_choices.csv +5 -0
- worthir_eval-1.2.0/examples/trec_walkthrough/source/qrels.tsv +8 -0
- worthir_eval-1.2.0/examples/trec_walkthrough/source/queries.csv +5 -0
- worthir_eval-1.2.0/examples/trec_walkthrough/source/routes.csv +4 -0
- worthir_eval-1.2.0/examples/trec_walkthrough/source/runs/base.trec +12 -0
- worthir_eval-1.2.0/examples/trec_walkthrough/source/runs/prf.trec +12 -0
- worthir_eval-1.2.0/examples/trec_walkthrough/source/runs/rerank.trec +12 -0
- worthir_eval-1.2.0/pyproject.toml +62 -0
- worthir_eval-1.2.0/quickstart/README.md +10 -0
- worthir_eval-1.2.0/quickstart/__init__.py +1 -0
- worthir_eval-1.2.0/quickstart/evaluator/README.md +8 -0
- worthir_eval-1.2.0/quickstart/evaluator/hidden_ledger.csv +19 -0
- worthir_eval-1.2.0/quickstart/participant/README.md +8 -0
- worthir_eval-1.2.0/quickstart/participant/example_actions.json +31 -0
- worthir_eval-1.2.0/quickstart/participant/legal_state.csv +8 -0
- worthir_eval-1.2.0/scripts/__init__.py +1 -0
- worthir_eval-1.2.0/scripts/actions_from_csv.py +98 -0
- worthir_eval-1.2.0/scripts/build_custom_task.py +507 -0
- worthir_eval-1.2.0/scripts/build_trec_task.py +497 -0
- worthir_eval-1.2.0/scripts/compare_policies.py +210 -0
- worthir_eval-1.2.0/scripts/init_task.py +92 -0
- worthir_eval-1.2.0/scripts/launcher.py +26 -0
- worthir_eval-1.2.0/scripts/run_integrity_tests.py +427 -0
- worthir_eval-1.2.0/scripts/run_smoke_test.py +52 -0
- worthir_eval-1.2.0/scripts/score_actions.py +85 -0
- worthir_eval-1.2.0/scripts/validate_framework.py +198 -0
- worthir_eval-1.2.0/scripts/validate_task.py +62 -0
- worthir_eval-1.2.0/setup.cfg +4 -0
- worthir_eval-1.2.0/src/worthir_eval/__init__.py +5 -0
- worthir_eval-1.2.0/src/worthir_eval/core.py +528 -0
- worthir_eval-1.2.0/task_template/.gitignore +5 -0
- worthir_eval-1.2.0/task_template/README.md +13 -0
- worthir_eval-1.2.0/task_template/__init__.py +1 -0
- worthir_eval-1.2.0/task_template/contracts/route_registry.json +23 -0
- worthir_eval-1.2.0/task_template/contracts/task_contract.json +40 -0
- worthir_eval-1.2.0/task_template/evaluator/ledger.csv +3 -0
- worthir_eval-1.2.0/task_template/participant/actions.json +11 -0
- worthir_eval-1.2.0/task_template/participant/legal_state.csv +2 -0
- worthir_eval-1.2.0/worthir.py +232 -0
- worthir_eval-1.2.0/worthir_eval.egg-info/PKG-INFO +105 -0
- worthir_eval-1.2.0/worthir_eval.egg-info/SOURCES.txt +63 -0
- worthir_eval-1.2.0/worthir_eval.egg-info/dependency_links.txt +1 -0
- worthir_eval-1.2.0/worthir_eval.egg-info/entry_points.txt +2 -0
- worthir_eval-1.2.0/worthir_eval.egg-info/top_level.txt +2 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 WorthIR Authors
|
|
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.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: worthir-eval
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: Evaluate cost-aware query-level retrieval routing
|
|
5
|
+
Author: WorthIR authors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Dynamic: license-file
|
|
13
|
+
|
|
14
|
+
# WorthIR
|
|
15
|
+
|
|
16
|
+
[English](https://github.com/HongTianShi/worthir-artifact/tree/_en) | [简体中文](https://github.com/HongTianShi/worthir-artifact/tree/zh-cn)
|
|
17
|
+
|
|
18
|
+
[](https://github.com/HongTianShi/worthir-artifact/actions/workflows/validate.yml)
|
|
19
|
+

|
|
20
|
+
[](LICENSE)
|
|
21
|
+
|
|
22
|
+
WorthIR compares query-level routing policies with fixed retrieval strategies
|
|
23
|
+
under a declared effectiveness measure and cost profile. It reports
|
|
24
|
+
effectiveness, cost, utility, regret, and the fixed-route Pareto curve.
|
|
25
|
+
|
|
26
|
+
If you are an AI tool, read [`README_FOR_AI.md`](README_FOR_AI.md) before
|
|
27
|
+
searching the repository.
|
|
28
|
+
|
|
29
|
+
## 60-second demo
|
|
30
|
+
|
|
31
|
+
Python 3.10 or newer is required. Choose one installation path.
|
|
32
|
+
|
|
33
|
+
**Source archive or Git clone:** run the local launcher. It creates the local
|
|
34
|
+
environment when first needed.
|
|
35
|
+
|
|
36
|
+
```powershell
|
|
37
|
+
.\worthir.cmd demo-custom
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
./worthir demo-custom
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Installed wheel:** install the wheel, then use the global command.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python -m pip install worthir_eval-1.2.0-py3-none-any.whl
|
|
48
|
+
worthir demo-custom
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Do not run both setup paths. Open `reproduced/custom_task/comparison.md` after
|
|
52
|
+
the command finishes. The published wheel uses English terminal messages; the
|
|
53
|
+
Chinese source branch provides Chinese launchers and documentation.
|
|
54
|
+
|
|
55
|
+
## Use your own task
|
|
56
|
+
|
|
57
|
+
Prepare `task.json`, `queries.csv`, `routes.csv`, and `outcomes.csv` as shown in
|
|
58
|
+
[`examples/custom_task/source/`](examples/custom_task/source/), then run:
|
|
59
|
+
|
|
60
|
+
```powershell
|
|
61
|
+
.\worthir.cmd build-custom my_source my_task
|
|
62
|
+
.\worthir.cmd validate-task my_task
|
|
63
|
+
.\worthir.cmd evaluate my_task choices.csv --policy-id my-router
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
This path accepts any named higher-is-better effectiveness measure, arbitrary
|
|
67
|
+
route prerequisites, fixed or query-dependent costs, and either cumulative or
|
|
68
|
+
incremental cost input. The router receives `queries.csv`, the public route
|
|
69
|
+
registry, lambda, and any costs declared as known at commitment time. Evaluator
|
|
70
|
+
outcomes and costs measured only after execution remain separate.
|
|
71
|
+
|
|
72
|
+
For qrels and six-column TREC runs, use the shorter [`build-trec` walkthrough](examples/trec_walkthrough/README.md).
|
|
73
|
+
All input formats are described in [`docs/ADAPT_TO_NEW_TASK.md`](docs/ADAPT_TO_NEW_TASK.md).
|
|
74
|
+
For direct library use, see the
|
|
75
|
+
[`worthir_eval` Python example](examples/python_api/README.md).
|
|
76
|
+
|
|
77
|
+
## Recompute the paper results
|
|
78
|
+
|
|
79
|
+
This uses released query--route ledgers and frozen route selections. It does
|
|
80
|
+
not redownload corpora or rerun retrieval models.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
python paper_results/run.py
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Open [`paper_results/reproduced/INDEX.md`](paper_results/reproduced/INDEX.md).
|
|
87
|
+
The index names the exact paper version, caption, output, and reproduction
|
|
88
|
+
level for every main-paper and appendix figure or table.
|
|
89
|
+
|
|
90
|
+
## Rebuild the original retrieval routes
|
|
91
|
+
|
|
92
|
+
This is a separate, resource-intensive workflow. It checks licensed corpora
|
|
93
|
+
and checkpoints, invokes a configured task adapter, and constructs new
|
|
94
|
+
query--route ledgers through five explicit stages. Start with
|
|
95
|
+
[`paper_results/full_replay/README.md`](paper_results/full_replay/README.md) and
|
|
96
|
+
its task-specific resource estimates. Raw corpora, indexes, and model weights
|
|
97
|
+
are not included in this repository.
|
|
98
|
+
|
|
99
|
+
The [`v1.2.0`](https://github.com/HongTianShi/worthir-artifact/releases/tag/v1.2.0)
|
|
100
|
+
release is the published artifact currently bound to the 2026-08-16 paper
|
|
101
|
+
mapping. The earlier `v1.0.0-ipmc2026` release remains the artifact submitted
|
|
102
|
+
with the accepted IP&MC 2026 paper.
|
|
103
|
+
|
|
104
|
+
WorthIR-authored code is released under the [MIT License](LICENSE). Third-party
|
|
105
|
+
data and model terms are listed in [NOTICE](NOTICE).
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# WorthIR
|
|
2
|
+
|
|
3
|
+
[English](https://github.com/HongTianShi/worthir-artifact/tree/_en) | [简体中文](https://github.com/HongTianShi/worthir-artifact/tree/zh-cn)
|
|
4
|
+
|
|
5
|
+
[](https://github.com/HongTianShi/worthir-artifact/actions/workflows/validate.yml)
|
|
6
|
+

|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
WorthIR compares query-level routing policies with fixed retrieval strategies
|
|
10
|
+
under a declared effectiveness measure and cost profile. It reports
|
|
11
|
+
effectiveness, cost, utility, regret, and the fixed-route Pareto curve.
|
|
12
|
+
|
|
13
|
+
If you are an AI tool, read [`README_FOR_AI.md`](README_FOR_AI.md) before
|
|
14
|
+
searching the repository.
|
|
15
|
+
|
|
16
|
+
## 60-second demo
|
|
17
|
+
|
|
18
|
+
Python 3.10 or newer is required. Choose one installation path.
|
|
19
|
+
|
|
20
|
+
**Source archive or Git clone:** run the local launcher. It creates the local
|
|
21
|
+
environment when first needed.
|
|
22
|
+
|
|
23
|
+
```powershell
|
|
24
|
+
.\worthir.cmd demo-custom
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
./worthir demo-custom
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Installed wheel:** install the wheel, then use the global command.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
python -m pip install worthir_eval-1.2.0-py3-none-any.whl
|
|
35
|
+
worthir demo-custom
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Do not run both setup paths. Open `reproduced/custom_task/comparison.md` after
|
|
39
|
+
the command finishes. The published wheel uses English terminal messages; the
|
|
40
|
+
Chinese source branch provides Chinese launchers and documentation.
|
|
41
|
+
|
|
42
|
+
## Use your own task
|
|
43
|
+
|
|
44
|
+
Prepare `task.json`, `queries.csv`, `routes.csv`, and `outcomes.csv` as shown in
|
|
45
|
+
[`examples/custom_task/source/`](examples/custom_task/source/), then run:
|
|
46
|
+
|
|
47
|
+
```powershell
|
|
48
|
+
.\worthir.cmd build-custom my_source my_task
|
|
49
|
+
.\worthir.cmd validate-task my_task
|
|
50
|
+
.\worthir.cmd evaluate my_task choices.csv --policy-id my-router
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
This path accepts any named higher-is-better effectiveness measure, arbitrary
|
|
54
|
+
route prerequisites, fixed or query-dependent costs, and either cumulative or
|
|
55
|
+
incremental cost input. The router receives `queries.csv`, the public route
|
|
56
|
+
registry, lambda, and any costs declared as known at commitment time. Evaluator
|
|
57
|
+
outcomes and costs measured only after execution remain separate.
|
|
58
|
+
|
|
59
|
+
For qrels and six-column TREC runs, use the shorter [`build-trec` walkthrough](examples/trec_walkthrough/README.md).
|
|
60
|
+
All input formats are described in [`docs/ADAPT_TO_NEW_TASK.md`](docs/ADAPT_TO_NEW_TASK.md).
|
|
61
|
+
For direct library use, see the
|
|
62
|
+
[`worthir_eval` Python example](examples/python_api/README.md).
|
|
63
|
+
|
|
64
|
+
## Recompute the paper results
|
|
65
|
+
|
|
66
|
+
This uses released query--route ledgers and frozen route selections. It does
|
|
67
|
+
not redownload corpora or rerun retrieval models.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
python paper_results/run.py
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Open [`paper_results/reproduced/INDEX.md`](paper_results/reproduced/INDEX.md).
|
|
74
|
+
The index names the exact paper version, caption, output, and reproduction
|
|
75
|
+
level for every main-paper and appendix figure or table.
|
|
76
|
+
|
|
77
|
+
## Rebuild the original retrieval routes
|
|
78
|
+
|
|
79
|
+
This is a separate, resource-intensive workflow. It checks licensed corpora
|
|
80
|
+
and checkpoints, invokes a configured task adapter, and constructs new
|
|
81
|
+
query--route ledgers through five explicit stages. Start with
|
|
82
|
+
[`paper_results/full_replay/README.md`](paper_results/full_replay/README.md) and
|
|
83
|
+
its task-specific resource estimates. Raw corpora, indexes, and model weights
|
|
84
|
+
are not included in this repository.
|
|
85
|
+
|
|
86
|
+
The [`v1.2.0`](https://github.com/HongTianShi/worthir-artifact/releases/tag/v1.2.0)
|
|
87
|
+
release is the published artifact currently bound to the 2026-08-16 paper
|
|
88
|
+
mapping. The earlier `v1.0.0-ipmc2026` release remains the artifact submitted
|
|
89
|
+
with the accepted IP&MC 2026 paper.
|
|
90
|
+
|
|
91
|
+
WorthIR-authored code is released under the [MIT License](LICENSE). Third-party
|
|
92
|
+
data and model terms are listed in [NOTICE](NOTICE).
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Example contracts
|
|
2
|
+
|
|
3
|
+
These files define the six-query smoke test. For a new task, use
|
|
4
|
+
`worthir build-custom`, or use `worthir build-trec` for qrels and TREC runs;
|
|
5
|
+
both create a bound contract and route registry.
|
|
6
|
+
|
|
7
|
+
The public interface fixes five invariants: higher effectiveness is better, the
|
|
8
|
+
ledger contains every query--route pair, costs are nonnegative and cumulative,
|
|
9
|
+
their decision-time availability is explicit, and oracle ties prefer lower cost
|
|
10
|
+
then registry order. Fixed commitment-time costs live on registered routes;
|
|
11
|
+
query-dependent commitment-time costs live in `participant/route_costs.csv`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Bundled quickstart contracts."""
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": "worthir-contract-v1.0",
|
|
3
|
+
"contract_id": "worthir-quickstart-v1",
|
|
4
|
+
"task_id": "worthir-synthetic-route-choice-v1",
|
|
5
|
+
"expected_query_count": 6,
|
|
6
|
+
"route_registry": "route_registry.json",
|
|
7
|
+
"development_selected_fixed_route": "dense",
|
|
8
|
+
"action_schema": {
|
|
9
|
+
"schema_version": "worthir-action-file-v1.0",
|
|
10
|
+
"top_level_fields": [
|
|
11
|
+
"schema_version",
|
|
12
|
+
"contract_id",
|
|
13
|
+
"policy_id",
|
|
14
|
+
"decisions"
|
|
15
|
+
],
|
|
16
|
+
"decision_fields": [
|
|
17
|
+
"query_uid",
|
|
18
|
+
"selected_route_id"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"ledger_schema": {
|
|
22
|
+
"columns": [
|
|
23
|
+
"query_uid",
|
|
24
|
+
"route_id",
|
|
25
|
+
"effectiveness",
|
|
26
|
+
"cost"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"metric": {
|
|
30
|
+
"name": "synthetic_ndcg_at_10",
|
|
31
|
+
"minimum": 0.0,
|
|
32
|
+
"maximum": 1.0
|
|
33
|
+
},
|
|
34
|
+
"cost_profile": {
|
|
35
|
+
"profile_id": "synthetic_declared_schedule-v1",
|
|
36
|
+
"provenance": "declared",
|
|
37
|
+
"lambda": 0.08,
|
|
38
|
+
"availability": "known_at_commitment"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"registry_id": "worthir-quickstart-routes-v1",
|
|
3
|
+
"cost_information": {
|
|
4
|
+
"availability": "known_at_commitment",
|
|
5
|
+
"mode": "fixed",
|
|
6
|
+
"route_costs_file": null
|
|
7
|
+
},
|
|
8
|
+
"routes": [
|
|
9
|
+
{
|
|
10
|
+
"label": "Stop after BM25",
|
|
11
|
+
"prerequisites": [],
|
|
12
|
+
"route_id": "bm25",
|
|
13
|
+
"cost": 0.0
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"label": "Dense candidate fusion",
|
|
17
|
+
"prerequisites": ["bm25"],
|
|
18
|
+
"route_id": "dense",
|
|
19
|
+
"cost": 0.2
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"label": "Cross-encoder rerank top 20",
|
|
23
|
+
"prerequisites": ["dense"],
|
|
24
|
+
"route_id": "ce20",
|
|
25
|
+
"cost": 0.8
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"schema_version": "worthir-route-registry-v1.2"
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Runnable examples bundled with the WorthIR wheel."""
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Bring your own router
|
|
2
|
+
|
|
3
|
+
Run the complete example from the repository root:
|
|
4
|
+
|
|
5
|
+
```powershell
|
|
6
|
+
.\worthir.cmd demo-custom
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
./worthir demo-custom
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The example builds a non-TREC task, runs `router.py`, binds its CSV decisions to
|
|
14
|
+
the task contract, and compares the router with every fixed route. The report is
|
|
15
|
+
written to `reproduced/custom_task/comparison.md`.
|
|
16
|
+
|
|
17
|
+
`router.py` reads the public task contract, route registry, lambda,
|
|
18
|
+
`participant/legal_state.csv`, and `participant/route_costs.csv`. It selects the
|
|
19
|
+
route with the highest predicted effectiveness minus lambda times public cost.
|
|
20
|
+
It never opens `evaluator/ledger.csv`, which contains information unavailable
|
|
21
|
+
when a route is selected. To use your own router, replace
|
|
22
|
+
`predicted_effectiveness()` and keep the two-column output format:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
query_uid,selected_route_id
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
For an existing task, evaluate that CSV in one command:
|
|
29
|
+
|
|
30
|
+
```powershell
|
|
31
|
+
.\worthir.cmd evaluate TASK choices.csv --policy-id my-router
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
./worthir evaluate TASK choices.csv --policy-id my-router
|
|
36
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""External-router walkthrough."""
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Cost-aware router using only participant-visible task files."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import csv
|
|
8
|
+
import json
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def read_json(path: Path) -> dict:
|
|
13
|
+
return json.loads(path.read_text(encoding="utf-8"))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def public_costs(task: Path, registry: dict) -> dict[tuple[str, str], float]:
|
|
17
|
+
info = registry["cost_information"]
|
|
18
|
+
if info["availability"] != "known_at_commitment":
|
|
19
|
+
raise ValueError("this router requires costs known at commitment time")
|
|
20
|
+
if info["mode"] == "fixed":
|
|
21
|
+
return {
|
|
22
|
+
("*", route["route_id"]): float(route["cost"])
|
|
23
|
+
for route in registry["routes"]
|
|
24
|
+
}
|
|
25
|
+
path = (task / "contracts" / info["route_costs_file"]).resolve()
|
|
26
|
+
with path.open("r", encoding="utf-8-sig", newline="") as stream:
|
|
27
|
+
return {
|
|
28
|
+
(row["query_uid"], row["route_id"]): float(row["cost"])
|
|
29
|
+
for row in csv.DictReader(stream)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def predicted_effectiveness(row: dict[str, str], route_id: str) -> float:
|
|
34
|
+
"""Replace these estimates with predictions from your own router."""
|
|
35
|
+
|
|
36
|
+
length = int(row["question_length"])
|
|
37
|
+
product_code = row["contains_product_code"].lower() == "true"
|
|
38
|
+
if route_id == "keyword_search":
|
|
39
|
+
return 0.86 if length <= 12 and not product_code else 0.58
|
|
40
|
+
if route_id == "semantic_search":
|
|
41
|
+
return 0.90 if length > 20 else 0.79
|
|
42
|
+
if route_id == "combined_review":
|
|
43
|
+
return 0.95 if product_code else 0.87
|
|
44
|
+
return 0.0
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def route(task: Path, output: Path) -> Path:
|
|
48
|
+
contract = read_json(task / "contracts" / "task_contract.json")
|
|
49
|
+
registry = read_json(task / "contracts" / contract["route_registry"])
|
|
50
|
+
costs = public_costs(task, registry)
|
|
51
|
+
route_ids = [item["route_id"] for item in registry["routes"]]
|
|
52
|
+
lam = float(contract["cost_profile"]["lambda"])
|
|
53
|
+
with (task / "participant" / "legal_state.csv").open(
|
|
54
|
+
"r", encoding="utf-8-sig", newline=""
|
|
55
|
+
) as stream:
|
|
56
|
+
rows = list(csv.DictReader(stream))
|
|
57
|
+
|
|
58
|
+
decisions = []
|
|
59
|
+
for row in rows:
|
|
60
|
+
query_uid = row["query_uid"]
|
|
61
|
+
selected = max(
|
|
62
|
+
route_ids,
|
|
63
|
+
key=lambda route_id: (
|
|
64
|
+
predicted_effectiveness(row, route_id)
|
|
65
|
+
- lam * costs.get((query_uid, route_id), costs.get(("*", route_id))),
|
|
66
|
+
-route_ids.index(route_id),
|
|
67
|
+
),
|
|
68
|
+
)
|
|
69
|
+
decisions.append({"query_uid": query_uid, "selected_route_id": selected})
|
|
70
|
+
|
|
71
|
+
output.parent.mkdir(parents=True, exist_ok=True)
|
|
72
|
+
with output.open("w", encoding="utf-8", newline="") as stream:
|
|
73
|
+
writer = csv.DictWriter(
|
|
74
|
+
stream, fieldnames=["query_uid", "selected_route_id"]
|
|
75
|
+
)
|
|
76
|
+
writer.writeheader()
|
|
77
|
+
writer.writerows(decisions)
|
|
78
|
+
return output
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def main() -> None:
|
|
82
|
+
parser = argparse.ArgumentParser(
|
|
83
|
+
description="Create cost-aware choices without reading evaluator outcomes."
|
|
84
|
+
)
|
|
85
|
+
parser.add_argument("task_dir", type=Path, help="built WorthIR task directory")
|
|
86
|
+
parser.add_argument("output", type=Path, help="choice CSV to create")
|
|
87
|
+
args = parser.parse_args()
|
|
88
|
+
print(f"WROTE: {route(args.task_dir.resolve(), args.output.resolve())}")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
if __name__ == "__main__":
|
|
92
|
+
main()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Build the custom task, run the example router, and compare its utility."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import shutil
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
ROOT = Path(__file__).resolve().parents[2]
|
|
13
|
+
OUTPUT_ROOT = ROOT if (ROOT / "paper_results").is_dir() else Path.cwd()
|
|
14
|
+
DESTINATION = OUTPUT_ROOT / "reproduced" / "custom_task"
|
|
15
|
+
CHOICES = OUTPUT_ROOT / "reproduced" / "custom_router_choices.csv"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def run(*arguments: str) -> None:
|
|
19
|
+
launcher = (
|
|
20
|
+
[sys.executable, str(ROOT / "worthir.py")]
|
|
21
|
+
if (ROOT / "worthir.py").is_file()
|
|
22
|
+
else [sys.executable, "-m", "worthir"]
|
|
23
|
+
)
|
|
24
|
+
completed = subprocess.run([*launcher, *arguments])
|
|
25
|
+
if completed.returncode:
|
|
26
|
+
raise SystemExit(completed.returncode)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def main() -> None:
|
|
30
|
+
if DESTINATION.exists():
|
|
31
|
+
shutil.rmtree(DESTINATION)
|
|
32
|
+
run(
|
|
33
|
+
"build-custom",
|
|
34
|
+
str(ROOT / "examples" / "custom_task" / "source"),
|
|
35
|
+
str(DESTINATION),
|
|
36
|
+
)
|
|
37
|
+
subprocess.run(
|
|
38
|
+
[
|
|
39
|
+
sys.executable,
|
|
40
|
+
str(Path(__file__).with_name("router.py")),
|
|
41
|
+
str(DESTINATION),
|
|
42
|
+
str(CHOICES),
|
|
43
|
+
],
|
|
44
|
+
check=True,
|
|
45
|
+
)
|
|
46
|
+
run(
|
|
47
|
+
"evaluate",
|
|
48
|
+
str(DESTINATION),
|
|
49
|
+
str(CHOICES),
|
|
50
|
+
"--policy-id",
|
|
51
|
+
"example-rule-router",
|
|
52
|
+
)
|
|
53
|
+
print(f"OPEN: {DESTINATION / 'comparison.md'}")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if __name__ == "__main__":
|
|
57
|
+
main()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Custom task input
|
|
2
|
+
|
|
3
|
+
This example is not a TREC ranking task. Its effectiveness measure is
|
|
4
|
+
`answer_coverage`, and its execution cost varies by query.
|
|
5
|
+
|
|
6
|
+
The four source files are the complete generic adapter interface:
|
|
7
|
+
|
|
8
|
+
- `task.json` names the effectiveness measure and cost profile.
|
|
9
|
+
- `queries.csv` contains only information a router may use.
|
|
10
|
+
- `routes.csv` defines available routes, prerequisites, and route costs.
|
|
11
|
+
- `outcomes.csv` contains evaluator-only effectiveness and cost outcomes for
|
|
12
|
+
every query--route pair.
|
|
13
|
+
|
|
14
|
+
Build and validate it from the repository root:
|
|
15
|
+
|
|
16
|
+
```powershell
|
|
17
|
+
.\worthir.cmd build-custom examples/custom_task/source reproduced/custom_task
|
|
18
|
+
.\worthir.cmd validate-task reproduced/custom_task
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
./worthir build-custom examples/custom_task/source reproduced/custom_task
|
|
23
|
+
./worthir validate-task reproduced/custom_task
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Use `cost` when cumulative route costs are already available. Use
|
|
27
|
+
`incremental_cost` when the tool should sum the transitive prerequisite closure.
|
|
28
|
+
Either column may appear in `outcomes.csv` to provide query-dependent values.
|
|
29
|
+
Set `cost_profile.availability` to `known_at_commitment` when the router may use
|
|
30
|
+
the cost before choosing a route. The builder then publishes fixed costs in the
|
|
31
|
+
route registry or query-dependent costs in `participant/route_costs.csv`. Use
|
|
32
|
+
`measured_after_execution` when cost is evaluator-only.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Generic non-TREC task example."""
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
query_uid,route_id,effectiveness,incremental_cost
|
|
2
|
+
faq-001,keyword_search,0.92,0.025
|
|
3
|
+
faq-001,semantic_search,0.88,0.105
|
|
4
|
+
faq-001,combined_review,0.94,0.070
|
|
5
|
+
faq-002,keyword_search,0.61,0.030
|
|
6
|
+
faq-002,semantic_search,0.84,0.115
|
|
7
|
+
faq-002,combined_review,0.96,0.075
|
|
8
|
+
faq-003,keyword_search,0.45,0.035
|
|
9
|
+
faq-003,semantic_search,0.81,0.140
|
|
10
|
+
faq-003,combined_review,0.93,0.095
|
|
11
|
+
faq-004,keyword_search,0.78,0.028
|
|
12
|
+
faq-004,semantic_search,0.80,0.110
|
|
13
|
+
faq-004,combined_review,0.91,0.080
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"task_id": "faq-answer-routing-v1",
|
|
3
|
+
"metric": {
|
|
4
|
+
"name": "answer_coverage",
|
|
5
|
+
"minimum": 0.0,
|
|
6
|
+
"maximum": 1.0,
|
|
7
|
+
"higher_is_better": true
|
|
8
|
+
},
|
|
9
|
+
"cost_profile": {
|
|
10
|
+
"profile_id": "measured-seconds-v1",
|
|
11
|
+
"provenance": "expected execution time estimated on an independent calibration set and available before route selection",
|
|
12
|
+
"lambda": 0.15,
|
|
13
|
+
"availability": "known_at_commitment"
|
|
14
|
+
},
|
|
15
|
+
"development_selected_fixed_route": "semantic_search"
|
|
16
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# TREC walkthrough
|
|
2
|
+
|
|
3
|
+
This is a tiny retrieval task in standard TREC formats. It demonstrates the
|
|
4
|
+
full human workflow without downloading data.
|
|
5
|
+
|
|
6
|
+
```powershell
|
|
7
|
+
.\worthir.cmd demo
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
./worthir demo
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The command computes NDCG@3 from `source/qrels.tsv` and the three TREC runs,
|
|
15
|
+
builds a WorthIR task, scores the supplied policy, evaluates every fixed route,
|
|
16
|
+
and writes `reproduced/trec_walkthrough/comparison.md`.
|
|
17
|
+
|
|
18
|
+
To try another policy after the demo:
|
|
19
|
+
|
|
20
|
+
```powershell
|
|
21
|
+
.\worthir.cmd actions reproduced/trec_walkthrough examples/trec_walkthrough/source/alternative_choices.csv --policy-id alternative
|
|
22
|
+
.\worthir.cmd compare reproduced/trec_walkthrough
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
./worthir actions reproduced/trec_walkthrough examples/trec_walkthrough/source/alternative_choices.csv --policy-id alternative
|
|
27
|
+
./worthir compare reproduced/trec_walkthrough
|
|
28
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""TREC task walkthrough."""
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
q1 Q0 d1 1 8.0 base
|
|
2
|
+
q1 Q0 x1 2 7.0 base
|
|
3
|
+
q1 Q0 d2 3 6.0 base
|
|
4
|
+
q2 Q0 x2 1 8.0 base
|
|
5
|
+
q2 Q0 d5 2 7.0 base
|
|
6
|
+
q2 Q0 d4 3 6.0 base
|
|
7
|
+
q3 Q0 d8 1 8.0 base
|
|
8
|
+
q3 Q0 x3 2 7.0 base
|
|
9
|
+
q3 Q0 d7 3 6.0 base
|
|
10
|
+
q4 Q0 d10 1 8.0 base
|
|
11
|
+
q4 Q0 d11 2 7.0 base
|
|
12
|
+
q4 Q0 x4 3 6.0 base
|