Documents
Home>Documents>AI>Inference

LLM 서빙에서 출력 길이를 강제로 줄이면 생기는 일: Token Budget, Early Stopping, Truncation의 비용 비교

12 min readSep 8, 2026Sep 8, 2026

운영자가 max_new_tokens에 손을 대는 이유는 단순하다. 긴 출력은 GPU를 오래 묶는다. TPOT(Time Per Output Token)는 동시 디코딩 중인 요청 수에 직선으로 비례하고, KV 캐시 점유 시간이 길수록 다음 요청의 대기도 늘어난다. 128로 묶어두면 배치를 빨리 순환시킬 수 있다는 생각은 합리적으로 보인다.

실제 운영에서 이 직관이 뒤집히는 경우가 있다.

KV 블록 예약과 스케줄러의 셈법

vLLM은 요청을 running 큐에 올리는 순간 KV 블록을 확보해야 한다. 이때 기준이 되는 숫자가 max_new_tokens다. 스케줄러는 입력 토큰 수 + max_new_tokens에 해당하는 블록이 여유 있는지 확인하고, 충분하면 요청을 수락한다. 기본 블록 크기가 16토큰이므로 max_new_tokens=128이면 8블록, max_new_tokens=512면 32블록이 예약 기준으로 잡힌다.

max_new_tokens를 작게 잡으면 블록 예약 요구량이 줄어드므로 스케줄러는 더 많은 요청을 동시에 수락한다. 배치가 커진다. 그런데 실제 출력이 설정값을 초과하는 요청이 생기면 vLLM은 해당 시퀀스를 preemption한다. 실행 중이던 시퀀스를 멈추고 KV 캐시를 비운 뒤 대기 큐로 돌려보낸다. 재처리 시 이전에 계산한 KV 캐시를 전부 다시 계산한다.

여러 요청이 동시에 블록 한계에 달하면 preemption이 연쇄적으로 발생한다. 스케줄러가 낙관적으로 많은 요청을 수락한 것이 연쇄 preemption의 원인이 된다. Sarathi-Serve(Agrawal et al., OSDI 2024)는 이 구조를 chunked prefill로 완화하는 접근을 제안하지만, 출력 길이 예측 오차 자체를 해결하지는 않는다.

preemption 비용

preemption이 비싼 이유는 재계산 때문이다. 8,000토큰 prefill을 처음부터 다시 돌리면 0.2~0.4초가 걸린다. swap 방식은 CPU로 KV 캐시를 옮겼다 복원하는데, PCIe 4.0 x16 대역폭(~32 GB/s) 기준으로도 긴 컨텍스트에서는 시간이 만만치 않다. vLLM v1 기본 모드는 recompute다.

실측 환경에서 GPU 캐시 사용률이 90%를 넘어 preemption이 시작되면 p99 TPOT가 200ms에서 8초까지 치솟는다. P99는 P50의 3.8배에 달하고, 그 격차의 약 70%가 preemption에서 비롯된다.

더 나쁜 경우는 "death spiral"이다. preemption된 요청이 큐로 돌아오면 새 요청과 경쟁하다 다시 preemption되는 사이클이 생긴다. GPU utilization 100%인데 처리량이 정체되는 상태가 이것이다.

세 가지 전략의 비용 구조

출력 길이를 제어하는 방법은 크게 셋이다.

전략KV 블록 점유Preemption 위험생성 품질
max_new_tokens 보수적 설정실사용 < 예약 시 낭비낮은 설정 → 동시 수락 증가 → 연쇄 preemption초과 시 절단
EOS 기반 Early Stopping자연 종료 시 즉시 해제상한 예측 어려워 max_model_len으로 잡히면 과다 예약자연 종료
Post-hoc Truncation전체 생성 동안 점유낮음생성은 완전, 결과만 절단

EOS 기반 early stopping이 이론상 가장 깔끔하다. EOS가 나오는 즉시 블록이 해제되므로 낭비가 없다. 단, 스케줄러가 수락 시점에 블록 예약 상한을 잡아야 하는데, 출력 길이를 모르는 상태에서 max_model_len을 상한으로 쓰면 동시 수락 수가 오히려 떨어진다.

Post-hoc truncation은 자원 낭비가 가장 크다. 2,000토큰 전체를 생성하는 동안 KV 블록이 점유된 채로 있다가, 완료 후 앞 512토큰만 반환한다. GPU 연산과 메모리를 전부 소모하고 결과만 자른다.

Reasoning 모델에서 Budget Forcing이 다른 이유

Qwen3, DeepSeek-R1 계열에서 thinking 토큰을 자르면 일반 truncation과 다른 방식으로 품질이 망가진다.

이 모델들은 <think>...</think> 블록에서 chain-of-thought 추론을 완성한 뒤 answer 토큰을 생성한다. Budget forcing은 thinking 블록이 완결되기 전에 강제로 </think> 구분자를 삽입하고 answer phase로 전환한다. 미완성 추론 위에서 답이 생성되는 구조다. 수학 문제라면 중간 계산을 포기한 채 정답을 추측하는 것과 같다.

DeepSeek-R1-32B 기준으로 thinking 토큰이 처음 500개 추가될 때마다 정확도가 약 +3.2% 오른다. 이 효과는 약 12,000토큰에서 포화된 뒤 음수로 전환된다. 이 곡선을 모른 채 512로 잘라버리면 추론이 가장 활발하게 진행되는 구간을 통째로 날리는 셈이다.

The Coupling Tax 논문은 이 현상을 고정된 총 출력 한도 안에서 thinking과 answer가 자원을 나눠 쓰는 구조 때문으로 분석한다. 둘이 같은 예산을 경쟁하면 어느 쪽도 충분히 확보하기 어렵다.

Qwen3는 thinking_budget 파라미터를 네이티브로 지원한다. /think 스위치와 함께 사용하면 모델 자체가 budget 안에서 추론을 완성하도록 학습되어 있어, 외부에서 강제로 자르는 것보다 품질 손실이 훨씬 작다. DeepSeek-R1은 네이티브 budget 제어가 없다. 외부에서 자르는 방법밖에 없고, 12,000토큰 미만에서 자를수록 추론 완성도가 선형으로 내려간다.

워크로드에 따른 선택

출력 길이 분포의 변동계수(CV = 표준편차/평균)가 0.3 이하인 워크로드라면 max_new_tokens를 평균 출력의 1.5~2배로 설정해도 preemption이 거의 발생하지 않는다. RAG 기반 요약이나 분류 레이블 추출처럼 출력 길이가 일정한 경우다. 스케줄러가 현실에 가깝게 블록을 예약할 수 있기 때문이다.

CV가 1.0을 넘는 워크로드 — reasoning, 코드 생성, 열린 대화 — 에서는 어떤 정적 값도 throughput과 품질을 동시에 만족시키기 어렵다.

한 가지 방법은 max_new_tokens를 넉넉하게 잡되(p90 출력의 1.5~2배) max_num_seqs를 줄여 동시 수락 수를 직접 제한하는 것이다. preemption 압력을 queueing latency로 전환하는 전략이고, 그러면 p99가 예측 가능해진다.

다른 방법은 앞단에 길이 예측 모델을 두고 요청마다 동적으로 max_new_tokens를 다르게 설정하는 것이다. Proxy Model-based Sequence Length Prediction처럼 작은 프록시 모델로 출력 길이를 먼저 추정하면 스케줄러가 훨씬 정확하게 블록을 예약할 수 있다. CV가 높은 워크로드에서 이 방식의 preemption 감소 효과가 가장 크게 나타난다.

Tags
LLMInference서빙KV 캐시vLLM메모리TPOT