같은 기능을 켠 채로 배수가 1.4배에서 0.8배가 됐습니다
손님이 늘수록 빈 좌석은 줄어듭니다. 추측 디코딩이 파먹던 것이 바로 그 좌석입니다.
추측 디코딩을 켜기 전에 확인해야 할 숫자는 논문의 배속이 아니라 여러분 서버의 동시 접속 수입니다. 저희는 같은 드래프터를 켜 둔 채로 손님 수만 1명에서 8명으로 늘렸더니 배수가 1.4배에서 0.8배가 되는 것을 봤습니다. 추론 서빙을 운영하면서 “왜 우리는 논문만큼 안 빨라지지”를 묻고 계신 분께 드리는 글입니다.
쉽게 말하면
셔틀버스를 떠올려 주세요. 큰 언어 모델이 글자 하나를 쓰려면 매번 모델 전체를 메모리에서 읽어 옵니다. 버스가 승객 한 명을 태우려고 차고에서 정류장까지 왕복하는 셈입니다. 왕복 비용은 승객 수와 거의 무관하니, 어차피 가는 편에 사람을 더 태우면 공짜에 가깝습니다. 추측 디코딩은 바로 그 빈 좌석을 쓰는 기술입니다. 눈치 빠른 안내원이 다음 승객 몇 명을 미리 지목해 태웁니다. 기사님은 도착해서 한 번에 확인합니다. 맞으면 그만큼 왕복을 아끼고 틀리면 그 사람만 내려 줍니다.
문제는 빈 좌석이 항상 있지는 않다는 데 있습니다. 손님이 몰리면 버스는 이미 만석입니다. 더 태울 자리가 없습니다. 버스를 작은 차로 바꾸면 왕복이 싸지는 대신 빈 좌석도 같이 줍니다. 이 글은 그 빈 좌석이 언제 사라지는지를 저희 장비에서 재 본 기록입니다.
배수는 기능이 아니라 조건에 붙어 있습니다
먼저 저희가 무엇을 켰는지 밝혀 두겠습니다. 타깃은 저희가 만든 27B 체크포인트입니다. 드래프터는 DFlash2를 붙여 한 번에 일곱 토큰씩 제안하게 했습니다. 엔진은 vLLM 0.28.0이고 샘플링은 실제 서비스와 같은 값을 썼습니다. 같은 실행 안에서 켠 팔과 끈 팔을 짝지어 쟀습니다. 배수는 그 짝 안에서만 말합니다.
그렇게 재 보면 배수는 하나의 숫자가 아니라 곡선입니다. 그리고 그 곡선은 1.0을 아래로 통과합니다. 통과하는 지점이 어디냐가 이 글의 전부입니다.
손님이 늘면 파먹을 자리가 없습니다
가장 먼저 무너지는 축은 동시성입니다. Edge 예산 조건에서 INT4 체크포인트를 놓고 자유 서술을 시켰을 때, 동시 1명에서는 1.4배였던 것이 2명에서 1.2배, 4명에서 1.1배로 내려오다가 8명에서 0.8배가 됩니다. 켜 둔 채로 그냥 두면 손님이 여덟 명일 때 오히려 느려집니다. 저희 프로덕션 체크포인트를 더 큰 배치로 밀어붙이면 같은 붕괴가 더 극적으로 나옵니다. 동시 64명에서 기준선은 초당 2,306토큰인데 드래프터를 켜면 595토큰으로 떨어집니다. 0.3배입니다.
슬라이더로 동시 접속 수를 옮겨 보시면 어느 조건이 어디에서 1.0을 지나는지 보입니다. 세 계열은 서빙 설정이 서로 달라 계열 간 절댓값 비교는 하지 않습니다.
같은 드래프터를 세 가지 조건에 붙여 자유 서술을 시켰을 때의 배수입니다. 가로는 동시 접속 수이고 세로는 타깃 체크포인트입니다.
| 조건 | 1명 | 2명 | 4명 | 8명 | 16명 | 64명 |
|---|---|---|---|---|---|---|
| NVFP4-GPTQ · 131k · 배치 256 | 1.34배 | 미측정 | 1.22배 | 미측정 | 1.05배 | 0.26배 |
| KV fp8 · 256k · Edge 예산 | 1.45배 | 1.34배 | 1.28배 | 1.27배 | 미측정 | 미측정 |
| INT4 · 256k · Edge 예산 | 1.43배 | 1.23배 | 1.06배 | 0.82배 | 미측정 | 미측정 |
세 줄 모두 왼쪽에서 오른쪽으로 내려갑니다. 다만 내려가는 속도가 다르고, 1.0을 지나는 지점도 다릅니다. 같은 기능을 켰다는 사실만으로는 이 표의 어느 칸에 있는지 알 수 없습니다.
즉, 사람 말로는 이렇습니다. 손님이 없을 때 안내원은 도움이 됩니다. 손님이 많을 때 안내원은 자리를 차지합니다.
기전은 연속 배칭에 있습니다. vLLM 같은 엔진은 요청을 순서대로 처리하지 않고 매 스텝마다 지금 살아 있는 요청들을 한 묶음으로 모아 한 번에 계산합니다. 손님이 여럿이면 그 묶음만으로도 연산 유닛이 이미 꽉 찹니다. 버스가 만석이 된 상태입니다. 이때 추측 디코딩은 좌석을 만들어 주지 않습니다. 확정되지도 않은 후보 토큰을 만석 버스에 억지로 밀어 넣을 뿐입니다. 기각되면 그 계산은 전부 버려집니다. 한가할 때 공짜였던 것이 붐빌 때는 그냥 낭비입니다.
그래서 운영에서 필요한 것은 켜거나 끄는 스위치가 아니라 임계 동시성입니다. 저희 경우 그 값은 체크포인트마다 달랐습니다. 같은 드래프터인데도 KV 캐시를 fp8로 둔 팔은 8명에서도 1.3배를 유지했습니다. INT4 팔은 같은 지점에서 이미 물에 잠겼습니다.
채점을 한 번에 하는 구조
왜 수용률이 그렇게 중요한지 보려면 검증이 어떻게 이뤄지는지 알아야 합니다. 드래프터는 다음 토큰 하나만 찍지 않습니다. 여러 갈래를 한꺼번에 제안합니다. 이 갈래들은 하나의 긴 줄로 펴진 다음, 어텐션 마스크가 각 후보에게 자기 조상만 보이도록 가려 줍니다. 이 가림막이 없으면 서로 다른 갈래의 후보들이 상대를 참고해 버려서 채점이 오염됩니다. 가림막 덕분에 타깃 모델은 단 한 번의 계산으로 모든 갈래를 동시에, 그러나 서로 독립적으로 채점합니다. 채점이 끝나면 가장 길게 살아남은 경로만 남기고 나머지는 버립니다.
버스로 돌아오면 안내원이 갈래를 만들어 태우는 셈입니다. “이 사람 다음엔 저 사람, 아니면 그 사람” 하는 식입니다. 기사님은 한 번 확인하면서 모든 갈래를 함께 검사합니다. 그러니 갈래를 아무리 늘려도 확인 비용은 거의 그대로입니다. 실제로 아끼는 것은 살아남은 경로의 길이만큼입니다. 이 길이를 수용 길이라고 부릅니다.
갈래를 하나의 줄로 펴고 마스크로 가린 뒤 한 번에 채점합니다. 살아남은 가장 긴 경로만 채택하고 나머지는 버립니다.
수용 길이가 배수를 지배합니다. 저희 측정에서 프롬프트를 그대로 옮겨 쓰는 복사형 작업의 수용 길이는 3.1이었습니다. 새 문장을 쓰는 자유 서술은 2.2에 그쳤습니다. 같은 조건에서 복사형은 동시 8명에서도 1.1배로 버텼고 자유 서술은 0.8배로 내려갔습니다. 차이는 오직 드래프터가 얼마나 잘 맞히느냐입니다.
수용률을 넣어 보세요
수용 길이는 수용률에서 계산으로 나옵니다. 한 토큰이 채택될 확률을 알파, 한 번에 제안하는 길이를 감마라고 하면 기대 수용 길이는 등비수열의 합이 됩니다. 아래 계산기에 여러분 서버의 수용률을 넣어 보시면, 왜 수용률이 조금만 떨어져도 배수가 급하게 무너지는지 눈으로 보실 수 있습니다. 저희 자유 서술 값 2.2가 곡선의 어디쯤인지도 함께 표시해 두었습니다.
곡선은 공식으로 계산한 값이고, 점선 두 개만 저희 실측입니다. 자유 서술이 2.2에 머무는 이유가 곡선의 완만한 구간에 있다는 것이 보입니다.
양자화는 이득을 줄이지만 없애지 않습니다
두 번째 축은 체크포인트입니다. 여기서 흔히 오해가 생깁니다. 저희도 처음에는 양자화가 추측 디코딩을 망가뜨린다고 의심했습니다. 같은 조건에서 체크포인트만 바꿔 재 보니 그렇지 않았습니다.
원본 bf16 모델에서 기준선은 초당 88.7토큰이었고 드래프터를 켜면 266.4토큰이 되어 3.0배였습니다. 4비트로 양자화한 저희 체크포인트에서는 기준선이 129.0토큰으로 올라갑니다. 읽어 올 가중치가 줄었으니 당연합니다. 여기에 같은 드래프터를 켜면 286.9토큰이 되어 2.2배입니다. 배수는 3.0배에서 2.2배로 줄었습니다. 그런데 절대 처리량은 양자화와 드래프터를 함께 쓴 쪽이 가장 높습니다.
버스로 말하면 이렇습니다. 양자화는 버스를 더 작고 빠른 차로 바꾼 것입니다. 왕복이 싸졌으니 승객 한 명당 비용이 줄었습니다. 대신 남는 빈 좌석도 함께 줄었습니다. 추측 디코딩이 파먹던 것이 바로 그 빈 좌석입니다. 두 최적화는 같은 병목을 공략하기 때문에 부분적으로 겹칩니다. 그래도 둘 다 켜는 쪽이 가장 빠릅니다.
양자화는 읽어 올 가중치를 줄여 기준선을 올립니다. 추측 디코딩이 파먹던 유휴가 그만큼 줄어듭니다. 두 최적화가 같은 병목을 공략하기 때문입니다.
이 구분이 중요한 이유는, 배수가 줄었다고 드래프터를 빼면 절대 속도가 함께 내려가기 때문입니다. 판단 기준은 배수가 아니라 최종 처리량이어야 합니다.
안내원을 고르는 방법도 결과의 부호를 바꿉니다
드래프터를 어떻게 만드느냐도 축입니다. 프롬프트에서 이어질 만한 구절을 찾아 제안하는 방식이 있습니다. 모델의 내부 상태를 보고 학습으로 예측하는 방식도 있습니다. 앞의 것은 정류장에 붙은 명단을 보고 찍는 안내원입니다. 뒤의 것은 단골 얼굴을 아는 안내원입니다.
명단을 보는 방식은 답이 프롬프트 안에 있을 때만 잘 맞습니다. 저희가 양자화한 체크포인트 네 개에서 이 방식을 재 봤더니 자유 서술에서 전부 기준선보다 느렸습니다. 반면 원본 bf16 모델에서는 같은 방식이 이득을 냈습니다. 같은 워크로드인데 체크포인트에 따라 결론의 부호가 뒤집힌 것입니다. 학습된 드래프터는 그 축소를 견뎠습니다. 명단을 보는 방식은 견디지 못했습니다.
여기에 샘플링이 하나 더 얹힙니다. 논문의 배속표는 대개 온도 0에서 측정됩니다. 저희 서비스는 모델 설정에 따라 온도 1.0으로 돕니다. 같은 모델과 같은 설정에서 온도만 바꿔 재 보니 명단 방식의 배수가 수학 문제에서 1.3배에서 4.2배 구간이던 것이 0.3배에서 1.0배 구간으로 내려갔습니다. 이유는 단순합니다. 안내원은 가장 그럴듯한 승객을 지목합니다. 온도가 높으면 버스는 다른 승객을 태웁니다. 지목은 기각되고 확인 비용만 남습니다.
대가는 지연이 아니라 자리입니다
마지막 축은 메모리 예산입니다. 드래프터도 모델이라 자기 KV 캐시를 씁니다. Edge 예산을 흉내 낸 조건에서 재 보니 KV 캐시 풀이 약 36퍼센트 줄었습니다. 그만큼 담을 수 있는 대화가 줄어듭니다. 이것을 세션 수로 옮기면 256k 컨텍스트를 기준으로 동시에 담을 수 있는 세션이 6.7개에서 4.3개가 됩니다.
즉, 사람 말로는 안내원도 좌석에 앉는다는 뜻입니다. 짧은 대화를 많이 처리하는 서비스라면 신경 쓸 필요가 없습니다. 긴 문서를 다루는 서비스에서는 이 손실이 속도 이득보다 먼저 아플 수 있습니다.
그래서 무엇을 바꾸면 되나
먼저 여러분의 워크로드 구성비를 재십시오. 저희가 실제 트래픽에서 생성한 토큰의 93.5퍼센트는 자유 서술이었습니다. 프롬프트를 그대로 옮겨 쓰는 비율은 0.1 언저리에 머물렀습니다. 공개 벤치마크는 복사형에 가까운 작업이 많아 실제보다 후한 배수를 보여 줍니다. 벤치마크의 배속표는 여러분의 열이 아닐 가능성이 높습니다.
다음으로 배수 곡선을 여러분 장비에서 직접 그리십시오. 필요한 것은 한 점이 아니라 1.0을 가로지르는 지점입니다. 재는 방법은 어렵지 않습니다. 드래프터를 켠 팔과 끈 팔을 같은 실행 안에서 짝지어 놓고, 동시 접속을 1, 2, 4, 8, 16으로 올리며 각 지점의 초당 생성 토큰을 기록하면 됩니다. 워크로드는 실제 서비스가 받는 프롬프트로 하십시오. 공개 벤치마크 프롬프트로 재면 복사형에 가까워져 곡선이 실제보다 위에 그려집니다. 그리고 팔 사이에 엔진 버전이나 양자화 방식이 섞이지 않게 하십시오. 그렇게 섞인 비교는 드래프터의 효과가 아니라 두 서버의 차이를 잰 것입니다. 그 지점보다 낮은 동시성에서만 드래프터를 켜는 것이 지금으로서는 가장 안전한 운영입니다. 요청마다 켜고 끄는 기능은 아직 없습니다. 추측 여부는 엔진을 띄울 때 정해지고 엔드포인트 전체에 걸립니다. 그래서 지연이 중요한 트래픽과 대량 배치 트래픽을 같은 엔드포인트에 태우고 있다면, 먼저 그 둘을 나누는 것이 순서입니다.
그리고 켜기 전에 서빙 설정부터 보십시오. 저희는 컴파일이 꺼진 상태와 켜진 상태의 차이가 추측 디코딩의 이득보다 훨씬 크다는 것을 이미 확인한 적이 있습니다. 기본값으로 띄운 엔드포인트에 드래프터를 얹는 것은 순서가 뒤바뀐 일입니다.
켜 둔 뒤에는 수용률을 계속 보십시오. vLLM 은 추측 디코딩의 제안 수와 채택 수를 지표로 내보냅니다. 이 두 값의 비가 곧 앞의 계산기에서 넣어 보신 알파입니다. 배포한 다음에 트래픽 성격이 바뀌면 이 값이 조용히 내려가고, 배수도 같이 내려갑니다. 모델을 바꾸지 않았는데 느려졌다는 제보가 들어오면 이 지표를 먼저 보십시오. 체크포인트를 교체할 때도 마찬가지입니다. 저희는 서드파티 INT4 체크포인트로 갈아 끼웠을 때 유효 구간이 달라지는 것을 확인했습니다. 새 체크포인트를 올릴 때마다 임계 동시성은 다시 재야 합니다.
마지막으로 판단 기준을 배수가 아니라 최종 처리량과 세션 수용량으로 잡으십시오. 배수는 기준선이 느릴수록 커지는 숫자라서, 잘 튜닝된 서버일수록 작아 보입니다.
못 믿을 부분
정직하게 남겨 둡니다. 동시성 곡선은 각 조건에서 한 번씩 실행한 값입니다. 자유 서술 저동시성 구간은 산포가 조금 큽니다. Edge 예산 측정은 8k 길이의 고정 프롬프트로 했기 때문에, 실제 256k 프롬프트에서 드래프터가 어떻게 움직이는지는 아직 재지 않았습니다. 측정 장비는 B200입니다. 최종 목표 장비는 세대가 달라 커널이 다릅니다. 부호는 옮겨갈 가능성이 높지만 절대값은 아닙니다. 64명 지점의 붕괴는 실측이지만 그 지점에 맞는 최적 배치 설정은 따로 찾아보지 않았습니다. 온도 비교는 명단 방식 드래프터에서 잰 값이므로 학습된 드래프터에 그대로 옮기면 안 됩니다.
ThakiCloud 관점
이 결과는 저희가 Metis 추론 서빙에서 추측 디코딩을 다루는 방식을 바꿨습니다. 기능을 전역으로 켜는 대신, 체크포인트마다 임계 동시성을 먼저 재고 그 아래 구간을 쓰는 엔드포인트에만 붙입니다. 온프렘 어플라이언스처럼 동시 사용자가 적고 응답 지연이 중요한 환경은 이 기술이 가장 잘 먹는 자리입니다. 반대로 대량 배치 처리에서는 켜지 않는 것이 낫습니다. 어떤 기능을 켤지를 아는 것만큼 언제 꺼야 하는지를 아는 것이 서빙 원가를 지킵니다.
함께 읽을 것
이 글은 품질이 아니라 속도를 다뤘습니다. 같은 간극을 품질 쪽에서 파고든 좋은 교육 자료가 있습니다. Lily Zhang과 Madison Kanna가 NeurIPS 2026 Education Track에 낸 Speculative Decoding: How It Evolved, When It Stays Lossless, and What’s Next는 추측 디코딩의 발전사와 무손실 보장이 배포 현장에서 언제 깨지는지를 그림과 인터랙티브 데모로 설명합니다. 특히 공개 트래픽의 일부만 측정된 도메인이라는 지적은 저희가 자체 트래픽에서 확인한 구성비 문제와 같은 이야기입니다.
시리즈의 앞선 글도 함께 보시면 도움이 됩니다. 원리는 투기 디코딩 쉽게 읽기, 양자화와의 조합은 초당 97토큰이 458토큰이 됐습니다, 드래프터 선택은 lookup이 안 맞았던 겁니다에서 다뤘습니다.
측정 원장은 사내 docs/measurements/2026-08-29-metis-edge-dflash2-drafter.json과 2026-08-31-metis-edge-dflash2-edge-budget.json입니다.