Repository navigation
[Frontend] Serve LiquidAI/d1-3B on /v1/systemone - #60676
Conversation
|
Documentation preview: https://vllm--60676.org.readthedocs.build/en/60676/ |
LucasWilkinson
left a comment
There was a problem hiding this comment.
Awesome work thanks! overall LGTM, i would like to figure out if theres a better home for model specific strategies (maybe in the model folders) but for now this seems fine since i assume in the short to medium term there will be churn on the strategy interface so maybe best to keep it all together for now
|
This pull request has merge conflicts that must be resolved before it can be |
A score's prompt labels now match its answer: level i is labeled "i", the same index the answer's legend and probabilities use. The old labels were 1 to 9, then A to Z past nine levels, so a prompt label never matched its answer key. A score now has at most 10 levels. A question type declares its labels with a label_set class variable, which build_question also uses for the option limit. This matches the interface in vllm-project#60676. A noul rejects criteria keys other than "true" and "false", so a typo such as "ture" is a 400. A side with no description is left out of the prompt. JevBench public items, native noul and score (one read each): model labels noul score label_mass (score) Qwen3-0.6B 1..9 36/74 5/18 0.90 Qwen3-0.6B 0..9 36/74 6/18 1.00 Qwen3-4B 1..9 43/74 8/18 1.00 Qwen3-4B 0..9 43/74 8/18 0.99 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Matt Mastracci <matthew@mastracci.com> Co-authored-by: Misha Goin <mgoin64@gmail.com>
…artup The strategy finds the token of each registered question type's labels when the server starts, and fails there if one is not a single distinct token after the chat prompt. This replaces the lookup per request and its cache. reply_label_ids takes the labels to check, as in vllm-project#60676. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Matt Mastracci <matthew@mastracci.com> Co-authored-by: Misha Goin <mgoin64@gmail.com>
|
This pull request has merge conflicts that must be resolved before it can be |
|
Hi @mgoin, I ran an adversarial pass on the d1 strategy on an H200. The prompt and readout hold up: every pick matched The image path has three bugs, plus two smaller items. The fixes are four commits on 1. A failed or overlapping decision breaks the next request with the same image (chat included)
Repro (failed request),
|
Add a read strategy for LFM2-VL that writes the prompt and reads the label tokens the way the prompt.py shipped with LiquidAI/d1-3B does. A next-token read now scores the best of a group of tokens per label, fetches a request's images once, and renders without the sender cache so a failed read leaves it in sync. Co-authored-by: Simon Veitner <sveitner@redhat.com> Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: mgoin <mgoin64@gmail.com>
|
/ci run |
|
✅ Triggered Buildkite CI #94240 for commit |
CI selector (shadow): 1 test steps (1 jobs) instead of 34 (47 jobs)Shadow mode: this changes nothing about what CI runs. It shows what the evidence-based selector would pick for this PR, next to today's rules. How it works. Feedback welcome: reply here if it would skip a step this change needs, or runs something unrelated.
Selector would run (1)
Would skip (today's rules run them) (33)
Would add (today's rules do not run them) (0)none AMD mirrors: would skip (32)
AMD mirrors: would add (0)none 3 changed files · base |
Overview
Serve
LiquidAI/d1-3Bon/v1/systemonewith answers that match the checkpoint's ownmodel.system_one(), for text and image states.The question types (#60696) and the
imagesrequest field (#61064) have since landed onmain, so this PR is now only the Liquid read strategy and the small changes to the next-token read that it needs.Demo
d1-3B playing Snake through
/v1/systemone, recorded in real time on one B300. Each move is one HTTP request with a singlechoicequestion (up / down / left / right), and the snake takes the model's top choice with no fallback logic.In this 15 second run it made 666 moves (44 a second, 23 ms median per request), ate 46 apples and died once. The state is a short text: where the apple is relative to the head, and what is in each of the four neighboring cells. Given raw coordinates or an ASCII grid instead, the model played poorly (14 and 4 apples in 400 moves, against 32). The recording used the default prefix caching; see Details for why turning it off is faster here.
Claims
/v1/systemonematch the reference implementation shipped with the checkpoint, for text and image states and all three question types.Validation
Prompt parity (CPU). For 15 questions over 11 cases, the rendered prompt and the label token ids are identical to what
prompt.pyin the d1-3B repo produces (renderandreadout_ids).Answers against the reference (one B300, bf16). Reference:
AutoModel.from_pretrained("LiquidAI/d1-3B", trust_remote_code=True).system_one(...)on transformers 5.18.0, each question asked alone. "Gap" is the largest absolute difference in any option's probability.atodEvery pick matches. The Japanese case has the same prompt tokens and the same pick; its distribution is spread over three options (0.33 / 0.51 / 0.16). I did not track down the source of that 0.031 gap.
Reviewer findings (thanks @simon-veitner-redhat). All five are addressed, re-implemented on the current
mainand re-checked on a B300:system_one()max()errorconfidencediffers fromsystem_one()Tests.
72 passed on a B300, on this branch as pushed.
Not covered in CI. There is no d1-3B end-to-end test, to avoid pulling a 3B checkpoint. The d1 prompt wording is pinned by a CPU-only unit test; the answer parity above was run by hand.
Details
QUESTION:/Options:/Reply with the option code only.) and pools label variants (yes/Yes/YES,A/A).LiquidStrategysubclassesNextTokenStrategyand overrides only the user turn and the label tokens.config.jsonis the same as the base model's, so everyLfm2VlForConditionalGenerationgets this prompt. Liquid's runner does the same.input_tokenssums the prompt of every question, so a multi-question request reports more than the reference, which counts the state once.choiceis still capped at 26 options (the reference switches to two-digit codes beyond that). An empty-string state is treated like anullstate.--no-enable-prefix-cachingbrings it back to a flat 14 ms. I did not trace the cause in the scheduler.JointSchemaStrategyto theReadStrategybase so both strategies use it, and every next-token render now skips the multimodal sender cache.Pull Request Checklist
I used vLLM's
/pr-checklistskill. (Mandatory for agents, optional for humans).AI assistance was used during the creation of this PR.
Design Fit: Minimizes impact on core components, reuses existing functionality, and justifies added complexity.
Testing and Validation: Validates the change and ensures any added tests are meaningful and reliable, with CI coverage or documented CI resource constraints and validation performed outside CI.
Code Quality and Style: Keeps code and comments clear and concise, and updates relevant documentation and examples.
Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.
🤖 Generated with Claude Code