이 프로젝트가 하는 일
이 프로젝트는 TensorFold v0.5.0을 사용해 두 대의 NVIDIA DGX Spark 시스템에서 GLM-5.3-Flash를 제공합니다. 각 Spark는 분산 rank 하나를 실행하며, 첫 번째 Spark는 OpenAI 호환 HTTP API도 호스팅합니다.
기본 구성은 동시 요청 4개, 요청당 최대 1,048,576 토큰의 컨텍스트 창, 이미지 및 동영상 입력, 도구 호출, 구조화된 출력, 토큰화 엔드포인트, Prometheus 메트릭을 지원합니다. 두 시스템 간 통신에는 직접 연결된 ConnectX-7 RoCE 링크를 사용합니다.
이 배포는 Mia-AiLab GLM-5.3-Flash EXL3 체크포인트를 사용합니다. 라우팅되는 전문가 가중치는 가중치당 약 4비트로 저장되며, 나머지 체크포인트 가중치는 BF16입니다. 전체 체크포인트의 크기는 약 176GB입니다.
주요 기능
- OpenAI 호환 API: 채팅 완성, 완성, 응답 및 모델 목록 엔드포인트를 사용할 수 있습니다.
- 긴 컨텍스트: 기본 FP8 KV 구성에서 개별 요청에 최대 1,048,576개의 프롬프트 및 응답 토큰을 사용할 수 있습니다.
- 동시 추론: 기본 DFlash2 드래프터를 사용해 최대 4개의 요청을 함께 디코딩합니다.
- 공유 캐시 풀: 동시 대화는 사용 가능한 메모리에 따라 약 210만~270만 토큰을 포함하는 하나의 FP8 KV 풀을 공유합니다.
- 멀티모달 요청: JPEG, PNG, WebP, MP4, WebM, MOV, MKV 및 FFmpeg로 디코딩할 수 있는 기타 동영상 입력을 제출할 수 있습니다.
- 추론 제어: 낮음, 높음, 최대 추론 수준을 선택하거나 요청에 대한 사고 기능을 비활성화할 수 있습니다.
- 에이전트 기능: xgrammar를 통해 도구 호출과 스키마 제약 구조화 출력을 사용할 수 있습니다.
- 운영 엔드포인트: 상태를 확인하고, 입력을 토큰화하거나 역토큰화하며, Prometheus 메트릭을 수집할 수 있습니다.
- 자동 배포: 한 번의 명령으로 두 시스템을 준비하고, 두 rank를 실행하며, 스모크 테스트를 수행하고, API 주소를 보고합니다.
하드웨어 및 소프트웨어 요구 사항
DGX Spark 두 대 또는 각각 128GB의 통합 메모리를 갖춘 GB10 시스템 두 대가 필요합니다. 서버가 시작될 때 각 GPU에 약 110GiB의 여유 공간이 있어야 하므로, 먼저 다른 대규모 GPU 작업을 중지하세요.
네트워크 요구 사항
QSFP 케이블로 ConnectX-7 포트를 연결하고 각 엔드포인트에 동일한 사설 서브넷의 IPv4 주소를 할당하세요. 예를 들어 헤드에는 192.0.2.1/24, 워커에는 192.0.2.2/24를 사용할 수 있습니다. 주소는 ping으로 연결할 수 있어야 하며 RoCE v2 GID를 사용할 수 있어야 합니다.
두 CX7 포트가 모두 연결되고 주소가 지정된 경우 프로젝트는 두 레일을 모두 사용할 수 있습니다. README 측정 결과에 따르면 두 레일을 사용하면 프롬프트 청크의 all-gather가 약 1.8배 빨라집니다.
SSH 및 시스템 요구 사항
- 헤드 Spark에서 워커로 키 기반 SSH 액세스가 가능해야 합니다.
- 두 시스템에 NVIDIA 컨테이너 런타임이 포함된 Docker가 설치되어 있어야 합니다.
- 두 시스템에서 계정이
docker그룹에 속해야 합니다. - 두 시스템에
rsync가 설치되어 있어야 합니다. - 각 Spark에 약 205GB의 디스크 공간이 필요합니다.
- 선택 사항으로, 헤드에 Hugging Face
hfCLI와 Hugging Face 토큰을 준비할 수 있습니다.
필요한 경우 SSH 키를 생성하고 워커에 복사한 다음, 비대화형 액세스를 확인하세요.
ssh-keygen -t ed25519
ssh-copy-id user@192.0.2.2
ssh -o BatchMode=yes user@192.0.2.2 trueDFlash2 드래프터는 CC BY-NC-ND 4.0 라이선스가 적용되며 상업적 용도로 사용할 수 없습니다. DFlash2를 다운로드하거나 사용하지 않으려면 최초 설정 전에 체크포인트의 MTP 드래프터를 선택하세요.
프로젝트 설치 및 구성
1. 헤드에서 저장소 복제
git clone https://github.com/MiaAI-Lab/GLM-5.3-Flash-EXL3-2x-DGX-Sparks-TensorFold.git
cd GLM-5.3-Flash-EXL3-2x-DGX-Sparks-TensorFold
cp scripts/local.sh.example scripts/local.sh워커에는 자체 체크아웃이 필요하지 않습니다. 설정 스크립트가 필요한 컨테이너 이미지와 모델 파일을 헤드에서 전송합니다.
2. 워커 주소 설정
scripts/local.sh를 편집하고 WORKER를 워커의 SSH 대상으로 설정하세요.
WORKER=user@192.0.2.2분산 rank는 워커에 연결할 때 사용되는 경로를 통해 통신합니다. WORKER가 다른 네트워크의 주소를 가리키는 경우 FABRIC_PEER를 워커의 사설 CX7 주소로 설정하세요.
WORKER=user@worker-hostname
FABRIC_PEER=192.0.2.23. 필요한 경우 드래프터 선택
기본값은 DRAFTER=dflash2이며, 최대 4개의 동시 요청을 허용하고 약 5~10%의 측정된 디코딩 성능 향상을 제공합니다. 대신 체크포인트의 MTP 헤드를 사용하려면 최초 시작 전에 다음과 같이 설정하세요.
DRAFTER=mtpMTP는 DFlash2 라이선스와 다운로드를 피할 수 있지만 기본적으로 한 번에 하나의 요청만 처리합니다.
4. 두 rank 시작
./start.sh처음 실행할 때 스크립트는 두 시스템을 확인하고, 약 25GB 크기의 컨테이너 이미지를 가져오거나 빌드하며, 헤드에서 체크포인트와 드래프터를 다운로드하고, 워커에 복사한 다음 CUDA 커널을 ~/.cache/tensorfold-glm53에 컴파일합니다.
이후 시작 시에는 일반적으로 각 Spark에 약 80GiB의 가중치를 로드하는 데 2~6분이 걸립니다. 런처는 rank 0의 로그를 추적하고 로딩 진행 상황을 보고하며, 분산 스모크 테스트를 실행한 뒤 포트 8888의 라이브 엔드포인트를 출력합니다.
API를 시작하지 않고 두 시스템을 준비하려면 다음을 실행하세요.
scripts/prepare.sh이미지를 완전히 새로 빌드하려면 다음을 사용하세요.
scripts/prepare.sh --rebuild첫 API 요청 보내기
기본 모델 식별자는 GLM-5.3-Flash-EXL3이며, 기본 URL은 http://<head-address>:8888/v1입니다.
사용 가능한 모델 나열
curl -s http://<head-address>:8888/v1/models채팅 완성 요청 보내기
curl -s http://<head-address>:8888/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "GLM-5.3-Flash-EXL3",
"messages": [
{"role": "user", "content": "Python 피보나치 함수를 작성하세요."}
],
"max_tokens": 2000
}'모델은 기본적으로 답변하기 전에 사고 과정을 거칩니다. 추론 결과는 reasoning_content에 반환되고, 최종 답변은 content에 표시됩니다. 두 단계에 충분한 출력 토큰을 할당하세요. content가 비어 있다면 추론 과정에서 출력 허용량을 모두 사용했을 가능성이 높습니다.
추론 및 샘플링 제어
reasoning_effort를 low, high 또는 max로 설정하세요. 사고 과정 없이 직접 답변을 요청하려면 none을 사용하세요.
curl -s http://<head-address>:8888/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "GLM-5.3-Flash-EXL3",
"messages": [{"role": "user", "content": "TCP를 두 문장으로 요약하세요."}],
"reasoning_effort": "low",
"temperature": 0,
"max_tokens": 1000
}'API는 temperature, top_p, top_k, min_p 및 seed도 지원합니다. 명시적인 시드가 없으면 샘플러가 프롬프트에서 키를 파생하므로 동일한 요청은 동일한 답변을 생성합니다.
이미지 및 동영상 보내기
GLM 비전 타워는 기본적으로 rank 0에서 실행됩니다. 이미지와 동영상은 사용자 메시지의 OpenAI 스타일 콘텐츠 파트로 표현합니다.
로컬 이미지 분석
IMG=$(base64 -w0 photo.jpg)
curl -s http://<head-address>:8888/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "GLM-5.3-Flash-EXL3",
"messages": [{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,'"$IMG"'"}},
{"type": "text", "text": "이 사진에 무엇이 있나요?"}
]
}],
"max_tokens": 2000
}'기본적으로 서버는 data URL을 통한 미디어를 허용합니다. 공개 HTTPS URL도 가져오도록 하려면 VISION_URLS=1을 설정하세요.
지원되는 미디어 제한
- 요청당 최대 이미지 50개, 이미지당 10 MB 및 전체 이미지 데이터 64 MB로 제한됩니다.
- 요청당 최대 동영상 4개, 동영상당 64 MB 및 전체 동영상 데이터 96 MB로 제한됩니다.
- 각 동영상에는 최대 1시간 분량의 영상이 포함될 수 있습니다.
- 요청 본문은 최대 96 MiB이며, base64로 인코딩된 미디어에는 약 70 MB가 남습니다.
- 사진 한 장에는 최대 2,048토큰이 할당되며, 한 요청의 모든 사진은 기본 16,384토큰 예산을 공유합니다.
- 동영상 샘플링은 기본적으로 초당 2프레임이며, 클립 전체에서 최대 128프레임입니다.
동영상의 경우 이미지 콘텐츠 파트를 data:video/mp4;base64,...와 같은 data URL을 포함하는 video_url 파트로 바꾸세요.
텍스트만 필요하다면 VISION=0을 설정하세요. 이렇게 하면 비전 타워가 로드되지 않아 rank 0에서 캐시 사용을 위해 약 1.8 GiB의 메모리를 더 확보할 수 있습니다.
서버 운영 및 모니터링
재시작 및 중지
./start.sh restart
./stop.sh영구 설정을 변경한 후에는 재시작이 필요합니다. 서비스를 중지하면 두 컴퓨터의 GPU 메모리가 해제됩니다.
로그 확인
docker logs -f glm53-flash-tf
ssh <worker> docker logs -f glm53-flash-tf첫 번째 명령은 헤드의 rank 0 로그를 계속 표시합니다. 두 번째 명령은 rank 1 로그를 표시하며, 특히 워커가 예기치 않게 종료될 때 유용합니다.
상태 및 메트릭 확인
curl -s http://<head-address>:8888/health
curl -s http://<head-address>:8888/metrics상태 응답에는 사용 중 상태, 활성 스트림 및 공유 풀 용량이 보고되며, pool_tokens와 pool_free_tokens도 포함됩니다. 메트릭 엔드포인트는 Prometheus 요청, 지연 시간, 첫 토큰까지의 시간 및 상태 지표를 제공합니다.
컨텍스트 및 공유 KV 메모리 이해
기본 구성은 FP8 KV 캐시를 사용하며 각 요청에 최대 1,048,576토큰의 윈도우를 제공합니다. 문서화된 한 시작 시점에는 4개의 요청이 2,684,928토큰으로 측정된 풀을 공유했지만, 정확한 용량은 여유 메모리에 따라 달라집니다.
단일 요청은 전체 윈도우를 사용할 수 있지만, 모든 활성 대화와 보존된 대화는 공용 풀에 들어가야 합니다. 예를 들어 두 대화가 각각 100만 토큰에 근접할 수 있으며, 더 짧은 동시 대화는 남은 용량을 공유할 수 있습니다. 아직 배치할 수 없는 요청은 다른 요청이 완료될 때까지 대기합니다.
맞는 최대 윈도우를 계산하려면 CONTEXT=0을 사용하세요. 단, 이렇게 하면 다른 대화의 프롬프트 상태를 보존할 메모리가 남지 않습니다. 정확한 BF16 KV 저장소로 전환하면 사용 가능한 윈도우가 크게 줄어듭니다.
통합 메모리가 고갈되면 깔끔한 할당 오류 대신 Spark가 멈출 수 있습니다. 메모리 절충을 이해하고 있는 경우가 아니라면 기본 예약 공간을 유지하고, 다른 워크로드가 컴퓨터를 공유한다면
MEMORY_RESERVE_GIB를 늘리세요.
고급 구성
설정은 환경 변수, scripts/local.sh 또는 start.sh 옆의 .env 파일을 통해 제공할 수 있습니다. 우선순위는 환경 변수, scripts/local.sh, .env, 저장소 기본값 순입니다.
한 번의 실행에서 동시성 변경
PARALLEL=2 ./start.sh restartPARALLEL은 DFlash2가 활성화된 경우 1에서 4 사이의 값으로 설정할 수 있습니다. MTP의 기본값은 한 번에 1개의 요청을 처리하는 것입니다.
컨텍스트 윈도우 변경
CONTEXT=524288 ./start.sh restart전체 100만 토큰 윈도우가 필요하지 않은 경우 더 작은 컨텍스트를 사용하면 캐시 부담을 줄일 수 있습니다.
기본 출력 허용량 늘리기
./start.sh restart --max-tokens 16384추가 명령줄 인수는 구성된 기본값 뒤에 추가되어 tensorfold serve로 전달되므로, 해당 인수가 우선 적용됩니다. 지원되는 인수를 확인하려면 ./start.sh --help를 실행하세요.
준비 과정 강제 실행 또는 건너뛰기
PREPARE=1 ./start.sh restart
PREPARE=0 ./start.sh restart첫 번째 명령은 설정 확인 및 준비 과정을 강제로 실행합니다. 두 번째 명령은 이를 건너뜁니다.
프롬프트 재사용 효과적으로 활용
공유 접두사 재사용은 기본적으로 SHARED_PREFIX=1로 활성화됩니다. 반복되는 시스템 프롬프트와 동일하게 유지되는 프롬프트는 다시 프리페치하지 않고 캐시된 상태에서 재개할 수 있습니다. 문서에 기록된 측정 결과에 따르면, 반복되는 64K 토큰 프롬프트는 34초에서 0.07초 미만으로 줄었고, 7.9K 토큰 시스템 프롬프트를 재사용하면 시작 시간이 4.24초에서 0.13초로 단축되었습니다.
캐시 및 가중치 정밀도 선택
KV=fp8이 기본값이며 가장 큰 컨텍스트 윈도우를 활성화합니다.KV=bf16은 정확한 캐시 저장을 사용하지만 사용 가능한 윈도우가 크게 줄어듭니다.DENSE=q4는 밀집 체크포인트 구성 요소의 기본값입니다.DENSE=fp8및DENSE=bf16도 사용할 수 있으며, 메모리 사용량이 서로 다릅니다.
추가 API 기능
채팅 완성 기능 외에도 서버는 /v1/completions, /v1/responses, /v1/models, /tokenize, /detokenize, /health, /metrics를 제공합니다. 토큰화 라우트는 /v1/ 아래에서도 사용할 수 있습니다. 서버는 Anthropic 호환 /v1/messages 엔드포인트를 제공하지 않습니다.
도구 호출은 tools 및 스트리밍 tool_calls를 지원하며, 인수는 제공된 스키마에 따라 형식이 지정됩니다. 구조화된 생성은 json_object, json_schema, guided JSON, 정규 표현식, 선택지, 문법 및 기타 구조화된 출력 필드를 지원하며, 추론이 완료된 후 xgrammar를 통해 적용됩니다.
프롬프트와 max_tokens의 합이 구성된 윈도우를 초과하면 API는 OpenAI 스타일 오류 코드 context_length_exceeded와 함께 HTTP 400을 반환합니다.
일반적인 시작 문제 해결
- 메모리 부족: 시작 시 사용 가능한 GiB가 제한적이라고 표시되면
docker ps를 확인하고 두 Sparks에서 실행 중인 다른 GPU 작업을 중지하세요. - RoCE 장치 또는 경로 없음:
ip -4 addr로 CX7 인터페이스에 IPv4 주소가 있는지 확인하세요. SSH가 다른 네트워크를 사용하는 경우 작업자의 CX7 주소로FABRIC_PEER를 설정하세요. - 작업자 캐시에 쓸 수 없음: 이전 컨테이너가 작업자의 Hugging Face 캐시 소유자를 root로 남긴 경우 소유권을 수정하세요.
- 한 랭크가 종료됨: 두 장비의 로그를 확인하세요. 일반적으로 어느 한쪽에서든 오류가 발생하면 런처가 나머지 랭크도 중지합니다.
- 설정 변경됨: 패치를 수정하거나 TensorFold, 기본 이미지 또는 관련 빌드 입력을 변경한 후에는
scripts/prepare.sh --rebuild를 실행하세요.
성능 기대치
README의 기본 두 Spark 측정 결과에서 일반 텍스트 디코딩 성능은 단일 요청에서 초당 60.4토큰, 동시 요청 4개에서 집계 기준 초당 108.8토큰이었습니다. 구조화된 생성 성능은 초당 114.7~227.9토큰의 집계 처리량을 보였습니다. 프리필 성능은 8,219토큰 프롬프트에서 초당 약 1,952토큰, 니들이 발견된 981,841토큰 니들-인-어-헤이스택 프롬프트에서 초당 1,015토큰이었습니다.
이 수치는 4개 스트림, FP8 KV 캐시, 4비트 밀집 가중치, DFlash2 및 copy 초안, 비전 활성화, GPU 클록 2,200MHz 제한 조건에서 측정되었습니다. 모든 환경에 대한 보장값이 아니라 해당 구성의 참고 결과로 보세요.
결론
이 배포 구성은 복잡한 2노드 TensorFold 설정을 실용적인 시작 워크플로와 OpenAI 호환 API 뒤에 패키징합니다. CX7 연결, SSH 액세스, Docker 런타임, 스토리지 및 작업자 주소가 준비되면 ./start.sh가 준비, 분산 실행, 검증 및 서비스를 처리합니다. 이후 표준 API 클라이언트를 사용하면서 워크로드에 맞게 동시성, 컨텍스트, 추론, 멀티모달 제한 및 메모리 동작을 조정할 수 있습니다.
