Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions src/vllm_router/routers/routing_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def __init__(
self.instance_id_to_ip = {}
self.session_key = session_key
self.hash_ring = HashRing()
self.tokenizer = None
self.tokenizers: Dict[str, AutoTokenizer] = {}

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.

high

Replacing self.tokenizer with self.tokenizers in KvawareRouter.__init__ will break LoadAwareRouter (which inherits from KvawareRouter). LoadAwareRouter.tokenize_prompt still references self.tokenizer (e.g., if self.tokenizer is None:), which will now raise an AttributeError because self.tokenizer is no longer initialized in KvawareRouter.__init__.

Please update LoadAwareRouter.tokenize_prompt to use self.tokenizers as well, or unify the tokenization logic between the two routers.

self.threshold = kv_aware_threshold

def start_kv_manager(self):
Expand Down Expand Up @@ -388,18 +388,28 @@ async def route_request(
token_ids = None
# Local-first tokenization, fall back to remote "/tokenize" API on failure
# TODO (Yuhan): Handle chat completions
model_name = request_json.get("model", "")
# Find the endpoint serving this model
model_endpoint = next(
(ep for ep in endpoints if model_name in ep.model_names),
endpoints[0] if endpoints else None,
)

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_json does not contain the "model" key, model_name defaults to "". This will cause AutoTokenizer.from_pretrained("") to fail, and the remote fallback will send "model": "" to the remote /tokenize endpoint, which is likely to fail or be incorrect.

To preserve backward compatibility and ensure robustness, we should default model_name to endpoints[0].model_names[0] if it is not provided or is empty.

        model_name = request_json.get("model", "")
        if not model_name and endpoints and endpoints[0].model_names:
            model_name = endpoints[0].model_names[0]
        # Find the endpoint serving this model
        model_endpoint = next(
            (ep for ep in endpoints if model_name in ep.model_names),
            endpoints[0] if endpoints else None,
        )

try:
if self.tokenizer is None:
self.tokenizer = AutoTokenizer.from_pretrained(
endpoints[0].model_names[0]
if model_name not in self.tokenizers:
self.tokenizers[model_name] = AutoTokenizer.from_pretrained(
model_name
)
token_ids = self.tokenizer.encode(request_json.get("prompt", ""))
token_ids = self.tokenizers[model_name].encode(
request_json.get("prompt", "")
)
except Exception:
# Remote /tokenize fallback (let errors bubble up to keep behavior simple)
remote_url = endpoints[0].url + "/tokenize"
if model_endpoint is None:
raise
remote_url = model_endpoint.url + "/tokenize"
headers = {"Content-Type": "application/json"}
data = {
"model": endpoints[0].model_names[0],
"model": model_name,
"prompt": request_json.get("prompt", ""),
}
body = requests.post(
Expand Down