Sign inSign up

carbathrv/andy

By carbathrv

โ€ขUpdated about 4 hours ago

On-device Android agent that picks the next UI action. 2B, 1.3 GB.

Model
0

27

carbathrv/andy repository overview

โ Andy

Andy picks the next tap, scroll or app to open on an Android screen, small enough to run on the phone itself.

Give Andy a goal, the screen's accessibility tree and a list of allowed actions. It replies with the single best next action as JSON. Andy is a 2B fine-tune of Qwen3.5-2B, distilled on AndroidControl, and at 1.3 GB it beats models twice its size on choosing the right next step.

Accuracy of Andy and other small models on AndroidControl

โ Tags

TagVersionSizeTest accuracy
latest, v2v2, Q4_K_M, recommended1.3 GB65.5%
v1v1, Q4_K_M1.3 GB63.5%

Same 2,003 AndroidControl test steps: Qwen3.5-2B 33.5%, Gemma 4 E2B 44.4%, Qwen3.5-4B 50.1%.

โ Run

docker model pull carbathrv/andy

Send Andy's system message and turn thinking off. With both, Docker Model Runner reproduces the evaluation prompt and answer exactly.

from openai import OpenAI

client = OpenAI(base_url="http://localhost:12434/engines/v1", api_key="unused")

SYSTEM = """You control an Android phone for the user. Choose the single next action that best advances the user's goal on the current screen.
Reply with exactly one JSON object copied from the allowed actions, and nothing else.
Actions: tap an element, type into a text field (the text itself is filled in later), scroll the screen up/down/left/right, go back, go home, open an app, wait for loading, done when the goal is complete, or handoff to ask the user when you cannot proceed.
Example reply format: {"op":"tap","id":0}"""

screen = """Goal: Watch the video on how to make molten chocolate cake in the Kitchen Stories app.
Current app: com.ajnsnewmedia.kitchenstories
Previous actions:
1. opened app Kitchen Stories
Screen: change since the last action unknown ยท 6 elements
Screen elements (@x,y = centre, % of screen width,height):
[1] FrameLayout #content @50,50
  [2] View "Our Latest Recipes" @43,75
  [3] Button "See all" @89,75 (click)
  [4] ImageView "Today, Tab 1 of 3" @16,94 (click,selected)
  [5] ImageView "Search, Tab 2 of 3" @50,94 (click)
  [6] ImageView "Profile , Tab 3 of 3" @83,94 (click)
Allowed actions:
{"op":"tap","id":3}
{"op":"tap","id":4}
{"op":"tap","id":5}
{"op":"tap","id":6}
{"op":"scroll","dir":"up"}
{"op":"scroll","dir":"down"}
{"op":"back"}
{"op":"home"}
{"op":"wait"}
{"op":"done"}
{"op":"handoff"}"""

r = client.chat.completions.create(
    model="carbathrv/andy",
    messages=[{"role": "system", "content": SYSTEM}, {"role": "user", "content": screen}],
    temperature=0,
    max_tokens=48,
    extra_body={"chat_template_kwargs": {"enable_thinking": False}},
)
print(r.choices[0].message.content)   # {"op":"tap","id":5}

Andy answers with one action from the allowed list. Check the reply against the list before executing it.

โ Prompt format

Keep the layout above: goal, current app, previous actions, the screen line, the element tree with positions, then the allowed actions. v1 expects the same layout without the screen line and the positions.

โ Confidence and hand-off

Andy is calibrated, so an agent can act on confident steps and hand the rest to the user. At its default threshold v2 hands off 22% of steps and is 75% accurate on the rest. This needs a score for every allowed action; use the GGUF files with llama.cpp and the helper from Hugging Face for it.

โ Limitations

  • Andy reads text only, so unlabelled icon buttons are hard for it.
  • It decides one step at a time. Step accuracy is not the same as finishing a task.
  • It was trained and tested on AndroidControl, in English.
  • Andy only chooses actions. The app that executes them must enforce its own safety rules.

โ License

  • Andy: Apache-2.0
  • Base model Qwen3.5-2B: Apache-2.0
  • Training data: AndroidControl by Google

Andy on Hugging Faceโ 

Tag summary

Content type

Model

Digest

sha256:27efac037โ€ฆ

Size

1.2 GB

Last updated

about 4 hours ago

docker model pull carbathrv/andy