콘텐츠로 이동

LLM 구성

범용 LLM 8종을 미리 구성했습니다. 각 LLM 모델에 맞는 최적의 구동 스크립트를 제공합니다.


구성 내용

구성 요약

LLMs 구동방식 실행 스크립트 모델 크기 Port
openai/gpt-oss-120b vLLM start-gpt-oss-120b-vllm.sh 183GB 8355
openai/gpt-oss-20b TensorRT-LLM start-gpt-oss-20b.sh 39GB 8356
Qwen/Qwen3-30B-A3B-Instruct-2507 vLLM start-qwen3-30b.sh 57GB 8357
Qwen/Qwen3-Coder-30B-A3B-Instruct vLLM start-qwen3-corder-30b.sh 57GB 8358
Qwen/Qwen2.5-VL-32B-Instruct vLLM start-qwen2.5-vl-32b.sh 64GB 8359
nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16 vLLM start-nemotron-3-nano-30b.sh 59GB 8360
mistralai/Devstral-Small-2-24B-Instruct-2512 vLLM start-devstral-small-2-24b.sh 48GB 8361
qwen3-vl:32b Ollama start-qwen3-vl-32b.sh 20GB 11434

실행 방법

모델별 실행 스크립트를 실행하여 모델을 구동합니다.

cd ~/lab/LLMs
./start-gpt-oss-120b-vllm.sh

메모리 제약

DGX Spark의 메모리 제약으로 한 번에 하나의 모델만 구동할 수 있습니다.


[참고] 모델 다운로드 방법

새로운 모델이 필요한 경우 인터넷이 가능한 환경에서 HuggingFace 전용 유틸리티로 다운로드할 수 있습니다.

다운로드 경로

~/.cache/huggingface/hub/

1단계: HuggingFace CLI 설치

pip install -U huggingface_hub --break-system-packages

2단계: HuggingFace 로그인

hf auth login

hf 명령어를 못 찾는 경우

실행 파일 경로를 직접 지정: ~/.local/bin/hf auth login

3단계: 모델 다운로드

모델 다운로드
hf download openai/gpt-oss-120b
hf download openai/gpt-oss-20b
hf download Qwen/Qwen3-30B-A3B-Instruct-2507
hf download Qwen/Qwen3-Coder-30B-A3B-Instruct
hf download Qwen/Qwen3-VL-30B-A3B-Instruct
hf download nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16
hf download mistralai/Devstral-Small-2-24B-Instruct-2512
hf download PaddlePaddle/PaddleOCR-VL
다운로드 확인
ls -l ~/.cache/huggingface/hub/

이해를 돕기 위한 자료

아래 내용대로 DGX Spark에 이미 구성이 되어 있습니다.

과정을 설명하기 위한 자료로 작성했습니다.


TensorRT-LLM 구동 방법

openai/gpt-oss-20b

Docker 이미지 준비

nvidia에서 제공하는 TensorRT-LLM 이미지를 사용합니다.

docker pull nvcr.io/nvidia/tensorrt-llm/release:spark-single-gpu-dev

필요 파일 준비

gpt-oss-20b 모델을 실행하기 위한 추가 파일들을 준비합니다.

파일 경로 용도
extra-llm-api-config.yml ./ TensorRT-LLM Serving 추가 설정
o200k_base.tiktoken ./harmony-reqs/ GPT 계열 토큰화 라이브러리
cl100k_base.tiktoken ./harmony-reqs/ GPT 계열 토큰화 라이브러리
extra-llm-api-config.yml 내용
print_iter_log: false
kv_cache_config:
  dtype: "auto"
  free_gpu_memory_fraction: 0.9
cuda_graph_config:
  enable_padding: true
disable_overlap_scheduler: true
max_num_tokens: 16384
guided_decoding_backend: "llguidance"
옵션 설명
print_iter_log 반복(iteration) 로그 출력 여부. false로 설정하여 불필요한 로그 감소
kv_cache_config.dtype KV 캐시 데이터 타입. auto는 모델에 맞게 자동 선택
kv_cache_config.free_gpu_memory_fraction KV 캐시에 할당할 GPU 메모리 비율 (0.9 = 90%)
cuda_graph_config.enable_padding CUDA Graph 패딩 활성화. 배치 처리 효율성 향상
disable_overlap_scheduler 오버랩 스케줄러 비활성화. 안정성 향상을 위해 true 권장
max_num_tokens 한 번에 처리할 최대 토큰 수. 메모리와 처리량 간 균형 조절
guided_decoding_backend 구조화된 출력을 위한 백엔드. llguidance 또는 xgrammar 선택 가능
tiktoken 파일 다운로드

tiktoken이란?

OpenAI에서 개발한 토큰화(Tokenization) 라이브러리입니다. GPT 계열 모델은 텍스트를 토큰 단위로 처리하는데, 이 파일들이 텍스트를 토큰으로 변환하는 규칙을 담고 있습니다.

  • o200k_base.tiktoken: GPT-4o, GPT-OSS 등 최신 모델용 (200K 어휘)
  • cl100k_base.tiktoken: GPT-4, GPT-3.5 등 이전 모델용 (100K 어휘)

다운로드 명령어

mkdir -p harmony-reqs
wget -O harmony-reqs/o200k_base.tiktoken \
  "https://openaipublic.blob.core.windows.net/encodings/o200k_base.tiktoken"
wget -O harmony-reqs/cl100k_base.tiktoken \
  "https://openaipublic.blob.core.windows.net/encodings/cl100k_base.tiktoken"

실행 스크립트

~/lab/LLMs/start-gpt-oss-20b.sh
#!/usr/bin/bash

export PORT=8356
export CONTAINER="gpt-oss-20b"
export MODEL_HANDLE="openai/gpt-oss-20b"

docker stop $CONTAINER 2>/dev/null
docker rm $CONTAINER 2>/dev/null

docker run -d \
  --name $CONTAINER \
  --gpus all \
  --ipc host \
  -p $PORT:8355 \
  -e MODEL_HANDLE="$MODEL_HANDLE" \
  -v $HOME/.cache/huggingface/:/root/.cache/huggingface/ \
  -v ./harmony-reqs/:/tmp/harmony-reqs/ \
  -v ./extra-llm-api-config.yml/:/tmp/extra-llm-api-config.yml/ \
  --restart unless-stopped \
  nvcr.io/nvidia/tensorrt-llm/release:spark-single-gpu-dev \
  bash -c '
    export TIKTOKEN_ENCODINGS_BASE="/tmp/harmony-reqs" && \
    trtllm-serve "$MODEL_HANDLE" \
      --max_batch_size 64 \
      --trust_remote_code \
      --host 0.0.0.0 \
      --port 8355 \
      --extra_llm_api_options /tmp/extra-llm-api-config.yml
  '

실행 점검

API 테스트
curl -s -X POST http://localhost:8356/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-oss-20b",
    "messages": [{"role": "user", "content": "안녕하세요. 모델 준비가 완료되었나요?"}],
  "max_tokens": 50,
  "temperature": 0.7
}' | jq

vLLM 구동 방법

openai/gpt-oss-120b

TensorRT-LLM에서 vLLM으로 전환한 이유

이 모델은 원래 TensorRT-LLM으로 운영했으나, 구조화된 출력(Structured Outputs) 기능의 한계로 vLLM으로 전환했습니다.


구조화된 출력이란?

모델의 응답을 특정 JSON Schema 형식에 맞게 강제하는 기능입니다. 에이전트 시스템이나 함수 호출(Function Calling) 등에서 필수적인 기능입니다.


TensorRT-LLM(Harmony)에서 발생한 문제

  • 구조화된 출력 라이브러리(xgrammar, llguidance)가 GPT-OSS 토크나이저와 충돌
  • 요청에서 strict: true 또는 json_schema 파라미터를 보내도 무시되고 일반 텍스트로 응답
  • NVIDIA Harmony 인터페이스가 출력을 가공하면서 데이터 무결성 훼손

vLLM 전환으로 해결

  • Outlines/XGrammar 통합: 토큰 레벨에서 문법을 강제하여 100% 규격 준수 JSON 생성
  • Strict 모드 지원: strict: true 파라미터를 엔진 수준에서 정확히 처리
  • 유연한 파서 옵션: --reasoning-parser openai_gptoss 등으로 복잡한 추론에서도 안정적 출력

결론: 추론 속도는 TensorRT-LLM이 우수하지만, 구조화된 출력의 안정성과 엄격함이 필요한 환경에서는 vLLM이 더 적합합니다.

Docker 이미지

spark-vllm-docker로 빌드한 vllm-node 이미지를 사용합니다.

spark-vllm-docker란?

DGX Spark(단일/멀티 노드)에 최적화된 vLLM Docker 이미지입니다.
커뮤니티에서 개발되었으며, Ray 기반 멀티노드 추론과 InfiniBand/RDMA(NCCL)를 지원합니다.

이미지 빌드 방법

1단계: 저장소 클론

git clone https://github.com/eugr/spark-vllm-docker.git
cd spark-vllm-docker

2단계: 이미지 빌드

# 단일 노드
./build-and-copy.sh --use-wheels

# 멀티 노드 클러스터 (이미지를 클러스터 전체에 배포)
./build-and-copy.sh --use-wheels -c

빌드가 완료되면 vllm-node 이미지가 생성됩니다.

필요 파일 준비

파일 경로 용도
o200k_base.tiktoken ./harmony-reqs/ GPT 계열 토큰화 라이브러리
cl100k_base.tiktoken ./harmony-reqs/ GPT 계열 토큰화 라이브러리
tiktoken 파일 다운로드
mkdir -p harmony-reqs
wget -O harmony-reqs/o200k_base.tiktoken \
  "https://openaipublic.blob.core.windows.net/encodings/o200k_base.tiktoken"
wget -O harmony-reqs/cl100k_base.tiktoken \
  "https://openaipublic.blob.core.windows.net/encodings/cl100k_base.tiktoken"

실행 스크립트

~/lab/LLMs/start-gpt-oss-120b-vllm.sh
#!/usr/bin/bash

# 환경 변수 설정
export PORT=8355
export CONTAINER="gpt-oss-120b-vllm"
export MODEL_HANDLE="openai/gpt-oss-120b"
export MODEL_PATH="/root/.cache/huggingface/hub/models--openai--gpt-oss-120b/snapshots/b5c939de8f754692c1647ca79fbf85e8c1e70f8a"

# 1. 기존 컨테이너가 있다면 중지 및 삭제
docker stop $CONTAINER 2>/dev/null
docker rm $CONTAINER 2>/dev/null

# 2. vLLM 컨테이너 구동
docker run -d \
  --name $CONTAINER \
  --privileged \
  --gpus all \
  --network host \
  --ipc host \
  --shm-size 64g \
  --restart unless-stopped \
  -v "$HOME/.cache/huggingface:/root/.cache/huggingface" \
  -v "./harmony-reqs:/tiktoken_encodings" \
  -e HF_HUB_OFFLINE=1 \
  -e TIKTOKEN_ENCODINGS_BASE=/tiktoken_encodings \
  vllm-node \
  bash -c "
    HF_HUB_OFFLINE=1 vllm serve '$MODEL_PATH' \
      --served-model-name '$MODEL_HANDLE' \
      --host 0.0.0.0 \
      --port $PORT \
      --load-format safetensors \
      --gpu-memory-utilization 0.9 \
      --max-model-len 131072 \
      --trust-remote-code \
      --enable-auto-tool-choice \
      --tool-call-parser openai \
      --reasoning-parser openai_gptoss
  "

echo "Container $CONTAINER is starting on port $PORT..."
echo "You can check logs with: docker logs -f $CONTAINER"

주요 옵션 설명

  • MODEL_PATH: 모델의 정확한 스냅샷 경로를 지정합니다. 오프라인 환경에서 모델을 확실하게 로드하기 위해 사용합니다.
  • HF_HUB_OFFLINE=1: HuggingFace Hub 오프라인 모드를 활성화하여 인터넷 연결 없이 로컬 캐시만 사용합니다.
  • --load-format safetensors: 안전하고 빠른 safetensors 포맷으로 모델을 로드합니다.
  • --trust-remote-code: 모델에 포함된 커스텀 코드 실행을 허용합니다.
  • --gpu-memory-utilization 0.9: GPU 메모리의 90%를 사용합니다.
  • --max-model-len 131072: 최대 컨텍스트 길이 128K 토큰을 지원합니다.
  • --enable-auto-tool-choice: 도구 호출 기능을 활성화합니다.
  • --tool-call-parser openai: OpenAI 호환 도구 호출 파서를 사용합니다.
  • --reasoning-parser openai_gptoss: GPT-OSS 모델의 추론 파서를 사용합니다.

실행 점검

API 테스트
curl -s -X POST http://localhost:8355/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-oss-120b",
    "messages": [{"role": "user", "content": "안녕하세요. 모델 준비가 완료되었나요?"}],
    "max_tokens": 50,
    "temperature": 0.7
  }' | jq

Qwen/Qwen3-30B-A3B-Instruct-2507

Docker 이미지

nvidia에서 제공하는 vLLM 이미지를 사용합니다.

docker pull nvcr.io/nvidia/vllm:25.12-py3

실행 스크립트

~/lab/LLMs/start-qwen3-30b.sh
#!/usr/bin/bash

export PORT=8357
export CONTAINER="qwen3-30b"
export MODEL_HANDLE="Qwen/Qwen3-30B-A3B-Instruct-2507"

docker stop $CONTAINER 2>/dev/null
docker rm $CONTAINER 2>/dev/null

docker run -d \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  --gpus all \
  -p $PORT:8000 \
  --name $CONTAINER \
  --restart unless-stopped \
  nvcr.io/nvidia/vllm:25.12-py3 \
  vllm serve $MODEL_HANDLE

실행 점검

API 테스트
curl -s -X POST http://localhost:8357/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen3-30B-A3B-Instruct-2507",
    "messages": [{"role": "user", "content": "안녕하세요. 모델 준비가 완료되었나요?"}],
    "max_tokens": 50
  }' | jq

Qwen/Qwen3-Coder-30B-A3B-Instruct

Docker 이미지

nvidia에서 제공하는 vLLM 이미지를 사용합니다.

docker pull nvcr.io/nvidia/vllm:25.12-py3

실행 스크립트

~/lab/LLMs/start-qwen3-corder-30b.sh
#!/usr/bin/bash

export PORT=8358
export CONTAINER="qwen3-corder-30b"
export MODEL_HANDLE="Qwen/Qwen3-Coder-30B-A3B-Instruct"

docker stop $CONTAINER 2>/dev/null
docker rm $CONTAINER 2>/dev/null

docker run -d \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  --gpus all \
  -p $PORT:8000 \
  --name $CONTAINER \
  --restart unless-stopped \
  nvcr.io/nvidia/vllm:25.12-py3 \
  vllm serve $MODEL_HANDLE

실행 점검

API 테스트
curl -s -X POST http://localhost:8358/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen3-Coder-30B-A3B-Instruct",
    "messages": [{"role": "user", "content": "안녕하세요. 모델 준비가 완료되었나요?"}],
    "max_tokens": 50
  }' | jq

Qwen/Qwen2.5-VL-32B-Instruct

Docker 이미지

nvidia에서 제공하는 vLLM 이미지를 사용합니다.

docker pull nvcr.io/nvidia/vllm:25.12-py3

실행 스크립트

~/lab/LLMs/start-qwen2.5-vl-32b.sh
#!/usr/bin/bash

export PORT=8359
export CONTAINER="qwen2.5-vl"
export MODEL_HANDLE="Qwen/Qwen2.5-VL-32B-Instruct"

docker stop $CONTAINER 2>/dev/null
docker rm $CONTAINER 2>/dev/null

docker run -d \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  --gpus all \
  -p $PORT:8000 \
  --name $CONTAINER \
  --restart unless-stopped \
  nvcr.io/nvidia/vllm:25.12-py3 \
  vllm serve $MODEL_HANDLE

실행 점검

API 테스트
curl -s -X POST http://localhost:8359/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-VL-32B-Instruct",
    "messages": [{"role": "user", "content": "안녕하세요. 모델 준비가 완료되었나요?"}],
    "max_tokens": 50
  }' | jq

nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16

Docker 이미지

nvidia에서 제공하는 vLLM 이미지를 사용합니다.

docker pull nvcr.io/nvidia/vllm:25.12-py3

실행 스크립트

~/lab/LLMs/start-nemotron-3-nano-30b.sh
#!/usr/bin/bash

export PORT=8360
export CONTAINER="nemotron-3-nano-30b"
export MODEL_HANDLE="nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16"

docker stop $CONTAINER 2>/dev/null
docker rm $CONTAINER 2>/dev/null

docker run -d \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  --gpus all \
  -p $PORT:8000 \
  --name $CONTAINER \
  --restart unless-stopped \
  nvcr.io/nvidia/vllm:25.12-py3 \
  vllm serve $MODEL_HANDLE \
  --trust-remote-code

실행 점검

API 테스트
curl -s -X POST http://localhost:8360/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16",
    "messages": [{"role": "user", "content": "안녕하세요. 모델 준비가 완료되었나요?"}],
    "max_tokens": 50
  }' | jq

mistralai/Devstral-Small-2-24B-Instruct-2512

Docker 이미지

vLLM 공식 Nightly 이미지를 사용합니다.

docker pull vllm/vllm-openai:nightly

실행 스크립트

~/lab/LLMs/start-devstral-small-24b.sh
#!/usr/bin/bash

export PORT=8361
export CONTAINER="devstral-small-2-24b"
export MODEL_HANDLE="mistralai/Devstral-Small-2-24B-Instruct-2512"

docker stop $CONTAINER 2>/dev/null
docker rm $CONTAINER 2>/dev/null

docker run -d \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  --gpus all \
  --ipc=host \
  --ulimit memlock=-1 \
  --ulimit stack=67108864 \
  -e VLLM_USE_V1=0 \
  -e VLLM_ATTENTION_BACKEND=FLASH_ATTN \
  -p $PORT:8000 \
  --name $CONTAINER \
  --restart unless-stopped \
  vllm/vllm-openai:nightly \
  --model $MODEL_HANDLE \
  --trust-remote-code \
  --max-model-len 32768 \
  --tool-call-parser mistral \
  --enable-auto-tool-choice \
  --dtype bfloat16 \
  --enforce-eager

안정적 구동을 위한 핵심 설정

구동 중 발생하는 커널 컴파일 오류 및 아키텍처 충돌을 해결하기 위해 아래 옵션을 지정했습니다.

  • -e VLLM_USE_V1=0: 최신 아키텍처와 충돌하는 V1 엔진을 끄고 안정적인 V0 엔진을 사용합니다.
  • --enforce-eager: (중요) 커널 컴파일(Autotuning) 실패를 방지하기 위해 즉시 실행하는 Eager 모드를 강제합니다. Blackwell 하드웨어에서 현재 가장 안정적인 방법입니다.
  • -e VLLM_ATTENTION_BACKEND=FLASH_ATTN: Triton 기반 백엔드 대신 컴파일이 필요 없는 표준 FlashAttention을 사용합니다.
  • --dtype bfloat16: bfloat16 데이터 타입을 명시적으로 지정합니다.

실행 점검

API 테스트
curl -s -X POST http://localhost:8361/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistralai/Devstral-Small-2-24B-Instruct-2512",
    "messages": [{"role": "user", "content": "안녕하세요. 모델 준비가 완료되었나요?"}],
    "max_tokens": 50
  }' | jq

Ollama 구동 방법

qwen3-vl:32b

왜 Ollama를 사용했나?

TensorRT, vLLM 모두 구동 실패하여 Ollama로 구성합니다.

Ollama가 사전에 구성되어 있어야 합니다. 상세 설정은 Ollama 구성을 참고하세요.

모델 다운로드

ollama pull qwen3-vl:32b

실행

별도 실행 불필요. 모델명을 지정하여 11434 포트로 API 요청하면 자동 실행됩니다.

실행 점검

API 테스트
curl -s -X POST http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3-vl:32b",
    "messages": [{"role": "user", "content": "안녕하세요."}],
    "max_tokens": 50
  }' | jq

미지원 모델

PaddlePaddle/PaddleOCR-VL

구동 불가

TensorRT, vLLM 모두 구동에 실패하였으며, Ollama는 Paddle 모델을 지원하지 않습니다.