Skip to content

Commit 2c4a284

Browse files
lvhan028cursoragent
andcommitted
refactor(serve): simplify generation config merge and defaults
Drop PROTOCOL_FALLBACKS in favor of GenerationConfig dataclass defaults, and streamline build_generation_config to merge request and HF config in one place. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 46e0352 commit 2c4a284

7 files changed

Lines changed: 63 additions & 97 deletions

File tree

lmdeploy/serve/anthropic/adapter.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import shortuuid
1010

1111
from lmdeploy.messages import GenerationConfig
12-
from lmdeploy.serve.core.generation_config import build_generation_config, extract_request_sampling_values
12+
from lmdeploy.serve.core.generation_config import build_generation_config
1313
from lmdeploy.serve.openai.protocol import Tool, ToolChoice, ToolChoiceFuncName
1414

1515
from .protocol import (
@@ -347,11 +347,10 @@ def to_generation_config(
347347
default_gen_config: dict | None = None,
348348
) -> GenerationConfig:
349349
"""Map Anthropic messages request to LMDeploy generation config."""
350-
request_values = extract_request_sampling_values(request)
351350
return build_generation_config(
352-
request_values,
351+
request,
353352
default_gen_config or {},
354-
max_tokens=request.max_tokens,
353+
max_new_tokens=request.max_tokens,
355354
stop_words=request.stop_sequences,
356355
include_stop_str_in_output=request.include_stop_str_in_output or False,
357356
skip_special_tokens=True,

lmdeploy/serve/core/generation_config.py

Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,14 @@
44

55
from __future__ import annotations
66

7+
import dataclasses
78
from typing import Any
89

910
from lmdeploy.messages import GenerationConfig
1011
from lmdeploy.utils import get_logger
1112

1213
logger = get_logger('lmdeploy')
1314

14-
PROTOCOL_FALLBACKS: dict[str, Any] = {
15-
'temperature': 0.7,
16-
'top_p': 1.0,
17-
'top_k': 40,
18-
'repetition_penalty': 1.0,
19-
'min_p': 0.0,
20-
'do_sample': True,
21-
}
22-
23-
REQUEST_SAMPLING_FIELDS = (
24-
'temperature',
25-
'top_p',
26-
'top_k',
27-
'min_p',
28-
'repetition_penalty',
29-
)
30-
3115

3216
def _load_hf_generation_config(path: str, trust_remote_code: bool) -> dict[str, Any]:
3317
from transformers import GenerationConfig
@@ -66,55 +50,45 @@ def resolve_default_gen_config(
6650
def merge_sampling_params(
6751
request_values: dict[str, Any],
6852
default_gen_config: dict[str, Any],
69-
fallbacks: dict[str, Any] | None = None,
7053
) -> dict[str, Any]:
71-
"""Merge sampling params with request > default_gen_config > protocol
72-
fallback priority."""
73-
fallbacks = fallbacks or PROTOCOL_FALLBACKS
54+
"""Merge sampling params with request > default_gen_config priority."""
7455
merged: dict[str, Any] = {}
75-
all_keys = set(fallbacks) | set(default_gen_config) | set(request_values)
76-
for key in all_keys:
56+
for key in set(default_gen_config) | set(request_values):
7757
if key in request_values:
7858
merged[key] = request_values[key]
79-
elif key in default_gen_config:
59+
else:
8060
merged[key] = default_gen_config[key]
81-
elif key in fallbacks:
82-
merged[key] = fallbacks[key]
8361
return merged
8462

8563

8664
def extract_request_sampling_values(request: Any) -> dict[str, Any]:
87-
"""Extract explicitly provided sampling fields from a request object."""
65+
"""Extract non-None GenerationConfig fields present on the request."""
8866
values: dict[str, Any] = {}
89-
for field in REQUEST_SAMPLING_FIELDS:
90-
if not hasattr(request, field):
67+
for field in dataclasses.fields(GenerationConfig):
68+
if not hasattr(request, field.name):
9169
continue
92-
value = getattr(request, field)
70+
value = getattr(request, field.name)
9371
if value is not None:
94-
values[field] = value
72+
values[field.name] = value
9573
return values
9674

9775

9876
def build_generation_config(
99-
request_values: dict[str, Any],
77+
request: Any,
10078
default_gen_config: dict[str, Any],
10179
*,
102-
max_completion_tokens: int | None = None,
103-
max_tokens: int | None = None,
104-
fallbacks: dict[str, Any] | None = None,
80+
max_new_tokens: int | None = None,
10581
**extra_kwargs: Any,
10682
) -> GenerationConfig:
10783
"""Build ``GenerationConfig`` from merged sampling defaults and request
10884
values."""
109-
merged = merge_sampling_params(request_values, default_gen_config, fallbacks)
110-
max_new_tokens = max_completion_tokens if max_completion_tokens is not None else max_tokens
85+
request_values = extract_request_sampling_values(request)
86+
merged = merge_sampling_params(request_values, default_gen_config)
87+
merged.pop('max_new_tokens', None)
88+
merged.pop('do_sample', None)
11189
return GenerationConfig(
11290
max_new_tokens=max_new_tokens,
113-
do_sample=merged.get('do_sample', PROTOCOL_FALLBACKS['do_sample']),
114-
top_k=merged['top_k'],
115-
top_p=merged['top_p'],
116-
temperature=merged['temperature'],
117-
repetition_penalty=merged['repetition_penalty'],
118-
min_p=merged['min_p'],
91+
do_sample=True,
92+
**merged,
11993
**extra_kwargs,
12094
)

lmdeploy/serve/openai/api_server.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
from lmdeploy.serve.core import AsyncEngine, EngineHealthMonitor
5050
from lmdeploy.serve.core.generation_config import (
5151
build_generation_config,
52-
extract_request_sampling_values,
5352
resolve_default_gen_config,
5453
)
5554
from lmdeploy.serve.openai.protocol import (
@@ -155,16 +154,13 @@ def get_engine_config(cls):
155154

156155
def _build_serving_generation_config(request, **extra_kwargs) -> GenerationConfig:
157156
"""Build ``GenerationConfig`` with server and request sampling merge."""
158-
request_values = extract_request_sampling_values(request)
159-
max_completion_tokens = getattr(request, 'max_completion_tokens', None)
160-
max_tokens = getattr(request, 'max_tokens', None)
161-
if max_completion_tokens is None and hasattr(request, 'max_output_tokens'):
162-
max_completion_tokens = getattr(request, 'max_output_tokens', None)
157+
max_new_tokens = getattr(request, 'max_completion_tokens', None)
158+
if max_new_tokens is None:
159+
max_new_tokens = getattr(request, 'max_tokens', None)
163160
return build_generation_config(
164-
request_values,
161+
request,
165162
VariableInterface.default_gen_config,
166-
max_completion_tokens=max_completion_tokens,
167-
max_tokens=max_tokens,
163+
max_new_tokens=max_new_tokens,
168164
**extra_kwargs,
169165
)
170166

lmdeploy/serve/openai/responses/request.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from fastapi.responses import JSONResponse
1010

1111
from lmdeploy.messages import GenerationConfig
12-
from lmdeploy.serve.core.generation_config import build_generation_config, extract_request_sampling_values
12+
from lmdeploy.serve.core.generation_config import build_generation_config
1313
from lmdeploy.serve.openai.protocol import Tool, ToolChoice, ToolChoiceFuncName
1414
from lmdeploy.serve.openai.responses.protocol import ResponsesRequest
1515
from lmdeploy.utils import get_logger
@@ -270,11 +270,10 @@ def to_generation_config(
270270
default_gen_config: dict | None = None,
271271
) -> GenerationConfig:
272272
stop_words = [request.stop] if isinstance(request.stop, str) else request.stop
273-
request_values = extract_request_sampling_values(request)
274273
return build_generation_config(
275-
request_values,
274+
request,
276275
default_gen_config or {},
277-
max_completion_tokens=request.max_output_tokens,
276+
max_new_tokens=request.max_output_tokens,
278277
stop_words=stop_words,
279278
ignore_eos=request.ignore_eos,
280279
skip_special_tokens=request.skip_special_tokens,

lmdeploy/serve/openai/serving_chat_completion.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
# Copyright (c) OpenMMLab. All rights reserved.
22
from typing import TYPE_CHECKING
33

4-
from lmdeploy.serve.core.generation_config import (
5-
PROTOCOL_FALLBACKS,
6-
extract_request_sampling_values,
7-
merge_sampling_params,
8-
)
4+
from lmdeploy.serve.core.generation_config import build_generation_config
95

106
from .protocol import ChatCompletionRequest
117

@@ -14,11 +10,12 @@
1410

1511

1612
def _effective_sampling(request: ChatCompletionRequest, server_context: 'VariableInterface') -> dict:
17-
return merge_sampling_params(
18-
extract_request_sampling_values(request),
19-
server_context.default_gen_config,
20-
PROTOCOL_FALLBACKS,
21-
)
13+
gen = build_generation_config(request, server_context.default_gen_config)
14+
return {
15+
'temperature': gen.temperature,
16+
'top_p': gen.top_p,
17+
'top_k': gen.top_k,
18+
}
2219

2320

2421
def check_request(request: ChatCompletionRequest, server_context: 'VariableInterface') -> str:

lmdeploy/serve/openai/serving_completion.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
# Copyright (c) OpenMMLab. All rights reserved.
22
from typing import TYPE_CHECKING
33

4-
from lmdeploy.serve.core.generation_config import (
5-
PROTOCOL_FALLBACKS,
6-
extract_request_sampling_values,
7-
merge_sampling_params,
8-
)
4+
from lmdeploy.serve.core.generation_config import build_generation_config
95

106
from .protocol import CompletionRequest
117

@@ -14,11 +10,12 @@
1410

1511

1612
def _effective_sampling(request: CompletionRequest, server_context: 'VariableInterface') -> dict:
17-
return merge_sampling_params(
18-
extract_request_sampling_values(request),
19-
server_context.default_gen_config,
20-
PROTOCOL_FALLBACKS,
21-
)
13+
gen = build_generation_config(request, server_context.default_gen_config)
14+
return {
15+
'temperature': gen.temperature,
16+
'top_p': gen.top_p,
17+
'top_k': gen.top_k,
18+
}
2219

2320

2421
def check_request(request: CompletionRequest, server_context: 'VariableInterface') -> str:

tests/test_lmdeploy/serve/test_generation_config.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,29 @@
11
# Copyright (c) OpenMMLab. All rights reserved.
22
from unittest.mock import patch
33

4+
from lmdeploy.messages import GenerationConfig
45
from lmdeploy.serve.core.generation_config import (
5-
PROTOCOL_FALLBACKS,
66
build_generation_config,
77
extract_request_sampling_values,
88
merge_sampling_params,
99
resolve_default_gen_config,
1010
)
1111
from lmdeploy.serve.openai.protocol import ChatCompletionRequest, CompletionRequest
1212

13+
_DEFAULTS = GenerationConfig()
14+
1315

1416
def test_merge_sampling_params_priority():
1517
merged = merge_sampling_params(
1618
{'temperature': 0.2},
1719
{'temperature': 0.5, 'top_k': 10},
18-
PROTOCOL_FALLBACKS,
1920
)
20-
assert merged['temperature'] == 0.2
21-
assert merged['top_k'] == 10
22-
assert merged['top_p'] == PROTOCOL_FALLBACKS['top_p']
21+
assert merged == {'temperature': 0.2, 'top_k': 10}
2322

2423

25-
def test_merge_sampling_params_uses_server_then_fallback():
26-
merged = merge_sampling_params({}, {'temperature': 0.5}, PROTOCOL_FALLBACKS)
27-
assert merged['temperature'] == 0.5
28-
assert merged['top_k'] == PROTOCOL_FALLBACKS['top_k']
24+
def test_merge_sampling_params_uses_server_defaults():
25+
merged = merge_sampling_params({}, {'temperature': 0.5})
26+
assert merged == {'temperature': 0.5}
2927

3028

3129
def test_extract_request_sampling_values_only_non_null():
@@ -35,10 +33,11 @@ def test_extract_request_sampling_values_only_non_null():
3533

3634

3735
def test_build_generation_config_from_merged_values():
36+
request = ChatCompletionRequest(model='test', messages='hi', temperature=0.2)
3837
gen_config = build_generation_config(
39-
{'temperature': 0.2},
38+
request,
4039
{'top_k': 5},
41-
max_completion_tokens=32,
40+
max_new_tokens=32,
4241
)
4342
assert gen_config.temperature == 0.2
4443
assert gen_config.top_k == 5
@@ -47,10 +46,18 @@ def test_build_generation_config_from_merged_values():
4746

4847

4948
def test_build_generation_config_max_new_tokens_defaults_to_none():
50-
gen_config = build_generation_config({}, {})
49+
request = CompletionRequest(model='test', prompt='hello')
50+
gen_config = build_generation_config(request, {})
5151
assert gen_config.max_new_tokens is None
5252

5353

54+
def test_build_generation_config_uses_generation_config_defaults():
55+
request = CompletionRequest(model='test', prompt='hello')
56+
gen_config = build_generation_config(request, {})
57+
assert gen_config.temperature == _DEFAULTS.temperature
58+
assert gen_config.top_k == _DEFAULTS.top_k
59+
60+
5461
@patch('lmdeploy.serve.core.generation_config._load_hf_generation_config')
5562
def test_resolve_default_gen_config_auto(mock_load):
5663
mock_load.return_value = {
@@ -74,9 +81,6 @@ def test_resolve_default_gen_config_lmdeploy():
7481

7582
def test_completion_request_sampling_merge():
7683
request = CompletionRequest(model='test', prompt='hello')
77-
gen_config = build_generation_config(
78-
extract_request_sampling_values(request),
79-
{'temperature': 0.9},
80-
)
84+
gen_config = build_generation_config(request, {'temperature': 0.9})
8185
assert gen_config.temperature == 0.9
82-
assert gen_config.top_k == PROTOCOL_FALLBACKS['top_k']
86+
assert gen_config.top_k == _DEFAULTS.top_k

0 commit comments

Comments
 (0)