Skip to content

Commit 04e0601

Browse files
nachiketb-nvidiaJason Zhou
authored andcommitted
feat: add and enable reasoning and tool parser flags for trtllm and sglang (#2713)
Signed-off-by: Jason Zhou <jasonzho@jasonzho-mlt.client.nvidia.com>
1 parent b9029f7 commit 04e0601

5 files changed

Lines changed: 73 additions & 10 deletions

File tree

components/backends/sglang/src/dynamo/sglang/args.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from argparse import Namespace
1111
from dataclasses import dataclass
1212
from enum import Enum
13-
from typing import Any, Dict
13+
from typing import Any, Dict, Optional
1414

1515
from sglang.srt.server_args import ServerArgs
1616

@@ -39,6 +39,10 @@ class DynamoArgs:
3939
endpoint: str
4040
migration_limit: int
4141

42+
# tool and reasoning parser options
43+
tool_call_parser: Optional[str] = None
44+
reasoning_parser: Optional[str] = None
45+
4246

4347
class DisaggregationMode(Enum):
4448
AGGREGATED = "agg"
@@ -71,6 +75,20 @@ def parse_args(args: list[str]) -> Config:
7175
"--version", action="version", version=f"Dynamo Backend SGLang {__version__}"
7276
)
7377

78+
# To avoid name conflicts with different backends, adoped prefix "dyn-" for dynamo specific args
79+
parser.add_argument(
80+
"--dyn-tool-call-parser",
81+
type=str,
82+
default=None,
83+
help="Tool call parser name for the model. Available options: 'hermes', 'nemotron_deci', 'llama3_json', 'mistral', 'phi4'.",
84+
)
85+
parser.add_argument(
86+
"--dyn-reasoning-parser",
87+
type=str,
88+
default=None,
89+
help="Reasoning parser name for the model. Available options: 'basic', 'deepseek_r1', 'gpt_oss'.",
90+
)
91+
7492
# Dynamo args
7593
for info in DYNAMO_ARGS.values():
7694
parser.add_argument(
@@ -123,6 +141,8 @@ def parse_args(args: list[str]) -> Config:
123141
component=parsed_component_name,
124142
endpoint=parsed_endpoint_name,
125143
migration_limit=parsed_args.migration_limit,
144+
tool_call_parser=parsed_args.dyn_tool_call_parser,
145+
reasoning_parser=parsed_args.dyn_reasoning_parser,
126146
)
127147
logging.debug(f"Dynamo args: {dynamo_args}")
128148

components/backends/sglang/src/dynamo/sglang/main.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,10 @@ async def gated_generate(request):
9797
async def register_model():
9898
"""Register the model and signal readiness"""
9999
registration_success = await register_llm_with_runtime_config(
100-
engine, generate_endpoint, server_args, dynamo_args.migration_limit
100+
engine,
101+
generate_endpoint,
102+
server_args,
103+
dynamo_args,
101104
)
102105

103106
if not registration_success:

components/backends/sglang/src/dynamo/sglang/register.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,29 @@
99

1010
from dynamo._core import Endpoint
1111
from dynamo.llm import ModelRuntimeConfig, ModelType, register_llm
12+
from dynamo.sglang.args import DynamoArgs
1213

1314

1415
async def register_llm_with_runtime_config(
1516
engine: sgl.Engine,
1617
endpoint: Endpoint,
1718
server_args: ServerArgs,
18-
migration_limit: int,
19+
dynamo_args: DynamoArgs,
1920
) -> bool:
2021
"""Register LLM with runtime config
2122
2223
Returns:
2324
bool: True if registration succeeded, False if it failed
2425
"""
25-
runtime_config = await _get_runtime_config(engine)
26+
runtime_config = await _get_runtime_config(engine, dynamo_args)
2627
try:
2728
await register_llm(
2829
ModelType.Backend,
2930
endpoint,
3031
server_args.model_path,
3132
server_args.served_model_name,
3233
kv_cache_block_size=server_args.page_size,
33-
migration_limit=migration_limit,
34+
migration_limit=dynamo_args.migration_limit,
3435
runtime_config=runtime_config,
3536
)
3637
logging.info("Successfully registered LLM with runtime config")
@@ -40,13 +41,17 @@ async def register_llm_with_runtime_config(
4041
return False
4142

4243

43-
async def _get_runtime_config(engine: sgl.Engine) -> Optional[ModelRuntimeConfig]:
44+
async def _get_runtime_config(
45+
engine: sgl.Engine, dynamo_args: DynamoArgs
46+
) -> Optional[ModelRuntimeConfig]:
4447
"""Get runtime config from SGLang engine"""
48+
runtime_config = ModelRuntimeConfig()
49+
# set reasoning parser and tool call parser
50+
runtime_config.reasoning_parser = dynamo_args.reasoning_parser
51+
runtime_config.tool_call_parser = dynamo_args.tool_call_parser
4552
try:
4653
# Try to check if the engine has a scheduler attribute with the computed values
4754
if hasattr(engine, "scheduler_info") and engine.scheduler_info is not None:
48-
runtime_config = ModelRuntimeConfig()
49-
5055
# Get max_total_num_tokens from scheduler_info
5156
if "max_total_num_tokens" in engine.scheduler_info:
5257
max_total_tokens = engine.scheduler_info["max_total_num_tokens"]
@@ -73,8 +78,8 @@ async def _get_runtime_config(engine: sgl.Engine) -> Optional[ModelRuntimeConfig
7378
"The engine may compute these values internally after initialization. "
7479
"Proceeding without runtime config - SGLang will use its internal defaults."
7580
)
76-
return None
81+
return runtime_config
7782

7883
except Exception as e:
7984
logging.warning(f"Failed to get runtime config: {e}. Proceeding without it.")
80-
return None
85+
return runtime_config

components/backends/trtllm/src/dynamo/trtllm/main.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,17 @@ async def init(runtime: DistributedRuntime, config: Config):
228228
async with get_llm_engine(engine_args) as engine:
229229
endpoint = component.endpoint(config.endpoint)
230230

231+
# should ideally call get_engine_runtime_config
232+
# this is because we don't have a good way to
233+
# get total_kv_blocks from the engine yet without calling get_stats_async
234+
# This causes an issue because get_stats_async doesn't work when no requests are sent to the engine
235+
# So for now, we just set the parsers from the config
236+
# TODO: fix this once we have a better way to get total_kv_blocks
237+
runtime_config = ModelRuntimeConfig()
238+
239+
runtime_config.reasoning_parser = config.reasoning_parser
240+
runtime_config.tool_call_parser = config.tool_call_parser
241+
231242
if is_first_worker(config):
232243
# Register the model with runtime config
233244
await register_llm(
@@ -237,6 +248,7 @@ async def init(runtime: DistributedRuntime, config: Config):
237248
config.served_model_name,
238249
kv_cache_block_size=config.kv_block_size,
239250
migration_limit=config.migration_limit,
251+
runtime_config=runtime_config,
240252
)
241253
# publisher will be set later if publishing is enabled.
242254
handler_config = RequestHandlerConfig(

components/backends/trtllm/src/dynamo/trtllm/utils/trtllm_utils.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ def __init__(self) -> None:
4949
self.next_endpoint: str = ""
5050
self.modality: str = "text"
5151

52+
self.reasoning_parser: Optional[str] = None
53+
self.tool_call_parser: Optional[str] = None
54+
5255
def __str__(self) -> str:
5356
return (
5457
f"Config(namespace={self.namespace}, "
@@ -73,6 +76,8 @@ def __str__(self) -> str:
7376
f"disaggregation_strategy={self.disaggregation_strategy}, "
7477
f"next_endpoint={self.next_endpoint}, "
7578
f"modality={self.modality})"
79+
f"reasoning_parser={self.reasoning_parser})"
80+
f"tool_call_parser={self.tool_call_parser})"
7681
)
7782

7883

@@ -234,6 +239,21 @@ def cmd_line_args():
234239
default="",
235240
help=f"Endpoint(in 'dyn://namespace.component.endpoint' format) to send requests to when running in disaggregation mode. Default: {DEFAULT_NEXT_ENDPOINT} if first worker, empty if next worker",
236241
)
242+
243+
# To avoid name conflicts with different backends, adoped prefix "dyn-" for dynamo specific args
244+
parser.add_argument(
245+
"--dyn-tool-call-parser",
246+
type=str,
247+
default=None,
248+
help="Tool call parser name for the model. Available options: 'hermes', 'nemotron_deci', 'llama3_json', 'mistral', 'phi4'.",
249+
)
250+
parser.add_argument(
251+
"--dyn-reasoning-parser",
252+
type=str,
253+
default=None,
254+
help="Reasoning parser name for the model. Available options: 'basic', 'deepseek_r1', 'gpt_oss'.",
255+
)
256+
237257
args = parser.parse_args()
238258

239259
config = Config()
@@ -294,4 +314,7 @@ def cmd_line_args():
294314
config.publish_events_and_metrics = args.publish_events_and_metrics
295315
config.modality = args.modality
296316

317+
config.reasoning_parser = args.dyn_reasoning_parser
318+
config.tool_call_parser = args.dyn_tool_call_parser
319+
297320
return config

0 commit comments

Comments
 (0)