vLLM 및 LiteLLM을 통해 로컬 LLM에서 Claude 코드 실행

발행: (2026년 2월 5일 오전 11:12 GMT+9)
11 min read
원문: Dev.to

Source: Dev.to

번역할 텍스트가 제공되지 않았습니다. 번역이 필요한 내용을 알려주시면 도와드리겠습니다.

Claude Code를 로컬에서 vLLM + LiteLLM으로 실행하기

목표: 독점 소스 코드를 온‑프레미스에 보관하면서도 Claude Code 워크플로우를 계속 사용한다.
해결책: LiteLLM을 통해 Claude Code의 Anthropic Messages API 호출을 프록시하고, 이를 로컬 vLLM 추론 서버가 이해하는 OpenAI‑호환 API로 변환한다.

Claude Code → LiteLLM (port 4000) → vLLM (port 8000) → Local GPU

1. 한 줄 환경 변수

export ANTHROPIC_BASE_URL="http://localhost:4000"

이제 Claude Code는 Anthropic 클라우드 엔드포인트가 아니라 LiteLLM 프록시를 가리키게 된다.

2. 모델 및 하드웨어

  • Model: Qwen3‑Coder‑30B‑A3B‑Instruct‑AWQ (Mixture‑of‑Experts, 총 30 B, 순방향당 3 B 활성)
  • GPUs: 듀얼 AMD MI60 (ROCm) 사용, 텐서‑패러럴리즘 (size = 2) 적용
  • Quantisation: AWQ → GPU 메모리에 여유롭게 적재 가능

2.1 vLLM Docker 서비스 (docker‑compose 스니펫)

services:
  vllm:
    image: nalanzeyu/vllm-gfx906:v0.11.2-rocm6.3
    container_name: vllm
    devices:
      - /dev/kfd:/dev/kfd
      - /dev/dri/card1:/dev/dri/card1
      - /dev/dri/card2:/dev/dri/card2
      - /dev/dri/renderD128:/dev/dri/renderD128
      - /dev/dri/renderD129:/dev/dri/renderD129
    shm_size: 16g
    environment:
      - HIP_VISIBLE_DEVICES=0,1
    command:
      - python
      - -m
      - vllm.entrypoints.openai.api_server
      - --model
      - QuantTrio/Qwen3-Coder-30B-A3B-Instruct-AWQ
      - --tensor-parallel-size
      - "2"
      - --max-model-len
      - "65536"
      - --gpu-memory-utilization
      - "0.9"
      - --enable-auto-tool-choice
      - --tool-call-parser
      - qwen3_coder

마지막 두 플래그는 왜?

  • --enable-auto-tool-choice – 모델이 언제 도구 호출을 내보낼지 스스로 결정하도록 함.
  • --tool-call-parser qwen3_coder – Qwen의 XML‑스타일 도구 호출을 LiteLLM이 기대하는 OpenAI 도구 호출 형식(최종적으로 Claude Code가 사용)으로 변환.

3. LiteLLM 구성

model_list:
  - model_name: claude-*
    litellm_params:
      model: hosted_vllm/QuantTrio/Qwen3-Coder-30B-A3B-Instruct-AWQ
      api_base: http://vllm:8000/v1
      api_key: "not-needed"
    model_info:
      max_tokens: 65536
      max_input_tokens: 57344
      max_output_tokens: 8192

litellm_settings:
  drop_params: true          # ignore Anthropic‑only params
  request_timeout: 600
  modify_params: true        # adapt params for OpenAI API

general_settings:
  disable_key_check: true    # no API key needed locally

설정 설명

설정효과
drop_params: trueOpenAI에 해당하는 필드가 없는 Anthropic 전용 필드를 조용히 삭제합니다.
modify_params: trueLiteLLM이 파라미터(예: max_tokens)를 대상 API의 기대에 맞게 재작성하도록 허용합니다.
disable_key_check: trueAPI 키 검증을 건너뛰며, 서버가 인증 없이 실행될 때 유용합니다.

4. 로컬 스택으로 Claude Code 실행하기

export ANTHROPIC_BASE_URL="http://localhost:4000"

cd my-project
claude          # launches Claude Code as usual

결과: 호스팅된 Anthropic API와 동일한 사용자 경험을 제공하지만, 모든 추론이 온‑프레미스에서 이루어집니다.

성능 및 제한

메트릭관찰 내용
처리량듀얼 MI60 기준 약 25‑30 토큰 / 초, 첫 토큰까지 약 175 ms
컨텍스트 윈도우64 K 토큰으로 제한 (Claude Opus는 200 K까지 가능)
모델 역량Qwen3‑Coder는 코딩에 특화되어 있으며, Claude는 보다 폭넓은 일반 지식과 명령 수행 능력을 가짐.

장점

  • API 비용 제로
  • 완전한 데이터 주권 (코드가 네트워크를 떠나지 않음)
  • 에어갭 환경에서도 작동

5. End‑to‑End 테스트: Flask Todo 앱 만들기

export ANTHROPIC_BASE_URL="http://localhost:4000"

cd /tmp && mkdir flask-test && cd flask-test
claude --dangerously-skip-permissions -p \
  "Build a Flask todo app with SQLite persistence, \
   modern UI with gradients and animations, \
   mobile responsive design, and full CRUD operations."

생성된 프로젝트 구조

flask_todo_app/
├── app.py              # Flask routes + SQLite setup
├── requirements.txt    # Dependencies
├── run_app.sh          # Launch script
├── static/
│   ├── css/
│   │   └── style.css   # Gradients, animations, hover effects
│   └── js/
│       └── script.js   # Client‑side interactions
└── templates/
    └── index.html      # Jinja2 template (responsive layout)

샘플 app.py

from flask import Flask, render_template, request, redirect, url_for
import sqlite3

app = Flask(__name__)

def init_db():
    conn = sqlite3.connect('todos.db')
    c = conn.cursor()
    c.execute('''CREATE TABLE IF NOT EXISTS todos
                 (id INTEGER PRIMARY KEY AUTOINCREMENT,
                  task TEXT NOT NULL,
                  completed BOOLEAN DEFAULT FALSE)''')
    conn.commit()
    conn.close()

init_db()

@app.route('/')
def index():
    conn = sqlite3.connect('todos.db')
    c = conn.cursor()
    c.execute('SELECT id, task, completed FROM todos ORDER BY id DESC')
    todos = c.fetchall()
    conn.close()
    return render_template('index.html', todos=todos)

샘플 CSS (static/css/style.css)

body {
    font-family: 'Poppins', sans-serif;
    background: linear-gradient(135deg, #667eea, #764ba2);
    min-height: 100vh;
    padding: 20px;
}

.container {
    max-width: 800px;
    margin: 0 auto;
}

.header {
    text-align: center;
    padding: 40px 0;
    color: white;
    text-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

앱 실행하기

cd flask_todo_app
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python app.py   # starts Flask on http://localhost:5000

이제 작업을 추가하고, 토글하고, 삭제할 수 있으며; SQLite DB는 재시작 후에도 유지됩니다.

6. TL;DR

  1. ANTHROPIC_BASE_URL 를 LiteLLM 프록시(http://localhost:4000)를 가리키도록 설정합니다.
  2. vLLM(Docker)을 Qwen3‑Coder 모델과 --enable-auto-tool-choice + --tool-call-parser qwen3_coder 플래그와 함께 실행합니다.
  3. LiteLLM을 구성하여 모든 claude-* 모델 이름을 로컬 vLLM 엔드포인트에 매핑합니다.
  4. Claude Code를 평소처럼 실행합니다 – 이제 온‑프레미스 GPU와 통신하므로 비용이 들지 않고, 완전한 Claude Code 워크플로(툴 호출 포함)를 유지하면서 주권적인 추론을 제공합니다.

보안성이 뛰어나고 고성능 코딩 지원을 경험해 보세요. 여러분의 독점 코드는 절대 외부로 전송되지 않습니다!

Generation Overview

  • 여러 에이전트 반복을 거쳐 전체 생성에 약 5분이 소요되었습니다.
  • 각 파일은 별도의 툴 호출이며: 모델이 생성하고, Claude Code가 실행하고, 결과가 반환되며, 모델이 다음 단계를 계획합니다.
  • 91 %의 프리픽스‑캐시‑히트율은 vLLM이 멀티‑턴 루프 전반에 걸쳐 컨텍스트를 효율적으로 재사용하고 있음을 보여줍니다.

이는 에이전트 워크플로가 정상적으로 작동함을 확인시켜 줍니다. 모델은 프롬프트를 읽고, 파일 구조를 계획하고, 디렉터리 생성 및 파일 작성을 위한 툴 호출을 내보내며, 기능적인 애플리케이션을 만들어냅니다. 모든 추론은 MI60에서 로컬로 이루어지며, 코드가 네트워크를 떠나지 않습니다.

Limitations & Future Work

  • Scale – 더 큰 코드베이스에서는 테스트되지 않았습니다. 작은 Flask 앱은 한 가지이지만, 수천 라인의 리팩터링은 또 다른 이야기입니다.
  • Context window – 64 K 토큰 제한이 결국 제약이 될 수 있으며, 모델은 실제 Claude가 능숙하게 처리하는 복잡한 아키텍처 결정에 어려움을 겪을 수 있습니다.
  • Current suitability – 집중된, 범위가 제한된 작업에 잘 맞습니다.

Claude Code Compatibility Checklist

RequirementDetails
Strong tool use모델이 구조화된 툴 호출을 안정적으로 내보내야 함
Code focusQwen3‑Coder가 잘 작동함; DeepSeek Coder와 CodeLlama 변형도 활용 가능
Sufficient context64 K를 사용함; 더 작은 윈도우도 가능하지만 테스트되지 않음

Observations

  • Qwen3‑Coder‑30B‑A3B는 직관적인 코딩 작업을 잘 처리합니다.
  • 복잡한 리팩터링이나 아키텍처 결정이 필요할 경우, 실제 Claude API가 더 나은 선택입니다.

Hardware Tips

  • VRAM이 64 GB가 없으면 Qwen2.5‑Coder‑7B 또는 Qwen3‑8B와 같은 작은 모델을 16 GB 또는 24 GB 카드 하나에 올릴 수 있습니다.
  • 이러한 구성은 테스트하지 않았으므로, 컨텍스트 제한이나 Claude Code의 에이전트 워크플로 처리 능력에 대해 확답할 수 없습니다.

Workflow Advice

  • “이 모듈을 리팩터링해 주세요”와 같은 광범위한 프롬프트 대신, 작업을 더 작고 구체적인 요청으로 나누세요.
  • 범위가 좁은 프롬프트가 작은 모델의 강점을 살리는 데 도움이 됩니다.

전체 Docker‑Compose 구성

services:
  vllm:
    image: nalanzeyu/vllm-gfx906:v0.11.2-rocm6.3
    container_name: vllm
    restart: unless-stopped
    ports:
      - "8000:8000"
    devices:
      - /dev/kfd:/dev/kfd
      - /dev/dri/card1:/dev/dri/card1
      - /dev/dri/card2:/dev/dri/card2
      - /dev/dri/renderD128:/dev/dri/renderD128
      - /dev/dri/renderD129:/dev/dri/renderD129
    group_add:
      - "44"
      - "992"
    shm_size: 16g
    volumes:
      - /mnt/cache/huggingface:/root/.cache/huggingface:rw
    environment:
      - HIP_VISIBLE_DEVICES=0,1
    command:
      - python
      - -m
      - vllm.entrypoints.openai.api_server
      - --model
      - QuantTrio/Qwen3-Coder-30B-A3B-Instruct-AWQ
      - --tensor-parallel-size
      - "2"
      - --max-model-len
      - "65536"
      - --gpu-memory-utilization
      - "0.9"
      - --host
      - "0.0.0.0"
      - --port
      - "8000"
      - --enable-auto-tool-choice
      - --tool-call-parser
      - qwen3_coder

  litellm:
    image: litellm/litellm:v1.80.15-stable
    container_name: litellm
    restart: unless-stopped
    ports:
      - "4000:4000"
    volumes:
      - ./litellm-config.yaml:/app/config.yaml:ro
    command:
      - --config
      - /app/config.yaml
      - --port
      - "4000"
      - --host
      - "0.0.0.0"
    depends_on:
      - vllm

스택 실행

# 시작 (nerdctl 또는 Docker 사용)
nerdctl compose -f coder.yaml up -d

네트워크에 연결된 어느 머신에서든 Claude CodeFeynman (GPU 워크스테이션) 에 지정하면 로컬 추론을 사용할 수 있습니다.

# 작업이 끝나면 정리
nerdctl compose -f coder.yaml down

최종 생각

  • 이 설정이 모든 사람에게 Claude API를 대체하진 않습니다.
  • 최대 성능이 필요하다면 Anthropic의 호스팅 모델이 여전히 최선의 선택입니다.
  • 데이터 주권을 중시하는 경우, 로컬 추론을 통해 독점 코드는 네트워크를 떠나지 않습니다.
  • Claude Code에 질문할 때마다 직접 GPU가 작동하는 모습을 보는 것 자체가 만족감을 줍니다.
Back to Blog

관련 글

더 보기 »