요청별 메트릭

요청별 메트릭 (Per-Request Metrics)

vLLM은 API 응답에 요청별 타이밍 메트릭을 직접 포함해서 반환할 수 있어요. 개별 요청 수준의 과금(billing), SLA 모니터링, 지연 시간 분석에 유용하며, 서버가 집계한 Prometheus 메트릭(/metrics 으로 노출)을 보완하는 역할을 합니다.

출처: 문서

본문

활성화 (Enabling)

--enable-per-request-metrics 플래그로 서버를 시작하세요.

vllm serve meta-llama/Llama-3.1-8B-Instruct --enable-per-request-metrics

이 플래그를 설정하면 지원되는 API 응답에 각 요청에 귀속되는 메트릭이 포함됩니다.

참고: 높은 동시성에서는 요청별 메트릭 계산이 무시할 수 없는 수준의 CPU 오버헤드를 유발할 수 있어요. 프로덕션에서 활성화하기 전에 실제 워크로드로 벤치마크하여 영향을 평가하세요.

응답 형식 (Response Format)

요청별 메트릭이 활성화되면 응답에 metrics 객체가 포함됩니다.

{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "model": "meta-llama/Llama-3.1-8B-Instruct",
  "choices": [ ... ],
  "usage": {
    "prompt_tokens": 42,
    "completion_tokens": 128,
    "total_tokens": 170
  },
  "metrics": {
    "time_to_first_token_ms": 85.2,
    "generation_time_ms": 1240.5,
    "queue_time_ms": 12.3,
    "mean_itl_ms": 9.1,
    "tokens_per_second": 103.2
  }
}
필드 설명
time_to_first_token_ms 요청이 스케줄된 시점부터 첫 번째 출력 토큰이 생성될 때까지의 시간(TTFT)입니다.
generation_time_ms 디코드 시간: 첫 번째 출력 토큰부터 마지막 출력 토큰까지의 시간입니다. 큐 대기와 prefill/TTFT는 제외됩니다.
queue_time_ms 요청이 처리되기 전에 스케줄러 큐에서 대기한 시간입니다.
mean_itl_ms 디코드 단계에서의 평균 토큰 간 지연 시간(연속 출력 토큰 사이의 평균 시간)입니다. 단일 토큰 응답에서는 null 입니다.
tokens_per_second 전체 출력 토큰 처리량: 추론 구간(스케줄링부터 마지막 출력 토큰까지) 동안 생성된 전체 토큰 수입니다. generation_time_ms 와 달리 prefill 단계를 포함하므로 순수 디코드 속도가 아니라 종단 간 생성 속도를 반영합니다.

해당 요청에 대한 기본 타이밍 데이터가 없다면 모든 필드는 null 이 됩니다.

참고: 타이밍 메트릭은 단일 생성 스트림을 설명하므로 요청이 정확히 하나의 스트림에 매핑될 때만 반환됩니다. n > 1 요청에서는 메트릭이 억제됩니다(metrics 객체가 null). 기본 타이밍 데이터가 n 개 시퀀스 중 하나만 반영하므로 요청 전체에 정확히 귀속될 수 없기 때문이에요. 하지만 토큰 사용량(prompt_tokens, completion_tokens)은 이 경우에도 정확하게 유지됩니다. 또한 요청별 메트릭은 기본적으로 켜져 있는 서버 측 통계 로깅을 요구하며, --disable-log-stats 가 설정된 경우 vLLM은 --enable-per-request-metrics 를 거부합니다.

예시 요청 (Example Request)

비스트리밍 (Non-streaming)

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="token")

response = client.chat.completions.create(
    model="meta-llama/Llama-3.1-8B-Instruct",
    messages=[{"role": "user", "content": "What is the capital of France?"}],
)

print(response.usage)
print(response.model_extra.get("metrics"))

스트리밍 (Streaming)

스트리밍 응답에서는 모든 콘텐츠 청크가 전송된 후 보내지는 최종 usage 청크에 메트릭이 붙어요. 이 청크는 stream_options.include_usage: true 로 usage 보고가 활성화되거나 --enable-force-include-usage 로 서버 측에서 강제할 때만 전송됩니다. 강제 usage가 없으면 스트리밍 클라이언트는 메트릭을 받기 위해 stream_options.include_usage: true 를 설정해야 합니다.

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="token")

stream = client.chat.completions.create(
    model="meta-llama/Llama-3.1-8B-Instruct",
    messages=[{"role": "user", "content": "What is the capital of France?"}],
    stream=True,
    stream_options={"include_usage": True},
)

for chunk in stream:
    if chunk.usage:
        print("Usage:", chunk.usage)
        print("Metrics:", chunk.model_extra.get("metrics"))

Completions API

요청별 메트릭은 /v1/completions 엔드포인트에서도 동일한 metrics 응답 필드를 통해 사용할 수 있어요. n > 1 과 마찬가지로, 타이밍 데이터를 단일 프롬프트의 생성에 귀속시킬 수 없으므로 여러 프롬프트를 가진 요청에서는 메트릭이 생략됩니다.

Responses API

요청별 메트릭은 /v1/responses 엔드포인트에서도 위에서 설명한 공통 metrics 객체로 사용할 수 있어요. 비스트리밍 응답은 최상위 레벨에 이를 포함하고, 스트리밍 응답은 response.completed 이벤트가 전달하는 최종 응답에 포함합니다. 중간 이벤트에는 메트릭이 없어요.

내장 도구 호출 워크플로우처럼 여러 모델 생성 턴을 수행하는 Responses 요청에서는 메트릭이 생략됩니다. 이 경우 응답이 단 하나의 생성 턴에 대한 타이밍 데이터만 보유하지만 토큰 사용량은 모든 턴에 걸쳐 누적되기 때문이에요.

Prometheus 메트릭과의 관계

metrics 응답 필드는 단일 요청에 대한 요청별 값을 제공합니다. /metrics Prometheus 엔드포인트는 모든 요청을 집계한 서버 수준 히스토그램(예: vllm:time_to_first_token_seconds)을 노출합니다.

스펙큘레이티브 디코딩 수용률 (Speculative Decoding Acceptance)

스펙큘레이티브 디코딩이 활성화되면 --per-request-spec-decode-metrics 를 통해 요청별 수용 메트릭(평균 수용 길이와 수용된 draft 길이 분포)을 반환할 수 있어요. 이들은 metrics.speculative_decoding 으로 이 metrics 객체를 공유하며, 타이밍 필드와 마찬가지로 단일 시퀀스(n == 1) 요청에 대해서만 보고됩니다. 자세한 내용은 Per-Request Acceptance Metrics 를 참고하세요.

더 알아보기 (Learn more)