2026/06/16

MacBook Pro M4 Max + Mac Studio M4 Max => RDMA 클러스터로 로컬 LLM 실행하기

서문

Apple Silicon Mac 두 대를 연결하면 강력한 로컬 LLM 클러스터를 구축할 수 있습니다. MacBook Pro M4 Max 64GB와 Mac Studio M4 Max 64GB를 Thunderbolt 케이블로 연결하고, Apple의 MLX 프레임워크에서 제공하는 JACCL 백엔드(RDMA over Thunderbolt)를 활용하면 두 기기의 GPU 성능을 합쳐 70B급 대형 모델을 로컬에서 실행할 수 있습니다.

이 가이드는 하드웨어 준비부터 SSH 설정, Thunderbolt RDMA 활성화, MLX 분산 추론 환경 구축, 그리고 mlx-lm을 통한 LLM 실행까지 전 과정을 단계별로 설명합니다.


1. 하드웨어 구성

사용 장비

두 기기의 주요 스펙은 다음과 같습니다.

구분 MacBook Pro M4 Max Mac Studio M4 Max
CPU 16코어 (12P+4E) 16코어 (12P+4E)
GPU 40코어 40코어
RAM 64GB 64GB
메모리 대역폭 546GB/s 546GB/s
Thunderbolt Thunderbolt 5 × 3 (최대 120Gb/s) Thunderbolt 5 × 4 (최대 120Gb/s)
이더넷 없음 (Thunderbolt 네트워크 사용) 10Gb Ethernet 내장
Wi-Fi Wi-Fi 6E Wi-Fi 6E

총 합산 메모리: 128GB, 총 GPU 코어: 80코어, 합산 메모리 대역폭: 1,092GB/s

이 사양은 70B급 모델을 4bit 양자화하여 두 기기에 분산 배치하기에 충분한 성능을 제공합니다.

필요한 장비

  • Thunderbolt 5 케이블 1개 (양쪽 USB-C to USB-C, 120Gb/s 지원)
  • 두 Mac 모두 같은 로컬 네트워크에 연결되어 있어야 함 (SSH 설정용)
  • Mac Studio: 10Gb Ethernet 포트가 있으므로 이더넷 케이블로도 연결 가능


2. 사전 준비

macOS 버전 확인

JACCL 백엔드(RDMA over Thunderbolt)를 사용하려면 macOS 26.2 (Sequoia 26.2) 이상이 필요합니다. 현재 macOS 버전을 확인하세요:

sw_vers

macOS 26.2 미만인 경우 Ring 백엔드(Thunderbolt over TCP)를 사용할 수 있습니다. 두 방식 모두 이 가이드에서 다룹니다.

SSH 키 설정 (비밀번호 없는 상호 인증)

두 Mac 간에 비밀번호 없이 SSH로 접속할 수 있어야 합니다. MacBook Pro에서 Mac Studio로, Mac Studio에서 MacBook Pro로 양방향 설정이 필요합니다.

MacBook Pro에서 실행

# SSH 키 생성 (아직 없다면)
ssh-keygen -t ed25519 -C "macbook-pro"

# Mac Studio의 IP 또는 호스트명으로 복사
ssh-copy-id user@mac-studio.local

# 연결 테스트
ssh mac-studio.local "hostname"
exit

Mac Studio에서 실행

# SSH 키 생성 (아직 없다면)
ssh-keygen -t ed25519 -C "mac-studio"

# MacBook Pro의 IP 또는 호스트명으로 복사
ssh-copy-id user@macbook-pro.local

# 연결 테스트
ssh macbook-pro.local "hostname"
exit

⚠️ 양방향 연결이 모두 정상 동작하는지 반드시 확인하세요. 양쪽 기기에서 서로의 호스트명으로 SSH 접속이 비밀번호 없이 되어야 합니다.


3. Thunderbolt RDMA 활성화 (JACCL용)

macOS 26.2 이상에서 RDMA over Thunderbolt를 활성화하려면 Recovery Mode에서 설정해야 합니다. 이 작업은 각 Mac에서 개별적으로 진행합니다.

  • Mac을 Recovery Mode로 부팅하기: 전원을 끈 후, 전원 버튼을 길게 누르고 '로딩 옵션을 표시하는 중...'이 나타날 때까지 유지한 후 놓기
  • 설정에서 현재 사용자의 디스크 암호 인증을 진행 (Apple Silicon은 이 단계 필요)
  • 메뉴 바에서 Utilities → Terminal 클릭
  • 터미널에서 다음 명령어 실행:
  • rdma_ctl enable
  • 정상적으로 실행되면 재부팅
# Recovery Mode 터미널에서 실행
rdma_ctl enable

# 재부팅 후 일반 macOS에서 확인
ibv_devices

성공 시 M4 Max 칩에서 다음과 같은 출력이 표시됩니다:

device         	node GUID
------         	----------------
rdma_en2       	8096a9d9edbaac05
rdma_en3       	8196a9d9edbaac05
rdma_en4       	8296a9d9edbaac05
rdma_en5       	8396a9d9edbaac05

⚠️ ibv_devices가 아무것도 출력하지 않거나 명령을 찾을 수 없다면 RDMA 활성화가 제대로 되지 않았습니다. Recovery Mode에서 다시 시도하세요.


4. MLX 및 mlx-lm 설치

두 Mac 모두에서 동일한 환경으로 설치해야 합니다. Python 가상 환경을 사용하는 것을 권장합니다.

# 두 Mac 모두에서 실행

# Python 가상 환경 생성
python3 -m venv ~/mlx-cluster
source ~/mlx-cluster/bin/activate

# MLX 및 mlx-lm 설치
pip install --upgrade pip
pip install mlx-lm

# 설치 확인
python -c "import mlx.core as mx; print(mx.__version__)"
mlx_lm.chat --help

⚠️ 두 기기의 MLX 버전이 정확히 동일해야 합니다. pip freeze로 버전 차이 없는지 확인하세요.


5. 클러스터 설정

두 가지 백엔드를 사용할 수 있습니다:

  • JACCL (권장): RDMA over Thunderbolt — 초저지연, 최대 성능
  • Ring: TCP over Thunderbolt — macOS 26.2 미만에서도 사용 가능

6. JACCL 백엔드 설정 (권장)

6-1. Thunderbolt 케이블 연결

MacBook Pro와 Mac Studio를 Thunderbolt 5 케이블로 직접 연결합니다. JACCL은 완전 연결(mesh) 토폴로지를 요구하므로, 2대의 경우 서로 1개 케이블로 충분합니다.

6-2. 연결 확인 및 자동 설정

MLX에서 제공하는 mlx.distributed_config 유틸리티로 연결을 확인하고 자동으로 설정할 수 있습니다. MacBook Pro에서 다음 명령어를 실행하세요:

# 연결 시각화 (GraphViz 필요)
mlx.distributed_config --verbose \
    --hosts macbook-pro.local,mac-studio.local \
    --over thunderbolt --dot | dot -Tpng | open -f -a Preview

# 자동 설정 + hostfile 생성
mlx.distributed_config --verbose \
    --hosts macbook-pro.local,mac-studio.local \
    --over thunderbolt --backend jaccl \
    --auto-setup --output cluster-jaccl.json

⚠️ --auto-setup 사용 시 sudo 비밀번호 없이 실행 가능해야 합니다. sudoers 설정이 되어 있지 않으면 명령어를 수동으로 따라야 합니다.

6-3. 수동 설정 (sudo 비밀번호 없는 경우)

--auto-setup 없이 실행하면 각 노드에서 실행해야 할 명령어가 표시됩니다. 각 Mac에서 해당 명령어를 sudo로 실행한 후 생성된 hostfile을 사용합니다.

# 자동 설정 없이 실행 → 명령어 출력
mlx.distributed_config --verbose \
    --hosts macbook-pro.local,mac-studio.local \
    --over thunderbolt --backend jaccl --output cluster-jaccl.json

6-4. 생성된 hostfile 확인

cluster-jaccl.json은 다음과 같은 구조를 가집니다:

[
    {
        "ssh": "macbook-pro.local",
        "ips": ["192.168.1.100"],
        "rdma": [null, "rdma_en2"]
    },
    {
        "ssh": "mac-studio.local",
        "ips": [],
        "rdma": ["rdma_en2", null]
    }
]

rdma 배열은 각 노드가 서로 어떤 RDMA 인터페이스로 연결되는지를 정의합니다. null은 자기 자신을 의미합니다.


7. Ring 백엔드 설정 (대안)

macOS 26.2 미만이거나 RDMA 활성화가 어려운 경우 Ring 백엔드를 사용할 수 있습니다. Ring은 TCP 소켓을 사용하므로 설정이 더 간단합니다.

# Thunderbolt over TCP 자동 설정
mlx.distributed_config --verbose \
    --hosts macbook-pro.local,mac-studio.local \
    --over thunderbolt --backend ring \
    --auto-setup --output cluster-ring.json

# 또는 Ethernet만 사용 (Thunderbolt 케이블 없이)
mlx.distributed_config --verbose \
    --hosts macbook-pro.local,mac-studio.local \
    --over ethernet --backend ring --output cluster-ring.json

Ring 백엔드는 JACCL보다 대역폭이 낮지만, 10Gb Ethernet이나 Thunderbolt over TCP로도 충분한 성능을 낼 수 있습니다.


8. 클러스터 테스트

실제 LLM을 실행하기 전에 클러스터 통신이 정상인지 테스트하세요.

import mlx.core as mx

world = mx.distributed.init()
x = mx.distributed.all_sum(mx.ones(10))
print(f"Rank {world.rank()}: all_sum result = {x}")

JACCL로 테스트

source ~/mlx-cluster/bin/activate
mlx.launch --verbose --backend jaccl \
    --hostfile cluster-jaccl.json \
    --env MLX_METAL_FAST_SYNCH=1 -- \
    python test_cluster.py

Ring으로 테스트

source ~/mlx-cluster/bin/activate
mlx.launch --verbose --backend ring \
    --hostfile cluster-ring.json \
    python test_cluster.py

두 노드 모두에서 Rank 0: all_sum result = [2, 2, 2, ..., 2]Rank 1: all_sum result = [2, 2, 2, ..., 2]가 출력되면 성공입니다.


9. 분산 LLM 추론 실행

9-1. mlx-lm을 통한 추론

mlx-lm은 MLX의 분산 기능을 자동으로 활용합니다. mlx.launch로 실행하면 각 노드의 GPU에 모델이 분산 배치됩니다.

# JACCL 백엔드로 70B 모델 분산 추론
source ~/mlx-cluster/bin/activate

mlx.launch --verbose --backend jaccl \
    --hostfile cluster-jaccl.json \
    --env MLX_METAL_FAST_SYNCH=1 -- \
    python -m mlx_lm chat \
    --model mlx-community/Meta-Llama-3.1-70B-Instruct-4bit

9-2. 권장 모델

128GB 총 메모리(64GB × 2) 환경에서 실행 가능한 모델:

모델 양자화 크기 비고
Llama 3.1 70B Instruct 4bit ~42GB 안정적 실행 가능
Qwen 2.5 72B Instruct 4bit ~43GB 한국어 지원 우수
Mistral Large 2 4bit ~46GB 고성능 추론
Llama 3.3 70B 4bit ~42GB 하이브리드 아키텍처
DeepSeek R1 0528 4bit ~47GB 추론형 모델

9-3. HTTP API 서버 실행

OpenAI 호환 API 서버를 클러스터에서 실행할 수 있습니다:

source ~/mlx-cluster/bin/activate

mlx.launch --verbose --backend jaccl \
    --hostfile cluster-jaccl.json \
    --env MLX_METAL_FAST_SYNCH=1 -- \
    python -m mlx_lm serve \
    --model mlx-community/Meta-Llama-3.1-70B-Instruct-4bit

서버가 시작되면 http://localhost:8080/v1/chat/completions 엔드포인트로 OpenAI 호환 API를 사용할 수 있습니다.

curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Llama-3.1-70B-Instruct",
    "messages": [
      {"role": "user", "content": "안녕하세요!介绍一下你自己"}
    ],
    "max_tokens": 512
  }'

10. 성능 최적화 팁

  • MLX_METAL_FAST_SYNCH=1 필수 설정: CPU-GPU 간 동기화 속도를 높여 분산 통신 성능을 크게 개선
  • 모델은 mlx-community에서 4bit 양자화된 버전을 사용: 메모리 효율이 가장 좋음
  • MacBook Pro는 전원에 연결한 상태로 실행: 성능 제한 방지
  • --max-kv-size 4096 또는 더 큰 값을 설정하여 긴 컨텍스트 처리 성능 향상
  • 모델을 로컬에 미리 다운로드: mlx_lm.download --model ~로 사전 다운로드

wired_limit_mb 설정 (대형 모델용)

모델 크기가 시스템 RAM을 초과할 수 있는 경우 macOS의 wired memory 제한을 늘려야 합니다:

# 현재 제한 확인
sysctl iogpu.wired_limit_mb

# 64GB Mac에서 55GB로 설정 (모델 + 캐치 용량 고려)
sudo sysctl iogpu.wired_limit_mb=56320

이 설정은 재부팅 시 초기화되므로 ~/.zshrc에 추가하거나 launchd plist로 영구 설정할 수 있습니다.


11. 문제 해결

SSH 연결 실패

mlx.launch가 SSH 연결에 실패하면 다음을 확인하세요:

  • 양방향 SSH 키 인증이 설정되었는지 확인 (ssh hostname 테스트)
  • .ssh/config에 각 Mac의 호스트명 설정이 올바른지 확인
  • 방화벽 설정에서 SSH 포트(22)가 열려 있는지 확인

JACCL 초기화 실패

  • ibv_devices가 RDMA 장치를 표시하는지 확인
  • Thunderbolt 케이블이 양쪽 포트에 제대로 연결되었는지 확인
  • mlx.distributed_config --hosts ~ --over thunderbolt --dot으로 연결 상태 시각화
  • macOS 26.2 이상인지 확인 (sw_vers)

모델 로드 실패

  • iogpu.wired_limit_mb가 모델 크기보다 충분한지 확인
  • 모델 파일이 두 기기에 모두 동일한 경로에 있는지 확인
  • mlx_lm.download로 모델을 사전 다운로드

Ring 백엔드에서 느린 성능

  • --connections-per-ip 4 이상으로 설정하여 TCP 연결 수 증가
  • 10Gb Ethernet 포트가 있다면 --over ethernet으로 설정
  • JACCL로 전환하는 것이 가장 확실한 해결책

12. 전체 아키텍처

┌─────────────────────────────┐         Thunderbolt 5          ┌─────────────────────────────┐
│    MacBook Pro M4 Max       │         (120Gb/s)              │    Mac Studio M4 Max        │
│    64GB RAM / 40-core GPU   │◄──────────────────────────────►│    64GB RAM / 40-core GPU   │
│                              │         JACCL (RDMA)           │                              │
│  ┌──────────────────────┐   │   ┌─────────────────────────┐  │  ┌──────────────────────┐   │
│  │   mlx.launch (rank 0)│   │   │                         │  │  │   mlx.launch (rank 1)│   │
│  │                      │   │   │   mlx.distributed       │  │  │                      │   │
│  │  mlx_lm.chat         │   │   │   init(backend="jaccl") │  │  │  mlx_lm.chat         │   │
│  │  --model 70B-4bit    │   │   │                         │  │  │  --model 70B-4bit    │   │
│  └──────────┬───────────┘   │   │  all_sum / all_gather  │  │  └──────────┬───────────┘   │
│             │               │   │  all_reduce / broadcast │  │             │              │
│    Metal GPU│               │   └─────────────────────────┘  │    Metal GPU│              │
│   (40 cores)│               │                                 │   (40 cores)│              │
└─────────────┘               └─────────────────────────────────┘  └─────────────┘
                           │
              ┌────────────┴────────────┐
              │   hostfile.json         │
              │   cluster-jaccl.json    │
              └─────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│                    클러스터 통신 흐름                              │
│                                                                    │
│  사용자 → MacBook Pro (rank 0)                                     │
│    ↓                                                                │
│  mlx_lm.chat (交互式 REPL)                                         │
│    ↓  tensor parallelism                                           │
│  Layer 0-N → MacBook Pro GPU    Layer N+1-End → Mac Studio GPU   │
│    ↓                          RDMA 통신                          ↓
│  MacBook Pro GPU ◄──────────────────────────────────► Mac Studio GPU
│    ↓                                                                │
│  all_reduce (gradient / attention)                                  │
│    ↓                                                                │
│  생성된 토큰 → 사용자에게 반환                                      │
└──────────────────────────────────────────────────────────────────┘

13. 요약

  • JACCL 백엔드는 RDMA over Thunderbolt를 사용하며, Ring 백엔드 대비 10배 낮은 지연 시간 제공
  • macOS 26.2 이상 필요 (Recovery Mode에서 rdma_ctl enable 필수)
  • mlx.distributed_config로 자동 설정 가능 (--auto-setup 사용 시 sudo 비밀번호 없이 실행 필요)
  • mlx.launch --backend jaccl로 분산 추론 실행, MLX_METAL_FAST_SYNCH=1 필수
  • 두 Mac의 총 128GB 메모리로 70B급 모델을 4bit 양자화하여 분산 실행 가능
  • Ring 백엔드는 macOS 26.2 미만에서도 사용 가능 (TCP over Thunderbolt/Ethernet)

참고 링크

  • MLX 공식 문서: https://ml-explore.github.io/mlx/
  • mlx-lm GitHub: https://github.com/ml-explore/mlx-lm
  • mlx-examples (분산 예제): https://github.com/ml-explore/mlx-examples
  • MLX Community Hugging Face: https://huggingface.co/mlx-community
  • Apple Support - Recovery Mode: https://support.apple.com/en-us/102518

이 가이드에서 설명한 설정은 로컬 환경에서 대규모 LLM을 실행하는 가장 효율적인 방법 중 하나입니다. 클라우드 GPU 대여 비용 없이 Apple Silicon Mac 두 대로 70B급 모델을 실시간 추론할 수 있습니다.

2026/06/15

Docker Compose 서비스 백업 및 복구 가이드

서론

Docker Compose 로 Self-Hosted 서비스를 운영할 때 가장 중요한 것은 데이터 백업입니다. 서버 장애, 디스크 손상, 실수로 인한 데이터 삭제 — 언제든 발생할 수 있는 상황들에 대비하기 위해 체계적인 백업 전략이 필요합니다.

이번 글에서는 Docker Compose 기반의 Self-Hosted 인프라(PostgreSQL, n8n, Ghost Blog 등)에 대한 백업 자동화, 복구 절차, 그리고 주의사항 을 교육 자료 형식으로 정리했습니다. 실제 운영 중인 서비스의 경로나 비밀번호는 제외하고, 누구나 적용 가능한 일반적인 가이드로 작성했습니다.


백업 대상과 중요도

Docker Compose 환경에서 백업해야 할 대상은 크게 세 가지로 나뉩니다.

  • 데이터베이스 — PostgreSQL, SQLite 등 구조화된 데이터 (최고 중요도)
  • 애플리케이션 데이터 — 워크플로우, 블로그 콘텐츠, 미디어 파일 (높은 중요도)
  • 설정 파일 — Nginx reverse proxy, SSL 인증서, 서비스 설정 (보통 ~ 높은 중요도)
서비스 Volume 경로 백업 방식 중요도
PostgreSQL./data/postgresVACUUM FULL → pg_dumpall🔴 최고
n8n./data/n8nVACUUM → tar (*.log 제외)🔴 최고
Ghostcontent/tar 압축🟡 높음
Certbot./data/certbottar 압축🟡 높음
Nginx./nginx/conftar 압축🟢 보통
SearXNG./data/searxngtar 압축🟢 보통

백업 스크립트 구성

백업 스크립트는 bash 로 작성하며, 각 서비스의 특성에 맞는 백업 전략을 적용합니다. 핵심은 데이터 무결성 보장 입니다.

PostgreSQL — SQL Dump 방식 (핵심)

PostgreSQL 은 tar 로 직접 덤프하면 안 됩니다. WAL 파일이 섞여 복구 시 데이터 손상이 발생할 수 있으므로, 반드시 pg_dumpall 명령을 통해 SQL 덤프를 생성한 후 gzip 으로 압축합니다.

# VACUUM FULL: 데이터베이스 파일 크기 축소
docker exec postgres psql -U ${POSTGRES_USER} -d ${POSTGRES_DB} -c "VACUUM FULL;"

# pg_dumpall: 전체 SQL 덤프 생성
docker exec postgres pg_dumpall -U ${POSTGRES_USER} > backups/pg_all_${DATE}.sql

# gzip 압축
gzip -f backups/pg_all_${DATE}.sql
VACUUM FULL 은 데이터베이스 파일의 물리적 크기를 축소하여 백업 파일 크기를 최소화합니다. pg_dumpall 은 서비스 중단 없이 백업 가능합니다.

n8n — SQLite VACUUM + tar 방식

n8n 은 SQLite 를 사용하므로 PostgreSQL 과 다른 전략이 필요합니다. 컨테이너를 중지한 후 sqlite3 VACUUM 명령으로 데이터베이스 파일을 최적화하고, tar 로 압축합니다. 로그 파일은 백업에서 제외하여 용량을 절약합니다.

# 컨테이너 중지
docker stop n8n

# SQLite VACUUM: DB 파일 최적화
sqlite3 ./data/n8n/database.sqlite "VACUUM;"

# 컨테이너 재시작
docker start n8n
sleep 2

# tar 압축 (*.log 제외)
tar -czf backups/n8n_${DATE}.tar.gz \
    --exclude='*.log' \
    -C ./data n8n

기타 서비스 — tar 압축

Ghost 콘텐츠, Certbot SSL 인증서, Nginx 설정, SearXNG 설정 등은 tar.gz 로 압축하는 단순한 방식이 적합합니다.

# Ghost 블로그 콘텐츠
tar -czf backups/ghost_${DATE}.tar.gz \
    -C ~/Developer/GhostBlog content

# Certbot SSL 인증서
tar -czf backups/certbot_${DATE}.tar.gz \
    -C . data/certbot

# Nginx 설정
tar -czf backups/nginx_conf_${DATE}.tar.gz \
    -C . nginx/conf

자동 백업 설정

  • 스크립트에 실행 권한 부여: chmod +x backup.sh
  • cron 에 등록하여 매일 새벽 자동 실행
  • 백업 로그를 파일로 출력하여 이력 추적
# 실행 권한 부여
chmod +x ~/Developer/WebServer/backup.sh

# crontab 편집 — 매일 새벽 3:30 자동 백업
crontab -e

# 추가할 라인:
30 3 * * * /Users/yourname/Developer/WebServer/backup.sh

cron 등록 후 확인: crontab -l | grep backup

백업 로그 실시간 확인: tail -f backups/backup.log


복구 절차

백업의 가치는 복구할 때才知道입니다. 정기적인 복구 테스트가 필수적입니다.

# 사용법
./restore.sh <backup_date> [service]

# 전체 복구
./restore.sh 20250614_030000 all

# 개별 서비스만 복구
./restore.sh 20250614_030000 pg
./restore.sh 20250614_030000 n8n
./restore.sh 20250614_030000 ghost

PostgreSQL 복구

  • 컨테이너 중지: docker stop postgres
  • SQL 덤프 압축 해제: gunzip -kf backups/pg_all_YYYYMMDD_HHMMSS.sql.gz
  • 데이터 적용: docker exec -i postgres psql -U ${USER} < backups/pg_all_*.sql
  • 임시 SQL 파일 삭제: rm backups/pg_all_*.sql
  • 컨테이너 재시작: docker start postgres

n8n 복구

  • 컨테이너 중지: docker stop n8n
  • 데이터 복구: tar -xzf backups/n8n_YYYYMMDD_HHMMSS.tar.gz -C ./WebServer
  • 컨테이너 재시작: docker start n8n (로그 파일은 자동 재생성됨)

Ghost 복구

  • 컨테이너 중지: docker stop ghost
  • 콘텐츠 복구: tar -xzf backups/ghost_YYYYMMDD_HHMMSS.tar.gz -C ~/Developer/GhostBlog
  • 컨테이너 재시작: docker start ghost

Nginx / Certbot / SearXNG 복구

설정 파일 복구는 tar 압축 해제 후 서비스 재시작만 필요합니다.

# Certbot 복구 후 Nginx 재시작
tar -xzf backups/certbot_${DATE}.tar.gz -C ./WebServer
docker restart nginx

# Nginx 설정 복구
tar -xzf backups/nginx_conf_${DATE}.tar.gz -C ./WebServer
docker restart nginx

# SearXNG 복구
tar -xzf backups/searxng_${DATE}.tar.gz -C ./WebServer
docker restart searxng

백업 파일 구조

backups/
├── backup.log                          # 백업 실행 로그 (누적 유지)
├── pg_all_20250614_030000.sql.gz      # PostgreSQL 전체 dump
├── n8n_20250614_030000.tar.gz         # n8n 데이터 (*.log 제외)
├── ghost_20250614_030000.tar.gz       # Ghost 콘텐츠
├── certbot_20250614_030000.tar.gz     # SSL 인증서
├── nginx_conf_20250614_030000.tar.gz  # Nginx 설정
├── searxng_20250614_030000.tar.gz     # SearXNG 설정
└── money_20250614_030000.tar.gz       # 기타 앱 데이터

백업 파일은 30일 보관 후 스크립트가 자동으로 삭제합니다. 디스크 공간을 효율적으로 관리하려면 retention 기간을 환경에 맞게 조정하세요.


주의 사항과 모범 사례

PostgreSQL — tar 로 직접 덤프 금지

가장 중요한 규칙입니다. PostgreSQL 데이터 디렉토리를 tar 로 백업하면 WAL 파일이 포함되고, 복구 시 데이터 손상이 발생할 수 있습니다. 항상 pg_dumpall 또는 pg_dump 명령을 사용하세요.

n8n — 컨테이너 중지 후 백업

n8n 은 SQLite 를 사용하므로 컨테이너 실행 중 백업하면 데이터 손상이 가능합니다. 반드시 컨테이너를 중지한 후 VACUUM → tar 순서로 진행하세요.

백업 디렉토리는 Git 에서 제외

백업 파일은 절대 Git 에 커밋하지 마세요. 민감한 데이터가 포함될 수 있고, 리포지토리 용량을 급증시킵니다.

# .gitignore
backups/

원격 저장소 동기화

로컬 백업만으로는 디스크 손상 시 복구가 불가능합니다. 백업 파일을 S3, Dropbox, Google Drive 등의 원격 저장소와 동기화하는 것이 안전합니다. rsync 또는 rclone 을 활용하세요.

정기적인 복구 테스트

백업이 성공했다고 믿기 전에 반드시 복구 테스트를 해보세요. 테스트 환경에서 백업 파일을 복구하고 데이터가 제대로 읽히는지 확인하는 것이 가장 확실한 검증 방법입니다.


문제 해결

백업이 실패할 때

  • 로그 확인: tail backups/backup.log
  • Docker 컨테이너 상태: docker ps
  • 디스크 공간: df -h
  • 특정 서비스 백업이 실패하면 해당 경로의 존재 여부를 확인

cron 이 실행되지 않을 때 (macOS)

  • cron 서비스 확인: launchctl list | grep cron
  • crontab 확인: crontab -l
  • 시스템 로그: log show --predicate 'eventMessage contains "cron"' --last 1h

복구가 실패할 때

  • 백업 파일 존재 확인: ls backups/
  • 파일 압축 해제 테스트: tar -tzf backups/XXX.tar.gz
  • 컨테이너 상태 확인: docker ps -a
  • 복구 스크립트를 단계별로 수동 실행하여 문제 지점 파악

마무리

백업은 '언젠가 해야 할 일' 이 아니라 '이미 해둔 일' 이어야 합니다. 오늘 백업 스크립트를 작성하고 cron 에 등록하면, 내일의 당신은 그 선택을 감사할 것입니다.

Docker Compose 환경에서는 스크립트 한 줄로 모든 서비스의 데이터를 보호할 수 있습니다. 복구 테스트를 잊지 마세요. 백업의 진짜 가치는 복구할 때 확인됩니다.

2026/06/13

27B 대 31B, 승자는 누구인가? Qwen 3.6과 Gemma 4 성능 전격 비교 분석

안녕하세요. 인공지능 기술 트렌드를 깊이 있게 파헤치는 테크 블로거입니다.

최근 대규모 언어 모델 시장은 그야말로 치열한 경쟁 구도를 형성하고 있습니다. 매일 새로운 모델이 쏟아져 나오면서, 개발자와 기업은 어떤 모델을 선택해야 할지 고민에 빠지기 쉽습니다. 그 중심에는 바로 Qwen 3.6과 Gemma 4 같은 강력한 오픈소스 거대 모델들이 자리 잡고 있습니다.

두 모델 모두 현존하는 최고 수준의 성능을 자랑하지만, 실제 사용 환경이나 목적에 따라 강점이 뚜렷이 갈립니다. 단순히 어느 것이 더 낫다고 단정하기보다는, 각 모델이 어떤 상황에서 빛을 발하는지 심층적으로 비교 분석해 보려 합니다. 지금부터 Qwen 3.6-27B와 Gemma 4-31B를 성능, 기술적 특성, 그리고 활용 사례별로 자세히 살펴보겠습니다.




객관적인 지표로 보는 성능 비교: 누가 더 똑똑할까?

모델의 성능을 측정하는 가장 확실한 방법은 벤치마크 점수를 확인하는 것입니다. 단순 문장 생성을 넘어 논리적 사고력과 전문 지식을 요구하는 영역에서 두 모델을 비교해 보겠습니다.

  • 지식 기반 추론: 방대한 학술 지식이 필요한 분야에서는 두 모델 모두 최고 수준의 성능을 보여주며 매우 치열한 경쟁 구도를 형성하고 있습니다. 이는 두 모델 모두 광범위한 데이터를 학습했음을 의미합니다.
  • 수학적 문제 해결: 단계별 논리 전개가 필요한 수학 문제를 풀 때도 높은 정확도를 보여줍니다. 복잡한 추론 능력이 중요한 분야에서 두 모델의 성능은 상호 보완적이며, 사용 목적에 따라 적합도가 달라질 수 있습니다.

단순 지식 검색을 넘어선 추론과 논리 전개가 핵심이라면, 두 모델 모두 강력한 옵션을 제공합니다. 어떤 벤치마크에서 우위를 점하는지는 사용자가 해결하려는 문제의 성격에 따라 달라진다고 보는 것이 정확합니다.

기술적 아키텍처 및 배포 환경 비교: 어떻게 사용할까?

아무리 성능이 좋아도 원하는 환경에서 구동할 수 없다면 실질적인 활용도가 떨어집니다. 모델의 크기와 배포 방식은 사용성을 결정하는 핵심 요소입니다.

Gemma 4의 강점: 구글의 강력한 기술력을 바탕으로 개발되었으며, 비교적 안정적인 아키텍처를 자랑합니다. 특히 기업 환경에서 온프레미스 방식으로 모델을 직접 구축하고 운영하는 데 유리하며, 자체 보안 정책이나 규제가 까다로운 기관에 적합할 수 있습니다.

Qwen 3.6의 강점: 높은 성능과 함께 다양한 배포 옵션을 제공합니다. 클라우드 API 형태로 손쉽게 접근할 수 있을 뿐만 아니라, 자체 서버에 모델을 구축하는 방식도 매우 유연하게 지원하여 개발 단계에서 빠르게 테스트하기 용이합니다.

두 모델 모두 API를 통한 사용과 로컬 환경에서의 직접 구동이 가능하지만, 인프라 상황과 보안 요구 사항에 따라 최적의 선택지가 달라집니다. 만약 최고 수준의 데이터 프라이버시가 중요하다면 자체 구축을 우선적으로 고려해야 합니다.

실전 적용 사례: 단순 채팅을 넘어 지능형 에이전트로

최신 대규모 언어 모델은 단순 질답을 넘어 복잡한 임무를 수행하는 에이전트의 형태로 진화하고 있습니다. 이 부분에서 두 모델 모두 매우 흥미로운 기능을 보여주고 있습니다.

  • 사고 과정 시각화: 단순히 최종 답만 내놓지 않고, 문제 해결을 위한 사고 과정을 단계별로 도식화하여 제시할 수 있습니다. 이는 개발자가 모델의 생각 흐름을 추적하고 디버깅하는 데 매우 유용합니다.
  • 계획 및 실행: 복잡한 목표를 달성하기 위해 여러 단계를 거치는 워크플로우 설계가 가능합니다. 단순 질답이 아닌 프로젝트 수행 맥락으로 모델을 활용할 수 있게 만듭니다.
  • 고급 추론 모드: 내부적으로 사고 과정을 명시하는 생각하기 모드를 적용하여, 사람처럼 생각의 단계를 거친 후 최종 결론을 내리게 하는 방식은 두 모델 모두 강력하게 지원하고 있는 핵심 기능입니다.

결론: 나에게 맞는 모델 선택 가이드라인

Qwen 3.6과 Gemma 4는 서로 다른 배경에서 탄생했지만, 목표 지점은 최고의 범용 인공지능이라는 공통분모를 가지고 있습니다. 어느 쪽이 절대적으로 우월하다고 말하기보다는, 프로젝트가 어떤 요구사항에 초점을 맞추는지에 따라 선택하는 것이 가장 현명합니다.

상황 및 목적추천 모델 및 이유고려 사항
최대 보안 및 로컬 운영 필수Gemma 4 온프레미스 구축자체 인프라 구축 비용과 전문성이 필요합니다.
빠른 프로토타이핑 및 유연한 배포Qwen 3.6 API 또는 자체 호스팅API 접근성이 뛰어나며 다양한 클라우드 환경에 쉽게 통합할 수 있습니다.
복잡한 추론 및 문제 해결 능력두 모델 모두 우수함사고 과정 시각화 등 고급 에이전트 기능 구현에 집중하세요.
특정 벤치마크 점수 극대화최신 테스트 결과 참고MMLU, GSM8K 등 목적에 맞는 전문 벤치마크를 활용하여 비교해야 합니다.

결국 대규모 언어 모델의 시대는 선택과 조합의 시대입니다. 두 모델을 하나의 시스템으로 통합하거나, 각자의 강점을 살려 역할을 분담시키는 방식이 가장 진보적인 인공지능 활용 방법이 될 것입니다. 여러분의 다음 프로젝트에 이 비교 분석 글이 도움이 되기를 바라며, 더 깊이 있는 기술 이야기로 찾아뵙겠습니다. 궁금한 점은 댓글을 통해 자유롭게 남겨주세요.

VRAM 부족 고민 끝! Qwen3.6-27B 양자화(4bit/8bit) 성능 비교 및 최적 선택 가이드

안녕하세요, AI 기술 트렌드를 깊이 파헤치는 테크 블로거입니다.

최근 대규모 언어 모델(LLM) 시장은 그야말로 폭발적인 성장을 거듭하고 있습니다. GPT-4급의 초대형 모델들이 성능의 기준을 높이고 있지만, 이 거대한 모델들을 일반 사용자의 로컬 PC나 제한된 클라우드 환경에서 구동하는 것은 여전히 큰 난제였습니다.

하지만 걱정하지 마십시오. 바로 양자화(Quantization) 기술이 그 해결책을 제시했습니다. 오늘 우리가 집중적으로 살펴볼 주제는 Qwen3.6-27B 모델입니다. 이 강력한 LLM을 4bit, 6bit, 그리고 8bit 같은 다양한 비트 단위로 경량화했을 때 성능과 효율성 측면에서 어떤 차이가 있는지, 전문적인 관점에서 깊이 있게 분석해 보겠습니다.




Qwen3.6-27B와 양자화, 그 관계는 무엇일까요?

Qwen3.6은 270억 개의 매개변수를 가진 매우 강력한 모델입니다. 이처럼 큰 모델을 그대로 구동하려면 엄청난 양의 VRAM(GPU 메모리)이 필요합니다. 여기서 양자화가 등장합니다. 양자화란 모델의 정밀도(Precision)를 낮춰 모델의 크기 자체를 줄이는 기술입니다. 예를 들어, 32비트 부동소수점 대신 4bit나 8bit 같은 낮은 비트를 사용해 데이터를 저장하는 방식이죠.

핵심 원리: 양자화는 모델의 크기를 일부 희생하여 속도와 메모리 효율성을 극대화합니다. 모델이 작아지면 더 적은 자원으로도 빠른 추론(Inference)이 가능해집니다.

비트 단위로 파헤치는 성능 비교: 4bit vs 8bit의 선택

가장 궁금하실 부분일 겁니다. 4bit를 쓰면 너무 품질이 떨어지는 것 아닌가? 이 질문에 답하는 것이 바로 다양한 비트 수준에서의 벤치마크 결과입니다.

메모리와 정확도의 트레이드오프 (Trade-off)

양자화 수준 메모리 사용량 추론 속도 정확도 및 품질
8bit (High Precision) 중간 빠름 최고 (성능 저하 최소화)
6bit (Balanced) 적음 매우 빠름 높음 (균형 잡힌 성능)
4bit (Efficiency First) 매우 적음 극대화 양호 (일부 미세한 손실 존재)

최신 벤치마크 자료들을 종합해 볼 때, Qwen3.6 모델은 비트 단위에 관계없이 전반적으로 뛰어난 능력을 보여주지만 어떤 목표를 가지고 사용하느냐에 따라 최적의 선택이 달라집니다.

사용자 시나리오별 추천 가이드

  • 최고의 정확도와 품질을 원한다면: 8bit 또는 그 이상의 정밀도를 유지하는 환경이 적합합니다. 자원이 충분한 고성능 워크스테이션이나 기업용 서버에서 안정적인 고품질 출력이 필요할 때 유리합니다.
  • 가장 빠른 속도와 적은 메모리가 중요하다면: 4bit 양자화 모델이 최고의 선택입니다. 로컬 PC나 클라우드 GPU의 자원 제한이 있을 때, 휴대성과 접근성을 극대화할 수 있습니다.
  • 균형 잡힌 성능을 원한다면: 6bit는 4bit와 8bit 사이에서 좋은 절충점을 찾고자 할 때 유용합니다. 일반적인 개발 및 테스트 환경에 가장 추천하는 옵션입니다.

Qwen3.6, 단순히 크기만 줄인 모델일까? 심화 분석

단순히 비트 수를 낮춘 것이라면 성능 저하가 클 수 있습니다. 하지만 Qwen3.6과 같은 최신 모델들은 양자화 과정에서도 뛰어난 능력을 유지하도록 설계되고 미세 조정(Fine-tuning)됩니다.

또한, 단순히 벤치마크 점수만 볼 것이 아니라 특정 작업 능력을 확인하는 것이 중요합니다.

  • 코딩 및 로직 추론: 코딩 관련 테스트에서 높은 성능을 보이는지 체크해야 합니다. 일부 자료는 Coding 능력을 강조하며 Qwen3.6의 우위를 명확히 언급합니다.
  • Agentic Workflow 이해: 복잡하고 여러 단계를 거쳐야 하는 에이전트 작업에 얼마나 잘 대응하는지를 확인하세요. 이 부분이 모델의 실제 활용 가치를 결정합니다.

결론: 현명한 선택이 가장 중요한 성능 지표입니다

Qwen3.6-27B는 양자화 기술 덕분에 폭넓은 환경에서 구동될 수 있는 매우 매력적인 모델임에 틀림없습니다. 결국 최고의 LLM을 가장 효율적으로 사용하는 것이 현재 AI 활용 트렌드의 핵심입니다.

여러분의 사용 목적과 가용 자원(VRAM)을 고려하여 4bit, 6bit, 8bit 중 가장 적절한 비트 레벨을 선택하는 것이 곧 최고의 성능을 얻는 지름길이 될 것입니다. 기술의 발전은 단순히 모델을 키우는 것이 아니라, 어떻게 더 스마트하게 활용하느냐에 달려 있습니다.

여러분의 다음 AI 프로젝트에서는 어떤 비트 레벨을 선택하실 계획인가요? 가용 자원과 목표 작업에 맞춰 최적의 균형을 찾아보시길 바랍니다. 궁금한 점이 있다면 댓글로 질문해 주세요.


참고 자료:

  • Qwen3.6 27B 4bit, 6bit, 8bit 벤치마크 관련 검색 결과
  • LLM 양자화 및 Qwen3.6 비교 분석 자료
  • 다양한 LLM 경량화 기술 및 최적 설정 가이드

LLM 에 MCP 를 연동하는 방법 — 날짜 서버로 배우는 Model Context Protocol

LLM(대형 언어 모델) 은 기본적으로 텍스트를 받아 텍스트를 내뱉는 시스템입니다. 하지만 외부 데이터에 접근하거나, 실시간 정보를 얻거나, 파일 시스템을 조작하려면 도구(Tool)가 필요합니다. MCP(Model Context Protocol) 는 LLM 이 외부 도구와 안전하게 통신할 수 있게 하는 표준 프로토콜입니다.

이 글에서는 "오늘 날짜를 알려주는 MCP 서버"를 예로 들어, MCP 서버를 직접 코딩하고, 설정하고, LLM 이 이를 호출하는 전체 과정을 단계별로 설명합니다.


1. MCP(Model Context Protocol) 란?

MCP 는 Anthropic 이 제안한 개방형 프로토콜로, LLM 애플리케이션과 외부 데이터 소스·도구들을 연결하는 표준 인터페이스입니다. USB 포트가 다양한 주변기기를 연결하듯, MCP 는 어떤 LLM 이든 어떤 MCP 서버든 연결할 수 있게 합니다.

MCP 가 없으면 각 LLM 플랫폼마다 전용 플러그인을 만들어야 합니다. MCP 가 있으면 한 번 만든 서버가 Claude, Cursor, Hermes Agent 등 모든 LLM 플랫폼에서 바로 동작합니다.

MCP 의 핵심 구성 요소

  • MCP Host: LLM 을 실행하는 애플리케이션 (예: Hermes Agent, Claude Desktop, Cursor)
  • MCP Server: 외부 도구나 데이터를 제공하는 서버 (예: 오늘 날짜를 반환하는 서버)
  • Transport: 호스트와 서버 간 통신 방식 (stdio, HTTP/SSE)
  • Tools: 서버가 호스트에 제공하는 기능 목록 (예: get_today)

MCP 가 해결하는 문제

  • 재사용: 한 번 작성한 MCP 서버가 모든 LLM 플랫폼에서 동작
  • 보안: LLM 은 MCP 서버를 통해만 외부에 접근 — 직접 네트워크/파일시스템 접근 불가
  • 표준화: JSON-RPC 기반의 통일된 프로토콜 — 각 플랫폼별 커스텀 플러그인 불필요

2. MCP 서버 코드 작성하기 — 날짜 서버 만들기

먼저 Python 으로 "오늘 날짜를 알려주는" MCP 서버를 직접 만들어보겠습니다. mcp Python 패키지를 사용하면 몇 줄로도 서버를 만들 수 있습니다.

2-1. 환경 준비

먼저 MCP SDK 를 설치합니다.

pip install mcp

2-2. 날짜 서버 전체 코드

#!/usr/bin/env python3
"""
today_mcp_server.py — 오늘 날짜를 알려주는 MCP 서버

사용법:
  python today_mcp_server.py        # stdio 모드로 실행
  python today_mcp_server.py --http  # HTTP 모드로 실행 (포트 8090)
"""

import argparse
from datetime import datetime
from zoneinfo import ZoneInfo
from mcp.server import Server

app = Server("today-server")

# ── 비즈니스 로직 ──────────────────────────────────────────
def get_today(timezone: str = "Asia/Seoul") -> dict:
    """지정된 시간대의 현재 날짜와 시간을 반환합니다."""
    try:
        tz = ZoneInfo(timezone)
        now = datetime.now(tz)
        weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday",
                    "Friday", "Saturday", "Sunday"]
        return {
            "datetime": now.strftime("%Y-%m-%d %H:%M:%S"),
            "timezone": timezone,
            "weekday": weekdays[now.weekday()],
            "date_only": now.strftime("%Y-%m-%d"),
            "time_only": now.strftime("%H:%M:%S")
        }
    except Exception as e:
        return {"error": str(e)}

def get_formatted_date(format_str: str, timezone: str = "Asia/Seoul") -> str:
    """strftime 포맷으로 날짜를 반환합니다."""
    try:
        tz = ZoneInfo(timezone)
        now = datetime.now(tz)
        return now.strftime(format_str)
    except Exception as e:
        return f"Error: {e}"

# ── MCP 서버 ───────────────────────────────────────────────
@app.tool()
def get_today_tool(timezone: str = "Asia/Seoul") -> dict:
    """현재 날짜와 시간을 반환합니다.

    Args:
        timezone: 시간대 (기본값: Asia/Seoul)
                 예: America/New_York, Europe/London, UTC

    Returns:
        날짜, 시간, 요일, 시간대 정보
    """
    return get_today(timezone)

@app.tool()
def get_formatted_date_tool(format_str: str, timezone: str = "Asia/Seoul") -> str:
    """지정된 포맷으로 날짜를 반환합니다.

    Args:
        format_str: strftime 포맷 (예: "%Y년 %m월 %d일")
        timezone: 시간대 (기본값: Asia/Seoul)

    Returns:
        포맷팅된 날짜 문자열
    """
    return get_formatted_date(format_str, timezone)

# ── 실행 ───────────────────────────────────────────────────
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Today MCP Server")
    parser.add_argument("--http", action="store_true", help="Run in HTTP mode")
    args = parser.parse_args()

    if args.http:
        from mcp.server.http import run_server_as_async_http_app
        import http.server
        import threading

        # Simple HTTP server for testing
        from wsgiref.simple_server import make_server
        from mcp.server.http import run_server_as_async_http_app

        async def main():
            app_instance = run_server_as_async_http_app(app)
            httpd = make_server("localhost", 8090, app_instance)
            print("MCP HTTP Server running on http://localhost:8090")
            httpd.serve_forever()

        import asyncio
        asyncio.run(main())
    else:
        from mcp.server.stdio import stdio_server
        import asyncio

        async def main():
            async with stdio_server() as (read, write):
                await app.run(read, write)

        asyncio.run(main())

코드 설명

이 코드는 크게 두 부분으로 나뉩니다.

1) 비즈니스 로직 (상단)

  • get_today(): 지정된 시간대의 현재 날짜/시간을 반환
  • get_formatted_date(): strftime 포맷으로 사용자 정의 날짜 형식 반환
  • 에러 처리: 잘못된 시간대 이름도 try/except 로 안전하게 처리

2) MCP 서버 (하단)

  • @app.tool(): 함수를 MCP 도구로 등록 — LLM 이 호출할 수 있음
  • stdio 모드: 기본 방식. 호스트가 서버를 자 프로세스로 실행하고 stdin/stdout 으로 통신
  • HTTP 모드: 서버를 별도 HTTP 엔드포인트로 실행 — 원격 호스트에서 연결 가능

테스트 해보기

이렇게 하면 서버를 거치지 않고 함수가 정상 동작하는지 확인할 수 있습니다.

# 서버를 거치지 않고 직접 테스트
from today_mcp_server import get_today, get_formatted_date

print(get_today())
# {"datetime": "2025-06-13 14:30:00", "timezone": "Asia/Seoul", ...}

print(get_formatted_date("%Y년 %m월 %d일 (%A)"))
# 2025년 06월 13일 (Friday)

3. MCP 서버 설정하기

서버 코드를 만들었다면, 이제 LLM 애플리케이션에 연결해야 합니다. Hermes Agent 를 예로 들어 설명합니다.

3-1. config.yaml 에 등록

~/.hermes/config.yaml 파일에 mcp_servers 섹션을 추가합니다.

mcp_servers:
  today:
    command: python
    args:
      - ~/Developer/scripts/today_mcp_server.py

여기서 today 는 서버 이름입니다. 이 이름이 도구 이름 앞에 붙습니다:

  • 서버의 get_today 도구 → today.get_today(로 인식됨)
  • 서버의 get_formatted_date 도구 → today.get_formatted_date(로 인식됨)

3-2. 설정 옵션 전체

mcp_servers:
  today:
    command: python                    # 실행할 명령어
    args:                              # 명령어 인수
      - ~/Developer/scripts/today_mcp_server.py
    env:                               # 환경 변수 (선택)
      API_KEY: "sk-xxx"
    timeout: 30                        # 연결 타임아웃 (초)
    disabled: false                    # 서버 비활성화

3-3. HTTP 방식 서버도 지원

stdio 대신 HTTP 로 통신하는 원격 MCP 서버도 연결할 수 있습니다.

mcp_servers:
  remote-server:
    url: http://your-server.com/mcp    # HTTP 엔드포인트

3-4. Hermes Agent 재시작

설정을 추가한 후 Hermes Agent 를 재시작하면:

  • 자동 감지: config.yaml 의 mcp_servers 를 읽어 MCP 서버 프로세스를 시작
  • 도구 등록: 서버가 제공하는 도구 목록(LLM 이 볼 수 있는 설명 포함)을 가져옴
  • 즉시 사용: 사용자가 대화를 시작하면 LLM 이 MCP 도구들을 사용할 수 있음
  • 에러 피드백: 서버가 시작 실패하면 Hermes Agent 가 콘솔에 에러를 출력
  • 핫 리로드: 서버 코드를 수정하면 다음 Agent 세션에서 자동으로 반영

4. LLM 이 MCP 를 호출하는 전 과정

이제 가장 중요한 부분입니다. 사용자가 "오늘 날짜 알려줘"라고 입력했을 때, 내부에서 어떤 일이 일어나는지 단계별로 추적해보겠습니다.

단계 1: 사용자 입력

메시지가 LLM 애플리케이션(Hermes Agent) 에 전달됩니다.

"오늘 날짜 알려줘"

단계 2: LLM 이 도구 사용 여부를 판단

LLM 은 다음 정보를 함께 받습니다:

  • 사용자의 질문
  • 등록된 MCP 도구 목록 (이름 + 설명 + 파라미터)
  • 시스템 프롬프트 (도구 사용 가이드라인)

단계 3: LLM 이 도구 호출을 결정

LLM 은 "오늘 날짜"라는 키워드를 보고 get_today 도구를 사용해야 한다고 판단합니다.

Tool: today.get_today
Description: 현재 날짜와 시간을 반환합니다.
Parameters:
  - timezone: 시간대 (기본값: Asia/Seoul)

단계 4: Hermes Agent 가 MCP 서버에 요청 전달

LLM 이 도구 호출을 결정하면, Hermes Agent 가 실제 MCP 서버에 요청을 보냅니다. JSON-RPC 2.0 프로토콜을 사용합니다.

Tool Call:
  tool_name: today.get_today
  arguments: {"timezone": "Asia/Seoul"}

이 요청은 MCP 서버 프로세스의 stdin 으로 전달됩니다.

실제 JSON-RPC 메시지는 다음과 같습니다:

// Hermes Agent → MCP Server
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_today",
    "arguments": {"timezone": "Asia/Seoul"}
  }
}

// MCP Server → Hermes Agent
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [{
      "type": "text",
      "text": "{"datetime": "2025-06-13 14:30:00", "timezone": "Asia/Seoul", "weekday": "Friday", ...}"
    }],
    "isError": false
  }
}

단계 5: 결과 LLM 에 전달

MCP 서버의 응답을 LLM 에 다시 전달합니다.

Tool Result (today.get_today):
현재 시간: 2025-06-13 14:30:00
시간대: Asia/Seoul
요일: Friday

단계 6: LLM 이 최종 답변 생성

LLM 은 도구 결과를 바탕으로 자연스러운 답변을 생성합니다.

"지금 한국 시간으로 2025년 6월 13일 금요일 오후 2시 30분입니다."

전체 흐름 다이어그램

┌─────────────┐     ┌──────────────────┐     ┌──────────────────┐
│   사용자    │────▶│  Hermes Agent     │────▶│  LLM (qwen3.6)   │
│             │     │                  │     │                  │
│ "오늘 날짜   │     │  MCP 서버 관리    │     │  1. 질문 분석     │
│  알려줘"    │◀────│  프로세스 실행    │◀────│  2. 도구 호출     │
│             │     │                  │     │     결정          │
└─────────────┘     └────────┬─────────┘     └──────────────────┘
                             │
                    ┌────────▼─────────┐
                    │  MCP Server      │
                    │  (today)         │
                    │                  │
                    │  get_today()     │
                    │  실행            │
                    └────────┬─────────┘
                             │
                    ┌────────▼─────────┐
                    │  JSON-RPC 응답   │
                    │                  │
                    │  {"datetime":    │
                    │   "2025-06-13    │
                    │   14:30:00", ...}│
                    └────────┬─────────┘
                             │
                    ┌────────▼─────────┐
                    │  Hermes Agent    │
                    │                  │
                    │  결과를 LLM 에   │
                    │  다시 전달       │
                    └────────┬─────────┘
                             │
                    ┌────────▼─────────┐     ┌─────────────┐
                    │  LLM             │────▶│   사용자    │
                    │                  │     │             │
                    │  최종 답변 생성   │     │ "지금 한국  │
                    │                  │     │  시간으로    │
                    └──────────────────┘     │  2025년 6월 │
                                            │  13일 금요일 │
                                            │  오후 2시    │
                                            │  30분입니다" │
                                            └─────────────┘

5. MCP 서버 작성 시 주의사항

5-1. docstring 은 LLM 이 보는 설명서

MCP 서버에서 docstring은 단순 주석이 아닙니다. LLM 이 도구 사용 여부를 결정하는 유일한 정보원입니다.

@app.tool()
def get_today(timezone: str = "Asia/Seoul") -> str:
    """현재 날짜와 시간을 반환합니다.

    Args:
        timezone: 시간대 (기본값: Asia/Seoul)
                 예: America/New_York, Europe/London, UTC

    Returns:
        현재 날짜와 시간 문자열
    """

docstring 이 명확해야 LLM 이 언제 이 도구를 호출해야 하는지 정확히 알 수 있습니다. 모호한 설명은 LLM 이 도구를 사용하지 않거나 잘못된 파라미터로 호출하는 원인이 됩니다.

5-2. 입력 파라미터 정의하기

@app.tool()
def search_files(directory: str, pattern: str) -> list:
    """지정된 디렉토리에서 패턴에 맞는 파일 목록을 반환합니다.

    Args:
        directory: 검색할 디렉토리 경로
        pattern: 파일 이름 패턴 (예: "*.py", "test_*")

    Returns:
        일치하는 파일 경로 목록
    """
  • 타입 힌트 필수: str, int, bool 등 명확한 타입 지정
  • 기본값 설정: 가능한 한 파라미터에 기본값 제공
  • Args 설명: 각 파라미터의 용도와 예시를 docstring 에 포함

5-3. 에러 처리는 반드시

@app.tool()
def get_weather(city: str) -> str:
    """도시의 현재 날씨를 반환합니다."""
    try:
        response = requests.get(f"https://api.weather.com/{city}")
        response.raise_for_status()
        return json.dumps(response.json(), ensure_ascii=False)
    except Exception as e:
        return f"날씨 조회 실패: {e}"

에러가 발생해도 서버가 크래시되지 않도록 try/except로 감싸야 합니다. 에러 메시지도 LLM 에 전달되므로, 의미 있는 에러 메시지를 반환하세요.

5-4. 보안 — 환경 변수는 명시적으로 전달

mcp_servers:
  weather:
    command: python
    args: [~/scripts/weather_server.py]
    env:
      WEATHER_API_KEY: "***"  # API 키는 여기에서 전달

API 키나 비밀번호는 코드에 하드코딩하지 말고 env 옵션으로 전달하세요. config.yaml 은 버전 컨트롤에 포함되지 않도록 .gitignore 에 추가하세요.


6. 실전 — 다른 MCP 서버 예시

파일 시스템 서버

mcp_servers:
  filesystem:
    command: npx
    args:
      - "-y"
      - "@modelcontextprotocol/server-filesystem"
      - "/Users/mulpats/Developer"  # 접근 허용 디렉토리

지정된 디렉토리 내의 파일을 읽고, 검색하고, 목록을 확인할 수 있습니다. 접근 허용 디렉토리만 지정해야 보안상 안전합니다.

GitHub 서버

mcp_servers:
  github:
    command: npx
    args:
      - "-y"
      - "@modelcontextprotocol/server-github"
    env:
      GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_xxx"

GitHub 리포지토리의 코드를 읽고, 이슈를 확인하고, PR 을 검토할 수 있습니다.

시간대 서버 (uvx)

mcp_servers:
  timezone:
    command: uvx
    args:
      - "mcp-server-timezone"

uvx 로 설치 없이 바로 실행할 수 있는 MCP 서버도 많습니다. uvx는 Python 패키지를 가상 환경에서 즉시 실행하는 도구입니다.


7. 문제 해결 가이드

MCP 도구가 인식되지 않음

# config.yaml 의 mcp_servers 섹션 확인
cat ~/.hermes/config.yaml | grep -A 5 mcp_servers

# Hermes Agent 재시작 후 로그 확인
hermes start  # 또는 재시작
  • config.yaml 의 YAML 들여쓰기가 정확한지 확인 (스페이스 2개 사용)
  • 서버 경로를 절대 경로로 변경해보기
  • Hermes Agent 를 재시작했는지 확인

"MCP SDK not available" 오류

# Python 환경 확인
which python
python --version

# MCP SDK 설치 확인
pip show mcp
  • pip install mcp 로 최신 버전 설치
  • 가상 환경이 활성화되어 있는지 확인
  • Python 버전이 3.9 이상인지 확인

서버 연결 실패

# 서버 직접 실행 (디버깅)
python ~/Developer/scripts/today_mcp_server.py

# HTTP 모드로 실행 테스트
python ~/Developer/scripts/today_mcp_server.py --http
# 브라우저에서 http://localhost:8090 접속
  • 서버를 직접 실행해서 에러 메시지 확인
  • 포트가 이미 사용 중인지 확인 (lsof -i :8090)
  • 방화벽 설정 확인 (macOS: 시스템 설정 → 네트워크 → 방화벽)

요약

  • MCP 는 LLM 과 외부 도구를 연결하는 표준 프로토콜
  • Python mcp 패키지로 몇 줄로도 MCP 서버 작성 가능
  • config.yaml 에 등록하면 Hermes Agent 가 자동으로 관리
  • LLM 은 도구 설명(docstring) 을 보고 언제 호출할지 결정
  • JSON-RPC 2.0 으로 호스트와 서버 간 통신
  • 에러 처리와 보안(API 키 관리) 을 반드시 고려

AI 개발자 필독! Mac Studio와 MacBook Pro 중 LLM 구동 최강자는 누구일까? M4 Max 64GB 완벽 분석

서론: AI 시대의 컴퓨팅 고민, 노트북으로 충분할까요?

최근 생성형 AI와 대규모 언어 모델(LLM)이 일상에 깊숙이 들어오면서, 개인 사용자부터 전문 개발자까지 나만의 강력한 AI 워크스테이션을 찾는 분들이 폭증하고 있습니다. 특히 M4 Max 칩과 64GB의 넉넉한 통합 메모리를 장착한 Apple Silicon Mac들은 뛰어난 성능으로 큰 주목을 받고 있습니다. 하지만 막상 눈앞에 Mac Studio와 MacBook Pro 두 기종이 놓여있다면, 어떤 것을 선택해야 할지 고민되실 겁니다. 내 주력 작업이 대규모 LLM 구동이라면, 데스크톱과 노트북 중 어느 쪽이 더 효율적일까요? 오늘은 최신 정보를 바탕으로 M4 Max 64GB 사양을 기준으로 두 기종의 장단점을 깊이 있게 비교 분석하고, 여러분의 AI 워크로드에 가장 적합한 선택지를 제시해 드리겠습니다.

본론: LLM 구동 관점에서 본 Mac Studio vs MacBook Pro 비교 분석

LLM을 로컬 환경에서 돌린다는 것은 단순한 웹 브라우징과는 차원이 다른 컴퓨팅 자원을 요구합니다. 단순히 CPU 성능만 높다고 끝나는 것이 아니라, 메모리 대역폭과 전체 메모리 용량이 핵심입니다.

Mac Studio: 최대 확장성을 추구하는 전문가의 선택

Mac Studio는 데스크탑 환경에 최적화된 극강의 성능을 자랑합니다. LLM처럼 지속적으로 높은 부하를 주는 작업에는 다음과 같은 장점이 있습니다.

  • 최대 확장성: Thunderbolt 5 및 다양한 고속 포트를 제공하여, 외장 GPU나 전문 네트워크 장비를 추가하기 용이합니다. 이는 복잡하고 거대한 AI 시스템을 구축하는 데 유리합니다.
  • 발열 관리 및 지속 성능: 전용 쿨링 시스템을 갖춘 워크스테이션 디자인은, 몇 시간 동안 쉬지 않고 대규모 모델 추론 작업을 돌려야 하는 환경에서 안정적인 성능 유지에 큰 강점입니다.
  • 고성능 I/O: 여러 개의 고속 모니터 연결이나 다수의 외장 스토리지 연동이 필요한 전문가 작업 흐름에 최적화되어 있습니다.

요약하자면, Mac Studio는 최대 성능과 확장성, 그리고 지속 가능한 부하 처리 능력이 가장 중요하고 책상 위에 고정적으로 두고 사용할 전문 연구자나 개발자에게 최고의 선택입니다.

MacBook Pro: 압도적인 휴대성을 갖춘 만능 AI 파트너

MacBook Pro는 강력한 성능을 유지하면서도 어디든 가져갈 수 있다는 것이 최대 무기입니다. M4 Max 64GB를 탑재한다면 다음과 같은 장점이 부각됩니다.

  • 휴대성과 전력 효율의 균형: LLM 작업은 고성능이 필수지만, 하루 종일 외부에서 작업을 해야 할 때 MacBook Pro는 최고의 파워와 배터리를 제공합니다.
  • 빠른 환경 전환: 카페, 회의실 등 다양한 장소에서 즉시 코딩 및 AI 테스트를 진행해야 하는 사용자에게 최적화되어 있습니다.

요약하자면, Mac Studio가 최대치라면 MacBook Pro는 최고의 성능을 유지하는 범용성입니다. 이동하며 개발하고 협업하는 환경이라면 단연코 MacBook Pro가 앞섭니다.

핵심 비교: LLM 구동에 결정적인 요소

구분 Mac Studio M4 Max 64GB MacBook Pro M4 Max 64GB
핵심 강점 확장성, 지속 성능 (데스크탑) 휴대성, 전력 효율성 (모바일)
LLM 구동 최적 환경 서버 연동, 장시간 대규모 배포 테스트 필드 테스트, 출장 개발, 즉각적인 프로토타이핑
메모리 활용 관점 PCIe 확장 슬롯을 통한 추가 자원 연결에 유리 통합 메모리로 모든 자원을 효율적으로 분배하여 사용

64GB 메모리의 중요성: LLM은 모델 크기와 컨텍스트 길이가 커질수록 메모리 요구량이 기하급수적으로 늘어납니다. 64GB는 단순히 많은 데이터를 담는 것을 넘어, 복잡한 검색 증강 생성(RAG) 파이프라인을 구동하거나 여러 개의 모델을 동시에 테스트할 수 있는 작업 공간 그 자체입니다.

결론: 나에게 맞는 AI 워크스테이션 선택 가이드

결국 Mac Studio와 MacBook Pro 중 어떤 것이 더 뛰어나다고 단정하기보다는 사용자의 주된 작업 패턴에 따라 선택하는 것이 가장 현명합니다. 집이나 회사 책상에서 24시간 AI 모델을 돌리거나 외장 장비 연결이 필수라면 Mac Studio가 답입니다. 반면 외부 출장이 잦고 카페나 미팅 자리에서도 강력한 LLM 테스트가 필요하다면 MacBook Pro의 성능을 포기할 수 없는 휴대성이 핵심입니다.

어떤 선택이든 M4 Max와 64GB 메모리는 현존하는 개인용 AI 개발 환경에서 최고의 조합 중 하나임은 분명합니다. 이 강력한 하드웨어를 바탕으로 여러분의 창의적인 아이디어를 현실로 만들어 가시길 응원합니다.

독자 여러분은 주로 어떤 환경에서 AI 개발을 진행하시나요? 고정된 워크스테이션이 더 생산성을 높여주나요, 아니면 언제 어디서나 코드를 실행할 수 있는 자유도가 더 중요하신가요? 댓글로 여러분의 의견을 들려주세요.

참고 자료

  • Mac Studio vs MacBook Pro LLM 비교 분석
  • AI 워크로드와 M4 Max 성능 분석
  • 고성능 컴퓨팅 및 메모리 대역폭의 중요성

Qwen3.6 27B 로컬 구동, GGUF와 MLX 중 어디가 진짜 끝판왕인가? (성능 비교 가이드)

거대 AI 모델, 이제 내 컴퓨터에서 돌리는 시대가 왔다

최근 대규모 언어 모델의 성능이 비약적으로 발전하면서, 전문가와 개발자 사이에서는 어떤 환경에서 가장 효율적으로 구동할 수 있는지가 핵심 화두로 떠올랐습니다. 특히 Qwen3.6-27B와 같은 거대 모델을 개인 컴퓨터나 맥북에서 직접 돌려보고자 하는 수요가 폭발적으로 증가했습니다. 하지만 GGUF, MLX, vLLM, SGLang 등 다양한 기술 용어가 난무하다 보니 선택에 어려움을 겪는 분들이 많습니다. 오늘 이 글에서는 복잡한 기술 스택을 정리하고, 각 환경의 장단점과 최적 사용 사례를 명쾌하게 비교해 드리겠습니다.


핵심 개념 이해하기: GGUF와 MLX는 무엇이 다른가

LLM 구동 환경을 비교하려면 먼저 두 가지 주요 아키텍처의 철학적 차이를 알아야 합니다. GGUF는 특정 하드웨어에 종속되지 않고 범용적으로 실행할 수 있도록 설계된 포맷입니다. llama.cpp나 Ollama와 같은 도구에서 주로 사용되며, CPU 자원을 효율적으로 활용하고 4비트 양자화를 통해 메모리 사용량을 혁신적으로 줄일 수 있습니다. 반면 MLX는 애플이 직접 개발한 프레임워크로, M 시리즈 칩셋의 아키텍처에 극도로 최적화되어 있습니다. 맥 환경에서는 네이티브하게 하드웨어 자원을 최대한 끌어내어 빠른 추론 속도를 제공합니다. GGUF는 어디든 쓸 수 있는 범용 포맷이라면, MLX는 특정 하드웨어에 맞춰 최고의 성능을 내도록 설계된 전문 도구라고 보시면 됩니다.

시나리오별 비교 분석: 나에게 맞는 최적의 조합은

사용 목적에 따라 최적의 조합은 달라집니다. 로컬 개인 구동 환경과 서버 배포 환경을 나누어 비교해 보겠습니다.

구분GGUF 기반 환경MLX 프레임워크vLLM 및 SGLang 엔진
최적 환경범용 PC, 다양한 OS애플 M 시리즈 맥북 및 데스크탑GPU 기반 서버 환경
핵심 강점높은 이식성, 커뮤니티 지원, CPU 효율화하드웨어 자원 극대화, 네이티브 최적화동시 요청 처리량 최적화
추천 목적다양한 기기에서의 안정적 테스트 및 구동맥 사용자를 위한 빠르고 매끄러운 로컬 실행다수 사용자에게 API 형태로 서비스 제공

만약 현재 사용 중인 기기가 M 시리즈 맥이라면 MLX를, 윈도우나 리눅스 등 범용성이 중요하다면 GGUF 조합을 우선 고려하는 것이 현명합니다. 반면 개인 구동을 넘어 서비스 형태로 LLM을 제공하거나 높은 처리량이 필요한 경우에는 vLLM이나 SGLang과 같은 전문 추론 엔진을 GPU 환경에 적용해야 합니다. 이들은 모델 자체의 효율성보다는 요청 처리 속도와 동시 접속자 관리 능력에 초점을 맞추고 있기 때문입니다.

결론: 최고는 사용 목적에 달렸다

궁극적으로 거대 언어 모델을 구동하는 방법에는 절대적인 정답이 없습니다.

  • 목표가 맥 환경에서 가장 매끄럽게 돌리는 것이라면 MLX를 우선 검토하세요.
  • 목표가 어떤 PC에서도 안정적으로 실행하는 것이라면 GGUF와 llama.cpp 조합이 현명합니다.
  • 목표가 서비스 형태로 다수의 사용자에게 제공하는 것이라면 GPU 기반의 vLLM이나 SGLang을 선택해야 합니다.

기술 발전 속도가 매우 빠르기 때문에, 오늘 정리한 내용을 하나의 가이드라인으로 삼으시고 직접 다양한 환경에서 모델을 테스트해 보시는 것을 추천합니다. 여러분의 하드웨어와 소프트웨어를 최적화하여 최고의 AI 경험을 만드시길 응원합니다.

SK하이닉스 ADR 상장 이후 한국 증시 급락의 원인 분석

분류: 증시분석 SK하이닉스 ADR 상장 이후 한국 증시 급락의 원인 분석 지난 7월 10일, SK하이닉스가 미국 나스닥에 미국주식예탁증서(ADR)를 상장했다. 공모가 149달러로 상장한 하이닉스 ADR은 첫 거래일인 13일 기준 약 168달...