AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Scientific RL and SFT post-training for AI agents: build evals that can fail, simulate situations, judge checked against people, pass@1 with a 95% interval, train with GRPO/SFT/DPO, prove every gain on a held-out set. uv add whileai
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
• Simulate. Give it your agent's tools and prompt. It writes the
situations the agent will meet and runs them against a fake world that
fails on purpose.
• Grade. Your judge or a verifier scores every rollout. The judge is
checked against people before its scores count.
• Measure. One run proves nothing. Ask whether a change is real or
noise before you ship it or train on it.
• Select. Keep the rows that carry signal: the 20 to 80% band for RL,
the best completion for SFT, nothing that leaks into your eval set.
• Train.查看完整 README ↗verifiers environment, or train and
serve on the While platform.wai is While's whale and the alias of the whileai SDK: import whileai as wai.
Runs on your machine against your models. Every default cites its source. You
own the model, the data and the weights: the datasets are built from your
production traces, the model is an open model post-trained with SFT and RL, and
the trained weights are yours to download and serve anywhere.
uv add whileai
Python 3.10 to 3.13, two dependencies, typed. import whileai takes under
200 ms and never touches the network.
No key, no network. seeded_agent is a stand-in that misbehaves on a
labeled fraction of rollouts, so you can check that your judge catches
exactly those rows.
import whileai as wai
@wai.tool
def get_order(order_id: str) -> dict:
"""Look up an order by id."""
...
data = wai.simulate(
wai.seeded_agent([get_order]),
tools=[get_order],
system_prompt="Help customers with orders.",
simulator=False, # situations from templates, no model
mode="rl",
repeats=4,
repeat_policy="fixed",
budget=64,
)
scored = data.grade(judge=lambda row: {"reward": int(not row["seeded"])})
print(scored.pass_at)
rows = scored.select(mode="rl")
print(rows)
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)
rl selection: kept 27 of 64 rows
band 20%..80% pass rate: 0 asks dropped (0 too easy, 0 too hard)
unanimous groups dropped: 6; duplicates dropped: 27; truncated drop: 0
privileged leaks dropped: 4
groups kept: 10
hack scan: train
pass@1 is the pass rate over tasks with a bootstrap interval. pass^4 is
how often all four rollouts of a task pass. Headroom is pass@4 minus
pass@1, the gap an RL update could close. select prints what each gate
dropped and why; rows.export("train.jsonl") writes them trainer-ready.
import whileai as wai
@wai.tool
def get_order(order_id: str) -> dict:
"""Look up an order by id.""" # the function is the tool; its signature is the schema
...
wai.configure(agent=wai.OpenAI("gpt-4.1-mini"), judge=wai.Anthropic("claude-haiku-4-5"))
data = wai.simulate(tools=[get_order], system_prompt=POLICY, mode="rl", repeats=8)
scored = data.grade(wai.Judge(rubric=RUBRIC)) # or a verifier, or any callable
print(scored.pass_at) # pass@1 0.61 [0.54..0.68] | pass@8 0.93 | headroom 0.32
print(wai.judge_trust(scored.rows)) # does the judge agree with people
rows = scored.select(mode="rl") # the 20..80% band, unanimous groups dropped
rows.export("train.jsonl") # or rows.push("my-agent-rl-v1")
Every role is a model behind an endpoint. A call keyword beats
wai.configure, with wai.context(...) beats both, then the environment.
Unconfigured, every role uses the model While hosts on wai login.
wai.OpenAI("gpt-4.1-mini") # key=OPENAI_API_KEY
wai.Anthropic("claude-haiku-4-5") # key=ANTHROPIC_API_KEY
wai.Fireworks("accounts/fireworks/models/llama-v3p1-8b-instruct") # key=FIREWORKS_API_KEY
wai.models.Bedrock("us.anthropic.claude-haiku-4-5-20251001-v1:0") # your AWS account
wai.Endpoint("Qwen/Qwen3-4B", url="http://localhost:8000/v1") # vLLM, SGLang, TGI
wai.Ollama("llama3")
wai.Hosted() # the model While hosts
Your agent is any callable returning {"steps": [...], "final_text": "..."},
or a backend object. A tool is a typed function under @wai.tool; the
mock world answers its calls, faults first. No tools yet?
wai.simulations.draft_tools("a support agent that issues refunds").
Evals only? wai init-evals finds your agent, writes a judge and a
runner around it, and gives you a pass rate with a 95% interval and a CI
test that goes red on regression.
docs.while.ai/evals.
| Step | Call | What it computes | Refs |
|---|---|---|---|
| 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] |
| Grade | data.grade(Judge(rubric=)), verify.MathEqual, verify.CodeExec | reward per rollout under one contract; verifiable rewards | [4], [5] |
| Validate the judge | judge_trust, judge_probes | agreement and Cohen's kappa against human gold; length bias; exploit probes | [6], [7] |
| Measure | pass_at, compare, 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] |
| Select | scored.select(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] |
| 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] |
| Train and export | rows.export, export_environment, platform.train, platform.serve | loss masks; a verifiers environment for GRPO; hosted LoRA SFT, GRPO, DPO, RM | [1], [19], [20] |
The first name in each row is wai.<name>; the rest are at
wai.simulations.<name>. How each is computed:
docs.while.ai/concepts/engine.
runs=3 adds a noise band, and
delta_report refuses a change that sits inside twice the run-to-run
standard deviation. holdout_size says how many prompts you need at 80%
power; most evals are too small.select(mode="rl") keeps the 20 to
80% band [13]. Rows keep sampling logprobs for the importance ratio [21].MathEqual, CodeExec against hidden
tests, JSONSchema.loss_mask, so the trainer learns the agent's
turns and not tool output.load_spec hashes the spec into a
version. The judge is checked against the spec's own labels, and
preference pairs are length-matched so the model learns the trait, not
"longer is better" [7], [23], [24].hack_scan finds the feature
that predicts reward within a task, against a shuffled baseline [17].
judge_probes tries flattery and the other tricks a policy finds first
[18]. decontaminate applies the 80% n-gram rule against your eval set
[16].One script and a README each. All run in CI.
| Step | Recipes |
|---|---|
| 01-simulate | bring your own agent, verifiers, a traced coding agent |
| 02-measure | eval your agent, pass@k, reward hacking, safety evals |
| 03-select | the row schema, GRPO data with a gradient gate, character |
| 04-train | hosted loop, identity SFT, GRPO and DPO on Modal, text-to-SQL |
| 05-export | Hugging Face datasets and adapters |
| papers | one recent paper per recipe, the number it moved with its interval |
Optional. Sign in once; the same rows push to an account, train on hosted GPUs, and come back as an OpenAI-compatible endpoint.
import whileai as wai
wai.platform.login() # once; or wai.configure(api_key="zp_...")
v1 = rows.push("refunds-v1", holdout=0.2) # the selection, gated
run = wai.platform.train(v1["datasetId"], method="grpo", steps=200) # sft | grpo | dpo | rm
run.wait()
model = wai.platform.serve("refunds-v2", run) # OpenAI-compatible endpoint
wai login, agents, runs, verdict and promote do the same from
a terminal, all with --json. push refuses RL data with no mixed groups.
docs.while.ai/reference/platform.
uv sync --extra dev
uv run pytest
uv run ruff check . && uv run mypy && uv run ty check
CI runs Python 3.10 to 3.13, gates coverage at 90%, and runs every
recipe's smoke.sh. CONTRIBUTING.md.
@software{weiss2026whileai,
title = {whileai: post-training data and evaluation for tool-using agents},
author = {Weiss, Jacob},
year = {2026},
url = {https://github.com/whilehq/whileai-sdk}
}
Apache-2.0