Skip to content

feat(vllm): route embedding worker through Rust preprocessor (opt-in via --use-vllm-tokenizer) - #11109

Draft
tzulingk wants to merge 1 commit into
mainfrom
perf/embedding-rust-preprocessor
Draft

feat(vllm): route embedding worker through Rust preprocessor (opt-in via --use-vllm-tokenizer)#11109
tzulingk wants to merge 1 commit into
mainfrom
perf/embedding-rust-preprocessor

Conversation

@tzulingk

@tzulingk tzulingk commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Overview:

Route the vLLM embedding worker through Dynamo's Rust OpenAIPreprocessor (tokenize off the engine process) instead of only handing raw text to vLLM — selectable at launch via the existing --use-vllm-tokenizer flag, exactly like chat/completions. Motivation: on text-input embeddings, vLLM tokenizes in-engine; moving tokenization to the Rust frontend is measurably faster (early A/B below).

Details:

EmbeddingWorkerHandler.generate now dispatches on use_vllm_tokenizer:

  • Text mode (--use-vllm-tokenizer, baseline): unchanged — raw {input} in, OpenAI {data:[…base64…]} out.

  • Tokens mode (default now): reads {token_ids} from the PreprocessedEmbeddingRequest, wraps each in TokensPrompt (so vLLM skips its own tokenizer), and returns the raw EmbeddingsEngineOutput shape so the Rust postprocessor does OpenAI formatting/base64.

  • worker_factory.py — embedding registration picks ModelInput.Text if config.use_vllm_tokenizer else ModelInput.Tokens (was hardcoded Text); threads the flag into the handler and the health-check payload.

  • handlers.py — extracted a shared _run_encode plus _parse_embedding_dimensions / _check_embedding_dimensions so both paths validate + encode identically (incl. the task="embed" pooling + Matryoshka dimensions handling from fix(vllm): pool embedding worker output via PoolingParams(task="embed") #10248).

  • health_check.pyVllmEmbeddingHealthCheckPayload gains use_text_input; probes with {input:"probe"} for Text mode and {token_ids:[[1]]} for Tokens mode (otherwise the probe fails with a missing-field error).

  • Tests — embedding registration-contract test (flag → ModelInput), tokens-mode handler tests, and updated health-check payload tests for the new default; existing text-path tests pinned to use_vllm_tokenizer=True.

Behavior change: the default is now the Tokens/Rust path, so any embedding model whose tokenizer the frontend can't resolve must be launched with --use-vllm-tokenizer.

Early A/B (single GB200, vLLM 0.24.0, vllm bench serve --backend openai-embeddings, text input, 4096 prompts, Qwen/Qwen3-Embedding-0.6B — embeddinggemma-300m is gated, run pending an HF token): candidate (Rust) vs baseline (--use-vllm-tokenizer) throughput = +27% / +46% / +13% at max-concurrency 128 / 512 / 1024. Tracking in DIS-2307.

Where should the reviewer start?

  • components/src/dynamo/vllm/handlers.pyEmbeddingWorkerHandler.generate dispatch, the new _generate_tokens_mode, and the shared _run_encode.
  • components/src/dynamo/vllm/worker_factory.py — the ModelInput.Text/Tokens selection driven by use_vllm_tokenizer.

🤖 Generated with Claude Code

…via --use-vllm-tokenizer)

Make the vLLM embedding worker able to receive pre-tokenized input from
Dynamo's Rust OpenAIPreprocessor (tokenize off the engine process),
selectable at launch via --use-vllm-tokenizer like chat/completions.

- worker_factory.py: embedding registration picks ModelInput.Text if
  use_vllm_tokenizer else ModelInput.Tokens (was hardcoded Text); threads
  the flag into the handler + health-check payload.
- handlers.py: EmbeddingWorkerHandler.generate dispatches on the flag —
  Text mode (raw {input} in, OpenAI out) unchanged; Tokens mode reads
  {token_ids} from PreprocessedEmbeddingRequest, wraps each in TokensPrompt,
  and returns EmbeddingsEngineOutput for the Rust postprocessor. Shared
  _run_encode + _parse/_check_embedding_dimensions helpers.
- health_check.py: payload gains use_text_input (probe {input} vs {token_ids}).
- tests updated for the new default.

WIP snapshot for A/B benchmarking (text-input throughput, baseline vs
candidate). Default is now the Tokens/Rust path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Tzu-Ling <tzulingk@nvidia.com>
@github-actions github-actions Bot added feat backend::vllm Relates to the vllm backend labels Jul 1, 2026
@datadog-official

datadog-official Bot commented Jul 1, 2026

Copy link
Copy Markdown

Pipelines

⚠️ Warnings

🚦 7 Pipeline jobs failed

Docs link check | lychee   View in Datadog   GitHub Actions

PR | backend-status-check   View in Datadog   GitHub Actions

PR | vllm-runtime / Multi-GPU Test cuda13.0, amd64   View in Datadog   GitHub Actions

View all 7 failed jobs.

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 0b55132 | Docs | Give us feedback!

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions Bot added the Stale label Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants