Skip to content
isdnetworks
Go back

RK3588 NPU로 로컬 LLM 서버를 포기한 이유

배경

개인 서비스에서 LLM을 활용할 일이 늘어나면서, API 비용을 줄이기 위해 로컬 LLM 서버를 검토하게 되었다. 마침 ARM SBC(Single Board Computer)에 탑재된 RK3588 칩의 NPU(Neural Processing Unit)가 6 TOPS 성능을 제공한다는 점에 주목했다. RKLLM이라는 Rockchip 공식 라이브러리를 사용하면 NPU에서 직접 LLM 추론이 가능했다.

목표는 명확했다. NPU 위에서 Qwen2.5 계열 모델을 돌려 OpenAI 호환 Chat Completion API를 제공하고, 이를 LLM 프록시 서비스의 백엔드로 연결하는 것이었다.

시도한 것들

1차: ctypes 직접 호출 프로토타입

RKLLM의 C 라이브러리(librkllmrt.so)를 Python ctypes로 직접 호출하는 Flask 기반 프로토타입을 만들었다. NPU에서 모델이 로딩되고 토큰이 생성되는 것을 확인하는 단계였다. 동작 자체는 성공했지만, 안정성이 낮고 에러 핸들링이 어려웠다.

2차: OpenAI 호환 API 구현

첫 프로토타입을 기반으로 OpenAI Chat Completion API 형식에 맞춘 서버를 구현했다. /v1/chat/completions 엔드포인트에서 스트리밍 응답까지 지원하도록 만들었다. 이 시점에서 LLM 프록시 서비스와의 연동 테스트도 진행했다.

3차: 멀티모델 지원 + 서비스화

FastAPI/uvicorn 기반으로 재작성하고, 여러 모델을 지원하도록 확장했다.

systemd 서비스로 등록하여 부팅 시 자동 시작되도록 구성했다. 여기까지가 약 3주간의 작업이었다.

포기한 이유

응답 품질의 벽

가장 결정적인 문제는 응답 품질이었다. 같은 Qwen2.5-7B 모델이라도 NPU에서 RKLLM으로 실행한 결과물과 클라우드에서 실행한 결과물 사이에 체감할 수 있는 품질 차이가 있었다. RKLLM의 양자화 과정에서 정밀도 손실이 발생하는 것으로 보였다.

특히 Gemini Free tier와 비교하면 격차가 더 두드러졌다. 무료로 사용 가능한 클라우드 API가 로컬 NPU보다 훨씬 나은 결과를 내는 상황에서, 로컬 서버를 유지할 명분이 사라졌다.

NPU 메모리 제약

RK3588의 NPU는 시스템 메모리를 공유하는 구조다. 7B 모델 하나를 로딩하면 상당량의 RAM을 점유하게 되고, 멀티턴 대화에서 컨텍스트가 길어지면 메모리 부족으로 품질이 급격히 저하되거나 OOM이 발생했다.

모델 전환 비용

멀티모델을 지원하려면 모델 로딩/언로딩이 필요한데, 7B 모델의 로딩에 수십 초가 소요되었다. 요청이 들어올 때마다 모델을 전환하는 것은 사실상 불가능했고, 상시 로딩 상태를 유지하면 메모리가 부족했다. 결국 하나의 모델만 상시 운영하는 것이 현실적이었는데, 그러면 멀티모델의 의미가 없었다.

유지보수 대비 이점

RKLLM 라이브러리는 Rockchip이 관리하는 비교적 니치한 프로젝트로, 문서가 부족하고 커뮤니티가 작다. 버그를 만나면 소스를 직접 분석해야 했고, 업데이트 주기도 불규칙했다. 이런 환경에서 프로덕션 서비스를 운영하는 것은 리스크가 컸다.

대체 방안: 클라우드 API + 프록시

LLM 프록시 서비스를 Docker로 운영하면서 여러 클라우드 API를 백엔드로 구성했다. 핵심은 자동 fallback이다.

Primary   → Gemini Free tier (RPM/RPD 제한 내)
Secondary → Gemini 유료 / OpenAI API (Free tier 초과 시)

이 구성의 장점은 다음과 같다.

Free tier의 분당/일일 요청 제한(RPM/RPD)을 초과하면 자동으로 유료 API로 전환되도록 설정했다. 실제 운영에서 유료 API로 넘어가는 경우는 월 몇 회 수준이라 비용 부담이 거의 없었다.

교훈

  1. 로컬 추론의 현실: 엣지 디바이스에서의 LLM 추론은 아직 프로덕션 품질에 미치지 못한다. 특히 7B 이상 모델은 전용 GPU 없이는 실용적이지 않다.

  2. 무료 API의 가성비: Gemini Free tier 같은 무료 클라우드 API의 존재가 로컬 LLM의 비용 절감 논리를 무력화한다. 전기세, 하드웨어 감가상각, 유지보수 시간을 고려하면 로컬이 오히려 비싸다.

  3. 프록시 패턴의 유연성: LLM 프록시를 두면 백엔드를 자유롭게 교체할 수 있다. 로컬에서 클라우드로 전환할 때도 클라이언트 코드 변경 없이 프록시 설정만 바꾸면 되었다.

  4. 매몰 비용을 인정할 것: 3주간의 작업을 버리는 것은 아깝지만, 품질이 기준에 미달하면 빠르게 방향을 전환하는 것이 낫다. 폐기한 4개의 프로젝트 디렉토리를 깔끔하게 삭제하고 결정 문서를 남겼다.

NPU 기술이 발전하면 다시 검토할 수 있겠지만, 현 시점에서는 클라우드 API + 프록시 조합이 소규모 팀에게 가장 합리적인 선택이었다.

참고 자료


Share this post on:

Previous Post
Windows IKEv2 VPN 클라이언트 설정과 Policy Match Error 해결
Next Post
Claude Code 프로젝트 설정 구조 — 실전 사례