执行摘要
- 一句话:新增 tool_call_parser_invocations_total Prometheus 指标
- 推荐动作:值得阅读 review 中关于指标设计、延迟初始化和低基数标签的讨论,有助于理解 vLLM 中 Prometheus 指标注册的约束与模式。
功能与动机
PR 正文指出:添加该指标以便操作员观察解析器运行频率及是否产生了工具调用,从而在模型上线或运行时变更中更容易发现工具调用回归。
实现拆解
- 创建
vllm/parser/metrics.py,定义 ToolCallOutcome 和 RequestType 枚举,以及 init_parser_metrics 和 record_tool_parser_invocation 函数。
- 在
vllm/entrypoints/openai/api_server.py 的 init_app_state 中,当 args.tool_call_parser 非 None 时调用 init_parser_metrics,传入模型名称。
- 修改
vllm/parser/abstract_parser.py 中的 DelegatingParser 类,在 extract_tool_calls 和 extract_tool_calls_streaming 方法中添加 record_tool_parser_invocation 调用,使用 try-finally 确保异常时也记录(当前异常视为 no tool call)。同时调整方法签名支持 ChatCompletionRequest | ResponsesRequest。
- 根据 review 建议移除了最初引入的环境变量开关,性能测试未观察到影响。
- 增加了
model_name 标签,便于跨实例聚合。
关键文件:
vllm/parser/metrics.py(模块 解析器;类别 source;类型 dependency-wiring;符号 ToolCallOutcome, RequestType, init_parser_metrics, record_tool_parser_invocation): 核心新增文件,包含指标注册、枚举定义和记录函数,是 PR 的主要贡献。
vllm/parser/abstract_parser.py(模块 解析器;类别 source;类型 dependency-wiring): DelegatingParser 是工具解析器的调度入口,在此注入指标记录逻辑,覆盖所有工具调用路径。
vllm/entrypoints/openai/api_server.py(模块 API服务;类别 source;类型 entrypoint): 在 API server 初始化阶段注册指标,确保指标在使用前已创建。
关键符号:init_parser_metrics, record_tool_parser_invocation, DelegatingParser.extract_tool_calls, DelegatingParser.extract_tool_calls_streaming
关键源码片段
vllm/parser/abstract_parser.py
DelegatingParser 是工具解析器的调度入口,在此注入指标记录逻辑,覆盖所有工具调用路径。
# vllm/parser/abstract_parser.py (DelegatingParser 相关方法 )
def extract_tool_calls(
self,
model_output: str,
request: ChatCompletionRequest | ResponsesRequest,
) -> ExtractedToolCallInformation:
if self._tool_parser is None:
return ExtractedToolCallInformation(
tools_called=False, tool_calls=[], content=model_output
)
result = None
is_tool_called: bool | Exception = False
try:
result = self._tool_parser.extract_tool_calls(
model_output,
request=request, # type: ignore[arg-type]
)
is_tool_called = bool(result.tools_called)
except Exception as e:
# 记录异常标记,后续统计为 no_tool_call,但继续抛出异常
is_tool_called = e
raise
finally:
# 无论是否异常,都记录调用;异常时 is_tool_called 为异常对象,
# record_tool_parser_invocation 内部会转为 NO_TOOL_CALL
record_tool_parser_invocation(
is_tool_called=is_tool_called,
is_streaming=False,
request=request,
)
return result
def extract_tool_calls_streaming(
self,
previous_text: str,
current_text: str,
delta_text: str,
previous_token_ids: Sequence[int],
current_token_ids: Sequence[int],
delta_token_ids: Sequence[int],
request: ChatCompletionRequest | ResponsesRequest,
) -> DeltaMessage | None:
if self._tool_parser is None:
return None
result = None
is_tool_called: bool | Exception = False
try:
result = self._tool_parser.extract_tool_calls_streaming(
previous_text,
current_text,
delta_text,
previous_token_ids,
current_token_ids,
delta_token_ids,
request=request, # type: ignore[arg-type]
)
is_tool_called = bool(
result.tool_calls is not None and len(result.tool_calls) > 0
)
except Exception as e:
is_tool_called = e
raise
finally:
record_tool_parser_invocation(
is_tool_called=is_tool_called,
is_streaming=True,
request=request,
)
return result
vllm/entrypoints/openai/api_server.py
在 API server 初始化阶段注册指标,确保指标在使用前已创建。
# vllm/entrypoints/openai/api_server.py (init_app_state 片段 )
# 当启用了 tool_call_parser 时,初始化 parser 相关的 Prometheus 指标
if args.tool_call_parser is not None:
from vllm.parser.metrics import init_parser_metrics
init_parser_metrics(
model_name=cast(str, vllm_config.model_config.served_model_name)
)
if supported_tasks is None:
warnings.warn(...)
评论区精华
风险与影响
- 风险:该变更新增 Prometheus 计数器,无 API/配置 breaking change。性能测试表明开销可忽略。主要风险:parser 内部异常被捕获时,当前视为 no tool call,无法区分真实错误。已在 docstring 说明,未来可通过 propagating exception 改进。多进程模式下 Prometheus 原生支持,已验证。
- 影响:用户:获得新指标
vllm:tool_call_parser_invocations_total,改进可观测性。系统:极低性能开销。团队:便于监控 tool-calling 回归,但该指标仅覆盖非 harmony 路径,harmony 路径尚未接入 DelegatingParser。
- 风险标记:新监控指标无兼容性问题, 多进程支持已验证, 异常场景统计可能不准, 缺少测试覆盖
关联脉络
- PR #35669 Feature/offloading manager stats: 同样为系统添加新的 Prometheus 指标,扩展可观测能力,体现了 metrics 基础设施的持续建设。
参与讨论