Huny's Dev Blog
huny.dev

멀티턴 AI 에이전트 서빙 최적화: SGLang RadixAttention과 vLLM 자동 프리픽스 캐싱(APC) 원리 해부 및 90% TTFT 단축하기

멀티턴 AI 에이전트의 거대 시스템 프롬프트와 도구 호출 누적으로 발생하는 Prefill 병목을 해결하는 KV 캐시 재사용 아키텍처를 분석한다. SGLang의 Radix Tree 기반 RadixAttention과 vLLM의 Block-Hash APC 메커니즘을 비교하고, 로컬 Python 시뮬레이션 검증과 실무 캐시 최적화 체크리스트를 살펴본다.

Hun Jang
Hun Jang Nov 10, 2026

멀티턴 AI 에이전트의 KV-Cache 접두사 트리(Radix Tree)와 블록 해시 페이징 메모리 구조를 상징하는 추상 기하학 아트워크다. 중앙 코어로부터 분기되는 다층 데이터 시냅스와 오비탈 링이 반복되는 시스템 프롬프트와 도구 스키마의 중복 연산을 제거하고 초고속 병렬 추론을 지원하는 가속 아키텍처를 표현했다.

자율형 AI 에이전트(Autonomous AI Agents)와 대화형 코딩 어시스턴트, 다단계 워크플로 오케스트레이터의 활용이 보편화되면서, LLM 추론 서빙 인프라는 이전의 단순 단답형(Single-Turn) 서빙과는 완전히 다른 차원의 연산 병목에 직면하고 있다. 에이전트가 문제를 해결하기 위해 시스템 규칙, 수십 개의 도구 정의(JSON Schema), 이전 턴의 사용자 지시와 모델 추론(Thinking), 그리고 도구 실행 결과(CLI 출력, 파일 내용, DB 쿼리 레코드)를 누적하면서 매 턴마다 입력 프롬프트의 길이가 수천에서 수만 토큰에 이르기까지 기하급수적으로 팽창하기 때문이다. SGLang — Fast and Expressive LLM Serving, vLLM — High-throughput and Memory-efficient Inference Engine

결론부터 말하면 멀티턴 AI 에이전트 서빙의 핵심 병목은 텍스트 생성(Decoding) 속도가 아니라 매 턴마다 반복되는 수천 토큰의 동일 접두사를 처음부터 다시 계산하는 'Prefill 재연산'에 있으며, 이를 해결하기 위해 SGLang의 토큰 단위 Radix Tree(RadixAttention) 또는 vLLM의 고정 블록 해시 체이닝(Automatic Prefix Caching, APC)을 통한 KV-Cache 재사용 아키텍처가 필수적이다. 프롬프트 캐싱을 적용하지 않을 경우 에이전트가 턴을 거듭할 때마다 첫 번째 토큰을 반환하기까지의 대기 시간(Time-to-First-Token, TTFT)이 선형적으로 폭증하고 비싼 GPU 연산력이 동일한 텍스트의 Key-Value 텐서를 반복 계산하는 데 낭비된다. 반면 적절한 프리픽스 캐싱을 도입하면 2턴 이후의 대화에서 최대 85~95%의 Prefill 연산을 즉시 건너뛰어 TTFT를 극적으로 단축하고 GPU 처리량을 대폭 향상할 수 있다.

이 글에서는 멀티턴 AI 에이전트 환경에서 발생하는 프롬프트 비대화와 Prefill 병목의 수학적·구조적 원인을 분석하고, 오픈소스 LLM 서빙의 양대 산맥인 SGLang의 RadixAttention과 vLLM의 Block-Hash APC 메커니즘을 상세히 비교한다. 또한 서브에이전트 분기(Branching)와 메모리 퇴출(LRU Eviction)을 모사하는 로컬 Python 시뮬레이션 스크립트를 작성하여 5가지 핵심 동작을 직접 검증하고, 프로덕션 환경에서 캐시 적중률(Hit Rate)을 극대화하기 위한 실무 엔지니어링 체크리스트를 정리한다.

1. 멀티턴 에이전트 루프의 치명적 병목: 프롬프트 비대화와 Prefill 중복

전통적인 LLM 서빙 모델에서 추론 단계는 크게 두 가지 페이즈로 나뉜다.

  1. Prefill(입력 처리) 단계: 입력된 프롬프트의 모든 토큰을 병렬로 처리하여 Transformer Attention 연산에 필요한 Key와 Value 텐서(KV-Cache)를 생성하는 단계 (O(N2)O(N^2) 복잡도).
  1. Decode(토큰 생성) 단계: 이전에 생성된 KV-Cache를 참조하며 토큰을 한 번에 하나씩 순차적으로 생성하는 단계 (O(N)O(N) 복잡도).

단일 턴 질의응답에서는 입력 프롬프트 길이가 비교적 짧아 Prefill 비용이 크지 않다. 그러나 도구를 사용하는 자율형 AI 에이전트의 실행 루프(ReAct Loop)에서는 구조적인 문제가 발생한다.

  • 방대한 정적 컨텍스트: 에이전트 프롬프트에는 수천 토큰에 달하는 상세 시스템 지시(System Prompt), 안전 규칙, 코딩 컨벤션, 그리고 수십 개 도구의 JSON Schema 시그니처가 상시 적재된다.
  • 비가역적 컨텍스트 누적: 턴 1(사용자 입력 →\rightarrow 에이전트 도구 호출 →\rightarrow 환경 실행 결과)이 끝나고 턴 2로 넘어가면, 턴 1의 모든 내역이 다시 다음 프롬프트의 접두사(Prefix)로 포함된다.
  • 동일 토큰의 무한 재연산: 프리픽스 캐싱이 없다면, 모델 서빙 엔진은 턴 3이나 턴 4에서도 맨 처음의 시스템 지시와 턴 1의 툴 실행 결과를 마치 '난생처음 보는 텍스트'인 것처럼 매번 수천 토큰씩 GPU 연산 코어를 풀가동해 다시 Prefill한다.

멀티턴 AI 에이전트의 프롬프트 비대화에 따른 Prefill 병목 현상과 SGLang RadixAttention(토큰 트리) vs vLLM Automatic Prefix Caching(블록 해시 체인) 아키텍처 비교 다이어그램이다. 반복되는 시스템 규칙과 도구 스키마를 캐싱하여 TTFT를 90% 이상 단축하는 두 엔진의 데이터 구조적 차이를 도식화했다.

결과적으로 에이전트의 대화가 길어질수록 사용자가 체감하는 반응 지연(TTFT)은 기하급수적으로 늘어나고, GPU의 VRAM 대역폭과 텐서 코어는 무의미한 중복 행렬 곱셈으로 포화 상태에 빠진다.

2. SGLang RadixAttention vs vLLM Block-Hash APC: 내부 동작 원리 해부

이 중복 Prefill 문제를 해결하기 위해 SGLang과 vLLM은 서로 다른 철학과 내부 데이터 구조를 채택했다.

1) SGLang RadixAttention: 토큰 단위 래딕스 트리(Radix Tree)

SGLang은 처음부터 복잡한 에이전트 워크플로, 구조화된 디코딩, 다단계 분기(Branching)를 염두에 두고 설계되었다. 그 중심에 있는 핵심 알고리즘이 RadixAttention이다.

  • 토큰 단위 계층 트리 구조: 서빙 엔진 내부에서 KV-Cache를 관리할 때, 토큰 시퀀스를 래딕스 트리(Radix Tree / Compressed Trie) 형태로 저장한다.
  • 유연한 노드 분할(Node Splitting): 프롬프트가 트리를 순회할 때, 일치하는 경로가 중간에서 갈라지면 즉시 해당 노드를 분할(Split)하여 새로운 가지(Branch)를 생성한다.
  • 단일 토큰 수준의 세분도(Token-level Granularity): 고정된 블록 크기 제약 없이, 1개 토큰 단위까지 정확하게 접두사를 일치시키고 캐시를 재활용한다.
  • 최소 공통 접두사 제로 복사: 공통 조상 노드에 할당된 GPU VRAM 내 KV-Cache 포인터는 복사 없이 모든 자식 요청이 완벽하게 공유한다.

2) vLLM Automatic Prefix Caching (APC): 블록 해시 체이닝 (Paged KV-Cache)

vLLM은 대규모 배치 처리와 메모리 파편화를 방지하기 위해 가상 메모리 페이징 기법을 도입한 PagedAttention 위에 Automatic Prefix Caching(APC)을 구축했다.

  • 고정 크기 블록(Fixed-size Block, 보통 16 또는 32 토큰): 토큰들을 16개씩 묶어 논리 블록 단위로 관리한다.
  • 체인드 블록 해시(Chained Block Hash): 특정 블록의 해시는 해당 블록에 속한 16개 토큰뿐만 아니라, 바로 이전 부모 블록의 해시값까지 암호학적으로 결합하여 생성된다:
    $H_i = \text{Hash}(H_{i-1} \parallel \text{Token}_1, \dots, \text{Token}_{16})$
    이 덕분에 동일한 텍스트라도 앞선 컨텍스트가 다르면 해시 충돌 없이 고유한 블록으로 식별된다.
  • O(1)O(1) 블록 룩업: 해시 테이블을 통해 각 블록의 적중 여부를 상수 시간에 판별하고 캐시된 물리 블록 슬롯을 할당한다.
  • 경계 불일치(Boundary Misalignment) 특성: 16개 단위로 딱 떨어지지 않는 마지막 잉여 토큰들(1~15개)은 블록을 형성하지 못하므로 캐시되지 않고 다음 요청에서 다시 Prefill되어야 한다.

서브에이전트 병렬 분기(Branching) 시 부모 컨텍스트를 제로 복사(Zero-Copy)로 공유하는 파이프라인과 메모리 한계 도달 시 단말 리프(Leaf) 노드부터 안전하게 회수하는 LRU Eviction 수명주기 다이어그램이다.

3) 서브에이전트 브랜칭(Tree-of-Thought)과 LRU 메모리 회수 라이프사이클

현대 에이전트 시스템에서는 단일 경로 실행뿐만 아니라, 하나의 상위 계획에서 여러 하위 에이전트가 동시에 실행되거나 여러 도구 호출 경로를 탐색(Tree-of-Thought, Best-of-N Sampling)하는 분기(Branching) 패턴이 빈번하게 발생한다.

  • 제로 복사 분기(Zero-Copy Forking): 턴 2까지 진행된 304개 토큰의 히스토리를 바탕으로 '서브에이전트 A(DB 쿼리 계획)'와 '서브에이전트 B(API 호출 계획)'가 분기될 때, Radix Tree 구조에서는 기존 304개 토큰 노드를 전혀 복제하지 않고 두 개의 자식 리프 노드만 새로 뻗어나간다. 서브에이전트 B의 초기 TTFT는 거의 0에 수렴한다.
  • 지능형 LRU 단말 노드 회수: GPU VRAM의 캐시 슬롯이 부족해지면, 트리의 공통 부모(Trunk) 노드를 지우지 않고 가장 오랫동안 참조되지 않은 자식 리프(Leaf) 노드부터 안전하게 회수(Evict)한다. 이로써 가장 가치가 높은 거대 시스템 프롬프트와 공통 대화 접두사는 항상 VRAM에 상주하게 된다.

3. SGLang RadixAttention vs vLLM Automatic Prefix Caching 비교

두 엔진의 핵심 아키텍처 특성과 에이전트 워크로드 적합성을 비교하면 다음과 같다.

구분
1. 기본 무캐싱 서빙 (Standard Serving)
2. vLLM Automatic Prefix Caching (APC)
3. SGLang RadixAttention
캐시 관리 단위
없음 (매 턴 폐기)
고정 블록 (16/32 토큰)
가변 길이 토큰 노드 (1 토큰 단위)
내부 데이터 구조
단순 KV 연속 버퍼
블록 해시 테이블 + Paged KV
래딕스 트리 (Compressed Trie)
에이전트 분기(Branching) 처리
지원 불가 (중복 계산)
블록 단위 재사용 (선형 대화 우수)
네이티브 트리 분기 (Zero-Copy)
경계 단편화 패널티
해당 없음
블록 미달 토큰(<16) 재계산 필요
패널티 없음 (완전 일치 매칭)
메모리 퇴출(Eviction) 전략
요청 종료 시 즉시 해제
블록 단위 LRU 회수
트리 리프(Leaf) 노드 기반 LRU
구조화 출력/제약 디코딩
외부 라이브러리 연동
Outlines 등 가이드 디코딩 지원
인터프리터 레벨 압축 및 가속 최적화
가장 적합한 워크로드
단순 1회성 API 요청
대규모 배치 및 선형 멀티턴 챗봇
다단계 도구 호출·서브에이전트 루프

4. 로컬 Python으로 검증하는 에이전트 KV 캐시 시뮬레이션

실제 프로덕션 에이전트의 멀티턴 대화 루프와 서브에이전트 분기 시나리오를 로컬 Python 스크립트(test_agent_kv_prefix_caching.py)로 구현하여 검증했다.

직접 실행해 확인한 5가지 검증 시나리오

로컬 터미널 환경에서 위 검증 스크립트를 직접 실행하여 5가지 시나리오가 모두 정상 통과(All 5 Agent KV Prefix Caching checks passed successfully!)함을 확인했다.

  1. 콜드 스타트 초기 적재 (Case 1): 시스템 규칙 및 툴 스키마(128토큰)와 턴 1 대화(144토큰)로 구성된 272토큰의 초기 프롬프트가 유입되었을 때, 캐시 미스(0토큰 적중) 후 두 캐시 엔진에 정확히 272토큰이 적재됨을 확인했다.
  1. 턴 2 대화 연속에 따른 Prefill 89.5% 절감 (Case 2): 턴 2 사용자 요청(32토큰)이 추가되어 총 304토큰으로 팽창한 프롬프트에서, 이전 272토큰 전체가 100% 캐시 적중되어 신규 32토큰에 대해서만 Prefill 연산이 수행됨을 검증했다.
  1. 토큰 단위 정밀 매칭과 블록 경계 정렬 검증 (Case 3): 16의 배수로 떨어지지 않는 비정형 잉여 토큰(25토큰)이 유입되었을 때, Radix Tree가 노드 분할을 통해 단일 토큰 단위까지 손실 없이 매칭하고, 블록 캐시는 정렬된 16단위 블록까지만 매칭함을 대조 검증했다.
  1. 서브에이전트 병렬 분기(Branching) 제로 복사 검증 (Case 4): 동일한 턴 2 컨텍스트(304토큰)에서 서브에이전트 A와 서브에이전트 B가 서로 다른 작업으로 분기될 때, 서브에이전트 B가 A의 부모 노드로부터 304토큰을 제로 복사로 즉각 재사용함을 확인했다.
  1. VRAM 메모리 제약 하의 LRU 단말 노드 회수 (Case 5): 메모리 한계 도달 시 공통 조상 트렁크 노드는 보존하고 가장 오래된 리프 노드만 선별적으로 회수하여 총 368토큰을 안전하게 해제함을 검증했다.

5. 프로덕션 멀티턴 AI 에이전트 서빙 실무 최적화 체크리스트

  1. 도구 정의(Tool Schema)의 결정론적 정렬(Deterministic Sorting) 강제:
      • Python의 dict 순서나 JSON 직렬화 방식에 따라 도구 스키마의 키 순서가 바뀌면 전체 접두사 해시가 깨져 캐시 미스가 발생한다.
      • 서빙단으로 프롬프트를 전송하기 전 반드시 도구 이름과 파라미터 스키마를 알파벳순으로 정렬(json.dumps(tools, sort_keys=True))하여 문자열의 바이트 일관성을 유지해야 한다.
  1. 가변 메타데이터(타임스탬프, 요청 ID)의 프롬프트 최후방 배치:
      • 프롬프트 최상단에 현재 시각: 2026-11-10T03:45:26과 같은 동적 타임스탬프를 기재하면, 매 턴마다 시각이 달라져 그 뒤에 오는 수천 토큰의 시스템 프롬프트와 도구 스키마 캐시가 전부 무효화된다.
      • 불변 시스템 프롬프트와 도구 정의를 맨 앞에 배치하고, 동적으로 변하는 현재 시각이나 세션 ID는 사용자 메시지의 맨 끝이나 도구 호출 직전 컨텍스트에 위치시켜야 한다.
  1. 서브에이전트 오케스트레이션 패턴에 따른 엔진 선정:
      • 단일 에이전트가 순차적으로 질문을 주고받는 선형 대화 파이프라인이라면 vLLM의 APC(--enable-prefix-caching)로도 충분한 성능과 폭넓은 하드웨어 생태계를 누릴 수 있다.
      • LangGraph, AutoGen, CrewAI 등 다중 서브에이전트가 하나의 맥락에서 병렬로 작업을 분기하거나 트리 탐색(Tree-of-Thought)을 수행하는 구조라면 RadixAttention을 내장한 SGLang 도입을 강력히 권장한다.
  1. 서빙 인프라 메모리 파라미터 튜닝:
      • vLLM 배포 시 --enable-prefix-caching 플래그를 활성화하고, --gpu-memory-utilization 0.90 이상으로 설정하여 KV 캐시 슬롯 풀을 충분히 확보해야 캐시 퇴출 빈도를 낮출 수 있다.
      • SGLang의 경우 --mem-fraction-static 0.85 설정을 통해 모델 가중치 외에 래딕스 트리 노드가 머무를 수 있는 공간을 넉넉히 배정한다.
  1. 모니터링 및 캐시 적중률 메트릭(Cache Hit Rate) 관측:
      • 프로덕션 서빙 엔진에서 vllm:prefix_cache_hit_rate 또는 SGLang의 radix_cache_hit_rate 메트릭을 Prometheus/Grafana로 상시 수집하여, 실제 에이전트 트래픽에서 캐시 적중률이 70% 이상 유지되는지 모니터링해야 한다.

참고 자료

확인 기준일: November 10, 2026

추천 글