32GB GPU 한 장으로 27B 로컬 LLM: 구성과 비용

Radeon AI PRO R9700(32GB)에 llama.cpp를 Vulkan으로 직접 빌드해 Qwen3.8 27B를 192K 컨텍스트로 돌린다. 사양표, 빌드·실행 명령, 속도와 VRAM, 재부팅 뒤 20배 느려졌던 원인, 들어간 돈.
VRAM 32GB GPU 한 장이면 27B급 모델을 4비트로 올리고 192K 컨텍스트까지 쓸 수 있다. AMD Radeon AI PRO R9700에 llama.cpp를 직접 빌드해 Qwen3.8 27B를 돌리고, Open WebUI와 텔레그램 에이전트에 붙여 쓴다. 생성 속도는 초당 45~55토큰이다. 홈서버 옆에 로컬 LLM 서버를 하나 둘까 고민한다면, 아래 구성과 숫자가 기준이 된다.
사양
| 부품 | 사양 |
|---|---|
| GPU | AMD Radeon AI PRO R9700, VRAM 32GB GDDR6, 대역폭 640GB/s, 보드 전력 300W |
| CPU | Ryzen 7 5700X |
| 램 | 32GB |
| OS | Debian 13, 커널 6.12 |
| 그래픽 드라이버 | Mesa RADV 26.1 (Vulkan). backports 저장소 |
| 추론 엔진 | llama.cpp, Vulkan 백엔드로 직접 빌드 |
| 모델 | Qwen3.8-27B dense, Unsloth UD-Q4_K_XL (약 17GB) + mmproj(이미지 입력) |
CPU와 램은 거들 뿐이다. 모델과 KV 캐시가 전부 GPU에 올라가면 속도는 VRAM 대역폭이 정한다.
왜 R9700인가
로컬 LLM에서 가장 먼저 막히는 것은 VRAM 크기다. 27B 모델 4비트 파일만 17GB 안팎이고, 긴 컨텍스트를 쓰면 KV 캐시가 그 위에 쌓인다. 24GB 카드에서는 빠듯하고 32GB부터 여유가 생긴다.
| 선택지 | VRAM | 가격 (2026 기준) | 메모 |
|---|---|---|---|
| R9700 | 32GB | 출시가 $1,299, 실판매 $1,400~1,900 | RDNA4. ROCm 7.2부터 공식 지원 |
| 24GB 소비자용 카드 | 24GB | 세대·중고 여부에 따라 차이 큼 | 27B 4비트 + 긴 컨텍스트는 빠듯 |
| 32GB 최상위 소비자용 | 32GB | R9700보다 한참 비쌈 | 속도는 가장 빠름 |
같은 32GB를 가장 싸게 얻는 길이 R9700이었다. 대신 CUDA가 아니라서 도구 지원을 직접 챙겨야 한다.
빌드: ROCm 대신 Vulkan
AMD 공식 경로는 ROCm(HIP)이다. 하지만 Debian 13용 ROCm 패키지가 없어 Ubuntu 22.04용 저장소를 끌어와야 하고, 시스템 업데이트 때마다 그 패키지들이 섞이지 않게 따로 관리해야 한다. 지금은 Mesa의 Vulkan 드라이버(RADV)로 돌린다. 배포판 저장소에 있는 드라이버라 관리가 쉽고, llama.cpp의 Vulkan 백엔드는 RDNA4를 잘 지원한다.
sudo apt install -t trixie-backports mesa-vulkan-drivers # 최신 RADV
sudo apt install build-essential cmake libvulkan-dev glslc
sudo usermod -aG render,video "$USER" # 다시 로그인
git clone https://github.com/ggml-org/llama.cpp && cd llama.cpp
cmake -S . -B build -DGGML_VULKAN=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j"$(nproc)"
./build/bin/llama-server --list-devices # Vulkan0: AMD Radeon AI PRO R9700 이 보여야 한다
시작 로그에 offloaded N/N layers to GPU가 나오면 전부 GPU에 올라간 것이다. 숫자가 다르면 드라이버나 render 그룹 권한을 다시 본다.
실행: 192K 컨텍스트
systemd 서비스로 돌린다. 실제 실행 명령이다.
llama-server \
-m Qwen3.8-27B-UD-Q4_K_XL.gguf --mmproj mmproj-F16.gguf --alias qwen3.8-27b \
-ngl 999 -c 196608 -ctk q8_0 -ctv q8_0 --jinja \
--spec-type draft-mtp --spec-draft-n-max 2 \
--chat-template-kwargs '{"enable_thinking":false}' \
--host 0.0.0.0 --port 11434 \
--temp 0.7 --top-p 0.8 --top-k 20 --min-p 0.0 --presence-penalty 1.5
API 키는 명령줄 대신 환경변수 LLAMA_API_KEY로 넣는다(systemd EnvironmentFile). 명령줄에 쓰면 ps에 그대로 보인다.
| 옵션 | 뜻 |
|---|---|
-ngl 999 | 모든 레이어를 GPU에 |
-c 196608 | 컨텍스트 192K. 모델은 256K(262,144)까지 되지만, 192K에서 이미 VRAM 27.8GB를 써서 256K는 32GB를 넘본다 |
-ctk/-ctv q8_0 | KV 캐시를 8비트로. 16비트 대비 절반이라 192K가 32GB 안에 들어간다 |
--jinja | 모델의 채팅 템플릿을 그대로 쓴다. 도구 호출(tool call)이 이것 없이는 깨진다 |
--spec-type draft-mtp --spec-draft-n-max 2 | 모델에 든 MTP 헤드로 다음 토큰을 미리 찍어 본다. 수용률은 코드 80%, 한국어 산문 61%. 깊이를 2로 묶으면 산문이 +3 tok/s, 코드는 -4 tok/s라 용도에 따라 고른다 |
--chat-template-kwargs '{"enable_thinking":false}' | 추론 모드를 서버 기본값에서 끈다. 켜 두면 “저녁 메뉴 하나” 같은 질문에도 350자를 생각하고 답해 첫 글자까지 2.7초, 끄면 0.2초. 필요한 요청만 enable_thinking: true로 켠다 |
--temp 0.7 --top-p 0.8 --presence-penalty 1.5 | 추론을 끈 모드의 Qwen 권장 샘플링 값. 추론 모드는 temp 1.0, top-p 0.95 |
| API 키 | 집 안이라도 건다. 키가 없으면 브라우저에서 연 아무 웹페이지가 이 서버를 부를 수 있다 |
--host 0.0.0.0은 다른 기기에서 붙기 위한 것이다. 이 서버는 집 안과 Tailscale에서만 닿게 두고 공유기 포트는 열지 않는다. 집 네트워크 구성은 홈 네트워크 지도에 있다.
속도
| 측정 | 값 |
|---|---|
| 생성 속도 (256토큰, 드래프트 포함) | 코드 52, 산문 46, 섞임 49 tok/s |
| 프롬프트 처리 (긴 문서) | 약 350 tok/s (15만 토큰 대화를 7분에 읽음) |
| VRAM 사용 (192K 설정, 생성 중) | 27.8GB / 32GB |
같은 모델, 같은 명령인데 드라이버 버전으로 속도가 달라졌다. Mesa 26.1.2에서는 23 tok/s였고, 26.1.6과 커널·펌웨어 업데이트 뒤 30 tok/s를 넘었다(짧은 64토큰 요청 기준. 256토큰에 MTP까지 더하면 위 표의 값). AMD 카드는 드라이버가 성능의 일부다. backports로 Mesa를 최신으로 유지할 이유가 생겼다.
재부팅 뒤 20배 느려진 날
업데이트 뒤 재부팅했더니 답이 한 글자씩 나왔다. 1.7 tok/s. 드라이버를 의심했지만 원인은 순서였다. llama-server가 GPU 장치 파일과 권한이 준비되기 전에 먼저 떠서 warning: no usable GPU found를 남기고 에러 없이 CPU로 돌고 있었다. health 엔드포인트는 ok를 돌려주니 겉으로는 정상이었다.
대응은 서비스 시작 전에 GPU를 기다리는 것이다.
# /etc/systemd/system/llama-server.service.d/10-wait-gpu.conf
[Service]
ExecStartPre=/usr/local/bin/llama-wait-gpu.sh # --list-devices 에 Vulkan0 이 보일 때까지 최대 2분
TimeoutStartSec=200
여기서 배운 것 하나. GPU 서버는 health만 보면 안 되고, 재부팅마다 짧은 생성 요청을 보내 tok/s까지 본다.
어디에 붙여 쓰나
| 붙인 곳 | 쓰는 일 |
|---|---|
| Open WebUI | 채팅 화면. OpenAI 호환 API로 연결 |
| 텔레그램 에이전트 (Hermes Agent + SearXNG) | 아침 날씨 브리핑, 관심 사이트 새 글 수집, 밖에서 메시지로 검색·요약 |
| VS Code 코딩 에이전트 | 규칙 파일·워크플로를 붙여 코드 작업 |
모델은 여러 개를 돌려 본 끝에 27B dense로 정했다. 코딩 벤치마크에서 더 큰 MoE 모델보다 나았고, 32GB 한 장에 긴 컨텍스트와 함께 들어가는 크기다.
솔직하게 적으면, 로컬 모델의 자리는 아직 정하는 중이다. 연동은 다 해 두었지만 매일 도는 일은 아침 날씨 브리핑과 뉴스 수집뿐이고, 코드 작업과 긴 글은 상용 구독(Claude, ChatGPT)으로 한다. 서버를 먼저 만들고 쓸 일을 나중에 찾는 순서가 됐다. 로컬 LLM을 고민한다면 “무엇을 시킬지”를 GPU 사기 전에 정하는 편이 낫다.
들어간 돈
| 항목 | 금액 |
|---|---|
| R9700 | 218만 원 |
| 나머지 | CPU는 기존 보유, 램·보드·케이스 중고, 파워만 새 제품 |
| 전기 | 대기 약 40W, 24시간 켜 두면 한 달 약 30kWh (주택용 요금으로 5천 원 안팎) |
GPU 한 장이 나머지 전부보다 비싸다. 32GB VRAM 값이다.
다음
32GB 한 장에 27B 4비트 모델과 192K 컨텍스트가 함께 올라간다. 로컬 LLM 서버를 처음 꾸린다면 GPU는 VRAM 크기로 먼저 고르고, 속도는 그다음에 본다. 그리고 느리다고 느껴지면 모델보다 추론 모드가 켜져 있는지부터 본다. 내 경우 응답이 늦은 이유의 대부분이 그것이었다.