whileai 0.65__tar.gz → 0.67__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.
- whileai-0.67/PKG-INFO +258 -0
- whileai-0.67/README.md +221 -0
- {whileai-0.65 → whileai-0.67}/pyproject.toml +3 -3
- {whileai-0.65 → whileai-0.67}/whileai/platform.py +116 -19
- whileai-0.67/whileai.egg-info/PKG-INFO +258 -0
- whileai-0.65/PKG-INFO +0 -1353
- whileai-0.65/README.md +0 -1316
- whileai-0.65/whileai.egg-info/PKG-INFO +0 -1353
- {whileai-0.65 → whileai-0.67}/LICENSE +0 -0
- {whileai-0.65 → whileai-0.67}/MANIFEST.in +0 -0
- {whileai-0.65 → whileai-0.67}/setup.cfg +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/__init__.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/_env.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/auth.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/cli.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/ingest.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/init_evals.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/py.typed +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/__init__.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/__main__.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/data.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/environment.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/export.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/__init__.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/actionspace.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/adapters.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/agents.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/anthropic_backend.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/coverage.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/diversity.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/embeddings.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/explore.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/generator.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/offline_agent.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/scenarios.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/generate/usage_meter.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/ingest/__init__.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/ingest/otel.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/ingest/platform.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/ingest/traces.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/monitor.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/py.typed +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/run/__init__.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/run/config.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/run/engine.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/run/rows.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/run/spec.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/schema.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/schemas/row-v1.json +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/__init__.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/agreement.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/audit.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/checklist.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/curriculum.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/delta.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/grade_llm.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/grading.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/grounding.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/hack_scan.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/hygiene.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/judge_trust.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/judging.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/labels.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/llm_judge.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/logprobs.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/markers.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/optimize.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/pairwise.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/passat.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/preflight.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/privileged.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/publish_gate.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/quality.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/reference.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/rubric.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/spec.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/stage.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/stats.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/style.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/score/trace.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/simulation.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/text.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/training.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/verify/__init__.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/verify/base.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/verify/code.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/verify/math.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/verify/structured.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/verify/text.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/world/__init__.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/simulations/world/sandbox.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/templates/__init__.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai/templates/evals.py +0 -0
- {whileai-0.65 → whileai-0.67}/whileai.egg-info/SOURCES.txt +0 -0
- {whileai-0.65 → whileai-0.67}/whileai.egg-info/dependency_links.txt +0 -0
- {whileai-0.65 → whileai-0.67}/whileai.egg-info/entry_points.txt +0 -0
- {whileai-0.65 → whileai-0.67}/whileai.egg-info/requires.txt +0 -0
- {whileai-0.65 → whileai-0.67}/whileai.egg-info/top_level.txt +0 -0
whileai-0.67/PKG-INFO
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: whileai
|
|
3
|
+
Version: 0.67
|
|
4
|
+
Summary: Post-training data and evaluation for tool-using LLM agents: simulate, grade, measure, select, train, export, with the checks from rlhfbook.com.
|
|
5
|
+
Author: Jacob Weiss
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/whilehq/whileai-sdk
|
|
8
|
+
Project-URL: Repository, https://github.com/whilehq/whileai-sdk
|
|
9
|
+
Project-URL: Issues, https://github.com/whilehq/whileai-sdk/issues
|
|
10
|
+
Project-URL: Datasets, https://huggingface.co/datasets/zero-proof-ai/agent-simulations
|
|
11
|
+
Keywords: zp,zeroproof,while,evals,agent-evals,rl,reinforcement-learning,grpo,synthetic-data,agents,tool-use,evaluation,simulation,llm
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: requests>=2.25.0
|
|
27
|
+
Requires-Dist: pydantic>=2.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff>=0.12; extra == "dev"
|
|
32
|
+
Requires-Dist: mypy>=1.16; extra == "dev"
|
|
33
|
+
Requires-Dist: types-requests; extra == "dev"
|
|
34
|
+
Provides-Extra: rl
|
|
35
|
+
Requires-Dist: verifiers>=0.3; (python_version >= "3.11" and python_version < "3.14") and extra == "rl"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
<p align="center">
|
|
39
|
+
<a href="https://while.ai">
|
|
40
|
+
<picture>
|
|
41
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/whilehq/whileai-sdk/main/docs/assets/wordmark-dark.png">
|
|
42
|
+
<img src="https://raw.githubusercontent.com/whilehq/whileai-sdk/main/docs/assets/wordmark-light.png" alt="while" width="300">
|
|
43
|
+
</picture>
|
|
44
|
+
</a>
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
<p align="center"><code>MID-TRAINING AND POST-TRAINING FOR LANGUAGE MODELS</code></p>
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
<a href="https://github.com/whilehq/whileai-sdk/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/whilehq/whileai-sdk/ci.yml?branch=main&label=ci&labelColor=0b1220&color=5cb08a" alt="CI"></a>
|
|
51
|
+
<a href="https://pypi.org/project/whileai/"><img src="https://img.shields.io/pypi/v/whileai?labelColor=0b1220&color=5cb08a" alt="PyPI"></a>
|
|
52
|
+
<a href="https://pypi.org/project/whileai/"><img src="https://img.shields.io/pypi/pyversions/whileai?labelColor=0b1220&color=3f8f6b" alt="Python"></a>
|
|
53
|
+
<a href="https://pypistats.org/packages/whileai"><img src="https://img.shields.io/pypi/dm/whileai?labelColor=0b1220&color=3f8f6b" alt="Downloads"></a>
|
|
54
|
+
<a href=".github/workflows/ci.yml"><img src="https://img.shields.io/badge/coverage-%E2%89%A5%2090%25%20gated-5cb08a?labelColor=0b1220" alt="Coverage gate"></a>
|
|
55
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-3f8f6b?labelColor=0b1220" alt="License"></a>
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
Post-training data and evaluation for tool-using language-model agents.
|
|
59
|
+
`whileai` simulates the situations an agent can meet, grades every rollout
|
|
60
|
+
under one judge contract, and turns graded rows into SFT, preference and
|
|
61
|
+
RL data with the checks the literature calls for. Each method cites its
|
|
62
|
+
source in [References](#references).
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
uv add whileai
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or `pip install whileai`. Python 3.10 to 3.13, one dependency, typed.
|
|
69
|
+
Formerly `zeroproof`; the old name still installs this package.
|
|
70
|
+
|
|
71
|
+
## Two ways in
|
|
72
|
+
|
|
73
|
+
**Evals and the harness, no training.** A pass rate with an interval, a
|
|
74
|
+
table of where the agent fails, and a check that turns red in CI.
|
|
75
|
+
`whileai init-evals` writes the harness around the agent it finds in your
|
|
76
|
+
project, `coverage_gap` names what your tests never reach, and
|
|
77
|
+
`compare_runs` says whether a prompt or tool edit helped on the same pinned
|
|
78
|
+
tasks. Start at [docs/evals.md](docs/evals.md).
|
|
79
|
+
|
|
80
|
+
**Post-training.** The same graded rows, selected and exported: the loop below.
|
|
81
|
+
|
|
82
|
+
## Sixty seconds, offline
|
|
83
|
+
|
|
84
|
+
No key, no network. The seeded agent misbehaves on a labeled fraction of
|
|
85
|
+
rollouts, so a judge that catches exactly those rows is a judge that works.
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
import whileai.simulations as wai
|
|
89
|
+
|
|
90
|
+
TOOLS = [
|
|
91
|
+
{
|
|
92
|
+
"type": "function",
|
|
93
|
+
"function": {
|
|
94
|
+
"name": "get_order",
|
|
95
|
+
"description": "Look up an order by id.",
|
|
96
|
+
"parameters": {
|
|
97
|
+
"type": "object",
|
|
98
|
+
"properties": {"order_id": {"type": "string"}},
|
|
99
|
+
"required": ["order_id"],
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
data = wai.simulate(
|
|
106
|
+
wai.seeded_agent(TOOLS),
|
|
107
|
+
tools=TOOLS,
|
|
108
|
+
system_prompt="Help customers with orders.",
|
|
109
|
+
simulator=False, # no model
|
|
110
|
+
mode="rl",
|
|
111
|
+
repeats=4,
|
|
112
|
+
repeat_policy="fixed",
|
|
113
|
+
budget=64,
|
|
114
|
+
)
|
|
115
|
+
scored = data.grade(judge=lambda row: {"reward": int(not row["seeded"])})
|
|
116
|
+
print(scored.pass_at)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
pass@1 0.67 [0.55..0.78] | pass^4 (pass_pow_k) 0.19 [0.00..0.38] | pass@4 1.00 [1.00..1.00] | headroom 0.33 (16 groups, k=4)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Your agent is a callable `agent(message) -> {"steps", "final_text"}` or a
|
|
124
|
+
model spec: `openai:<model>`, `anthropic:<model>`, `vllm:<model>@<url>`,
|
|
125
|
+
`ollama:<model>`. With no `agent=`, hosted Qwen runs on your key
|
|
126
|
+
(`whileai login`) and Phi-4 judges, so the judge is never the policy.
|
|
127
|
+
|
|
128
|
+
## The loop
|
|
129
|
+
|
|
130
|
+
| Step | Call | What it computes | Refs |
|
|
131
|
+
|---|---|---|---|
|
|
132
|
+
| Simulate | `simulate(agent, tools=, system_prompt=, mode="rl", repeats=k)` | covering array over tools, world state and user stance; k rollouts per prompt; scheduled tool faults | [2], [3] |
|
|
133
|
+
| Grade | `data.grade(judge=)`, `verify.MathEqual`, `verify.CodeExec` | reward per rollout under one contract; verifiable rewards | [4], [5] |
|
|
134
|
+
| Validate the judge | `judge_trust`, `judge_probes` | agreement and Cohen's kappa against human gold; length bias; exploit probes | [6], [7] |
|
|
135
|
+
| Measure | `pass_at`, `delta_report`, `eval_variance`, `holdout_size` | pass@1, pass^k, pass@k with bootstrap intervals over tasks; paired delta with a permutation p-value; noise band; power | [8], [9], [10], [11] |
|
|
136
|
+
| Select | `optimize(mode="rl"\|"sft")`, `build_preference_pairs`, `curriculum` | 20 to 80% difficulty band, unanimous-group drop, rejection sampling, length-matched pairs, curriculum | [12], [13], [14], [15] |
|
|
137
|
+
| Guard | `decontaminate`, `hack_scan`, `trace_markers`, `HackMonitor` | overlap with the eval set; reward-feature correlation within task against a shuffle floor; trajectory lies | [16], [17], [18] |
|
|
138
|
+
| Train and export | `export_dataset`, `export_environment`, `train`, `serve` | loss masks; a `verifiers` environment for GRPO; hosted LoRA SFT, GRPO, DPO, RM | [1], [19], [20] |
|
|
139
|
+
|
|
140
|
+
## The science
|
|
141
|
+
|
|
142
|
+
**Supervised fine-tuning.** `optimize(mode="sft")` is rejection sampling
|
|
143
|
+
[14], [16] with random selectors as the chance control. Rows carry a
|
|
144
|
+
per-message `loss_mask`, `unroll=True` trains each turn on the context it
|
|
145
|
+
had, and `format="trl"` is what `SFTTrainer` loads [1, ch. 4].
|
|
146
|
+
|
|
147
|
+
**RL with verifiable rewards.** A reward is a program where it can be [5].
|
|
148
|
+
`mode="rl"` probes each prompt twice and fills to k only where the group
|
|
149
|
+
splits: a unanimous group has zero advantage under a group-relative
|
|
150
|
+
baseline [19] (dynamic sampling [12]). `optimize(mode="rl")` keeps the 20
|
|
151
|
+
to 80% band [13] and handles overlong rollouts by policy [12].
|
|
152
|
+
`export_environment` writes tasks, world and reward as a `verifiers`
|
|
153
|
+
package. Rows carry logprobs for the importance ratio [21] and `mean_kl`
|
|
154
|
+
reads drift from a reference [22].
|
|
155
|
+
|
|
156
|
+
**Character training.** A constitution is a versioned object [23], [24]:
|
|
157
|
+
`load_spec` hashes its principles into `spec.version`, the judge is checked
|
|
158
|
+
against the spec's own labels, pairs are length-matched [7], and
|
|
159
|
+
`must_not_regress=spec.behaviors()` fails a run that traded one trait for
|
|
160
|
+
another. [docs/character-training.md](docs/character-training.md).
|
|
161
|
+
|
|
162
|
+
**Evaluation.** pass@1 is a bootstrap over tasks, not rollouts [8], [10],
|
|
163
|
+
[11]. `runs=3` replays an eval and `delta_report` refuses a verdict inside
|
|
164
|
+
twice the re-run standard deviation. `holdout_size` returns the prompts a
|
|
165
|
+
gain needs at 80% power [11]. `decontaminate` applies the 80% n-gram
|
|
166
|
+
coverage rule [16] and an optional embedding pass.
|
|
167
|
+
[docs/evals.md](docs/evals.md).
|
|
168
|
+
|
|
169
|
+
**Over-optimization.** Reward is a proxy and a strong optimizer finds the
|
|
170
|
+
gap [17]. `hack_scan` ranks reward-feature correlation within task against
|
|
171
|
+
a shuffle floor; `judge_probes` tries the exploits a policy finds first,
|
|
172
|
+
sycophancy included [18]; `delta_report(proxy=, target=)` fails when the
|
|
173
|
+
proxy rose and the target did not; `HackMonitor` runs the scan inside a
|
|
174
|
+
TRL loop. [docs/reward-hacking.md](docs/reward-hacking.md).
|
|
175
|
+
|
|
176
|
+
## Recipes
|
|
177
|
+
|
|
178
|
+
One post-training run as five steps; every recipe runs in CI.
|
|
179
|
+
|
|
180
|
+
| Step | Recipes |
|
|
181
|
+
|---|---|
|
|
182
|
+
| [01-simulate](recipes/01-simulate) | bring your own agent, verifiers, a traced coding agent |
|
|
183
|
+
| [02-measure](recipes/02-measure) | eval your agent, pass@k, reward hacking, safety evals |
|
|
184
|
+
| [03-select](recipes/03-select) | the row schema, GRPO data with a gradient gate, character |
|
|
185
|
+
| [04-train](recipes/04-train) | hosted loop, identity SFT, GRPO and DPO on Modal, text-to-SQL |
|
|
186
|
+
| [05-export](recipes/05-export) | Hugging Face datasets and adapters |
|
|
187
|
+
| [papers](recipes/papers) | one recent paper per recipe, the number it moved with its interval |
|
|
188
|
+
|
|
189
|
+
## Platform
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
v1 = data.push("refunds-v1", holdout=0.2, gate=True) # refuses gradient-free RL data
|
|
193
|
+
run = wai.train(v1["datasetId"], method="grpo", steps=200) # sft | grpo | dpo | rm
|
|
194
|
+
run.wait()
|
|
195
|
+
model = wai.serve("refunds-v2", run) # OpenAI-compatible endpoint
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Your own trainer reports through `wai.TrainerCallback`; production traces
|
|
199
|
+
come back as `traces=` and aim the next run at what failed.
|
|
200
|
+
|
|
201
|
+
## Documentation
|
|
202
|
+
|
|
203
|
+
[docs/reference.md](docs/reference.md): every call, knob, report and gate.
|
|
204
|
+
[docs/engine.md](docs/engine.md): how a row is made.
|
|
205
|
+
[CHANGELOG.md](CHANGELOG.md): one entry per release.
|
|
206
|
+
|
|
207
|
+
## Development
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
uv sync --extra dev
|
|
211
|
+
uv run pytest
|
|
212
|
+
uv run ruff check . && uv run mypy
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
CI gates coverage at 90% and runs every recipe's `smoke.sh`.
|
|
216
|
+
[CONTRIBUTING.md](CONTRIBUTING.md).
|
|
217
|
+
|
|
218
|
+
## Cite
|
|
219
|
+
|
|
220
|
+
```bibtex
|
|
221
|
+
@software{weiss2026whileai,
|
|
222
|
+
title = {whileai: post-training data and evaluation for tool-using agents},
|
|
223
|
+
author = {Weiss, Jacob},
|
|
224
|
+
year = {2026},
|
|
225
|
+
url = {https://github.com/whilehq/whileai-sdk}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## References
|
|
230
|
+
|
|
231
|
+
1. Lambert, N. *Reinforcement Learning from Human Feedback*. arXiv:2504.12501, 2025.
|
|
232
|
+
2. Kuhn, D. R., Wallace, D. R., Gallo, A. M. Software Fault Interactions and Implications for Software Testing. *IEEE TSE* 30(6), 2004.
|
|
233
|
+
3. Yao, S. et al. τ-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains. arXiv:2406.12045, 2024.
|
|
234
|
+
4. Ouyang, L. et al. Training Language Models to Follow Instructions with Human Feedback. NeurIPS, 2022.
|
|
235
|
+
5. Lambert, N. et al. Tülu 3: Pushing Frontiers in Open Language Model Post-Training. arXiv:2411.15124, 2024.
|
|
236
|
+
6. Cohen, J. A Coefficient of Agreement for Nominal Scales. *Educational and Psychological Measurement* 20(1), 1960.
|
|
237
|
+
7. Zheng, L. et al. Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena. NeurIPS, 2023.
|
|
238
|
+
8. Chen, M. et al. Evaluating Large Language Models Trained on Code. arXiv:2107.03374, 2021.
|
|
239
|
+
9. Wilson, E. B. Probable Inference, the Law of Succession, and Statistical Inference. *JASA* 22(158), 1927.
|
|
240
|
+
10. Efron, B., Tibshirani, R. J. *An Introduction to the Bootstrap*. Chapman & Hall, 1993.
|
|
241
|
+
11. Miller, E. Adding Error Bars to Evals. arXiv:2411.00640, 2024.
|
|
242
|
+
12. Yu, Q. et al. DAPO: An Open-Source LLM Reinforcement Learning System at Scale. arXiv:2503.14476, 2025.
|
|
243
|
+
13. He, J. et al. Skywork Open Reasoner 1 Technical Report. arXiv:2505.22312, 2025.
|
|
244
|
+
14. Yuan, Z. et al. Scaling Relationship on Learning Mathematical Reasoning with Large Language Models. arXiv:2308.01825, 2023.
|
|
245
|
+
15. Rafailov, R. et al. Direct Preference Optimization. NeurIPS, 2023.
|
|
246
|
+
16. Touvron, H. et al. Llama 2: Open Foundation and Fine-Tuned Chat Models. arXiv:2307.09288, 2023.
|
|
247
|
+
17. Gao, L., Schulman, J., Hilton, J. Scaling Laws for Reward Model Overoptimization. ICML, 2023.
|
|
248
|
+
18. Sharma, M. et al. Towards Understanding Sycophancy in Language Models. ICLR, 2024.
|
|
249
|
+
19. Shao, Z. et al. DeepSeekMath. arXiv:2402.03300, 2024.
|
|
250
|
+
20. DeepSeek-AI. DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning. arXiv:2501.12948, 2025.
|
|
251
|
+
21. Schulman, J. et al. Proximal Policy Optimization Algorithms. arXiv:1707.06347, 2017.
|
|
252
|
+
22. Ziegler, D. M. et al. Fine-Tuning Language Models from Human Preferences. arXiv:1909.08593, 2019.
|
|
253
|
+
23. Bai, Y. et al. Constitutional AI: Harmlessness from AI Feedback. arXiv:2212.08073, 2022.
|
|
254
|
+
24. OpenAI. Model Spec, 2024. model-spec.openai.com.
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
Apache-2.0
|
whileai-0.67/README.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://while.ai">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/whilehq/whileai-sdk/main/docs/assets/wordmark-dark.png">
|
|
5
|
+
<img src="https://raw.githubusercontent.com/whilehq/whileai-sdk/main/docs/assets/wordmark-light.png" alt="while" width="300">
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center"><code>MID-TRAINING AND POST-TRAINING FOR LANGUAGE MODELS</code></p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://github.com/whilehq/whileai-sdk/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/whilehq/whileai-sdk/ci.yml?branch=main&label=ci&labelColor=0b1220&color=5cb08a" alt="CI"></a>
|
|
14
|
+
<a href="https://pypi.org/project/whileai/"><img src="https://img.shields.io/pypi/v/whileai?labelColor=0b1220&color=5cb08a" alt="PyPI"></a>
|
|
15
|
+
<a href="https://pypi.org/project/whileai/"><img src="https://img.shields.io/pypi/pyversions/whileai?labelColor=0b1220&color=3f8f6b" alt="Python"></a>
|
|
16
|
+
<a href="https://pypistats.org/packages/whileai"><img src="https://img.shields.io/pypi/dm/whileai?labelColor=0b1220&color=3f8f6b" alt="Downloads"></a>
|
|
17
|
+
<a href=".github/workflows/ci.yml"><img src="https://img.shields.io/badge/coverage-%E2%89%A5%2090%25%20gated-5cb08a?labelColor=0b1220" alt="Coverage gate"></a>
|
|
18
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-3f8f6b?labelColor=0b1220" alt="License"></a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
Post-training data and evaluation for tool-using language-model agents.
|
|
22
|
+
`whileai` simulates the situations an agent can meet, grades every rollout
|
|
23
|
+
under one judge contract, and turns graded rows into SFT, preference and
|
|
24
|
+
RL data with the checks the literature calls for. Each method cites its
|
|
25
|
+
source in [References](#references).
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uv add whileai
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Or `pip install whileai`. Python 3.10 to 3.13, one dependency, typed.
|
|
32
|
+
Formerly `zeroproof`; the old name still installs this package.
|
|
33
|
+
|
|
34
|
+
## Two ways in
|
|
35
|
+
|
|
36
|
+
**Evals and the harness, no training.** A pass rate with an interval, a
|
|
37
|
+
table of where the agent fails, and a check that turns red in CI.
|
|
38
|
+
`whileai init-evals` writes the harness around the agent it finds in your
|
|
39
|
+
project, `coverage_gap` names what your tests never reach, and
|
|
40
|
+
`compare_runs` says whether a prompt or tool edit helped on the same pinned
|
|
41
|
+
tasks. Start at [docs/evals.md](docs/evals.md).
|
|
42
|
+
|
|
43
|
+
**Post-training.** The same graded rows, selected and exported: the loop below.
|
|
44
|
+
|
|
45
|
+
## Sixty seconds, offline
|
|
46
|
+
|
|
47
|
+
No key, no network. The seeded agent misbehaves on a labeled fraction of
|
|
48
|
+
rollouts, so a judge that catches exactly those rows is a judge that works.
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
import whileai.simulations as wai
|
|
52
|
+
|
|
53
|
+
TOOLS = [
|
|
54
|
+
{
|
|
55
|
+
"type": "function",
|
|
56
|
+
"function": {
|
|
57
|
+
"name": "get_order",
|
|
58
|
+
"description": "Look up an order by id.",
|
|
59
|
+
"parameters": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"properties": {"order_id": {"type": "string"}},
|
|
62
|
+
"required": ["order_id"],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
data = wai.simulate(
|
|
69
|
+
wai.seeded_agent(TOOLS),
|
|
70
|
+
tools=TOOLS,
|
|
71
|
+
system_prompt="Help customers with orders.",
|
|
72
|
+
simulator=False, # no model
|
|
73
|
+
mode="rl",
|
|
74
|
+
repeats=4,
|
|
75
|
+
repeat_policy="fixed",
|
|
76
|
+
budget=64,
|
|
77
|
+
)
|
|
78
|
+
scored = data.grade(judge=lambda row: {"reward": int(not row["seeded"])})
|
|
79
|
+
print(scored.pass_at)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
pass@1 0.67 [0.55..0.78] | pass^4 (pass_pow_k) 0.19 [0.00..0.38] | pass@4 1.00 [1.00..1.00] | headroom 0.33 (16 groups, k=4)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Your agent is a callable `agent(message) -> {"steps", "final_text"}` or a
|
|
87
|
+
model spec: `openai:<model>`, `anthropic:<model>`, `vllm:<model>@<url>`,
|
|
88
|
+
`ollama:<model>`. With no `agent=`, hosted Qwen runs on your key
|
|
89
|
+
(`whileai login`) and Phi-4 judges, so the judge is never the policy.
|
|
90
|
+
|
|
91
|
+
## The loop
|
|
92
|
+
|
|
93
|
+
| Step | Call | What it computes | Refs |
|
|
94
|
+
|---|---|---|---|
|
|
95
|
+
| Simulate | `simulate(agent, tools=, system_prompt=, mode="rl", repeats=k)` | covering array over tools, world state and user stance; k rollouts per prompt; scheduled tool faults | [2], [3] |
|
|
96
|
+
| Grade | `data.grade(judge=)`, `verify.MathEqual`, `verify.CodeExec` | reward per rollout under one contract; verifiable rewards | [4], [5] |
|
|
97
|
+
| Validate the judge | `judge_trust`, `judge_probes` | agreement and Cohen's kappa against human gold; length bias; exploit probes | [6], [7] |
|
|
98
|
+
| Measure | `pass_at`, `delta_report`, `eval_variance`, `holdout_size` | pass@1, pass^k, pass@k with bootstrap intervals over tasks; paired delta with a permutation p-value; noise band; power | [8], [9], [10], [11] |
|
|
99
|
+
| Select | `optimize(mode="rl"\|"sft")`, `build_preference_pairs`, `curriculum` | 20 to 80% difficulty band, unanimous-group drop, rejection sampling, length-matched pairs, curriculum | [12], [13], [14], [15] |
|
|
100
|
+
| Guard | `decontaminate`, `hack_scan`, `trace_markers`, `HackMonitor` | overlap with the eval set; reward-feature correlation within task against a shuffle floor; trajectory lies | [16], [17], [18] |
|
|
101
|
+
| Train and export | `export_dataset`, `export_environment`, `train`, `serve` | loss masks; a `verifiers` environment for GRPO; hosted LoRA SFT, GRPO, DPO, RM | [1], [19], [20] |
|
|
102
|
+
|
|
103
|
+
## The science
|
|
104
|
+
|
|
105
|
+
**Supervised fine-tuning.** `optimize(mode="sft")` is rejection sampling
|
|
106
|
+
[14], [16] with random selectors as the chance control. Rows carry a
|
|
107
|
+
per-message `loss_mask`, `unroll=True` trains each turn on the context it
|
|
108
|
+
had, and `format="trl"` is what `SFTTrainer` loads [1, ch. 4].
|
|
109
|
+
|
|
110
|
+
**RL with verifiable rewards.** A reward is a program where it can be [5].
|
|
111
|
+
`mode="rl"` probes each prompt twice and fills to k only where the group
|
|
112
|
+
splits: a unanimous group has zero advantage under a group-relative
|
|
113
|
+
baseline [19] (dynamic sampling [12]). `optimize(mode="rl")` keeps the 20
|
|
114
|
+
to 80% band [13] and handles overlong rollouts by policy [12].
|
|
115
|
+
`export_environment` writes tasks, world and reward as a `verifiers`
|
|
116
|
+
package. Rows carry logprobs for the importance ratio [21] and `mean_kl`
|
|
117
|
+
reads drift from a reference [22].
|
|
118
|
+
|
|
119
|
+
**Character training.** A constitution is a versioned object [23], [24]:
|
|
120
|
+
`load_spec` hashes its principles into `spec.version`, the judge is checked
|
|
121
|
+
against the spec's own labels, pairs are length-matched [7], and
|
|
122
|
+
`must_not_regress=spec.behaviors()` fails a run that traded one trait for
|
|
123
|
+
another. [docs/character-training.md](docs/character-training.md).
|
|
124
|
+
|
|
125
|
+
**Evaluation.** pass@1 is a bootstrap over tasks, not rollouts [8], [10],
|
|
126
|
+
[11]. `runs=3` replays an eval and `delta_report` refuses a verdict inside
|
|
127
|
+
twice the re-run standard deviation. `holdout_size` returns the prompts a
|
|
128
|
+
gain needs at 80% power [11]. `decontaminate` applies the 80% n-gram
|
|
129
|
+
coverage rule [16] and an optional embedding pass.
|
|
130
|
+
[docs/evals.md](docs/evals.md).
|
|
131
|
+
|
|
132
|
+
**Over-optimization.** Reward is a proxy and a strong optimizer finds the
|
|
133
|
+
gap [17]. `hack_scan` ranks reward-feature correlation within task against
|
|
134
|
+
a shuffle floor; `judge_probes` tries the exploits a policy finds first,
|
|
135
|
+
sycophancy included [18]; `delta_report(proxy=, target=)` fails when the
|
|
136
|
+
proxy rose and the target did not; `HackMonitor` runs the scan inside a
|
|
137
|
+
TRL loop. [docs/reward-hacking.md](docs/reward-hacking.md).
|
|
138
|
+
|
|
139
|
+
## Recipes
|
|
140
|
+
|
|
141
|
+
One post-training run as five steps; every recipe runs in CI.
|
|
142
|
+
|
|
143
|
+
| Step | Recipes |
|
|
144
|
+
|---|---|
|
|
145
|
+
| [01-simulate](recipes/01-simulate) | bring your own agent, verifiers, a traced coding agent |
|
|
146
|
+
| [02-measure](recipes/02-measure) | eval your agent, pass@k, reward hacking, safety evals |
|
|
147
|
+
| [03-select](recipes/03-select) | the row schema, GRPO data with a gradient gate, character |
|
|
148
|
+
| [04-train](recipes/04-train) | hosted loop, identity SFT, GRPO and DPO on Modal, text-to-SQL |
|
|
149
|
+
| [05-export](recipes/05-export) | Hugging Face datasets and adapters |
|
|
150
|
+
| [papers](recipes/papers) | one recent paper per recipe, the number it moved with its interval |
|
|
151
|
+
|
|
152
|
+
## Platform
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
v1 = data.push("refunds-v1", holdout=0.2, gate=True) # refuses gradient-free RL data
|
|
156
|
+
run = wai.train(v1["datasetId"], method="grpo", steps=200) # sft | grpo | dpo | rm
|
|
157
|
+
run.wait()
|
|
158
|
+
model = wai.serve("refunds-v2", run) # OpenAI-compatible endpoint
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Your own trainer reports through `wai.TrainerCallback`; production traces
|
|
162
|
+
come back as `traces=` and aim the next run at what failed.
|
|
163
|
+
|
|
164
|
+
## Documentation
|
|
165
|
+
|
|
166
|
+
[docs/reference.md](docs/reference.md): every call, knob, report and gate.
|
|
167
|
+
[docs/engine.md](docs/engine.md): how a row is made.
|
|
168
|
+
[CHANGELOG.md](CHANGELOG.md): one entry per release.
|
|
169
|
+
|
|
170
|
+
## Development
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
uv sync --extra dev
|
|
174
|
+
uv run pytest
|
|
175
|
+
uv run ruff check . && uv run mypy
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
CI gates coverage at 90% and runs every recipe's `smoke.sh`.
|
|
179
|
+
[CONTRIBUTING.md](CONTRIBUTING.md).
|
|
180
|
+
|
|
181
|
+
## Cite
|
|
182
|
+
|
|
183
|
+
```bibtex
|
|
184
|
+
@software{weiss2026whileai,
|
|
185
|
+
title = {whileai: post-training data and evaluation for tool-using agents},
|
|
186
|
+
author = {Weiss, Jacob},
|
|
187
|
+
year = {2026},
|
|
188
|
+
url = {https://github.com/whilehq/whileai-sdk}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## References
|
|
193
|
+
|
|
194
|
+
1. Lambert, N. *Reinforcement Learning from Human Feedback*. arXiv:2504.12501, 2025.
|
|
195
|
+
2. Kuhn, D. R., Wallace, D. R., Gallo, A. M. Software Fault Interactions and Implications for Software Testing. *IEEE TSE* 30(6), 2004.
|
|
196
|
+
3. Yao, S. et al. τ-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains. arXiv:2406.12045, 2024.
|
|
197
|
+
4. Ouyang, L. et al. Training Language Models to Follow Instructions with Human Feedback. NeurIPS, 2022.
|
|
198
|
+
5. Lambert, N. et al. Tülu 3: Pushing Frontiers in Open Language Model Post-Training. arXiv:2411.15124, 2024.
|
|
199
|
+
6. Cohen, J. A Coefficient of Agreement for Nominal Scales. *Educational and Psychological Measurement* 20(1), 1960.
|
|
200
|
+
7. Zheng, L. et al. Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena. NeurIPS, 2023.
|
|
201
|
+
8. Chen, M. et al. Evaluating Large Language Models Trained on Code. arXiv:2107.03374, 2021.
|
|
202
|
+
9. Wilson, E. B. Probable Inference, the Law of Succession, and Statistical Inference. *JASA* 22(158), 1927.
|
|
203
|
+
10. Efron, B., Tibshirani, R. J. *An Introduction to the Bootstrap*. Chapman & Hall, 1993.
|
|
204
|
+
11. Miller, E. Adding Error Bars to Evals. arXiv:2411.00640, 2024.
|
|
205
|
+
12. Yu, Q. et al. DAPO: An Open-Source LLM Reinforcement Learning System at Scale. arXiv:2503.14476, 2025.
|
|
206
|
+
13. He, J. et al. Skywork Open Reasoner 1 Technical Report. arXiv:2505.22312, 2025.
|
|
207
|
+
14. Yuan, Z. et al. Scaling Relationship on Learning Mathematical Reasoning with Large Language Models. arXiv:2308.01825, 2023.
|
|
208
|
+
15. Rafailov, R. et al. Direct Preference Optimization. NeurIPS, 2023.
|
|
209
|
+
16. Touvron, H. et al. Llama 2: Open Foundation and Fine-Tuned Chat Models. arXiv:2307.09288, 2023.
|
|
210
|
+
17. Gao, L., Schulman, J., Hilton, J. Scaling Laws for Reward Model Overoptimization. ICML, 2023.
|
|
211
|
+
18. Sharma, M. et al. Towards Understanding Sycophancy in Language Models. ICLR, 2024.
|
|
212
|
+
19. Shao, Z. et al. DeepSeekMath. arXiv:2402.03300, 2024.
|
|
213
|
+
20. DeepSeek-AI. DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning. arXiv:2501.12948, 2025.
|
|
214
|
+
21. Schulman, J. et al. Proximal Policy Optimization Algorithms. arXiv:1707.06347, 2017.
|
|
215
|
+
22. Ziegler, D. M. et al. Fine-Tuning Language Models from Human Preferences. arXiv:1909.08593, 2019.
|
|
216
|
+
23. Bai, Y. et al. Constitutional AI: Harmlessness from AI Feedback. arXiv:2212.08073, 2022.
|
|
217
|
+
24. OpenAI. Model Spec, 2024. model-spec.openai.com.
|
|
218
|
+
|
|
219
|
+
## License
|
|
220
|
+
|
|
221
|
+
Apache-2.0
|
|
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "whileai"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "
|
|
7
|
+
version = "0.67"
|
|
8
|
+
description = "Post-training data and evaluation for tool-using LLM agents: simulate, grade, measure, select, train, export, with the checks from rlhfbook.com."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "Apache-2.0"}
|
|
11
11
|
requires-python = ">=3.10"
|
|
12
12
|
dependencies = ["requests>=2.25.0", "pydantic>=2.0"]
|
|
13
|
-
authors = [{name = "
|
|
13
|
+
authors = [{name = "Jacob Weiss"}]
|
|
14
14
|
keywords = [
|
|
15
15
|
"zp", "zeroproof", "while", "evals", "agent-evals",
|
|
16
16
|
"rl", "reinforcement-learning", "grpo", "synthetic-data", "agents",
|