한 줄 정의

BF16 KV는 LLM이 다음 토큰을 만들 때 다시 쓰는 KV 캐시를 BF16, 즉 bfloat16 16비트 형식으로 저장하는 방식이야. 모델 전체가 BF16이라는 뜻은 아니고, key/value 캐시를 어떤 dtype으로 남길지 정하는 실행 설정에 가까워.

이 표현은 보통 FP8 가중치와 같이 나올 때 헷갈려. 예를 들어 Qwen3.6 27B FP8은 모델 가중치를 FP8로 줄인 배포본이지만, Reddit 실행 사례는 KV cache를 BF16으로 둔 구성이었어. 가중치는 8비트로 줄이고, 긴 문맥에서 계속 다시 읽는 캐시는 16비트로 남긴 셈이야.

그래서 BF16 KV는 “빠른 모드”라기보다 긴 문맥 추론에서 정밀도와 GPU VRAM을 맞바꾸는 선택지야. BF16은 원소 하나가 2바이트고, FP8은 1바이트라 단순 dtype 폭만 보면 BF16 캐시가 FP8 캐시보다 두 배 무겁다. 대신 캐시를 더 낮은 정밀도로 줄였을 때 생길 수 있는 긴 답변 품질 회귀를 피하려는 이유가 생겨.

어떻게 작동하나

토큰을 하나씩 생성하는 모델은 이미 읽은 토큰의 key와 value를 저장해 둬. 새 토큰이 들어올 때 이전 문맥을 처음부터 다시 계산하지 않고, 이 캐시를 읽어서 attention을 이어 가는 구조야. 그래서 컨텍스트4K에서 200K로 커지면 입력 길이만 커지는 게 아니라 캐시에 남겨야 할 값도 같이 늘어.

캐시 메모리는 대략 토큰 수 × 캐시를 쓰는 레이어 수 × KV head 수 × head dimension × key/value 2개 × dtype 바이트 방향으로 커져. 실제 값은 모델 구조, sliding window, hybrid attention, prefix cache, 런타임의 block 관리에 따라 달라져서 이 식 하나로 고정하면 위험해. 그래도 BF16이 원소당 2바이트라는 사실만으로도 긴 문맥에서 왜 VRAM 압박이 커지는지 감은 잡을 수 있어.

vLLM에서는 --kv-cache-dtype bfloat16처럼 캐시 dtype을 별도로 지정하는 경로가 있어. vLLM v0.20.1 문서는 --kv-cache-dtype 선택지에 auto, bfloat16, float16, fp8 계열을 함께 적고, auto일 때는 모델 dtype을 쓴다고 설명해. 그러니까 서버가 실제로 BF16 KV를 쓰는지는 모델 카드가 아니라 실행 인자와 로그에서 확인해야 해.

왜 중요한가

BF16 KV가 중요한 이유는 로컬 추론의 병목이 “모델 파일이 GPU에 올라가느냐”에서 끝나지 않는다는 걸 보여 주기 때문이야. Qwen/Qwen3.6-27B-FP8 모델 카드는 이 모델이 FP8 quantized weights와 block size 128 설정을 담고, 27B parameters와 native context 262,144 tokens를 적어. 여기까지 보면 가중치가 줄었으니 긴 문맥도 쉽게 될 것 같지만, 실제 서버에서는 KV cache가 따로 자리를 차지해.

LocalLLaMA 게시글Qwen3.6 27B FP8RTX 5000 PRO 48GB 한 장에서 vLLM 0.20.1, CUDA 12.9, --max-model-len 196608, BF16 KV cache 조건으로 돌린 사례를 제시해. 글 제목은 약 200K tokens의 BF16 KV cache와 약 80 TPS를 말해. 이건 꽤 흥미로운 숫자지만, 공식 보장 성능이 아니라 특정 장비와 런타임 조합에서 나온 커뮤니티 실행값이야.

2차 분석인 StartupFortune 글은 이 구성에서 FP8 모델 가중치가 대략 27GB, 200K BF16 KV cache가 대략 19~21GB를 쓴다고 해석해. 반면 NVIDIA RTX PRO 5000 Blackwell 사양은 해당 카드 계열의 48GB 또는 72GB GDDR7 ECC1,344 GB/sec memory bandwidth를 공식 숫자로 보여 줘. 숫자를 나눠 읽으면 결론이 더 차분해져. 48GB라서 넉넉한 게 아니라, 가중치와 캐시가 거의 같이 꽉 차는 구성에 가깝다.

FP8 KV와 어떻게 다른가

FP8 KVKV cache 자체를 8비트로 줄이는 쪽이야. vLLM의 quantized KV cache 문서는 FP8 캐시가 메모리 사용량을 줄이고 더 긴 컨텍스트를 담는 데 도움을 줄 수 있다고 설명해. 대신 적절한 scale 없이 낮은 정밀도로 저장하면 정확도가 떨어질 수 있다는 경고도 붙어.

BF16 KV는 반대로 캐시를 더 보수적으로 남기는 선택이야. FP8 가중치와 BF16 KV를 같이 쓰면 “모델 가중치는 줄이고, 생성 중 계속 재사용하는 캐시는 덜 줄인다”는 구성이 돼. 긴 코딩 에이전트나 문서 묶음 요약처럼 앞 문맥의 작은 차이가 뒤 답변에 계속 영향을 주는 작업에서는 이 선택이 꽤 자연스러워.

다만 BF16 KV가 항상 낫다는 뜻은 아니야. 짧은 챗봇, 작은 컨텍스트, 동시 요청이 많은 서버라면 FP8 KV나 quantized cache가 더 실용적일 수 있어. 반대로 100K 이상 문맥을 한 요청에서 길게 유지하고 답변 품질 회귀를 줄이고 싶다면 BF16 KV를 기준선으로 두고 FP8 KV를 비교해 볼 만해.

주의해서 볼 점

첫째, BF16 KV라는 말이 보이면 “가중치 dtype인지, 캐시 dtype인지”부터 갈라야 해. Qwen3.6 27B FP8 사례처럼 모델 이름에는 FP8이 붙고 실행 인자에는 BF16 KV가 붙을 수 있어. 둘은 같은 설정이 아니야.

둘째, 캐시 크기 숫자는 모델 구조를 알아야 읽을 수 있어. 레이어 수, KV head 수, head dimension, sliding window, batch size, 동시 요청 수, vision encoder 사용 여부가 모두 캐시 예산을 바꿔. 200K BF16 KV라는 말만 보고 다른 27B 모델도 같은 VRAM을 쓸 거라고 보면 자주 틀려.

셋째, 벤치마크에는 최소한 아래 항목이 같이 있어야 해.

BF16 KV는 긴 문맥을 더 믿고 쓰기 위한 단서가 될 수 있어. 대신 그 대가로 VRAM을 더 쓰는 설정이라서, 좋은 소식도 늘 메모리 표와 같이 봐야 해.