Views
No views yet
| Part | Runs on | What changes | API cost during training? |
|---|---|---|---|
| Reward-data generation | OpenRouter/local workers | Nothing; records every worker's answer, score, cost, and latency | Yes, once per task × worker |
| SFT warm-start | Your GPU | Router LayerNorm + classification head | No |
| Contextual-bandit RL | Your GPU | Same small routing head | No |
| Sep-CMA-ES (optional) | CPU after one GPU embedding pass | Final linear routing layer | No |
| Inference | Your GPU + selected worker | Nothing | One worker call per prompt, unless fallback is needed |
Qwen/Qwen3-0.6B. With three workers, its trainable head is only a
few thousand parameters. The backbone stays frozen, so the project is practical on modest
GPUs. The exact memory depends on sequence length and software, but the default normally
fits comfortably above roughly 4 GiB of VRAM.1flowchart TD
2 A[BenchGen tasks] --> B[Call every worker once]
3 B --> C[Quality, cost, latency rewards]
4 C --> D[Reward matrix JSONL]
5 D --> E[SFT warm-start]
6 E --> F[Contextual-bandit RL]
7 F --> G[Optional Sep-CMA-ES]
8 G --> H[Local router checkpoint]
9 H --> I[Single API endpoint]
10 I --> J[Selected OpenRouter or local worker]python -c "import torch; print(torch.cuda.is_available())" already prints True, keep that installation.1unzip BenchGen_Fugu_Lite.zip
2cd fugu-lite
3python3 -m venv .venv
4source .venv/bin/activate
5python -m pip install --upgrade pip
6pip install -e '.[dev]'
7cp .env.example .env
8chmod 600 .env.env on the server and set OPENROUTER_API_KEY. Never paste the real key into source
code, YAML, a Git commit, or chat. Check the machine:fugu-lite doctor1fugu-lite generate \
2 --workers configs/workers.mock.yaml \
3 --tasks data/tasks.sample.jsonl \
4 --output data/rewards.mock.jsonlpytest -q1fugu-lite list-models --contains qwen --limit 30
2fugu-lite list-models --contains free --limit 30cp configs/workers.openrouter.example.yaml configs/workers.yamlopenai_compatible worker. Any server
that exposes /v1/chat/completions can be used; an example vLLM entry is already commented
in the YAML.{"task_id":"math-101","prompt":"Solve ...","domain":"math","reference_answer":"42","grader":{"type":"numeric","tolerance":0.0},"split":"train","tags":["algebra"]}exact, contains, numeric, and regex. For an open-ended
task, use llm_judge, add a clear grader.rubric, and configure reward.judge_model in the
worker YAML. LLM judging adds one judge call for each worker response and should be audited
on a human-labeled sample.prompt; only the grader sees
the reference answer. Keep benchmark test sets out of training. A useful first real run is:data/rewards.schema.example.jsonl. worker_ids order must remain identical in
every row, and rewards[i] must belong to worker_ids[i].1fugu-lite generate \
2 --workers configs/workers.yaml \
3 --tasks data/tasks.jsonl \
4 --output data/rewards.real.jsonl \
5 --limit 10--resume. The number of primary
calls is number_of_tasks × number_of_workers; llm_judge doubles that count. OpenRouter's
non-streaming usage object is recorded when it provides token and cost fields.1fugu-lite generate \
2 --workers configs/workers.yaml \
3 --tasks data/tasks.jsonl \
4 --output data/rewards.real.jsonl \
5 --resume1fugu-lite train-sft \
2 --config configs/train_sft.yaml \
3 --data data/rewards.real.jsonl \
4 --output artifacts/router-sft1fugu-lite train-rl \
2 --config configs/train_rl.yaml \
3 --data data/rewards.real.jsonl \
4 --checkpoint artifacts/router-sft \
5 --output artifacts/router-rlestimator: expected_reward in train_rl.yaml is lower variance.
For a closer analogue to the reported Sakana optimization style, optionally run separable
CMA-ES. It caches backbone features once and evolves only the last linear layer:1fugu-lite train-es \
2 --config configs/train_es.yaml \
3 --data data/rewards.real.jsonl \
4 --checkpoint artifacts/router-rl \
5 --output artifacts/router-es1fugu-lite evaluate \
2 --checkpoint artifacts/router-rl \
3 --data data/rewards.real.jsonl \
4 --split test \
5 --output artifacts/router-rl/test_metrics.json| Metric | Meaning |
|---|---|
router_utility | Mean reward obtained by the learned greedy route |
oracle_utility | Upper bound if the best worker were known for every task |
best_fixed_utility | Strongest single worker used for every task |
random_utility | Uniform random routing baseline |
regret | Oracle utility minus router utility; lower is better |
oracle_route_accuracy | Fraction of tasks routed to an oracle-best worker |
1fugu-lite route \
2 --checkpoint artifacts/router-rl \
3 --domain code \
4 --prompt "Find the bug in this Python function ..."1fugu-lite ask \
2 --checkpoint artifacts/router-rl \
3 --workers configs/workers.yaml \
4 --domain code \
5 --prompt "Find the bug in this Python function ..."1fugu-lite serve \
2 --checkpoint artifacts/router-rl \
3 --workers configs/workers.yaml \
4 --host 0.0.0.0 \
5 --port 80801curl http://127.0.0.1:8080/v1/chat/completions \
2 -H 'Content-Type: application/json' \
3 -d '{"model":"fugu-lite","domain":"code","messages":[{"role":"user","content":"Explain this stack trace..."}]}'fugu_lite field with route probabilities, the actual served model,
latency, cost when available, and fallback errors. In production, put authentication and
TLS in front of this service; do not expose it directly to the public internet.CALL(worker, subtask), VERIFY(worker),
SYNTHESIZE, and STOP; collect complete multi-turn trajectories in a sandbox; and optimize
the final verified task reward plus cost/latency penalties. Do that only after this one-step
router reliably beats fixed-worker baselines—otherwise multi-agent complexity hides basic
data and reward problems.cmaes Sep-CMA implementation: https://github.com/CyberAgentAILab/cmaes