로컬 LLM을 사용하여 자율적으로 파일을 읽고 쓰고, 터미널에서 명령어를 실행하며 개발을 진행해 주는 자율형 AI 코딩 에이전트를 구동하는 환경을 만들어 보았습니다.
최근 들어 Claude Code와 같은 자율형 AI 코딩 에이전트가 급속하게 진화하고 있습니다. 하지만 실제로 로컬 환경에서 구동하려고 하면 다음과 같은 두 가지 큰 장벽에 부딪힙니다.
호스트 환경 오염/파괴 위험:
에이전트에게 셸 명령어 실행, 라이브러리 설치, 파일 편집을 자유롭게 허용할 경우, 호스트 OS(Windows나 WSL)의 설정이 망가지거나 불필요한 파일로 어질러지게 될 공포가 있습니다. -
VRAM 부족 (하드웨어 사양의 벽):
복잡한 프로그래밍 작업을 수행하려면 30B 이상의 모델이나 MoE(Mixture of Experts) 모델처럼 높은 지능을 가진 LLM이 필요합니다. 하지만 일반 소비자용 GPU(RTX 3060/4070 등의 VRAM 12GB~16GB)로는 그대로는 VRAM이 초과되어(OOM) 구동조차 할 수 없습니다.
본 기사에서는 이 두 가지 큰 문제를 한 번에 해결하는 **'최강의 로컬 AI 개발 샌드박스 환경'**을 구축합니다!
일회용 개발 환경: OpenCode를 Docker 컨테이너(샌드박스) 내부에 격리했습니다. AI가 아무리 거친 명령어를 실행해도 호스트 환경은 무사합니다. 망가져도 언제든지 컨테이너 재시작으로 리셋이 가능합니다. -
MoE 튜닝으로 VRAM 부족 극복: llama.cpp의 파라미터 튜닝(n-cpu-moe나 KV 캐시 양자화)을 활용하여, VRAM 12GB 환경에서도 35B급 MoE 모델(Ornith-1.5:35B 등)을 부드럽게 구동할 수 있습니다. -
프록시 불필요 직결 연결: OpenCode에서 llama.cpp의 OpenAI 호환 엔드포인트(/v1)로 직접 연결합니다. 불필요한 프록시를 거치지 않아 심플하고 빠릅니다. -
Docker Compose 원샷 구동: 추론 인프라(llama.cpp)와 개발 환경(OpenCode 샌드박스)을 하나의 docker-compose.yml에 통합했습니다. docker compose up -d만으로 모든 환경이 구동됩니다.
시스템 전체 구성은 다음과 같습니다. 동일한 Docker Compose 네트워크 내에서 완결됩니다.
┌────────────────────────────────────────────────────────────────────────┐
│ Docker Compose 일괄 관리 │
│ │
...
본 구성의 가장 큰 장치는 llama.cpp의 프리셋 설정(presets.ini)을 통한 MoE(Mixture of Experts) 모델 하이브리드 오프로딩입니다.
일반적인 Dense 모델(모든 가중치를 매 토큰마다 계산하는 모델)을 CPU로 오프로드하면, PCIe 버스의 대역폭이 병목 현상을 일으켜 극도로 느려집니다.
하지만 **MoE 모델(예: Ornith-1.5:35B 또는 Gemma-4:26B 등)**은 토큰마다 활성화되는 Expert(전문가 뉴런)가 아주 일부(수십 개 중 2~8개 정도)로 제한됩니다.
따라서 다음과 같은 역할 분담을 수행합니다:
주간층 (Attention 레이어 등): 항상 계산되므로 **GPU(VRAM)**에 배치합니다 (n-gpu-layers = 99). -
Expert층 (거대한 파라미터군): 선택된 부분만 계산되기 때문에 CPU / 메인 RAM으로 오프로드합니다 (n-cpu-moe = 999).
이를 통해 VRAM 12GB의 그래픽 보드에서도 35B 모델이 메모리 부족 없이, 그리고 실용적인 추론 속도로 동작할 수 있습니다!
version = 1
# ---- 모든 모델 공통 설정 ----
[*]
...
:n-cpu-moe = 999
지정한 숫자 이상의 MoE Expert층을 CPU 측에서 처리합니다. 999처럼 큰 값을 지정함으로써, 모든 Expert를 메인 RAM으로 옮겨 VRAM을 극적으로 절약합니다. -
:cache-type-k = q4_0 / cache-type-v = q4_0
에이전트가 긴 코드나 프로젝트 전체를 읽어들이면 컨텍스트 길이가 수만 토큰에 달합니다. KV 캐시(KV cache)를 양자화(quantize)함으로써, 65,536 토큰에서도 VRAM 소비를 몇 GB 이내로 억제할 수 있습니다.
- Ollama 모델 Blob 직접 참조:
이미 Ollama로 pull한 모델이 있는 경우, 그 실제 경로(/root/.ollama/models/blobs/...)를 마운트하여 그대로 llama.cpp에서 읽어올 수 있습니다. 모델 파일을 이중으로 다운로드하거나 저장할 필요가 없습니다. 물론 ./models/ 폴더에 둔 자체 .gguf 파일도 직접 지정이 가능합니다.
AI 에이전트에게 자율적인 코딩을 요청하면, AI는 때때로 다음과 같은 행동을 일으킵니다:
- 알 수 없는 외부 패키지를 전역(global)으로 설치함
rm -rf를 동반한 대규모 파일 정리 실행
- 기존의 Python이나 Node.js 환경 변수를 덮어씀 (overwrite)
이들을 호스트 OS(WSL 또는 Windows)에서 직접 수행하게 하는 것은 매우 위험합니다.
컨테이너 내에서 구동함으로써, "무슨 일이 생겨도 호스트 측은 100% 안전한" 일회용 환경을 얻을 수 있습니다. 컨테이너 내부에는 OpenCode 실행에 필요한 Node.js 및 Python 환경을 구축하고, 비(non-)root 사용자(openvscode-server)로 안전하게 작동시킵니다.
FROM ubuntu:latest
ENV DEBIAN_FRONTEND=noninteractive
# 빌드 툴, Python 등 설치
...
컨테이너 내부의 OpenCode가 llama.cpp의 OpenAI 호환 API에 직접 연결되도록 설정합니다.
{
"$schema": "https://opencode.ai/config.json",
"provider": {
...
추론 서버와 OpenCode 샌드박스를 단 하나의 docker-compose.yml에 통합합니다.
version: "3.8"
services:
# -------------------------------------------------------------
...
이렇게 하면, 다음 명령어를 실행하는 것만으로 모든 서비스가 한 번에 시작됩니다!
docker compose up -d --build
llama.cpp에 등록된 여러 모델을 테스트할 때, 설정 파일을 매번 수동으로 수정하는 것은 번거롭습니다.
그래서 컨테이너 내부에서 대화형 메뉴를 통해 즉시 모델을 전환할 수 있는 Python 스크립트 switch-model을 마운트했습니다.
# 샌드박스 컨테이너로 진입
docker compose exec -it opencode-sandbox bash
# 모델 전환 도구 실행
...
실행 화면:
======================================================================
🦙 llama.cpp 모델 목록 (연결처: http://llama-cpp:8080/v1)
======================================================================
...
번호를 입력하고 Enter를 누르는 것만으로, opencode.jsonc의 모델 설정이 실시간으로 업데이트되며 즉시 새로운 모델로 프롬프트를 실행할 수 있습니다.
docker compose exec -it opencode-sandbox bash
터미널 상에 TUI가 표시됩니다.
일본어로 프롬프트를 던져봅시다:
> FastAPI를 사용해서, 사용자 등록과 로그인(JWT 인증 포함)이 가능한 최소한의 REST API를 작성해 주세요.
OpenCode는 자동으로 다음을 실행합니다:
- 필요한 라이브러리(
fastapi, uvicorn, pyjwt 등)를 컨테이너 내에 설치 -
/home/workspace/ 바로 아래에 main.py나 auth.py 등의 소스 코드를 생성 - 서버 시작 테스트를 컨테이너 내부 터미널에서 실행하고, 오류가 발생하면 자동 수정
호스트 측의 Windows나 WSL 환경은 전혀 오염되지 않습니다. 생성된 코드는 ./workspace 폴더에 마운트되어 있기 때문에, 호스트 측에서 선호하는 에디터(VS Code 등)로 바로 확인 및 커밋이 가능합니다!
만약 AI가 불필요한 패키지를 대량으로 설치하거나 환경을 망가뜨렸더라도 안심할 수 있습니다:
# 호스트 측에서 컨테이너를 재시작하는 것만으로, 순식간에 초기 상태로 리셋 가능
docker compose restart opencode-sandbox
이번 환경을 구축함으로써 다음과 같은 장점을 얻었습니다:
- VRAM 부족의 완전한 해결:
n-cpu-moe = 999 및 KV 캐시 4bit 양자화를 통해, 12GB VRAM에서도 35B급 MoE 모델이 원활하게 작동합니다.
- 완벽한 안전성: OpenCode를 샌드박스 컨테이너에 가두어 명령어 실행이나 패키지 도입을 두려워하지 않고 완전 자동화 프로그래밍을 즐길 수 있습니다.
- 관리의 초간단화: 하나의
docker-compose.yml에 정리함으로써 시작과 종료 모두 원(one) 명령어만으로 가능합니다.
- 프록시 불필요: 불필요한 중간 컨테이너를 거치지 않고, llama.cpp와 OpenCode를 직접 연결하여 빠르고 간단하게 운영할 수 있습니다.
본 기사에서 설명한 구성 일체(docker-compose.yml, Dockerfile, presets.ini, switch-model.py 등)는 그대로 클론하여 작동시킬 수 있는 형태로 MIT 라이선스로 공개하고 있습니다. 부디 자유롭게 활용해 주십시오!
로컬 LLM과 AI 에이전트의 조합은 보안적인 측면에서도 실용적인 측면에서도 매우 매력적입니다. 여러분도 꼭 한번 시도해 보시기 바랍니다!