DrumsBench

Experiments / EXP-014

Self-hosted UI-TARS-1.5-7B serving ladder for an open-weight agent

Serve the pinned UI-TARS-1.5-7B model unquantized on one GPU host, behind a keyless loopback endpoint shared by every arm, at the largest context that provably serves the frozen agent configuration without shrinking screenshots.

plannedWritten and reviewed as code or protocol, but not executed. No numbers.
Date
2026-10-25
Hypothesis
A 24 GB L4 can serve the frozen six-screenshot 1920x1080 agent context at 32768 tokens or more in BF16; if it cannot, the record says so as a failed prerequisite rather than quantizing.
Arms
uitars-serving
Hardware
1x NVIDIA L4, 22888 MiB usable (operator-reported); a g6.2xlarge-class host is named as operator-side
OS
Linux host with docker and the nvidia runtime (not yet identified)
Model
ByteDance-Seed/UI-TARS-1.5-7B, revision 683d002dd99d8f95104d31e70391a39348857f4e, BF16, no quantization
Workload
serving probes only: text-only, one image, six images, calibrated input-bound request; no CUA episode
Code
claude/ecstatic-archimedes-456go6 at 0e16bc5
Limitation
Nothing has been served; no model loaded, no inference run, no serving-report.json or serving-lock.json exists.

In one paragraph

The frontier route (EXP-012) cannot feed training, and the official OSWorld UI-TARS-1.5 agent is the open-weight agent we intend to run on both arms through the thin cua_adapter. That agent needs a served model, and the model must not become a hidden variable between arms, so model_serving puts one private endpoint on 127.0.0.1, serves the pinned checkpoint through the authors' own named TGI container pinned by digest, and climbs down a context ladder (65536, 49152, 32768) until a level passes every measured gate. The floor is 32768 because the frozen agent config needs at least 25,338 tokens (design value, arithmetic from public configs). A 24 GB L4 may not serve the frozen config at any level; the report would then name failed_prereq rather than quantize, drop history or shrink screenshots. Nothing has been served.

Setup

Pins (model_serving/pins.py)

The ladder

Levels 65536, 49152, 32768, each a fresh container; the largest level that passes everything is chosen and written to serving-lock.json. Input bound is context - 1024 so max_tokens=1000 always fits. Each level must pass, with every claim either measured or reported unverified (an unverified claim fails the level):

Why 32768 is the floor

The frozen agent config (cua_adapter.config, the official qwen25vl_normal runtime: history_n=5, 1920x1080 screenshots, no shrinking, max_tokens=1000) sends up to six screenshots of about 2691 vision tokens each plus text: at least 25,338 tokens (design value: 6 x 2691 + 8192 + 1000, "rough arithmetic only (not a feasibility proof)"). A lower context would force dropping history images or shrinking screenshots, and neither is ever applied.

Outcome vocabulary

What ran

Nothing on a GPU. The only live acts claimed are reading the image digest from the public registry and the operator reporting the GPU (1x NVIDIA L4, 22888 MiB usable).

Results

None. The back-of-envelope figures in SERVING.md (weights ~15 to 17 GiB in BF16, KV cache ~56 KiB per token, ~3.5 GiB at 65536; all estimates) are not results and are not shown as such.

Failures and surprises

None recorded.

Limitations

Reproduce

python -m model_serving describe
python -m model_serving environment --model-dir /data/uitars
python -m model_serving pull
python -m model_serving plan --out /data/uitars-plan.json
python -m model_serving download --model-dir /data/uitars --expect-plan /data/uitars-plan.json
python -m model_serving ladder --model-dir /data/uitars --evidence /var/lib/drumsbench/serving-1
python -m model_serving start --model-dir /data/uitars --context <chosen>
DOUBAO_API_URL=http://127.0.0.1:18080/v1 DOUBAO_API_KEY=none-required python -m cua_adapter run ... --serving-lock .../serving-lock.json
python -m model_serving stop

ladder leaves no container behind and writes the report and, on success, the lock, which cua_adapter run --serving-lock verifies against the pins and records in episode.json.

Sources