Skip to content

About

149M on-device first tier for phone agents: pre-registered routing to frontier models (AndroidControl). Paper, model, per-step outputs, registration log.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

A 149M Text Encoder as the First Tier for Phone Agents: Pre-Registered Routing to Frontier Models

DOI

Paper: paper/main.pdf (preprint: doi:10.5281/zenodo.23818333). Model: Milo Pointer on Hugging Face.

All Claude API calls behind the AndroidControl results cost $86.75 in total (Batch prices), and each training run of the model takes about 6.4 hours on one NVIDIA T4.

Cost and accuracy on 1,000 held-out steps; routing curves

  • A 149M text-only model scores 86.1% on AndroidControl-Low under the protocol screenshot agents report, above the 85.2% reported for OS-Atlas-7B (step sets differ slightly).
  • Small model + frontier beats the frontier alone. The small model answers about 70% of steps on the device and hands the rest to Claude Opus 5.5. In a pre-registered confirmatory test routing beat Opus alone by 2.8 points (p = 0.003); pooled over all 1,650 test steps the gain is 1.5 points (95% CI [+0.5, +2.4]), at under a third of Opus's API cost.
  • What did not work is documented too. About 40 registered experiments, negative ones included, with timestamps (paper/PREREGISTRATION.md).

A 149M-parameter local model answers the phone-agent steps it is confident about and hands the rest to a frontier model. On 1,000 held-out AndroidControl steps (offline, one step at a time, pre-registered):

System Run 1 Run 2 Steps on device API $ per 1k steps (Batch)
Small model alone (149M) 869 869 100% 0
Claude Opus 5.5, 16 retrieved examples 882 879 0% 9.54
Small model, then Opus when unsure 892 890 70.7% 2.82
Claude Sonnet 5.5, 16 retrieved examples 857 862 0% 4.80
Small model, then Sonnet when unsure 881 889 70.7% 1.41

A further registered test on 650 steps from test episodes used in no earlier sample, with a learned hand-off rule frozen beforehand, found routing to Opus more accurate than Opus alone: 599 vs 581 (+2.8 points, 95% CI [+1.0, +4.5], p = 0.003), with 73.7% of steps answered locally (python bench/ac_confirm_score.py, needs numpy).

Limits: offline single steps with a human-written step instruction; a comparable cascade lost on live AndroidWorld tasks; the small model alone is not better than Opus given the same examples; on a Pixel 6a CPU the model takes a median 3.4 s per step. Details in paper/main.pdf.

Follow-up, goal only (registered 2026-10-30, after the paper): a 1.5B planner (Qwen2.5-1.5B, LoRA, trained on the dataset's human step instructions) writes the instruction for the same executor. On 1,804 in-domain steps: human instruction 90.2%, goal alone 19.3%, planner 53.0%. The planner helps (+33.7 points, p < 1e-100) but does not come within 10 points of human instructions (registered margin missed by a wide gap), and the executor's confidence does not catch wrong plans. Details: training/kaggle_planner/RESULT.md.

Contents

Path What
paper/ Paper (PDF, LaTeX), figures, and PREREGISTRATION.md: every hypothesis with its timestamp, written before the data were scored
release/milo-pointer/ The model's Python interface (milo_pointer.py), model card, parity check; weights: https://huggingface.co/coolnow/milo-pointer
release/milo-pointer/android/ ONNX export, on-phone benchmark (ONNX Runtime via app_process, no APK), live phone demo and its recording
bench/ Frontier harnesses (ac_frontier.py, ac_fewshot.py), routing and re-scoring scripts, step samples
bench/results/ Per-step outputs of every Claude run, and billed token counts
training/ Training script (ac/pointer_v2/src/v2.py), clean-protocol retrain, dataset builder notebook, frozen per-step outputs and confidences of the small model

Reproduce the headline numbers (no model calls, no cost)

./reproduce.sh                       # standard library only
pip install pytest numpy && pytest -q tests   # asserts every headline number and registered outcome

Re-scoring on AndroidControl-Curated labels and re-running Claude need the AndroidControl text file (training/ac/androidcontrol_text.jsonl.gz, built from the public AndroidControl release by training/kaggle_ac/androidcontrol_text.ipynb), pip install -r requirements.txt and, for Claude, an Anthropic API key in ANTHROPIC_API_KEY (the Claude arms cost money).

Scripts that run the model need the weights next to milo_pointer.py:

hf download coolnow/milo-pointer --local-dir release/milo-pointer

The clean retrain used by the shortlist test (bench/sl_prepare.py) is on the same model page under clean_r3/; copy clean_r3/pointer_clean_r3.pt to training/ac/pointer_clean_r3/. bench/ptr_latency.py reads the training checkpoint training/ac/pointer_v2/pointer.pt and bench/pointer_eval_local.py takes one as an argument; neither checkpoint is shipped, and the released model.safetensors holds the same weights.

Use the model

from milo_pointer import MiloPointer
m = MiloPointer.load("release/milo-pointer")   # folder with model.safetensors (see above)
a = m.predict(goal, instruction, elements, width, height, last_step="new step")
if a["defer"]:
    ...  # send this step to your frontier agent

License

Code: Apache 2.0. Model: Apache 2.0, fine-tuned from ModernBERT-base (Apache 2.0) on AndroidControl (Apache 2.0).

Citation

@misc{talapalli2026firsttier,
  title  = {A 149M Text Encoder as the First Tier for Phone Agents: Pre-Registered Routing to Frontier Models},
  author = {Talapalli, Chaitanya},
  note   = {ORCID 0009-0000-8811-3349},
  year   = {2026},
  doi    = {10.5281/zenodo.23818333},
  url    = {https://doi.org/10.5281/zenodo.23818333}
}

About

149M on-device first tier for phone agents: pre-registered routing to frontier models (AndroidControl). Paper, model, per-step outputs, registration log.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages