← TinyGPT · docs · devlog · roadmap · speedup
source: docs/prds/vlm-ab-uivenus-vs-qwen3vl.md · view on GitHub ↗

VLM A/B — UI-Venus-1.5-2B vs Qwen3-VL-2B for Pace’s vision pillar

Status: PRD (2026-06-09). The 2026-06-09 research sweep flagged Qwen3-VL-2B as a competitor to our UI-Venus-1.5-2B port target. This A/B decides which one we actually port to MLX-Swift / CoreML / ANE for #266.

Why this matters

#266 (UI-Venus M4 port) is 6-9 days of focused MLX-Swift work. We should not port the wrong model. If Qwen3-VL-2B wins the A/B on Pace’s actual use cases:

If UI-Venus wins:

Models on disk (downloaded 2026-06-09)

Both available for A/B without further setup.

Test plan (1-2 days, no porting required)

Run both via mlx_lm in Python (no Swift port needed for A/B). Compare on a Mac-specific fixture set.

Fixture set construction

pace/evals/fm-vlm-fixtures-mac-v1/ — 30 fixtures, captured via tinygpt ax-capture:

Categories:

  1. Identity (8): “what app is this” on Mac apps Microsoft probably didn’t train on — Xcode, Final Cut, Logic, OmniFocus, Bear, Things, Tot, Drafts
  2. Read-on-screen (8): “read the error message” / “what’s the title of this email” / “what’s the current playback time”
  3. Click target (8): “where do I click to send this” / “find the New Folder button” — model emits (x,y) or label, scored against ground-truth AX bounds
  4. Activity context (6): “what am I doing right now” — multi-modal answer (app + visible content + task)

Capture process: 30 manual ax-capture sessions across daily Mac use (existing tool, ~30 min).

Eval methodology

For each model:

  1. Load via mlx_lm chat
  2. For each fixture: pass the screenshot + AX-tree-as-text + the question
  3. Score via:
    • Identity: string match on app name
    • Read: substring containment of expected text in response
    • Click: response label matches AX-tree label OR (x,y) lies inside ground-truth bounds
    • Activity: LLM-as-judge (Qwen3-14B teacher) scores 0-2 on coverage

Eval script: scripts/archive/eval_pace_vlm_ab.py (write — extends eval_pace_v2.py pattern).

Metrics captured

MetricUI-Venus-1.5-2BQwen3-VL-2B
Identity accuracy (/8)??
Read accuracy (/8)??
Click accuracy (/8)??
Activity accuracy (/6)??
Total (/30)??
Per-call latency (MPS)? ms? ms
Per-call latency (ANE via CoreML if convertible)? ms? ms
Disk (post-quantization to 4-bit MLX)? MB? MB
Formula score??

Tiebreakers (when scores are close)

  1. Same family wins (Qwen3) — one tokenizer + one MLX pipeline for planner + embedding + VLM. Worth ~5pp.
  2. Smaller bundle wins — Pace’s total bundle budget matters for v1 ship.
  3. Better ANE conversion path wins — whichever model converts to ANE-chunked CoreML with less drama.

Decision tree

ResultAction
Qwen3-VL ≥ UI-Venus by ≥ 5pp on Mac fixturesSwitch port target to Qwen3-VL-2B. Same family alignment compounds the win.
UI-Venus ≥ Qwen3-VL by ≥ 5ppStay on UI-Venus. Continue M4 port.
Within 5pp tiePick Qwen3-VL — family alignment + ecosystem momentum (Qwen3-VL native computer/mobile control per research).

What “Mac-tune later” looks like (out of scope here)

Either winner can be fine-tuned later on Pace’s ax-capture corpus once Pace is deployed and we have real screen+AX pairs. The A/B picks the BASE; tuning is a separate factory pass.

Done when