Views
No views yet
<|+|> → action is correct (score = 1.0)<|-|> → action is wrong (score = 0.0)2026-08-10 update: this repo is now a self-contained merged checkpoint (LoRA fused + the separately-trainedlm_head.weightbaked in). An earlier upload shipped the LoRA adapter fused onto the untrained bootstraplm_head.weight(the trainer writes the trained head to deepspeed checkpoint shards, not intoadapter_model.safetensors, and a naiveswift merge_lorasilently keeps the bootstrap head — seelm_head_source.txtin this repo for provenance). That made the<|+|>/<|-|>logits nearly indistinguishable (row-norm diff ~3.8e-6 in the old upload vs. ~0.16 now). This upload uses the trained head and drops the LoRA-loading path below in favor of loading the model directly. Re-validated withrm_evalbefore publishing (see Evaluation below).
[system] You are a helpful assistant. + mobile_use tool spec (with screen resolution)
[user] The user query: <goal>
Task progress (You have done the following operation on the current device):
Step1: <action> <image>
...
StepN: <action>; <image>
[assistant] <tool_call>{"name": "mobile_use", "arguments": {...}}</tool_call>
[user] Was the agent's action above correct given the current screen state?
Answer with exactly one token: <|+|> for correct, <|-|> for wrong.
[assistant] ← model generates <|+|> or <|-|>pip install vllm transformers torch pillow1from vllm import LLM, SamplingParams
2from transformers import AutoProcessor
3from PIL import Image
4
5MODEL_PATH = "Gyubeum/Qwen3-VL-8B-Instruct-UI-Genie"
6
7POS_TOKEN = "<|+|>"
8NEG_TOKEN = "<|-|>"
9
10JUDGE_PROMPT = (
11 "Was the agent's action above correct given the current screen state? "
12 "Answer with exactly one token: <|+|> for correct, <|-|> for wrong."
13)
14
15SYSTEM_PROMPT = (
16 "You are a helpful assistant.\n\n# Tools\n\n"
17 "You may call one or more functions to assist with the user query.\n\n"
18 "You are provided with function signatures within <tools></tools> XML tags:\n"
19 "<tools>\n"
20 '{"type": "function", "function": {"name": "mobile_use", '
21 '"description": "Use a touchscreen to interact with a mobile device. '
22 "The screen's resolution is 540x1200.\", "
23 '"parameters": {"properties": {"action": {"type": "string", '
24 '"enum": ["click", "long_press", "swipe", "type", "key", "system_button", "open", "wait", "terminate"]}, '
25 '"coordinate": {"type": "array"}, "text": {"type": "string"}, "button": {"type": "string"}}, '
26 '"required": ["action"]}}}\n</tools>\n\n'
27 "For each function call, return a json object within <tool_call></tool_call> XML tags:\n"
28 "<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call>"
29)
30
31# Load the merged model directly — no LoRA adapter needed.
32llm = LLM(
33 model=MODEL_PATH,
34 dtype="bfloat16",
35 gpu_memory_utilization=0.7,
36 max_model_len=8192,
37 limit_mm_per_prompt={"image": 10},
38 enforce_eager=True,
39)
40processor = AutoProcessor.from_pretrained(MODEL_PATH, max_pixels=1_048_576)
41tokenizer = processor.tokenizer
42
43pos_id = tokenizer.encode(POS_TOKEN, add_special_tokens=False)[0]
44neg_id = tokenizer.encode(NEG_TOKEN, add_special_tokens=False)[0]
45
46sampling_params = SamplingParams(max_tokens=1, temperature=0.0)
47
48
49def score_action(goal, prior_steps_text, tool_call_response, screenshot):
50 """
51 Score a GUI agent action.
52
53 Args:
54 goal: Task goal string.
55 prior_steps_text: String like "Step1: tap search\nStep2: type query\n"
56 tool_call_response: The agent's raw tool_call response string to judge.
57 screenshot: PIL.Image of the current screen state.
58
59 Returns:
60 float: 1.0 (correct), 0.0 (wrong), or 0.5 (undecided).
61 """
62 user_content = [
63 {"type": "text", "text": f"The user query: {goal}\nTask progress (...): {prior_steps_text}; "},
64 {"type": "image"},
65 ]
66
67 messages = [
68 {"role": "system", "content": SYSTEM_PROMPT},
69 {"role": "user", "content": user_content},
70 {"role": "assistant", "content": tool_call_response.strip()},
71 {"role": "user", "content": JUDGE_PROMPT},
72 ]
73
74 prefix_text = processor.apply_chat_template(
75 messages, tokenize=False, add_generation_prompt=True
76 )
77
78 output = llm.generate(
79 [{"prompt": prefix_text, "multi_modal_data": {"image": [screenshot]}}],
80 sampling_params,
81 )[0]
82
83 gen_id = output.outputs[0].token_ids[0] if output.outputs[0].token_ids else None
84 if gen_id == pos_id:
85 return 1.0
86 if gen_id == neg_id:
87 return 0.0
88 return 0.5 # neither token — treated as undecided
89
90
91# Example
92screenshot = Image.open("screenshot.png").convert("RGB")
93tool_call = '<tool_call>\n{"name": "mobile_use", "arguments": {"action": "click", "coordinate": [540, 120]}}\n</tool_call>'
94
95score = score_action(
96 goal="Tap the search button",
97 prior_steps_text="Step1: opened the app\n",
98 tool_call_response=tool_call,
99 screenshot=screenshot,
100)
101print(f"Score: {score}") # 1.0 = correct, 0.0 = wrongrm_eval1python eval_rm.py \
2 --rm_path Gyubeum/Qwen3-VL-8B-Instruct-UI-Genie \
3 --datasets ui-genie \
4 --mode discrete \
5 --uigenie_jsonl /path/to/reward_data_rm_pairs_last5.jsonl \
6 --uigenie_images_dir /path/to/images \
7 --output_dir results/| Dataset | Pairs | Pair accuracy | Source |
|---|---|---|---|
| UI-Genie (held-out) | 1000 | 72.0% (720/1000); chosen-side 87.5%, rejected-side 80.1% | Fresh rm_eval run, 2026-08-10, on this exact uploaded checkpoint |
| AndroidFlux (OOD multi-agent replay) | 203 | 19.2% (39/203); chosen-side 29.6%, rejected-side 75.9% | rm_eval run, 2026-04-30, on this exact checkpoint (mtime-verified) |
<|-|> on this out-of-domain, multi-agent replay data (chosen-side accuracy 29.6% vs. rejected-side 75.9%) — a known domain-gap limitation of this SFT stage, not an artifact of this upload's fix.| Field | Value |
|---|---|
| Base model | Qwen/Qwen3-VL-8B-Instruct |
| Training method | SFT (LoRA, merged + trained lm_head baked in) |
| Training data | UI-Genie-RM-517k (64k pairs training split) |
| Output | Discrete preference token: <|+|> / <|-|> |
| Scoring | Greedy-decode 1 token → 1.0 / 0.0 / 0.5 |
1@misc{qwen3technicalreport,
2 title={Qwen3 Technical Report},
3 author={Qwen Team},
4 year={2025},
5 eprint={2505.09388},
6 archivePrefix={arXiv},
7 primaryClass={cs.CL},
8}