메모리와 모델

최종 업데이트

KV 캐시 메모리 줄이기: vLLM FP8 설정과 답변 확인

KV 캐시는 앞선 문맥의 계산 상태를 보관해요.

KV 캐시1는 언어 모델이 앞서 읽은 토큰2의 key와 value를 보관하는 공간이에요. 답변을 이어 쓸 때 이 상태를 다시 사용해서 앞부분의 계산을 반복하는 일을 줄여요. 문맥이 길거나 여러 요청이 겹치면 캐시도 메모리를 많이 사용하므로, vLLM의 FP83 설정으로 공간을 줄이는 방법을 살펴볼게요.

여기서는 함수가 빈 목록을 받았을 때 어떤 오류가 생기는지 묻고, 테스트 코드를 제안받는 작업으로 비교해요. 기본 캐시와 FP8 캐시에서 같은 코드를 보내 답변, 사용 메모리와 완료 시간을 기록하면 설정을 바꾼 효과를 확인할 수 있어요.

실행 조건과 핵심 내용
  • 가중치 정밀도와 KV 캐시 정밀도는 각각 설정해요.
  • 문맥 길이·동시 요청·모델 구조가 캐시 사용량에 영향을 줘요.
  • FP8 지원 backend에서 메모리와 답변의 정확성을 함께 확인해요.

대화를 이어 갈수록 기억할 상태가 늘어요

모델은 질문을 읽는 프리필4 단계에서 토큰 사이의 관계를 계산해요. 답변을 한 토큰씩 생성할 때는 앞선 토큰을 다시 참고하죠. KV 캐시에 저장된 key와 value를 사용하면 앞선 문맥의 상태를 처음부터 만들지 않고 다음 계산을 이어갈 수 있어요.

함수를 읽고 설명을 만든 뒤 그 설명을 바탕으로 테스트를 요청하면, 다음 요청에는 원래 코드와 이전 답변이 함께 들어갈 수 있어요. 새 질문과 출력도 문맥에 추가되므로 모델 파일이 그대로여도 캐시 사용량은 달라져요. 앱이 오래된 메시지를 제외하거나 문맥을 다시 구성하는 방식도 영향을 줘요.

사용자가 한 줄만 질문해도 앱이 코드 파일 전체나 긴 PDF를 함께 보내면 입력 토큰은 많아져요. 앱의 토큰 표시나 서버 로그에서 실제 입력 길이를 확인하세요. 별도 요청이 동시에 실행되면 요청별 상태도 필요하므로, 혼자 대화할 때와 여러 작업을 겹칠 때를 나눠 시험해요.

긴 입력에서 계산한 키와 값을 서랍에 저장하고 다음 토큰을 만들 때 꺼내 쓰는 그림
앞선 토큰의 계산 상태를 재사용해 답변을 이어가요.

가중치와 캐시의 정밀도를 따로 고르는 이유

Q4나 NVFP45는 모델 가중치를 저장하는 표현이에요. KV 캐시는 실행 중 만들어지는 상태여서 별도 정밀도를 사용해요. 지원되는 실행기에서는 캐시를 8비트나 4비트로 저장해 긴 문맥에 필요한 공간을 줄일 수 있어요.

캐시 변환에는 계산이 추가되고, 표현할 수 있는 값의 정밀도도 달라져요. 메모리 절약, 생성 속도와 답변의 정확성을 각각 비교해야 하는 이유예요. 짧은 문맥에서는 변환 비용이 이득을 상쇄할 수 있고, 프리필 성능도 head dimension과 backend에 영향을 받아요.

실행 중 메모리를 어디에 쓰는지 나눠 살펴요.
영역담는 내용영향을 주는 조건
모델 가중치학습된 모델 데이터모델 크기·양자화·배치 위치
KV 캐시앞선 토큰의 계산 상태문맥 길이·계층 구조·정밀도·동시 요청
실행 버퍼현재 연산의 임시 데이터backend·배치·실행 설정
답변 토큰이 늘어날 때마다 키와 값 카드가 짝으로 캐시 서랍에 쌓이는 그림
긴 문맥과 동시 요청은 더 많은 캐시 공간을 사용해요.

기본 서버에서 답변을 먼저 받아요

아래 예시는 gpt-oss-20b를 지원하는 vLLM 환경에서 실행해요. 모델을 적재하고 캐시를 만들 메모리 여유가 있어야 해요. GPU6 수와 메모리 이용률은 임의로 고정하지 않고, 설치한 backend의 모델 지원과 로딩 로그를 먼저 확인해요.

첫 명령을 실행하고 서버가 요청을 받을 준비가 되면 새 터미널에서 curl 명령을 보내요. first_item 함수는 목록의 첫 원소를 읽으므로, 빈 목록에서는 인덱스 오류가 생겨요. 답변이 이 원인을 설명하고 빈 목록 테스트를 제안하는지 확인해 기준 결과를 저장해요.

기본 KV 캐시로 기준 서버 시작
vllm serve openai/gpt-oss-20b --host 127.0.0.1 --port 8000 --max-model-len 8192
이 모델을 지원하는 vLLM 빌드에서 실행하고, 로딩 완료 로그 뒤 요청을 보내요.
빈 목록 처리 설명 요청
curl --fail-with-body http://127.0.0.1:8000/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"openai/gpt-oss-20b","messages":[{"role":"user","content":"Review this function for empty-list input and suggest one test: def first_item(items): return items[0]"}],"temperature":0,"max_tokens":128}'
같은 함수와 질문을 기본 설정과 FP8 설정에 각각 보내요.

캐시만 FP8로 바꿔 같은 요청을 보내요

기준 요청이 성공하면 서버를 종료하고 --kv-cache-dtype fp8을 추가한 명령으로 다시 시작해요. 모델, 문맥, 가중치 형식과 동시 요청 수는 유지해요. 로그에서 FP8 KV와 실제 attention7 backend가 선택됐는지 확인한 뒤 위의 같은 curl 요청을 보내요.

GPU・attention backend・모델 구조가 FP8 KV를 지원해야 해요. 공식 Hopper·Blackwell 평가 조건은 해당 경로의 자료로 읽고, 다른 GPU에서는 설치 버전의 지원표를 확인해요. GPT-OSS처럼 global attention과 sliding-window 계층이 섞이면 짧은 창의 계층을 기본 정밀도로 남기는 설정도 비교할 수 있어요.

두 번째 명령의 --kv-cache-dtype-skip-layers sliding_window가 그 선택지예요. 해당 옵션을 지원하는 빌드에서 모든 계층 FP8과 skip-layer 설정을 각각 실행하고 같은 함수 질문을 보내요.

모든 계층에 FP8 KV 캐시 적용
vllm serve openai/gpt-oss-20b --host 127.0.0.1 --port 8000 --max-model-len 8192 --kv-cache-dtype fp8
모델과 문맥 설정은 두고 캐시 정밀도만 바꿔요.
sliding-window 계층의 기본 정밀도 유지
vllm serve openai/gpt-oss-20b --host 127.0.0.1 --port 8000 --max-model-len 8192 --kv-cache-dtype fp8 --kv-cache-dtype-skip-layers sliding_window
공식 skip-layer 옵션을 지원하는 빌드에서 별도 비교해요.

메모리 절약과 답변 결과를 함께 기록해요

모델 로딩을 마친 뒤 준비 요청을 제외하고 반복 측정해요. TTFT8, 토큰 간 지연, 전체 완료 시간과 peak GPU memory를 남기고, 우선 요청 한 개끼리 비교해요. 긴 문맥이나 동시 요청이 목적이라면 그다음 입력 길이 또는 요청 수를 하나씩 늘려요. 처음 읽는 입력과 prefix를 재사용하는 입력도 나눠 기록해요.

답변에서는 빈 목록의 오류 설명과 제안한 테스트를 실제 코드와 대조해요. 여러 함수 질문을 미리 정해 같은 방식으로 비교하면 특정 질문 하나의 우연을 줄일 수 있어요. 속도 차이가 작아도 긴 입력을 메모리 안에 담거나 더 많은 요청을 안정적으로 마쳤다면, 목표에 맞는 개선이에요.

캐시 상한을 두거나 오래된 상태를 지우는 설정을 사용한다면, 대화 처음에 준 정보를 나중에도 답할 수 있는지 시험해요. 새 대화에서는 맞고 이어진 대화에서만 틀리면 실제 전달된 메시지와 상태 유지 설정을 대조하세요. 앱 전체 메모리 그래프는 부족해진 시점을 찾는 데 쓰고, KV 캐시 자체의 사용량은 서버가 제공하는 지표로 확인해요.

정밀한 KV 캐시와 적은 비트로 저장한 작은 KV 캐시를 나란히 놓은 그림
캐시를 줄인 뒤에도 필요한 코드 조건이 답변에 남는지 확인해요.

시작 오류와 메모리 부족에 맞춰 설정을 조절해요

dtype나 backend 오류로 서버가 시작되지 않으면 FP8 옵션을 제거하고 기준 명령을 다시 실행해요. 기본 설정은 되고 FP8만 실패한다면 캐시 지원 조건을 확인하세요. 기본 서버도 실패하면 모델 지원, 드라이버와 설치 버전을 먼저 점검해요.

긴 요청 중 메모리가 부족하면 입력 문맥이나 동시 요청 수를 하나씩 줄여요. 답변에서 코드 조건을 자꾸 놓친다면 기본 정밀도로 돌아가 같은 질문을 비교해요. 원하는 문맥과 요청 수에서 정확성과 안정성을 유지하는 설정을 최종값으로 남기면 돼요.

용어 각주

  1. KV 캐시 — 어텐션에서 이전 토큰의 키·값을 저장해 다음 토큰 생성 때 재사용하는 메모리입니다. 문맥 길이와 배치 크기에 따라 용량이 달라집니다.

    본문으로 돌아가기
  2. 토큰 — 모델이 입력이나 출력을 나누어 처리하는 단위입니다.

    본문으로 돌아가기
  3. FP8 — 값 하나를 8비트로 표현하는 부동소수점 수치 형식입니다.

    본문으로 돌아가기
  4. 프리필 — LLM이 입력 프롬프트를 읽고 각 토큰의 내부 표현을 계산하는 단계입니다. 입력이 길수록 처리할 토큰이 많아집니다.

    본문으로 돌아가기
  5. NVFP4 — NVIDIA가 정의한 4비트 부동소수점 데이터 형식입니다. 지원 여부는 GPU 세대, 모델과 소프트웨어 구현에 따라 다릅니다.

    본문으로 돌아가기
  6. GPU — 많은 계산을 병렬로 처리하는 프로세서입니다. AI 모델 실행에서는 모델 계산을 맡습니다.

    본문으로 돌아가기
  7. 어텐션 — 입력 토큰 사이의 관련도를 계산해 각 위치의 정보를 현재 표현에 반영하는 신경망 연산입니다.

    본문으로 돌아가기
  8. 첫 토큰 지연 — 요청을 보낸 뒤 첫 출력 토큰이 도착하기까지 걸린 시간입니다.

    본문으로 돌아가기

자주 묻는 질문

이 글에서 가장 먼저 확인할 것은 무엇인가요?
KV 캐시는 언어 모델이 앞서 읽은 토큰의 key와 value를 보관하는 공간이에요. 답변을 이어 쓸 때 이 상태를 다시 사용해서 앞부분의 계산을 반복하는 일을 줄여요. 문맥이 길거나 여러 요청이 겹치면 캐시도 메모리를 많이 사용하므로, vLLM의 FP8 설정으로 공간을 줄이는 방법을 살펴볼게요.
필요한 메모리는 어느 정도인가요?
캐시 상한을 두거나 오래된 상태를 지우는 설정을 사용한다면, 대화 처음에 준 정보를 나중에도 답할 수 있는지 시험해요. 새 대화에서는 맞고 이어진 대화에서만 틀리면 실제 전달된 메시지와 상태 유지 설정을 대조하세요. 앱 전체 메모리 그래프는 부족해진 시점을 찾는 데 쓰고, KV 캐시 자체의 사용량은 서버가 제공하는 지표로 확인해요.