229 lines
6.9 KiB
Python
229 lines
6.9 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
"""
|
|
Tests for max_tokens_per_doc and max_tokens_per_query.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
from dataclasses import dataclass
|
|
|
|
import pytest
|
|
import requests
|
|
|
|
from tests.utils import VLLM_PATH, RemoteOpenAIServer
|
|
from vllm.entrypoints.pooling.scoring.protocol import RerankResponse
|
|
|
|
os.environ["VLLM_LOGGING_LEVEL"] = "WARNING"
|
|
|
|
TEMPLATE_DIR = str(VLLM_PATH / "examples/pooling/score/template")
|
|
ExpectedPromptTokens = int | tuple[int, ...]
|
|
|
|
long_query = "What is the capital of France?" * 20
|
|
long_doc = "The capital of France is Paris. " * 20
|
|
|
|
|
|
@dataclass
|
|
class TestConfig:
|
|
model: str
|
|
args: list[str]
|
|
without_truncated_prompt_tokens: ExpectedPromptTokens
|
|
with_max_tokens_per_query_prompt_tokens: ExpectedPromptTokens
|
|
with_max_tokens_per_doc_prompt_tokens: ExpectedPromptTokens
|
|
with_max_tokens_per_query_and_doc_prompt_tokens: ExpectedPromptTokens
|
|
|
|
|
|
RERANK_CONFIGS = [
|
|
# 1. cross-encoder
|
|
TestConfig(
|
|
model="jinaai/jina-reranker-v2-base-multilingual",
|
|
args=[
|
|
"--enforce-eager",
|
|
"--max-model-len",
|
|
"1024",
|
|
"--trust-remote-code",
|
|
],
|
|
without_truncated_prompt_tokens=284,
|
|
with_max_tokens_per_query_prompt_tokens=154,
|
|
with_max_tokens_per_doc_prompt_tokens=154,
|
|
with_max_tokens_per_query_and_doc_prompt_tokens=24,
|
|
),
|
|
# 2. cross-encoder + score template
|
|
TestConfig(
|
|
model="Qwen/Qwen3-Reranker-0.6B",
|
|
args=[
|
|
"--enforce-eager",
|
|
"--max-model-len",
|
|
"1024",
|
|
"--hf-overrides",
|
|
json.dumps(
|
|
{
|
|
"architectures": ["Qwen3ForSequenceClassification"],
|
|
"classifier_from_token": ["no", "yes"],
|
|
"is_original_qwen3_reranker": True,
|
|
}
|
|
),
|
|
"--chat-template",
|
|
os.path.join(TEMPLATE_DIR, "qwen3_reranker.jinja"),
|
|
],
|
|
without_truncated_prompt_tokens=352,
|
|
with_max_tokens_per_query_prompt_tokens=223,
|
|
with_max_tokens_per_doc_prompt_tokens=221,
|
|
with_max_tokens_per_query_and_doc_prompt_tokens=92,
|
|
),
|
|
# 3. bi-encoder
|
|
TestConfig(
|
|
model="intfloat/multilingual-e5-small",
|
|
args=[
|
|
"--enforce-eager",
|
|
"--max-model-len",
|
|
"512",
|
|
"--trust-remote-code",
|
|
],
|
|
# This model has produced both prompt-token totals in CI/local cache;
|
|
# keep truncation checks exact while tolerating the boundary delta.
|
|
without_truncated_prompt_tokens=(285, 286),
|
|
with_max_tokens_per_query_prompt_tokens=(155, 156),
|
|
with_max_tokens_per_doc_prompt_tokens=155,
|
|
with_max_tokens_per_query_and_doc_prompt_tokens=25,
|
|
),
|
|
# 4. late-interaction
|
|
TestConfig(
|
|
model="answerdotai/answerai-colbert-small-v1",
|
|
args=[
|
|
"--enforce-eager",
|
|
"--max-model-len",
|
|
"512",
|
|
"--trust-remote-code",
|
|
],
|
|
without_truncated_prompt_tokens=285,
|
|
with_max_tokens_per_query_prompt_tokens=155,
|
|
with_max_tokens_per_doc_prompt_tokens=155,
|
|
with_max_tokens_per_query_and_doc_prompt_tokens=25,
|
|
),
|
|
# 5. jinaai/jina-reranker-v3
|
|
TestConfig(
|
|
model="jinaai/jina-reranker-v3",
|
|
args=[
|
|
"--enforce-eager",
|
|
"--max-model-len",
|
|
"1024",
|
|
"--trust-remote-code",
|
|
],
|
|
without_truncated_prompt_tokens=567,
|
|
with_max_tokens_per_query_prompt_tokens=308,
|
|
with_max_tokens_per_doc_prompt_tokens=436,
|
|
with_max_tokens_per_query_and_doc_prompt_tokens=177,
|
|
),
|
|
]
|
|
|
|
|
|
def assert_prompt_tokens(actual: int, expected: ExpectedPromptTokens) -> None:
|
|
if isinstance(expected, int):
|
|
assert actual == expected
|
|
else:
|
|
assert actual in expected
|
|
|
|
|
|
@pytest.fixture(scope="module", params=RERANK_CONFIGS, ids=lambda c: c.model)
|
|
def server(request):
|
|
config: TestConfig = request.param
|
|
with RemoteOpenAIServer(config.model, config.args) as remote_server:
|
|
yield config, remote_server
|
|
|
|
|
|
def test_without_truncated(server):
|
|
"""Test that max_tokens_per_doc truncates documents correctly."""
|
|
config, remote_server = server
|
|
|
|
response = requests.post(
|
|
remote_server.url_for("rerank"),
|
|
json={"model": config.model, "query": long_query, "documents": [long_doc]},
|
|
)
|
|
response.raise_for_status()
|
|
rerank = RerankResponse.model_validate(response.json())
|
|
|
|
assert rerank.id is not None
|
|
assert rerank.results is not None
|
|
assert len(rerank.results) == 1
|
|
assert_prompt_tokens(
|
|
rerank.usage.prompt_tokens,
|
|
config.without_truncated_prompt_tokens,
|
|
)
|
|
|
|
|
|
def test_max_tokens_per_query(server):
|
|
"""Test that max_tokens_per_doc truncates documents correctly."""
|
|
config, remote_server = server
|
|
|
|
response = requests.post(
|
|
remote_server.url_for("rerank"),
|
|
json={
|
|
"model": config.model,
|
|
"query": long_query,
|
|
"documents": [long_doc],
|
|
"max_tokens_per_query": 10,
|
|
},
|
|
)
|
|
response.raise_for_status()
|
|
rerank = RerankResponse.model_validate(response.json())
|
|
|
|
assert rerank.id is not None
|
|
assert rerank.results is not None
|
|
assert len(rerank.results) == 1
|
|
assert_prompt_tokens(
|
|
rerank.usage.prompt_tokens,
|
|
config.with_max_tokens_per_query_prompt_tokens,
|
|
)
|
|
|
|
|
|
def test_max_tokens_per_doc(server):
|
|
"""Test that max_tokens_per_doc truncates documents correctly."""
|
|
config, remote_server = server
|
|
|
|
response = requests.post(
|
|
remote_server.url_for("rerank"),
|
|
json={
|
|
"model": config.model,
|
|
"query": long_query,
|
|
"documents": [long_doc],
|
|
"max_tokens_per_doc": 10,
|
|
},
|
|
)
|
|
response.raise_for_status()
|
|
rerank = RerankResponse.model_validate(response.json())
|
|
|
|
assert rerank.id is not None
|
|
assert rerank.results is not None
|
|
assert len(rerank.results) == 1
|
|
assert_prompt_tokens(
|
|
rerank.usage.prompt_tokens,
|
|
config.with_max_tokens_per_doc_prompt_tokens,
|
|
)
|
|
|
|
|
|
def test_max_tokens_per_query_and_doc(server):
|
|
"""Test that max_tokens_per_doc truncates documents correctly."""
|
|
config, remote_server = server
|
|
|
|
response = requests.post(
|
|
remote_server.url_for("rerank"),
|
|
json={
|
|
"model": config.model,
|
|
"query": long_query,
|
|
"documents": [long_doc],
|
|
"max_tokens_per_query": 10,
|
|
"max_tokens_per_doc": 10,
|
|
},
|
|
)
|
|
response.raise_for_status()
|
|
rerank = RerankResponse.model_validate(response.json())
|
|
|
|
assert rerank.id is not None
|
|
assert rerank.results is not None
|
|
assert len(rerank.results) == 1
|
|
assert_prompt_tokens(
|
|
rerank.usage.prompt_tokens,
|
|
config.with_max_tokens_per_query_and_doc_prompt_tokens,
|
|
)
|