TokenRouter가 토큰 단위 LLM 라우팅 서빙 병목을 걷어낸다
TokenRouter: Efficient Serving System for Token-Level LLM Routing
무엇인가
LLM 라우팅은 세션·쿼리 단위에서는 이미 상용 시스템에 널리 쓰인다. ChatGPT나 Cursor처럼 질의 난이도나 주제에 따라 백엔드 모델을 고르는 방식이다. 그런데 최근 알고리즘 연구는 더 잘게 쪼갠 토큰 단위 라우팅이 쿼리 단위가 닿지 못하는 이득을 준다고 보고한다. 논문이 든 예로 R2R은 32B 모델 품질을 유지하면서 토큰의 5%만 32B로 보내고 나머지를 1.5B로 디코딩한다. 같은 품질을 쿼리 단위로 얻으려면 질의의 약 40%를 32B로 보내야 한다. 문제는 기존 서빙 시스템이 이걸 감당하지 못한다는 점이다. SGLang, vLLM 같은 시스템은 모든 활성 요청이 매 디코딩 스텝에서 동기화된다는 단일 LLM 가정 위에 세워져 있다. 토큰 단위 라우팅은 매 스텝 목표 모델이 바뀌므로 이 가정이 깨지고, 세 가지 문제가 생긴다. 모델별 스텝 지연 차이 때문에 배치 전체가 가장 느린 모델을 기다리며 빠른 모델이 노는 스텝 비동기화, 잦은 모델 전환으로 목표 모델이 이전 배치를 처리 중일 때 도착한 요청이 다음 배치까지 대기하며 배치가 파편화되는 배치 편입 지연, 그리고 스텝별 라우팅 결정을 표현할 프로그래밍 인터페이스가 없어 큰 코드베이스를 고쳐야 하는 구현 복잡도다.
어떻게 동작하나
TokenRouter의 설계 원칙은 "요청 중심 프로그래밍, 모델 중심 실행"이다. 개발자는 하나의 요청이 협력하는 LLM들 사이를 어떻게 이동하는지만 기술하고, 런타임은 LLM마다 서브서버를 하나씩 띄워 요청을 비동기로 디스패치한다. 각 서브서버는 자체 스케줄러와 전용 KV 캐시 풀을 가진 LLM 러너, 그리고 사용자가 정의한 라우터·송신기·수신기 함수를 소유한다. 서브서버들은 서로 독립적으로 진행하며 피어 요청으로 통신하고, 내부 구조가 동일해 LLM을 추가하려면 서브서버를 하나 더 띄우면 된다. 외부로는 단일 서버 인터페이스만 노출하므로 클라이언트 프로토콜은 참여 모델 수와 무관하게 vLLM·SGLang과 같고, 기존 단일 LLM 서버를 그대로 대체할 수 있다.
무엇과 다른가
프로그래밍 인터페이스는 route, send, receive 세 요소로 이뤄진다. route(result)는 각 디코딩 스텝 뒤에 배치 안 각 요청의 목적지 인덱스를 정한다. 0이면 로컬에서 계속 디코딩하고, 0이 아니면 해당 피어 모델로 넘긴다. send(req)는 라우팅이 요청을 위임할 때 호출되어 요청 ID, 피어가 아직 보지 못한 토큰 접미사, 요청이 살아 있는지 종료됐는지를 나타내는 상태 필드, 알고리즘별 필드를 담은 PeerReq 메시지를 만든다. 전송 직전의 디코딩 위치를 나타내는 앵커 req.loc도 함께 붙어 수신자가 최소 접미사 범위를 판단할 수 있다. receive(peer_req)는 피어에서 온 PeerReq를 로컬 요청 형식으로 변환해 디코딩을 이어가게 한다. 기본 동작은 전이된 토큰을 전부 커밋하는 것으로 대부분의 토큰 단위 라우팅 알고리즘에 충분하고, 핸드오프 의미가 특수할 때만 재정의하면 된다. 논문은 이 주기가 receive→decode→route→send→peer receive→peer decode→peer route로 반복된다고 정리한다. CITER, R2R, Co-LLM은 불확실한 토큰에서 큰 모델을 호출하고 한 토큰 뒤 제어를 돌려받으며, R-Stitch는 토큰 엔트로피로 양방향 전환하고, ME는 앙상블 가중치에 따라 매 토큰마다 다음 모델을 고른다.
어떻게 쓰나
실행 구조에서 TokenRouter는 기존 서버의 두 비동기 루프(요청 수락·응답 스트리밍을 담당하는 클라이언트-서버 루프, 스케줄링·모델 실행을 담당하는 디코딩 루프)에 세 번째인 모델 간 루프를 추가한다. 위임된 요청은 로컬 배치를 떠나 피어 요청이 돌아올 때 재개되고, 그동안 남은 로컬 요청은 자기 속도로 계속 실행된다. 재개 시 새 호출로 취급해 프리픽스 매칭과 KV 캐시 할당을 다시 하는 낭비를 막기 위해 running과 finished 사이의 중간 상태인 pending을 도입한다. 스케줄러는 pending 요청을 건너뛰되 서빙 상태는 보존하고, 복귀 시 피어 출력에 따라 running이나 finished로 전환한다. 끝나지 않았다면 새 토큰을 덧붙여 마치 떠난 적 없는 것처럼 배치에 다시 넣는다. 스케줄링 쪽에서는 지연 배칭을 쓴다. 피어 요청이 도착하는 즉시 새 스텝을 시작하면 이미 배치를 처리 중인 모델에는 편입될 수 없어 대기가 반복되므로, 수신 요청을 버퍼에 모아 임계값 B에 도달했을 때 배치를 시작한다. 이때 처리량 최적 임계값 B*는 토큰 단위 라우팅 과정을 이산시간 마르코프 체인으로 모델링해, 동시성 N과 라우팅 확률, 모델별 스텝 지연이 주어졌을 때 처리량을 B의 함수로 유도하고 최대화하는 값으로 해석적으로 구한다.
전제와 한계
실험은 CITER, R2R, R-Stitch, Co-LLM, ME 다섯 알고리즘을 Qwen3-0.6B·8B·32B 조합으로, 8×A100-80G 서버에서 평가했다. 워크로드는 AIME2024 기반 저난도 추론(입력 약 100토큰, 최대 출력 2,048), 고난도 추론(최대 출력 8,192, Qwen3-32B 풀이가 8,192토큰을 넘는 문제만), SWE-Smith 기반 에이전트 멀티턴(입력 약 8,192토큰, 최대 출력 1,024) 세 가지다. 15개 알고리즘-워크로드 조합 전부에서 더 강한 베이스라인 대비 처리량이 2.01~64.15배 높았고, 표준 SGLang 기반 베이스라인 대비 종단 지연을 2.03~63.64배 줄였다. 각 알고리즘의 원래 설정에서 공식 구현과 비교하면 지연 2.78~21.61배, 처리량 2.73~21.97배 개선이다. 출력 길이를 2,048에서 8,192로 늘렸을 때 TokenRouter는 처리량을 유지했지만 표준 서빙 베이스라인은 58.1~85.2%를 잃었다. 동시성을 1에서 16으로 올리면 처리량이 8.61배 늘고 단일 사용자 속도의 51.7%를 유지한 반면, 공식 R2R은 5.14배와 31.3%에 그쳤다. 동시성 16에서 TokenRouter는 R2R 동시성 1 대비 18.58배 처리량을 내면서 사용자 속도도 1.13배 높았다.
어블레이션에서 확장 CUDA 그래프를 포함한 엔지니어링 최적화만으로 처리량이 132.78에서 230.79 token/s로 올라 공식 R2R(134.9 token/s)의 1.71배가 됐고, 비동기 실행이 296.86, 지연 배칭이 372.48 token/s를 더해 총 2.76배가 됐다. 모델 조합을 바꿔도 공식 R2R 대비 1.99~3.21배 처리량을 냈다. 병렬화 전략에서는 LLM 텐서 병렬 크기를 키우는 것이 처리량에 중요하고 SLM 쪽은 영향이 적어, 기본값을 LLM 2, SLM 1로 둔다. AMC23에서 Qwen3-0.6B·32B 조합, 그리디 디코딩, 최대 8,192토큰 조건으로 처리량-정확도 파레토 프론티어를 그렸을 때 TokenRouter는 토큰 단위 라우팅을 새로운 프론티어로 밀어 올려, SGLang 같은 최신 프레임워크 위에서 세밀한 라우팅이 거친 라우팅보다 경쟁력 있게 만든다고 주장한다.
개발자 입장에서 이 논문의 실용적 요점은 라우팅 알고리즘과 서빙 최적화를 분리했다는 것이다. 알고리즘을 route/send/receive 세 함수로 표현하면 나머지 배칭·스케줄링·비동기 실행은 런타임이 맡고, 클라이언트는 기존 단일 LLM 서버를 쓰던 코드를 그대로 유지할 수 있다. 토큰 단위 라우팅을 연구하거나 사내 서빙에 얹으려는 팀이라면 알고리즘별 라우팅 신호가 어떤 상태를 피어로 넘겨야 하는지, 그리고 지연 배칭 임계값이 자기 워크로드의 동시성과 모델 지연 분포에서 어떤 값으로 유도되는지를 먼저 확인해야 한다. 논문이 제시한 수치는 8×A100 환경과 특정 Qwen3 조합에서 나온 것이므로, 실제 배포에서는 모델 쌍과 트래픽 패턴을 바꿔 같은 이득이 나오는지 검증하는 절차가 필요하다.
저자들이 밝힌 한계는 처리량 최적 임계값을 구하는 수학적 모델이 연속된 두 번의 send 사이에 생성되는 토큰 수가 기하분포를 따른다고 가정한다는 점이다. 대부분의 토큰 단위 라우팅 알고리즘에는 성립하지만 이 가정을 위반하는 예외적 경우는 향후 과제로 남겨 두었다.