Skip to content

[llm][kv][8/N] Move tokenization in-process of LLMRouter ingress replica - #64642

Merged
kouroshHakha merged 6 commits into
masterfrom
in-process-tokenization
Jul 29, 2026
Merged

[llm][kv][8/N] Move tokenization in-process of LLMRouter ingress replica#64642
kouroshHakha merged 6 commits into
masterfrom
in-process-tokenization

Conversation

@jeffreywang88

@jeffreywang88 jeffreywang88 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Description

After this PR, pre-routing tokenization for KV-aware routing runs in-process inside LLMRouter, using the engine's own vLLM OnlineRenderer, instead of issuing a per-request RPC to a model replica's /tokenize.

KV-aware routing needs prompt token IDs to score replicas. Prior to this PR, the router obtained them via a per-request RPC to a replica's /tokenize. That round-trip sits directly on the routing critical path and contends with inference traffic, so it collapses under concurrency. Tokenizing in-process removes the RPC entirely, so the router keeps up as concurrency scales.

image Screenshot 2026-07-23 at 6 16 30 PM

This PR also ships the enablement of fastokens:

llm_config = LLMConfig(
    model_loading_config=dict(
        model_id="qwen3-0.6b",
        model_source="Qwen/Qwen3-0.6B",
    ),
    runtime_env=dict(
        env_vars={
            "VLLM_USE_FASTOKENS": "1",
        },
    ),
    deployment_config=dict(
        autoscaling_config=dict(min_replicas=1, max_replicas=2),
        request_router_config=dict(request_router_class=KVAwareRouter),
    ),
)

Related issues

Link related issues: "Fixes #1234", "Closes #1234", or "Related to #1234".

Additional information

Optional: Add implementation details, API changes, usage examples, screenshots, etc.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the pre-routing tokenization mechanism by replacing remote /tokenize endpoint calls with an in-process Tokenizer that utilizes vLLM's OnlineRenderer directly. This keeps the router engine-agnostic by lazily importing the tokenizer only when KV-aware routing is enabled. Feedback on the changes suggests adding a guard when dumping tools in _render_chat to handle cases where tools might be raw dictionaries instead of Pydantic models, preventing potential AttributeErrors.

Comment on lines +163 to +167
tool_dicts = (
None
if request.tools is None
else [tool.model_dump() for tool in request.tools]
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If request.tools contains raw dictionaries (e.g., if validation allowed them or if they were bypassed), calling tool.model_dump() will raise an AttributeError. Using a guard like hasattr(tool, "model_dump") ensures compatibility with both Pydantic models and raw dictionaries.

        tool_dicts = (
            None
            if request.tools is None
            else [
                tool.model_dump() if hasattr(tool, "model_dump") else tool
                for tool in request.tools
            ]
        )

@jeffreywang88
jeffreywang88 force-pushed the in-process-tokenization branch from 712a930 to 309d524 Compare July 9, 2026 21:32
Base automatically changed from load-tracking to master July 10, 2026 17:56
@jeffreywang88
jeffreywang88 force-pushed the in-process-tokenization branch from 309d524 to 62c85a6 Compare July 11, 2026 23:13
@jeffreywang88
jeffreywang88 changed the base branch from master to vllm-0.25.0 July 11, 2026 23:14
@jeffreywang88 jeffreywang88 added the go add ONLY when ready to merge, run all tests label Jul 11, 2026
@jeffreywang88
jeffreywang88 force-pushed the in-process-tokenization branch 2 times, most recently from ad9bcdd to d0e4494 Compare July 13, 2026 18:44
Base automatically changed from vllm-0.25.0 to master July 15, 2026 19:40
…returning calls

_svc.delete_worker's Rust binding returns a future, not a coroutine, so passing
it straight to create_task raised TypeError. _schedule now wraps whatever it is
given in a coroutine, keeping the call sites direct.

Signed-off-by: Jeffrey Wang <jeffreywang@anyscale.com>
Pure relocation of the tokenizer module (and its unit test) from
core/ingress to routing_policies/kv_aware, updating import paths. No
logic change; the vLLM-specific rewrite follows in the next commit.

Signed-off-by: Jeffrey Wang <jeffreywang@anyscale.com>
…s vLLM renderer

Replace the per-request /tokenize RPC with an in-process tokenizer that drives
the engine's own vLLM OnlineRenderer: render_chat for chat (the engine's own
entry point, covering the HF chat template, Harmony for gpt_oss, and Mistral)
and preprocess_completion for text prompts. Routing token ids are therefore
byte-identical to the replica's prefill tokens without contending with
inference on the replica processes. The vLLM renderer imports live at module
top (OnlineRenderer needs vLLM >= 0.25); the ingress router imports the
tokenizer lazily so non-KV paths never pull the renderer in.

Signed-off-by: Jeffrey Wang <jeffreywang@anyscale.com>
@jeffreywang88
jeffreywang88 force-pushed the in-process-tokenization branch from d0e4494 to 22b77f0 Compare July 21, 2026 22:17
@jeffreywang88 jeffreywang88 changed the title [llm][kv][8/N] Move tokenization in-process instead of processing through engine-native ASGI /tokenize RPC [llm][kv][8/N] Move tokenization in-process of LLMRouter ingress replica Jul 21, 2026
@jeffreywang88
jeffreywang88 marked this pull request as ready for review July 21, 2026 22:23
@jeffreywang88
jeffreywang88 requested a review from a team as a code owner July 21, 2026 22:23

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the pre-routing tokenization mechanism to run in-process using vLLM's OnlineRenderer instead of making remote calls to the replica's /tokenize endpoint. It introduces lazy loading of the tokenizer for KV-aware routers to keep the non-KV ingress path engine-agnostic, and adds comprehensive exactness tests comparing the in-process tokenizer with Hugging Face's transformers library. The review feedback suggests initializing the tokenizer synchronously on the main thread during startup to avoid potential thread-safety issues with asyncio.to_thread, and wrapping background tasks in _schedule with try-except blocks to prevent exceptions from failing silently.

Comment thread python/ray/llm/_internal/serve/core/ingress/router.py Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5b7e662. Configure here.

@ray-gardener ray-gardener Bot added the serve Ray Serve Related Issue label Jul 22, 2026

@kouroshHakha kouroshHakha left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread python/ray/llm/_internal/serve/routing_policies/kv_aware/tokenizer.py Outdated
Signed-off-by: Jeffrey Wang <jeffreywang@anyscale.com>
@jeffreywang88

jeffreywang88 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

does this approach work with fasttokens as well? https://github.com/vllm-project/vllm/blob/0b6aa3c47ce69a1f3c8a19cafe3b9dc2871d1f6b/docs/configuration/optimization.md?plain=1#L281 can we test that and confirm?

Plumbed env var to enable that in fc63345 and added a test accordingly. Here's the API shape:

llm_config = LLMConfig(
    model_loading_config=dict(
        model_id="qwen3-0.6b",
        model_source="Qwen/Qwen3-0.6B",
    ),
    runtime_env=dict(
        env_vars={
            "VLLM_USE_FASTOKENS": "1",
        },
    ),
    deployment_config=dict(
        autoscaling_config=dict(min_replicas=1, max_replicas=2),
        request_router_config=dict(request_router_class=KVAwareRouter),
    ),
)

@kouroshHakha
kouroshHakha merged commit 23dc035 into master Jul 29, 2026
6 checks passed
@kouroshHakha
kouroshHakha deleted the in-process-tokenization branch July 29, 2026 05:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

go add ONLY when ready to merge, run all tests serve Ray Serve Related Issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ray fails to serialize self-reference objects

2 participants