OpenAI 호환 로컬 LLM을 위한 llama.swap 모델 스위처 빠른 시작 가이드
클라이언트를 변경하지 않고 로컬 LLM을 핫스왑합니다.
곧 vLLM, llama.cpp 등 여러 스택을 각각 다른 포트에서 관리하게 될 것입니다. 모든 다운스트림 시스템은 여전히 하나의 /v1 기본 URL 을 요구하며, 그렇지 않으면 포트, 프로필, 일회성 스크립트를 계속 조정해야 합니다. llama-swap은 이러한 스택들 앞에 위치한 /v1 프록시입니다.
llama-swap은 하나의 OpenAI 및 Anthropic 호환 진입점을 제공하며, 각 model 이름을 해당 업스트림을 시작하는 명령어에 매핑하는 YAML 파일을 사용합니다. 모델을 요청하면 프록시가 해당 모델을 시작하거나 전환합니다. VRAM 이 부족하거나 여러 모델이 공존해야 하는 경우 TTL 과 그룹을 구성할 수 있습니다. 이 가이드에서는 설치 경로, 실용적인 config.yaml, HTTP 표면, 스트리밍과 역 프록시가 도입될 때 발생하는 오류 모드에 대해 다룹니다.
LLM 호스팅 옵션에 대한 광범위한 비교는 LLM 호스팅 2026: 로컬, 셀프 호스팅 및 클라우드 인프라 비교 를 참고하세요.
OpenAI 호환 로컬 LLM API 를 위한 llama-swap 모델 스위처 개요
llama-swap 은 경량 프록시 서버로, 단순한 운영 모델인 하나의 바이너리, 하나의 YAML 설정 파일, 의존성 없음을 기반으로 구축되었습니다. Go 로 작성되어 나머지 스택과 함께 단일 정적 바이너리로 제공되며, Python 런타임이나 데스크톱 앱이 필요 없습니다. 이는 OpenAI 및 Anthropic 호환 업스트림 앞에 위치하여 모델 전환 레이어로 작동합니다.
개념적으로 이는 로컬 LLM 스택에서 자주 발생하는 매우 실용적인 질문에 답합니다:
OpenAI 호환 클라이언트로 모델을 어떻게 전환하나요?
llama-swap 을 사용하면 평소와 마찬가지로 /v1/... 요청을 계속 사용하되, 요청하는 model 을 변경하기만 하면 됩니다. llama-swap 은 해당 model 값을 읽어 매칭되는 서버 구성을 로드하고, 잘못된 업스트림이 실행 중이면 올바른 것으로 교체합니다.
프로덕션급 설정에서 중요한 몇 가지 설계 세부사항이 있습니다:
llama-swap 은 MIT 라이선스를 사용하며 텔레메트리 없음입니다—실제 프롬프트를 보는 호스트의 경우 여전히 확인이 필요합니다.
이는 llama.cpp, vLLM, Whisper, stable-diffusion.cpp와 같은 백엔드를 온디맨드로 로드하도록 설계되었으며, 단일 추론 엔진에 고정되는 것이 아닙니다.
기본 설정 (특별한 그룹 없음) 에서는 한 번에 하나의 모델만 실행됩니다: 다른 model 을 요청하면 현재 업스트림을 중지하고 올바른 것을 시작합니다. 한 개 이상의 상주 모델이나 공존에 대한 세밀한 제어가 필요한 경우 groups 를 구성합니다.
대부분의 개발자가 유용하게 여기는 사고 모델은 다음과 같습니다:
flowchart LR
C[Your app or SDK\nOpenAI-compatible client] -->|/v1/chat/completions\nmodel = qwen-coder| LS[llama-swap proxy\nsingle endpoint]
LS -->|starts or routes to| U1[Upstream server A\nllama-server]
LS -->|starts or routes to| U2[Upstream server B\nvLLM OpenAI server]
LS --> M[Management endpoints\nrunning, unload, events, metrics]
이것이 모델 스위처 프록시가 “모델만 실행"하는 것과 다른 이유입니다: 이는 하나 이상의 추론 서버 위에 오케스트레이션과 라우팅을 제공합니다.
llama-swap vs Ollama vs LM Studio vs llama.cpp 서버
네 가지 옵션 모두 “로컬 LLM API"를 제공할 수 있지만, 서로 다른 워크플로우에 최적화되어 있습니다. 선택하는 가장 빠른 방법은 런타임 (모델 다운로드 + 실행) 을 원하는지 라우터/프록시 (런타임 간 전환 + 오케스트레이션) 를 원하는지 결정하는 것입니다.
llama-swap
llama-swap 은 OpenAI 호환 엔드포인트 ( /v1/chat/completions, /v1/completions, /v1/embeddings, /v1/models 포함) 를 지원하고 요청된 모델에 따라 올바른 업스트림으로 요청을 라우팅하는 투명한 프록시에 중점을 둡니다. 또한 /running, /logs/stream 및 /ui 의 Web UI 와 같은 비추론 운영 엔드포인트도 제공합니다.
Ollama
Ollama 는 자체 HTTP API (POST /api/chat, POST /api/generate, 포트 11434 의 일반적인 로컬 기본값) 를 노출합니다.
keep_alive 는 모델이 로드된 상태를 유지하는 시간을 제어하며, 0 은 즉시 언로드함을 의미합니다.
이는 최소한의 설정으로 모델을 다운로드하고 채팅하려는 사용자에게 적합합니다. llama-swap은 모델별 명령, 혼합 백엔드, 모든 클라이언트에 대한 하나의 OpenAI 형식 URL에 적합합니다—vLLM 을 llama-server 옆에 배치하고 모델마다 다른 플래그를 오케스트레이션하는 것은 Ollama 의 목표가 아닙니다.
LM Studio
LM Studio 는 Developer 탭 (localhost 또는 LAN) 에서 로컬 API 서버를 제공하는 데스크톱 앱으로, OpenAI 호환 및 Anthropic 호환 모드와 터미널의 lms server start를 포함합니다.
이는 GUI 우선 워크플로우에 적합합니다: 모델을 탐색하고 클릭하여 테스트합니다. llama-swap은 서버 스타일 역할에 적합합니다: YAML, 프로세스 감시, 혼합 업스트림, 데스크톱 세션 없음.
llama.cpp 서버
llama-server 는 /v1/completions, /v1/chat/completions, /v1/responses를 노출하며, 일반적인 패턴은 OpenAI 클라이언트를 base_url을 통해 이 서버로 지시하는 것입니다.
llama.cpp 는 라우터 모드도 제공합니다: llama-server를 라우터로 실행하고 --models-dir를 설정한 다음 POST /models/load 및 POST /models/unload를 사용하여 별도의 프록시 없이 GGUF 모델을 관리합니다. 전체 설정 가이드는 llama-server 라우터 모드: 재시작 없는 동적 모델 전환 를 참고하세요.
모든 모델이 하나의 llama.cpp 라우터 아래에 있으면 추가 프록시는 종종 불필요합니다. llama.cpp 가 vLLM 이나 다른 OpenAI 형식 서버와 함께 있어야 할 때, llama-swap 은 하나의 /v1 표면과 그 뒤의 여러 프로세스를 제공합니다.
유사한 OpenAI 호환 호스팅 솔루션에 대해서는 LocalAI QuickStart: 로컬에서 OpenAI 호환 LLM 실행 또는 SGLang QuickStart: OpenAI API 를 통한 LLM 설치, 구성 및 제공 를 참고하세요.
Docker, Homebrew, WinGet 또는 바이너리로 llama-swap 모델 스위처 설치
Linux, macOS, Windows 는 모두 일급 지원 대상입니다: Docker, Homebrew, WinGet, GitHub 바이너리, 또는 소스 빌드. 일반적인 선택지: 헤드리스 서버에서는 Docker, 워크스테이션에서는 Homebrew 또는 WinGet, 설치 footprint 를 최소화해야 할 때는 독립 실행형 바이너리를 사용합니다.
Docker 설치
하드웨어와 일치하는 이미지를 풀하세요. 이미지는 업스트림을 밀접하게 추적하며 (나이트리 빌드) CUDA, Vulkan, Intel, MUSA, CPU 를 포함합니다—습관대로 “최신"이 아니라 실제로 가속하는 방식에 맞는 것을 선택하세요.
# 예시 플랫폼 풀
docker pull ghcr.io/mostlygeek/llama-swap:cuda
docker pull ghcr.io/mostlygeek/llama-swap:vulkan
docker pull ghcr.io/mostlygeek/llama-swap:intel
docker pull ghcr.io/mostlygeek/llama-swap:musa
docker pull ghcr.io/mostlygeek/llama-swap:cpu
가능하다면 비루트 이미지 변형을 선호하세요: 컨테이너 경계가 잘못되었을 경우 후회할 일이 적습니다.
Homebrew 설치
macOS 와 Linux 에서 tap 을 추가하고 설치합니다:
brew tap mostlygeek/llama-swap
brew install llama-swap
llama-swap --config path/to/config.yaml --listen localhost:8080
WinGet 설치
Windows 에서:
winget install llama-swap
winget upgrade llama-swap
사전 빌드된 바이너리 및 릴리스
패키지 관리자가 원치 않는 경우 GitHub Releases 에서 Linux, macOS, Windows, FreeBSD 바이너리를 제공합니다.
릴리스 버전은 빠르게 이동합니다 (예를 들어 2026 년 초 v198, v197 주변)—자동화에서 “어제 있었던 것"을 부동하게 두기보다는 버전을 고정하세요.
모델 전환, TTL, 그룹을 위한 config.yaml 로 llama-swap 구성
llama-swap 의 모든 것은 구성 기반입니다. 최소한의 생존 가능한 구성은 단순히 models: 사전과 각 모델에 대한 cmd이며, 종종 ${PORT}가 모델별로 대체되어 llama-server를 실행합니다.
구성 시스템은 단순히 “프로세스 시작"보다 훨씬 더 깊어지며, 몇 가지 옵션은 초기에 이해할 가치가 있습니다. 이는 자주 묻는 질문 스타일의 문제 (자동 언로드, 보안, /v1/models에 의존하는 클라이언트) 에 직접적으로 답하기 때문입니다.
실제로 사용할 전역 설정
healthCheckTimeout은 llama-swap 이 시작 후 모델이 건강해지기를 기다리는 시간입니다 (기본값 120 초, 최소 15 초). 느린 디스크에서 멀티 GB 로딩의 경우 프록시를 비난하기 전에 이 값을 늘리세요.
globalTTL은 자동 언로드 전의 유휴 초수입니다; 기본값 **0**은 설정하지 않는 한 “언제나 언로드 안 함"을 의미합니다—장난감 설정을 넘어선 모든 것에 대해 VRAM 이 잊혀진 모델로 채워지지 않도록 TTL 을 명시적으로 선택하세요.
startPort는 ${PORT} 매크로의 시드입니다 (기본값 5800); 할당은 알파벳 순서 모델 ID로 결정론적이며, “누가 어떤 포트를 가져갔는지” 디버깅할 때는 기능이나 모델을 부주의하게 이름 바꾸면 발목 잡히는 요소가 됩니다.
includeAliasesInList는 별칭이 /v1/models에서 별도의 행으로 표시되는지 여부를 결정합니다; UI 가 열거된 모델만 제공하는 경우 켜세요.
apiKeys는 로컬호스트에서 접근 가능한 모든 것을 보호합니다: Basic, Bearer, 또는 x-api-key. llama-swap 은 전달 전에 이러한 헤더를 제거하여 업스트림 로그가 클라이언트 비밀을 유지할 가능성이 줄어듭니다.
프로덕션 사용성을 위한 모델 수준 설정
모델마다 cmd가 유일한 필수 필드입니다.
proxy는 기본값으로 http://localhost:${PORT}이며, 이는 해당 모델 업스트림의 전달 대상입니다.
checkEndpoint는 기본값으로 /health이며, 백엔드에 건강 라우트가 없거나 콜드 스타트가 기다릴 시간을 초과할 경우 "none"으로 설정합니다—손상된 /health를 두고 ready에 도달하지 않는 이유를 궁금해하지 마세요.
ttl: -1은 globalTTL을 상속하고, 0은 절대 언로드하지 않으며, N > 0은 N 초 유휴 후 언로드합니다—한 모델은 오래 머물고 다른 모델은 빠르게 사라져야 할 때 모델별 TTL 을 사용하세요.
aliases와 useModelName은 업스트림이 특정 식별자를 요구하면서도 안정적인 클라이언트 표시 이름을 유지합니다.
cmdStop은 컨테이너에 필수적입니다: docker stop(또는 동등한 것) 에 매핑하세요; 없으면 llama-swap 이 시작한 PID 에 대해 POSIX SIGTERM / Windows taskkill 이 실행되며, 이는 순수 바이너리에는 적합하지만 컨테이너 이름에는 적합하지 않습니다.
concurrencyLimit은 초과 시 HTTP 429 로 모델별 병렬 요청을 제한합니다—영구적으로 대기하기보다는 부하를 줄이고 싶을 때 설정하세요.
groups는 공존 (swap, exclusive) 과 항상 실행 모델 (persistent) 을 다룹니다. 후크는 시작 시 사전 로드할 수 있습니다; 그룹 없이 여러 모델을 한 번에 사전 로드하면 경쟁을 예상하세요—먼저 그룹을 정의하여 모델이 GPU 를 공유하는 방식을 사전 로딩이 일치하도록 하세요.
llama.cpp 와 vLLM 을 위한 최소 config.yaml 예시
이 예시는 모범 사례를 보여주는 “필요한 만큼"을 목표로 합니다: 기본 TTL, 명시적 건강 확인, 안정적인 별칭, 큰 채팅 모델이 전환되는 동안 작은 “항상 실행” 모델을 실행하는 그룹.
# config.yaml
healthCheckTimeout: 180
globalTTL: 900 # 15 분 유휴 후 언로드
includeAliasesInList: true
startPort: 5800
# 로컬 개발을 넘어선 모든 것에 대해 선택적이지만 권장됨
apiKeys:
- "${env.LLAMASWAP_API_KEY}"
models:
llama-chat:
cmd: |
llama-server --port ${PORT} --model /models/llama-chat.gguf
--ctx-size 8192
aliases:
- "llama-chat-latest"
# 기본값 사용:
# proxy: http://localhost:${PORT}
# checkEndpoint: /health
# ttl: -1 (globalTTL 상속)
qwen-coder:
cmd: |
llama-server --port ${PORT} --model /models/qwen-coder.gguf
--ctx-size 8192
aliases:
- "qwen-coder-latest"
vllm-coder:
# 설명적 패턴: 컨테이너화된 OpenAI 호환 서버 관리
proxy: "http://127.0.0.1:${PORT}"
cmd: |
docker run --name ${MODEL_ID} --init --rm -p ${PORT}:8000 vllm/vllm-openai:latest
cmdStop: docker stop ${MODEL_ID}
checkEndpoint: "none"
ttl: 0 # 자동 언로드 안 함 (예: GPU 에 유지)
groups:
chat-models:
swap: true
exclusive: true
members: ["llama-chat", "qwen-coder"]
always-on:
persistent: true
swap: false
exclusive: false
members: ["vllm-coder"]
이 중 장식적인 것은 없습니다: cmd는 프로세스를 구동하고, proxy/checkEndpoint/ttl은 라우팅과 생명 주기를 제어하며, cmdStop은 Docker 기반 업스트림이 실제로 중지되는 것을 보장하고, groups는 “한 번에 하나의 큰 모델"과 “이 두 채팅 모델은 공존할 수 있지만 임베딩 서버는 고정됨"을 구분합니다.
OpenAI 호환 엔드포인트를 통한 모델 실행 및 전환
llama-swap 이 실행되면 다른 OpenAI 호환 엔드포인트와 마찬가지로 상호작용합니다. API 표면에는 /v1/chat/completions, /v1/completions, /v1/embeddings, /v1/models와 같은 핵심 엔드포인트가 포함되며, llama-swap 은 요청된 model을 사용하여 실행하고 라우팅할 업스트림을 결정합니다.
실용적인 빠른 시작 흐름:
# 1) llama-swap 시작
llama-swap --config ./config.yaml --listen localhost:8080
# 2) 사용 가능한 모델 발견
curl http://localhost:8080/v1/models
모델 목록은 일급 관리 기능이며 ID 로 정렬, unlisted 모델 제외, 선택적 별칭 포함 등의 동작을 포함합니다.
# 3) 특정 모델에 대한 채팅 완료 요청
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${LLAMASWAP_API_KEY}" \
-d '{
"model": "qwen-coder",
"messages": [{"role":"user","content":"Write a TypeScript function that retries fetch with backoff."}]
}'
이제 "model": "llama-chat"로 호출을 반복하면 llama-swap 은 업스트림 프로세스를 전환합니다 (그룹 구성이 공존을 허용하지 않는 한). 이는 요청에서 요청된 모델을 추출하고 적절한 서버 구성을 로드하기 때문입니다.
SDK 를 사용하는 경우 클라이언트를 http://localhost:8080/v1로 지시하세요—llama-server를 대상으로 하는 OpenAI Python 라이브러리와 같은 트릭이지만, 안정적인 URL 은 이제 llama-swap 이며 model 필드가 업스트림을 선택합니다.
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8080/v1",
api_key="sk-your-llamaswap-key"
)
resp = client.chat.completions.create(
model="qwen-coder",
messages=[{"role": "user", "content": "Explain the difference between mutexes and semaphores."}],
)
print(resp.choices[0].message.content)
첫 번째 실제 요청 전에 모델을 예열하려면 (콜드 스타트 대기 시간 숨김) /upstream/<model>을 사용하세요—필요시 자동 로드하고 해당 업스트림으로 바로 전달합니다. 벤치마크나 스크립트 테스트 전에 가중치가 상주하도록 보장하는 간단한 방법입니다.
관리 API 엔드포인트 및 SSE 이벤트를 통한 llama-swap 제어 및 모니터링
llama-swap 은 단순히 “프록시"가 아닙니다: 모델 생명 주기와 관측성 주변의 도구 구축을 위한 운영 제어 엔드포인트도 노출합니다.
실행 중인 항목 확인
GET /running은 로드된 모델의 런타임 상태를 반환하며, ready, starting, stopping, stopped, shutdown과 같은 상태 값을 포함합니다.
curl http://localhost:8080/running
VRAM 을 확보하기 위해 모델 언로드
모든 것을 즉시 언로드하려면 API 버전된 엔드포인트 POST /api/models/unload를 사용하세요. 단일 모델 (ID 또는 별칭) 을 언로드하려면 POST /api/models/unload/<model>을 사용하세요. 호환성을 위한 레거시 GET /unload도 존재합니다.
# 모두 언로드
curl -X POST http://localhost:8080/api/models/unload
# 하나의 모델 언로드
curl -X POST http://localhost:8080/api/models/unload/qwen-coder
TTL 을 기다리지 않고 VRAM 이 지금 필요할 때 이 엔드포인트를 사용하세요—벤치마크, 빠른 모델 전환, 의도한 것보다 훨씬 큰 체크포인트를 로드한 후 등.
SSE 를 통한 라이브 이벤트 스트리밍
GET /api/events는 Server-Sent Events 스트림을 설정하며 모델 상태 변경, 로그, 메트릭, 대기 중인 요청 수를 포함하는 실시간 업데이트를 위해 설계되었습니다.
curl -N http://localhost:8080/api/events
중간 상자가 버퍼링할 때 SSE 와 토큰 스트리밍이 중단됩니다—nginx(또는 동등한 것) 에서 /api/events와 /v1/chat/completions에 대해 버퍼링을 비활성화하세요. llama-swap 은 SSE 에서 X-Accel-Buffering: no를 설정하지만—프록시도 수정해야 합니다. 헤더는 올바른 프록시 구성의 대체가 아닙니다.
메트릭 및 요청 캡처
GET /api/metrics는 토큰 사용량 메트릭을 반환하며, 메모리 내 보존은 metricsMaxInMemory(기본값 1000) 로 제어됩니다.
GET /api/captures/<id>는 captureBuffer > 0이 구성되었을 때만 전체 요청/응답 캡처를 가져올 수 있습니다.
로그 및 Web UI
llama-swap 은 웹 인터페이스를 위한 /ui와 실시간 모니터링을 위한 /logs, /logs/stream과 같은 운영 로그 엔드포인트를 노출합니다.

apiKeys를启用하면 심층 방어를 가정하세요: /health와 /ui의 일부는 키 없이 접근 가능합니다—로컬 신뢰 경계에서는 괜찮지만, 호스트가 공유 네트워크에 있다면 안 좋습니다. llama-swap 을 실제 정책을 강제하는 것 뒤에 두세요; 내장 인증은 공공 다중 테넌트 API 가 아니라 우연한 클라이언트를 정직하게 유지하기 위한 것입니다.
프로덕션에서 llama-swap 모델 전환 문제 해결
대부분의 llama-swap 문제는 소수의 운영 범주로 나뉩니다: 역 프록시를 통한 스트리밍, 콜드 스타트 중 건강 확인, 포트 및 프로세스 생명 주기, 인증.
nginx 또는 다른 역 프록시 뒤에서 스트리밍이 끊김
nginx 는 SSE 와 스트림된 완료 버퍼링을 기꺼이 수행합니다. /api/events와 /v1/chat/completions에 대해 proxy_buffering(및 proxy_cache) 을 비활성화하세요. llama-swap 은 SSE 에서 X-Accel-Buffering: no를 방출하여 도움이 되지만—어쨌든 프록시를 수정하세요.
모델이 준비 상태로 전환되지 않음
기본값으로 모델별 checkEndpoint는 /health이며 프로세스가 준비 상태로 간주되려면 HTTP 200 을 반환해야 합니다. checkEndpoint를 다른 경로나 "none"으로 설정하여 건강 확인을 완전히 비활성화할 수 있습니다.
큰 모델이 로드하는 데 더 오래 걸린다면 healthCheckTimeout(기본값 120 초) 를 늘리거나 특정 업스트림에 맞춘 건강 확인을 사용하세요.
모델 전환 후 오래된 컨테이너가 실행 중임
업스트림이 Docker 또는 Podman 인 경우 cmdStop을 설정하세요— 그렇지 않으면 llama-swap 이 래퍼 프로세스만 중지하고 컨테이너가 배경에서 VRAM 을 계속 소비합니다.
보안启用 후 401 응답 수신
apiKeys가 구성되면 llama-swap 은 유효한 키를 요구하며 세 가지 방법 (Basic 인증, Bearer 토큰, x-api-key) 을 허용합니다. 업스트림 전달 전에 인증 헤더도 제거합니다.
429 Too Many Requests 수신
concurrencyLimit은 초과 시 설계대로 429 를 반환합니다—자원이 부족하면 상한을 높이거나, 의도하지 않았던 경우 제한을 낮추세요.
포트 충돌 또는 이상한 라우팅 문제
cmd에서 하드코딩된 포트를 피하고 ${PORT}를 사용하며 5800+가 다른 것과 충돌하면 startPort를 이동하세요. 포트는 모델 ID 알파벳 순서로 할당됨을 기억하세요—모델 이름을 바꾸면 포트 매핑이 이동합니다.
운영 디버깅 체크리스트
진실을 위한 /running, 시작이 불투명할 때 /logs/stream, VRAM 이 지금 필요할 때 POST /api/models/unload. 이 세 가지는 대부분의 “왜 GPU 가 가득 찼나요” 세션을 해결합니다.