Instructions to use YijiaFan/CaPtain-4B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use YijiaFan/CaPtain-4B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="YijiaFan/CaPtain-4B") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("YijiaFan/CaPtain-4B") model = AutoModelForMultimodalLM.from_pretrained("YijiaFan/CaPtain-4B", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use YijiaFan/CaPtain-4B with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "YijiaFan/CaPtain-4B" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "YijiaFan/CaPtain-4B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/YijiaFan/CaPtain-4B
- SGLang
How to use YijiaFan/CaPtain-4B with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "YijiaFan/CaPtain-4B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "YijiaFan/CaPtain-4B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "YijiaFan/CaPtain-4B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "YijiaFan/CaPtain-4B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use YijiaFan/CaPtain-4B with Docker Model Runner:
docker model run hf.co/YijiaFan/CaPtain-4B
CaPtain-4B
CaPtain-4B is the final model of CaPtain: A Pipeline for Post-Training Code-as-Policy Robot Agents. It is Qwen3.5-4B after supervised fine-tuning (SFT) and reinforcement learning (RL). It is a code-as-policy agent: it controls a robot by writing Python in CaPtain-Harness, reads the receipts of its own robot calls, and decides itself when the task is done.
| Paper | CaPtain: A Pipeline for Post-Training Code-as-Policy Robot Agents |
| Project page | https://waltstephen.github.io/captain/ |
| Pipeline code (SFT, RL) | https://github.com/waltstephen/CaPtain |
| Harness (required to run the model) | https://github.com/waltstephen/CaPtain-Harness |
| SFT initialisation and KL reference | YijiaFan/CaPtain-4B-SFT |
| SFT data | YijiaFan/CaPtain-SFT-Data |
| RL starts, critic warm start, configs, evaluation inputs | YijiaFan/CaPtain-artifacts |
What the model is
- A code-writing agent, not a VLA. The model never outputs actions or joint targets directly. At every request it
writes Python for the harness's single
pythontool: a persistent, sandboxed Python 3.11 session. The robot API in that session has 22 low-level capabilities (perception, geometric measurement, IK-level guarded motion) plusfinish(). There are no grasp or place macros. - What it sees: camera images, its own code and output, and a one-line text receipt for every robot call.
- What it never sees: object poses, contacts and the success predicate. These stay on the host.
- Perception runs as services. The harness's
segmentandmark_pointtools call SAM 3 and Molmo2-8B, and positions come from depth back-projection. The model calls these tools; it does not replace them. - Format. bf16 safetensors with the
Qwen3_5ForConditionalGenerationarchitecture. Thelm_headis untied. The tokenizer, processor and chat template are the same as Qwen3.5-4B. During SFT the vision tower was kept frozen.
How to use
The model only works well inside CaPtain-Harness (see Prompt format). Serve it with vLLM as an OpenAI-compatible endpoint, start the perception services, and run episodes with the harness.
# 1. policy server (vLLM 0.29, OpenAI-compatible; these are the flags used for the paper's evaluations)
vllm serve YijiaFan/CaPtain-4B --served-model-name captain-4b --dtype bfloat16 --max-model-len 81920 \
--enable-prefix-caching --limit-mm-per-prompt '{"image":12}' --max-num-seqs 16 \
--reasoning-parser qwen3 --enable-auto-tool-choice --tool-call-parser qwen3_xml --port 8600
# (the harness wraps this command as: services/serve_policy.sh YijiaFan/CaPtain-4B 8600)
# 2. harness, perception services and one LIBERO episode
git clone https://github.com/waltstephen/CaPtain-Harness.git && cd CaPtain-Harness
# install as in INSTALL.md (LIBERO venv + the agent's sandboxed Python 3.11), then:
services/start_perception.sh # SAM 3 :8114 + Molmo2-8B :8122
export POLICY_URL=http://127.0.0.1:8600/v1 STUDENT_PYTHON=~/envs/student-py311/bin/python EGL_DEVICE=0
eval/run_episode.sh libero_spatial 0 11 runs/demo
cat runs/demo/libero_spatial_0_seed-11/episode_result.json # host_final_success, agent_finished, ...
# 3. a whole benchmark, scored as in the paper
python3 eval/run_jobs.py eval/tasks/libero_official_240.tsv --out runs/captain-4b --parallel 8
python3 eval/summarize.py eval/tasks/libero_official_240.tsv runs/captain-4b
Evaluation protocol used for every number below (the defaults of eval/run_episode.sh):
- sampling T = 1.0, top_p = 1.0, thinking on;
- budgets per episode: 60 model requests, 1,080 s wall time and 150 physical actions;
- context: a 64k-token window with the harness's compaction.
The task lists for LIBERO-PRO, LIBERO-Plus, LIBERO-MAX and the transfer benchmarks are in the harness
(eval/tasks/, eval/transfer/).
Prompt format
CaPtain-4B was trained on the harness's exact request template:
- the system prompt and environment context the harness sends;
TASK.md, inlined in the system prompt;- the
pythontool schema (python-runtime/v1contract); - receipts, context compaction notes and image placement.
The model uses the standard Qwen3.5 chat template, with <think> reasoning and XML tool calls, but it expects this
harness-specific content. Do not hand-write prompts for it: run it through CaPtain-Harness, and do not change
model-visible text (TASK.md, tool descriptions, receipts, request template) when evaluating it. Outside the harness it
behaves like an ordinary small VLM, with no robot ability.
Results
All numbers are success rates (%) in simulation under the protocol above.
- Host success: the benchmark's hidden goal predicate holds at the end of the episode.
- Strict success: host success, and the agent also called
finish()itself. - The LIBERO row uses the held-out official initial states 11β16 of all 40 tasks of the four standard suites. RL never used these states.
- LIBERO-PRO, LIBERO-Plus and LIBERO-MAX were never used in training.
LIBERO family (host / strict):
| Benchmark | Episodes | Qwen3.5-4B | CaPtain-4B-SFT | CaPtain-4B |
|---|---|---|---|---|
| LIBERO, official held-out states 11β16 | 240 | 0.0 / 0.0 | 55.4 / 52.1 | 73.8 / 67.5 |
| LIBERO-PRO Pos+Task, 6-cell mean | 600 | 0.3 / 0.2 | 59.5 / 56.7 | 78.5 / 71.5 |
| LIBERO-PRO Pos+Task, 8-cell mean | 800 | 0.2 / 0.1 | 49.2 / 45.1 | 68.6 / 58.9 |
| LIBERO-Plus, 7 categories | 700 | 0.0 / 0.0 | 48.6 / 44.6 | 66.1 / 59.0 |
| LIBERO-PRO, 4 categories | 160 | 0.0 / 0.0 | 48.8 / 48.1 | 68.8 / 60.6 |
| LIBERO-MAX Dynamic | 80 | 0.0 / 0.0 | 40.0 / 40.0 | 61.2 / 50.0 |
| LIBERO-MAX Base | 80 | 0.0 / 0.0 | 51.2 / 45.0 | 70.0 / 63.8 |
Zero-shot transfer (RL used only the 40 LIBERO tasks):
| Benchmark | Protocol | CaPtain-4B |
|---|---|---|
| RoboTwin 2.0 | official Hard protocol, 50 tasks Γ 100 trials | 22.6 (single-arm subset 30.0) |
| SimplerEnv | WidowX (Bridge) visual matching, 4 tasks Γ 24 | 83.3 |
| CaP-Bench | Cube Lift + Cube Stack at CaP-Gym's step horizon | 75.0 |
| RoboDojo | 42 tasks, official layouts and action budget (leaderboard Score) | 1.7 |
The transfer backends give the agent inputs beyond the benchmarks' official policy observation: simulated depth, camera
calibration, a wrist force or contact signal, and on SimplerEnv an added wrist camera. They are listed per benchmark in
the harness (eval/transfer/README.md). The agent never receives object poses, the success predicate or task progress.
Reference points for each benchmark are in the paper and the CaPtain README.
Training
- Base. Qwen3.5-4B, with the
lm_headuntied from the embeddings. - SFT β CaPtain-4B-SFT. Trained on
CaPtain-SFT-Data:
- synthetic agent trajectories collected in CaPtain-Harness, plus visual QA at loss weight 0.5;
- only assistant turns are supervised, the vision tower is frozen, and a text-hint mask (p = 0.2) hides earlier pixel coordinates;
- 2,435 steps (1.5 epochs), peak LR 1e-5 with a cosine schedule, DeepSpeed ZeRO-3, bf16.
- RL β CaPtain-4B. On-policy RL in LIBERO with a simulator critic:
- A small critic (5 MLPs) reads the simulator's physical state: object poses, grasp state and sub-goal progress. The change in its predicted success across each model request becomes that request's credit. The policy never sees this state. The critic starts from an offline warm start and is co-trained online.
- Advantages: GAE (Ξ» = 0.9) on the critic, combined with a group-relative outcome term (G = 4 rollouts per start).
- Loss: SAO-style with a double-sided ratio mask, plus a k3 KL term (Ξ² = 0.002) to CaPtain-4B-SFT.
- Batch: 256 episodes per round (64 starts Γ G = 4); K = 4 rounds per optimizer update, so 1,024 episodes per update.
- CaPtain-4B is round 300 = 75 optimizer updates (76,800 training episodes), on wide-layout LIBERO start states with randomised lighting, camera pose and materials.
The full configurations are in the CaPtain repository (sft/configs/captain-4b-sft.yaml, rl/configs/captain-4b.json)
and in CaPtain-artifacts.
Limitations
- Simulation-trained. RL used only the 40 LIBERO tasks. The SFT data are simulated episodes, almost all on LIBERO (see the dataset card). Transfer to other benchmarks is weaker than in-domain performance.
- Missed finishes. Sometimes the scene is solved but the agent does not call
finish(). This explains most of the gap between host and strict success. - Hard tasks. Failures concentrate in long-horizon and articulated tasks (LIBERO-10, some LIBERO-Goal tasks).
- Two-arm coordination. The policy acts with one arm at a time. On RoboTwin, tasks that need simultaneous two-arm motion fail. Reach limits of unfamiliar arms are the other common transfer failure.
- Inputs. The model relies on the harness's perception services (SAM 3, Molmo2-8B), depth and camera calibration. The transfer backends add the inputs listed above.
- Real robots need adaptation. The harness has a hardware backend (driver protocol, kinematic twin, cameras), but this checkpoint was not trained on real-robot data. The paper's real-robot episodes used an embodiment-adapted checkpoint. Running the model on hardware needs your own driver, calibration and safety guards.
- Interface ceiling. The agent is bounded by the 22-capability API and by what the SFT trajectories demonstrate. For example, sustained pressing (CaP-Bench Wipe) cannot be expressed with the guarded motion API.
- Research artifact. Not validated for safety-critical use or for unsupervised use on physical robots.
License
Apache-2.0, the license of the base model Qwen3.5-4B. When you run the model together with other components (LIBERO,
SAM 3 under the SAM License, Molmo2, simulators), their licenses also apply; see THIRD_PARTY_LICENSES.md in the CaPtain
repositories.
Citation
@article{fan2026captain,
title = {CaPtain: A Pipeline for Post-Training Code-as-Policy Robot Agents},
author = {Fan, Yijia and He, Xilin and Jiang, Yilei and Wu, Dongming and Wang, Jiaxu and Yue, Xiangyu},
journal = {arXiv preprint},
year = {2026}
}
Contact: Xiangyu Yue (xyyue@ie.cuhk.edu.hk), MMLab, The Chinese University of Hong Kong.
- Downloads last month
- 11