콘텐츠로 이동

아키텍처 개요

목차


mlxcel이란

mlxcel은 Rust로 작성된 범용 AI 추론 엔진입니다. 텍스트·비전·오디오·비디오 입력을 처리하는 생성과 멀티모달 이해뿐 아니라 음성 인식·합성, Nemotron VoiceChat 전이중(full-duplex) 음성 대화, 확산 생성, 객체 검출, 밀집·다중 벡터 임베딩, 텍스트·멀티모달 재순위화를 실행합니다. Apple Silicon에서는 Metal과 통합 메모리를 사용하고, NVIDIA GPU에서는 CUDA를, AMD GPU에서는 실험적으로 ROCm을 사용하며 요청 경로에 Python 런타임이 없습니다.

핵심 아키텍처적 결정은 Python을 완전히 우회하여 Rust에서 MLX C++로 직접 바인딩하는 것입니다. 모델별 제어 로직은 Rust에 있고 순전파, 샘플링, 풀링, 정규화, 순위 계산 등의 텐서 연산은 이 네이티브 브릿지를 통해 MLX 런타임에서 실행됩니다.


고수준 런타임 다이어그램

아래 그림은 명령줄 또는 HTTP 진입점에서 모델 종류 감지, 과제별 작업자, 네이티브 텐서 연산, MLX 런타임으로 이어지는 공통 경로를 보여 줍니다. 생성은 배치 또는 순차 스케줄러를 사용하고 임베딩과 재순위화는 MLX 배열을 소유하는 전용 작업자를 사용합니다. 확산, 오디오, 시퀀스 변환 비전, 객체 검출도 같은 로딩·디바이스·FFI 기반 위에서 전용 런타임을 사용합니다.

mlxcel 시스템 고수준 다이어그램 요청은 CLI 또는 서버에서 들어와 Rust 제어 평면을 거치고 mlxcel-core에서 실행되며 FFI 브릿지를 통해 MLX C++를 호출합니다. 진입점 mlxcel CLI generate / embed / rerank mlxcel-server 생성 / 임베딩 / 순위화 제어 평면 (Rust / src) 모델 로딩 모델 종류 탐지 로드 정책 ModelKind / LoadedModel 토크나이저 멀티모달 파이프라인 과제 설정 스케줄러 / 전용 작업자 코어 라이브러리 mlxcel-core 모델 순전파 경로 KV / 인코더 상태 풀링 / 샘플링 레이어 / 순위 연산 전용 런타임 MLX C++ FFI 브릿지 MLX 런타임 Metal / CUDA / CPU
진입점에서 MLX C++ 실행까지 이어지는 생성, 임베딩, 재순위화 고수준 흐름.

명령줄 명령은 체크포인트를 해석하고 과제를 선택하여 일치하는 순전파 경로를 호출합니다. 서버는 배치 스케줄러로 여러 생성 요청을 조율하는 한편 임베딩 작업자와 재순위화 작업자가 각각 모델, 토크나이저, MLX 배열을 소유합니다. 이러한 과제별 경로는 Metal, CUDA, ROCm, CPU에서 같은 네이티브 MLX 바인딩과 공통 텐서 기본 연산을 공유합니다.


제어 평면 vs 데이터 평면

mlxcel은 제어 평면과 데이터 평면 사이에 명확한 경계를 긋습니다.

제어 평면은 src/(메인 크레이트)에 위치하며 다음을 담당합니다.

  • config.json을 읽어 모델 아키텍처를 식별
  • 올바른 로더를 선택하고 실행
  • LoadedModel 열거형 래퍼를 구성
  • 토크나이저 로드 및 관리
  • 채팅 템플릿 적용(minijinja 기반 Jinja2)
  • 설정된 경우 로드 시점 모델 변환 파이프라인 설치
  • 사용자 대향 파라미터로부터 SamplingConfig 조립
  • 이미지 전처리 및 임베딩 프로젝션을 통한 VLM 요청 라우팅
  • 임베딩 풀링, 정규화, 지시문, 길이 제한 결정
  • 재순위화 쌍, 멀티모달 항목, 응답 형식 구성
  • HTTP 서버, 생성 스케줄러, 전용 작업자 큐, 요청 수명 주기 관리

표준 자기회귀 경로에서 제어 평면은 LanguageModel 트레이트와 mlxcel-core의 디코딩 Engine을 통해 데이터 평면과 통신합니다. mlxcel generate는 Engine의 단일 시퀀스 클라이언트인 DirectEngine으로 디코딩하고, 서버의 BatchScheduler는 요청 수락, 틱 정책, 선점, 프롬프트 캐시 조회를 맡되 모든 순전파는 Engine을 거쳐 실행합니다. 임베딩, 재순위화, 오디오, 검출, 디퓨전, 시퀀스 변환 런타임은 과제별 모델 또는 작업자 인터페이스를 사용합니다.

데이터 평면은 src/lib/mlxcel-core/에 위치하며 다음을 담당합니다.

  • LanguageModel::forward()로 autoregressive 모델의 순전파 실행
  • 모든 순전파, 샘플러 추출, 종료 판정을 Engine(open, prefill, step, 파이프라인용 submit/finish_rows 쌍, close)으로 실행. 시퀀스 하나는 크기 1인 단계 배치로 처리
  • KVCache, RotatingKVCache, ChunkedKVCache로 KV 캐시 상태를 관리하며, 이 캐시가 모델 대신 덴스 어텐션과 페이지드 어텐션 중 하나를 고름(KVCache::attend, cache::attend_batched)
  • PrefillPlan으로 프리필 형태를 정하고, compose_token_bias로 토큰 바이어스를 합성한 뒤 RowSampler로 행마다 샘플링
  • src/lib/mlxcel-core/src/lib.rs의 cxx bridge와 연산별 Rust wrapper를 통해 텐서 연산을 MLX C++로 연결
  • 투기적 디코딩 라운드 루프 실행: 프롬프트 조회 드래프터와 풀 모델 드래프터를 위한 엔진 토큰 전용 루프(Engine::verify_round), MTP와 DFlash 드래프터
  • 임베딩·순위 모델이 사용하는 공통 어텐션 마스크, 풀링, 정규화, 사영, 레이어 연산 제공

데이터 평면은 tensor computation에 집중하며 Metal, CUDA, ROCm, CPU에서 실행할 수 있습니다. mlxcel 자체 fused 커널은 src/lib/mlxcelverse/kernels/에 있고 결정된 GPU 백엔드에 따라 선택됩니다. 대부분의 커널에는 Metal, CUDA, ROCm(HIP) 포트가 있으며, 어떤 커널의 포트가 없는 백엔드는 그 단계에서 MLX 그래프 대체 경로를 사용합니다. HTTP routing이나 chat-template policy는 모르지만 model wrapper는 architecture-specific tensor graph를 담습니다.

이렇게 분리하면 각 관심사를 독립적으로 테스트할 수 있습니다. sampling.rs의 샘플링 로직은 간단한 float 텐서로 테스트할 수 있습니다. engine/의 엔진은 스텁 LanguageModel 구현으로 테스트할 수 있습니다. loading/mod.rs의 제어 평면 라우팅은 가중치 로딩을 모킹하여 테스트할 수 있습니다.


주요 설계 원칙

1. Python 의존성 제로

mlxcel은 cxx를 사용하여 Python 인터프리터 없이 MLX C++에 직접 바인딩합니다. 브릿지 선언은 src/lib/mlxcel-core/src/lib.rs에 있고 연산별 Rust 래퍼는 같은 크레이트의 모듈들에 나뉘어 있습니다.

그 결과 Python 시작 시간, Python GIL 경합, Python 객체 오버헤드가 사라집니다. 추론 프로세스가 pip 의존성 없이 단일 네이티브 바이너리가 되는 셈입니다.

2. Config 기반 모델 탐지

mlxcel에 모델 디렉터리를 지정하면 config.json과 관련 체크포인트 메타데이터를 읽습니다. src/models/detection.rs의 get_model_type()은 알려진 생성 키를 ModelType에 매핑하고 architectures, sentence-transformers 풀링 배치, 양방향 표시, 시퀀스 분류 헤드는 일반 생성 분기보다 먼저 임베딩 또는 재순위화 종류를 선택할 수 있습니다.

등록된 아키텍처 변형에는 완전한 분기를 사용합니다. 알 수 없거나 서로 모순된 배치는 잘못된 과제 또는 아키텍처를 조용히 선택하지 않고 명확한 오류로 실패합니다.

일부 모델 타입은 추가 검사가 필요합니다. 예를 들어, hunyuan은 num_experts 필드를 확인하여 MoE와 dense 변형을 구별합니다. 최상위 레벨에 vision_config 필드가 있는 모델은 자동으로 VLM 변형으로 리다이렉트됩니다.

3. 열거형 기반의 완전 분기 처리

로드된 생성 모델은 src/loaded_model.rs의 LoadedModel 열거형에 저장되며 로컬, 분산, 텍스트, VLM, SSM/RNN, 하이브리드 실행 경로를 아우릅니다. 임베딩, 재순위화, 오디오, 객체 검출 모델은 모든 모델 종류를 생성 열거형에 억지로 넣지 않고 과제별 트레이트 또는 런타임 래퍼를 사용합니다.

LanguageModel 트레이트는 delegate_language_model! 매크로로 내부 모델에 위임되며 이 매크로가 모든 variant에 대한 완전한 match arm을 생성합니다. 두 가지 속성이 보장됩니다.

  • 새 모델 variant를 추가하면서 분기 매크로를 업데이트하지 않으면 조용히 잘못된 동작으로 폴백하는 대신 컴파일 오류가 발생합니다.
  • Rust 컴파일러는 모든 variant에 대해 모든 트레이트 메서드가 커버됨을 검증할 수 있습니다.

열거형 접근 방식은 패밀리 정체성을 보존하며 이는 기능 분기(예: VLM 임베딩 경로가 필요한지 결정)에 중요합니다.

4. LanguageModel 트레이트

mlxcel-core/src/generate.rs의 LanguageModel 트레이트는 텍스트 생성을 위한 제어 평면과 데이터 평면 사이의 단일 인터페이스입니다. 다음을 정의합니다.

메서드 목적
forward() 표준 단일 시퀀스 순전파
forward_with_embeddings() 사전 계산된 시각 임베딩을 사용하는 VLM 프리필
forward_batched() 연속 배칭을 위한 배치 디코드
embed_tokens() VLM 병합을 위한 토큰 임베딩 추출
make_caches() 이 모델의 레이어별 KV 캐시 할당
num_layers() 캐시 초기화를 위한 레이어 수
eos_token_ids() 종료 토큰 ID
after_prefill() VLM 프리필 완료 후 호출되는 훅
supports_batching() 모델이 연속 배칭에 참여할 수 있는지 여부

Mamba, Mamba2, Jamba, NemotronH, RWKV7을 포함한 대부분의 패밀리는 supports_batching()에서 true를 반환합니다. 순환 상태나 모델 소유 상태를 SequenceId로 구분해 보관하므로 여러 시퀀스가 하나의 배치 forward 패스를 공유할 수 있습니다. batched_decode_kind()는 모델이 그 패스를 하나의 공유 그래프로 실행하면 BatchedDecodeKind::Native를, 행마다 반복 실행하면 PerRowFallback을 반환하며, 서버는 시작할 때 decode path: native batched forward 또는 decode path: per-row fallback을 로그로 남깁니다. false를 반환하는 모델(예: OCR, Florence-2, Nemotron-Parse, Nemotron VoiceChat, 확산 텍스트 런타임)은 max_batch_size 1로 제한되어 한 번에 시퀀스 하나씩 처리합니다.

5. 모듈식 VLM 파이프라인

비전-언어 모델은 텍스트 생성 파이프라인을 세 가지 추가 단계로 확장합니다.

  1. Visual Encoder: 이미지 백본(SigLIP, CLIP, ViT, MobileNetV5 등)이 픽셀 데이터를 시각적 특성 텐서로 변환합니다.
  2. Projection / Connector: 학습된 프로젝션이 시각적 특성 공간을 언어 모델의 임베딩 공간으로 매핑합니다.
  3. Embedding Merger: 프로젝션된 시각 토큰이 이미지 플레이스홀더 토큰으로 표시된 위치에서 토큰 임베딩 시퀀스에 삽입됩니다.

병합된 임베딩 시퀀스는 프리필 단계에서 일반적인 input_ids 경로를 대체합니다. 프리필 이후의 VLM 디코드 단계는 표준 텍스트 생성과 동일합니다. 즉, 모델이 누적된 KV 캐시를 사용하여 한 번에 하나의 토큰을 처리합니다.

각 VLM 패밀리에는 자체 이미지 전처리 파이프라인과 플레이스홀더 토큰 규약이 있습니다. 이들은 src/multimodal/과 src/vision/ 하위의 패밀리별 모듈에서 처리됩니다.


모듈 맵

디렉터리 역할
src/main.rs CLI 진입점, 인수 파싱, 명령 분기
src/lib.rs 라이브러리 크레이트 루트, 공개 재익스포트
src/models/ 아키텍처별 모델 구현과 ModelType 열거형
src/models/detection.rs config.json에서 ModelType으로의 매핑
src/loading/ 모델 로딩 진입점과 라우트 선택
src/loading/config_backed.rs 표준 config 기반 로더
src/loading/nonstandard.rs 커스텀 디렉터리 로더
src/loading/special.rs 특수 아키텍처를 위한 가중치 기반 로더
src/loading/vlm.rs VLM 디렉터리 로더
src/http_tls.rs 프로세스 전체에서 쓰는 ring rustls 프로바이더를 설치하고 모든 reqwest 클라이언트(모델 다운로드, 미디어 가져오기)를 만듭니다. 서버 인증서는 운영체제 신뢰 저장소로 검증하며, MLXCEL_EXTRA_CA_CERTS로 루트를 추가할 수 있습니다
src/loaded_model.rs LoadedModel 열거형과 LanguageModel 위임
src/loaded_model_capabilities.rs VLM 분기를 위한 기능 헬퍼
src/model_metadata.rs 로드 정책 레지스트리, 라우트 선택 로직
src/backend/ forward()를 실행할 계산 엔진의 경계입니다. 제품 빌드는 MLX를 제공하며 남아 있는 OpenXLA 소스는 루트 Cargo manifest에 노출되지 않습니다. OpenXLA 백엔드 소스 상태 참조.
src/tokenizer/ HuggingFace, SentencePiece, Tiktoken 토크나이저 백엔드
src/multimodal/ VLM 프롬프트 조립과 이미지 토큰 삽입
src/vision/ 이미지 전처리, 시각 인코더, 프로젝션 레이어
src/embeddings/ 임베딩 트레이트, 감지·로딩 지원, 풀링, 정규화, 길이 제한, 배칭, 최대 유사도 합산
src/rerank/ 재순위화 트레이트, 교차 인코더·생성형 점수, 쌍 구성, 배칭
src/execution/runtime.rs 디바이스 선택과 wired 메모리 한도 설정
src/execution/sampling.rs 사용자 파라미터로부터 SamplingConfig 조립
src/lora/ LoRA 어댑터 로딩과 가중치 융합
src/surgery.rs 프로세스 전역 로드 시점 surgery pipeline 연동
src/server/ HTTP 서버, 생성 스케줄러, 임베딩·재순위화 작업자, 요청 라우팅, 전송 형식
src/server/webui/ 번들 관리용 WebUI: 내장 정적 자산, /ui-api/v1 제어 평면, 브라우저 보안 검사. WebUI 참조
src/distributed/ 텐서 병렬, 파이프라인 병렬, 비집계 서빙
src/lib/mlxcel-core/ 데이터 평면: 디코딩 엔진, KV 캐시, 샘플링, FFI
src/lib/mlxcel-surgery/ 런타임 모델 변환 연산과 YAML 해석
src/lib/mlxcel-core/src/lib.rs MLX C++에 대한 cxx::bridge 선언과 공개 Rust 래퍼
src/lib/mlxcel-core/src/generate.rs LanguageModel 트레이트
src/lib/mlxcel-core/src/engine/ Engine(모델과 CachePool 소유; open, prefill, step, submit/finish_rows, close), direct.rs의 DirectEngine(generate, 벤치마크, 추론 세션이 쓰는 원시 완성 클라이언트), speculative.rs와 verify_round.rs(generate --prompt-lookup, --draft-model, 서버가 공유하는 토큰 전용 투기 디코딩 루프), rows.rs(행별 샘플링과 종료 판정)
src/lib/mlxcel-core/src/prefill_plan.rs PrefillPlan: 채택한 접두부 건너뛰기, 이력 경계 분할, 청크 조각, 패딩 프리필 타일
src/lib/mlxcel-core/src/cache.rs KVCache, RotatingKVCache, ChunkedKVCache, CachePool
src/lib/mlxcel-core/src/cache/attend.rs 캐시가 소유하는 어텐션 분기: KvAttention, KVCache::attend, cache::attend_batched
src/lib/mlxcel-core/src/sampling.rs 토큰 샘플링과 페널티 로직
src/lib/mlxcel-core/src/sampling_row_step.rs 엔진이 서버와 CLI 양쪽에서 실행하는 행별 샘플링 단계 RowSampler
src/lib/mlxcel-core/src/sampling_token_bias.rs compose_token_bias(logit_bias, 언어 바이어스, 토큰 억제)
src/lib/mlxcel-core/src/speculative/ 토큰 전용 드래프터(PromptLookupDrafter, FullModelDrafter)와 MTP 라운드 루프
src/lib/mlxcelverse/ MLX C++ 빌드: CMakeLists.txt가 고정된 MLX 커밋을 받아오고, overlays/{cpu,metal,cuda,rocm}/가 libmlx 컴파일 전에 업스트림 백엔드 파일을 대체하며, kernels/에 mlxcel 자체 fused 커널과 런처가 있습니다
src/lib/mlxcel-core/src/drafter/ DFlash 계열(Qwen 3.5 DFlash, LFM2 DSpark, Muse Glimmer assistant, Laguna DFlash), Gemma 4 assistant, Qwen 3.5 MTP drafter 구현

두 개의 바이너리

mlxcel 워크스페이스는 두 개의 바이너리를 생성합니다.

mlxcel은 커맨드라인 도구입니다. 다음과 같은 사용자용 서브명령어를 지원합니다.

  • run: 위치 기반 모델 인자를 대화형 채팅 모드로 실행하거나, -p를 사용해 한 번 생성합니다. repo-id와 bare 이름 인자는 첫 사용 시 자동 다운로드됩니다.
  • generate(별칭 gen): 프롬프트에 대해 생성 패스를 실행하거나, 프롬프트를 생략하면 같은 대화형 REPL로 진입합니다. 모든 모델, 생성, 샘플링 옵션을 받습니다.
  • embed: 텍스트 또는 이미지 임베딩을 오프라인으로 만들고 코사인 또는 최대 유사도 합산 비교를 출력합니다.
  • rerank: 질의에 대한 문서 점수를 오프라인으로 계산하고 순위를 출력합니다.
  • inspect: 로컬 경로, repo-id, bare 모델 이름에 대해 텐서를 로드하지 않고 로드 전 메모리 예산을 출력합니다.
  • detect: RT-DETRv2 객체 검출을 이미지에 실행하고 text 또는 JSON 박스를 출력합니다.
  • serve: 생성, 임베딩, 재순위화, 오디오, 유틸리티 HTTP 서버를 시작하며 서버와 과제별 모델 제공자 설정을 받습니다.
  • list(별칭 ls): 로컬 store에 다운로드된 모델 스냅샷을 나열하며 --json / -q / -v / --sort로 출력 형식을 조절합니다.
  • arch(별칭 supported): 지원되는 모든 모델 아키텍처를 계열별로 묶어 출력합니다.
  • download: HuggingFace 저장소 스냅샷을 기본적으로 전역 mlxcel store에 다운로드하며 --local-dir로 정확한 디렉터리를 지정할 수 있습니다.
  • rm: 관리 대상 mlxcel store에서 다운로드된 모델 스냅샷을 제거합니다.
  • tune: 특정 모델·프롬프트에 대한 Metal fast-path 후보를 benchmark하고 tuning cache를 기록합니다.

mlxcel-server는 serve 기능만 따로 담은 전용 서버 바이너리로, 서버 실행 파일 하나만 배포하면 되는 환경을 겨냥합니다. 서버 전용 배포 이미지에서도 Python 도구 없이 모델 스냅샷을 받을 수 있도록 공유 download 하위 명령어도 제공합니다.

두 바이너리는 모든 라이브러리 코드를 공유합니다. 차이점은 진입점과 인수 인터페이스뿐입니다.


환경 설정

여기서는 두 가지 기반 런타임 변수를 요약합니다. 메모리 제한, 스케줄러, 캐시, 투기 디코딩, 임베딩, 재순위화, 미디어, 진단 제어를 포함한 전체 목록은 환경 변수를 참고하십시오.

변수 기본값 값
MLXCEL_DEVICE gpu gpu, metal, cpu
MLXCEL_WIRED_LIMIT GPU 최대 메모리 max, 0, none, NGB, NMB, 바이트

MLXCEL_DEVICE는 연산 백엔드를 선택합니다. Apple Silicon에서 gpu와 metal은 동일하며 MLX의 Metal 백엔드를 통해 연산을 라우팅합니다. cpu로 설정하면 모든 연산이 CPU에서 강제 실행되는데 속도는 훨씬 느리지만 디버깅에 유용합니다.

MLXCEL_WIRED_LIMIT는 MLX가 메모리에서 제거되지 않도록 고정(wire)하는 GPU 메모리 양을 제어합니다. 기본 동작은 Python mlx-lm과 동일합니다. 즉, 대형 모델의 모델 가중치가 메모리에 상주하도록 총 GPU 메모리 크기로 한도가 설정됩니다. 0 또는 none으로 설정하면 고정이 완전히 비활성화됩니다. 여러 프로세스가 GPU 메모리를 공유하는 시스템에서는 24GB와 같은 명시적 값으로 세밀하게 제어할 수 있습니다.