llama.cpp 서버 운영, OpenAI 호환 API·병렬 요청·Flash Attention을 나누는 법
AI를 활용하여 생성한 이미지입니다.
llama.cpp의 서버 모드는 모델을 한 번 실행하는 명령보다 운영 요소가 많아요. 모델을 올리는 것과 API를 외부에 노출하는 것은 별개이고, 여러 요청을 동시에 받는 것과 컨텍스트를 크게 잡는 것도 서로 다른 메모리 문제를 만듭니다. 로컬 서버를 안정적으로 쓰려면 엔드포인트, 병렬성, 메모리, 네트워크 노출을 따로 측정해야 합니다.
서버와 단일 실행을 구분해요
llama.cpp 서버는 HTTP API를 제공하고, OpenAI 호환 API와 멀티모달·모니터링·연속 배치 같은 기능을 지원합니다.[1] 반면 단일 CLI 실행은 한 번의 프롬프트를 확인하기에는 쉽지만, 여러 클라이언트가 같은 모델에 접근할 때 필요한 큐·동시성·인증 경계를 대신 만들어 주지 않아요.
| 목표 | 먼저 볼 항목 | 실패하기 쉬운 지점 |
|---|---|---|
| 로컬 앱 연결 | /v1/chat/completions와 모델 이름 |
클라이언트가 기대하는 응답 형식 |
| 여러 요청 처리 | 병렬 슬롯·KV 캐시·메모리 | 동시 요청이 늘며 지연과 메모리 사용 증가 |
| 속도 개선 | Flash Attention·오프로딩·컨텍스트 | 지원 여부를 확인하지 않고 옵션만 켬 |
| 외부 기기 접근 | 바인드 주소·CORS·인증 | 로컬 전용 서버를 LAN에 그대로 공개 |
OpenAI 호환 엔드포인트부터 확인해요
서버를 띄운 뒤에는 모델이 실제로 로드됐는지보다 먼저 HTTP 경로와 응답 형식을 확인합니다. llama.cpp 문서는 /v1/chat/completions와 /v1/completions를 제공하고, curl이나 OpenAI 클라이언트에서 호출하는 예시를 보여 줍니다.[1] 클라이언트가 model 필드를 보내도록 요구한다면 서버가 허용하는 모델 이름과 맞춰야 해요.
첫 테스트는 긴 문장이나 스트리밍이 아니라 짧은 요청으로 시작하세요. HTTP 상태 코드, 응답 JSON의 메시지 경로, 토큰 사용량 필드, 스트리밍 종료 여부를 각각 기록하면 모델 문제와 클라이언트 파서 문제를 구분하기 쉽습니다. Ollama도 로컬 추론에서 http://localhost:11434/api/chat를 사용하고, 로컬 서버에는 인증 헤더를 생략할 수 있다고 안내합니다.[2]
병렬 요청은 슬롯 수만의 문제가 아니에요
llama.cpp 서버는 여러 사용자를 위한 병렬 디코딩과 연속 배치를 지원하지만, 동시 요청이 늘면 요청마다 필요한 KV 캐시와 출력 대기 시간이 달라집니다.[1] 서버가 빨라지는지 보려면 한 요청의 토큰 생성 속도만 보지 말고, 요청 수별 첫 토큰까지 걸린 시간과 전체 완료 시간을 따로 측정하세요.
메모리가 빠듯한 상태에서 병렬 슬롯을 올리면 모델이 로드되지 않거나, 운영체제가 메모리를 압박해 오히려 모든 요청이 느려질 수 있어요. Ollama도 시스템 메모리 또는 GPU 추론의 VRAM이 충분할 때 여러 모델을 동시에 로드할 수 있다고 설명합니다.[3] 이 원칙은 llama.cpp에서도 그대로 고려할 대상이지만, 모델·양자화·백엔드별 실제 값은 직접 측정해야 합니다.
측정 순서
- 슬롯 하나로 짧은 요청을 세 번 보냅니다.
- 첫 토큰 시간과 전체 시간을 기록합니다.
- 동시 요청 두 개로 같은 테스트를 반복합니다.
- 메모리 사용량과 오류 로그를 함께 봅니다.
- 지연이 급증하면 슬롯보다 컨텍스트와 KV 캐시를 먼저 줄여 봅니다.
Flash Attention은 무조건 빠른 버튼이 아니에요
llama.cpp 서버 문서의 --flash-attn은 on, off, auto를 제공하고 기본값은 auto로 설명됩니다.[1] Ollama FAQ는 지원되는 백엔드에서 Flash Attention이 컨텍스트가 커질수록 메모리 사용량을 크게 줄일 수 있다고 안내합니다.[3] 하지만 같은 옵션을 켰다고 모든 모델과 장치에서 속도가 같은 비율로 오르지는 않아요.
먼저 auto 상태에서 짧은 컨텍스트와 긴 컨텍스트를 비교하고, 그 다음 on과 off를 각각 시험하세요. 응답 품질이 달라졌다고 느껴지면 속도보다 토큰화, 샘플링, 모델 템플릿 차이를 먼저 확인합니다. 측정하지 않은 성능 배수는 기록하지 않는 편이 안전해요.
컨텍스트 길이와 병렬성을 함께 올리지 않아요
긴 컨텍스트는 한 요청이 볼 수 있는 토큰 범위를 넓히지만, KV 캐시가 차지하는 메모리도 늘릴 수 있어요. 여기에 병렬 요청까지 늘리면 같은 메모리를 여러 세션이 나눠 쓰게 됩니다. 먼저 실제 프롬프트 길이와 출력 길이를 정한 뒤, 필요한 만큼만 컨텍스트를 잡으세요.
긴 문서를 자주 넣는다면 문서를 무조건 한 번에 넣기보다 검색·요약·후속 질의로 나누는 방식이 메모리와 지연을 관리하기 쉽습니다. 이 글은 특정 GPU에서의 최대 컨텍스트 수치를 제시하지 않아요. 양자화 형식, 모델 크기, 오프로딩 레이어, 백엔드에 따라 결과가 달라지기 때문입니다.
LAN 공개와 도구 권한은 별도로 막아요
로컬 서버를 다른 기기에서 쓰려면 바인드 주소를 바꾸게 되지만, 접속 가능해졌다는 사실이 안전하다는 뜻은 아닙니다. Ollama는 기본적으로 127.0.0.1의 11434 포트에 바인드하고, OLLAMA_HOST로 바인드 주소를 바꿀 수 있다고 설명합니다.[3] 공유기 안쪽이라도 인증·방화벽·허용 IP를 함께 설계하세요.
llama.cpp 문서는 --tools나 --agent를 켜면 API에서 파일 읽기·쓰기가 노출될 수 있고, CORS 기본 범위가 localhost로 제한될 수 있다고 경고합니다.[1] 채팅 API 테스트가 목적이라면 도구 권한을 먼저 켜지 마세요. 필요한 경우에도 읽기 전용 디렉터리와 별도 계정으로 범위를 좁히는 편이 낫습니다.
장애를 나누는 진단표
| 증상 | 가능성이 큰 층 | 확인 순서 |
|---|---|---|
| 연결 거부 | 서버 프로세스·포트·바인드 | localhost 호출과 실제 listen 주소 확인 |
| 응답 JSON 파싱 실패 | 엔드포인트·스트리밍 형식 | 스트리밍을 끄고 짧은 요청으로 비교 |
| 두 요청부터 급격히 느림 | KV 캐시·메모리·병렬 슬롯 | 슬롯을 낮추고 컨텍스트를 고정해 재측정 |
| 도구 호출이 위험함 | tools·agent·CORS 노출 | 기능을 끄고 localhost 전용으로 복귀 |
운영 전 체크리스트
- 짧은 단일 요청으로 엔드포인트와 응답 형식을 확인해요.
- 동시 요청 수를 하나씩 늘리며 TTFT와 전체 시간을 기록해요.
- 컨텍스트·KV 캐시·병렬성을 한 번에 하나만 바꿔요.
- Flash Attention은 auto·on·off를 같은 프롬프트로 비교해요.
- LAN 공개 전 바인드 주소·방화벽·인증·CORS를 따로 점검해요.
정리
llama.cpp 서버 튜닝은 옵션을 많이 켜는 일이 아니라 병목의 위치를 분리하는 일에 가까워요. API 형식을 먼저 고정하고, 그 다음 동시성·컨텍스트·Flash Attention을 하나씩 측정하면 로컬 AI 서버를 훨씬 덜 흔들리게 운영할 수 있습니다.
서버를 처음 열었다면 외부 접속보다 localhost의 짧은 요청 세 번을 먼저 통과시키고, 결과와 메모리 사용량을 기록해 보세요.