modular/modular) 딥다이브Modular Platform은 "AI를 만들고 배포하는 전 과정을 하나의 스택으로 통합한다"를 내건 플랫폼이고, 이 저장소는 그중 오픈소스로 공개된 부분들을 모아 둔 곳이다. README가 스스로 밝히는 두 주인공은 MAX 프레임워크와 Mojo 언어다. Mojo는 "언어", MAX는 "그 언어 위에 세운 추론 플랫폼"이라고 보면 관계가 깔끔하다.
Mojo는 Python의 문법·생태계에 시스템 프로그래밍(성능·저수준 제어)과 메타프로그래밍을 결합한 새 언어다. README의 표현으로는 "연구와 프로덕션 사이의 간극을 메우는 언어"이자 "CPU·GPU를 겨냥해 극도로 빠른 코드를 쓰기 위한 언어"다. MAX는 그 위에서 도는 "대형 언어모델(LLM)을 위한 고성능 추론 서버"로, max serve 한 줄이면 OpenAI 호환 엔드포인트가 뜬다 — 기존에 OpenAI API로 짠 코드를 그대로 붙일 수 있다는 뜻이다.
지금의 AI 스택은 국제회의장 같다. Python이 사회를 보고, 속도가 필요하면 C++ 통역사를 부르고, NVIDIA GPU에는 CUDA 통역사, AMD·Apple에는 또 다른 통역사를 세운다. 통역이 한 단계 낄 때마다 비용과 오해가 생긴다.
Mojo는 "그 모든 상대와 직접 대화하는 한 명의 다국어 화자"를 지향한다. 같은 소스 코드가 CPU에서도, NVIDIA에서도, AMD에서도, Apple 실리콘에서도 돈다. MAX는 그렇게 만든 빠른 부품(커널)들을 엮어 실제 모델을 서빙하는 "무대 운영팀"이다.
가장 빠른 체험은 작은 모델 하나를 서빙해 OpenAI API처럼 불러 보는 것이다.
# 1) 설치 (pixi 권장) 후 프로젝트에 max 추가
pixi add max-all
# 2) 작은 모델을 OpenAI 호환 서버로 띄우기
max serve --model Qwen/Qwen2.5-0.5B-Instruct
# → http://localhost:8000/v1/... 에 OpenAI 호환 엔드포인트가 열린다
추론 엔진·서빙 스택은 이미 많다(vLLM, TensorRT-LLM, llama.cpp, PyTorch 등). 그럼에도 modular/modular가 2026년에 다시 상위 트렌딩에 오른 건 네 가지가 겹쳤기 때문이다.
저장소 HEAD가 Mojo 1.1.0·MAX 26.6.0으로 락파일을 고정하고 있다. 릴리스 노트는 v24.1(2024 초)부터 v26.5(2026-08-11)까지 이어진다. 초창기 블로그에서 보던 실험 언어가 안정 버전(1.x) 궤도에 들어섰다는 신호다. (참고: 이 때문에 예전 문법과 지금 문법이 다르다 — 뒤 6번에서 짚는다.)
이게 핵심 차별점이다. max/kernels/README.md는 지원 하드웨어로 NVIDIA GPU(T4·A10G·L40·A100·H100·RTX 40 시리즈)와 AMD GPU(MI355X·MI325X·Radeon RX 9000)를 명시하고, v26.5 노트는 Apple 실리콘 GPU를 M1까지 지원한다고 밝힌다. 이 GPU 커널들이 CUDA C가 아니라 Mojo로 쓰였다는 점이 결정적이다 — 저장소 전체에서 CUDA .cu 파일은 단 2개뿐이고, GPU 코드는 3,681개의 .mojo 파일이 담당한다.
README는 "우리는 Modular Platform을 계속 더 오픈소스로 공개하고 있다"고 말한다. 컴파일러(KGEN) 같은 핵심부는 아직 닫혀 있지만, Mojo 표준 라이브러리와 MAX 가속기 라이브러리(GPU 커널), 모델 아키텍처, 예제는 열려 있고 기여도 받는다. "AI 컴퓨팅의 민주화(democratizing AI compute)"라는 슬로건 아래, 그동안 벤더 종속적이던 GPU 커널이 읽고 고칠 수 있게 됐다는 서사가 개발자들의 관심을 모았다.
max/python/max/pipelines/architectures/에는 95개 모델 아키텍처가 들어 있다 — DeepSeek V3/V3.2, Llama3, Gemma3/4, GLM5, Qwen, GPT-OSS, FLUX2, Whisper 등. 여기에 FP8·NVFP4·MXFP4 양자화, 투기적 디코딩(MTP), 도구 호출, 구조화 출력까지 최신 기법이 붙는다. "새 모델이 나오면 곧 MAX로 서빙 가능"에 가깝다.
| 도구 | 강점 | MAX/Mojo와의 차이 |
|---|---|---|
| vLLM | 인기 있는 LLM 서빙 엔진, PagedAttention | 주로 NVIDIA 중심(Python+CUDA). MAX는 한 언어로 NVIDIA·AMD·Apple을 겨냥 |
| TensorRT-LLM | NVIDIA에서 최고 성능 | NVIDIA 전용·폐쇄적. MAX는 크로스벤더 + 커널이 오픈 |
| llama.cpp | 가볍고 어디서나 도는 C/C++ 추론 | 수작업 최적화. Mojo는 컴파일러(MLIR)로 하드웨어별 코드를 생성 |
| modular/modular | 한 언어로 모든 하드웨어 + OpenAI 호환 서버 | Mojo(언어) + MAX(플랫폼)를 함께 배포, GPU 커널 오픈소스 |
이 저장소는 "언어를 만드는 부분"과 "그 언어로 만든 플랫폼"이 한 지붕 아래 있는 대형 모노레포다. 파일 수로 보면 Mojo가 3,681개로 1위 — 이 플랫폼은 말 그대로 "Mojo가 먼저(Mojo-first)"이고, C++는 컴파일러·런타임 같은 내부 엔진에만 남아 있다. 스택을 "언어·컴파일러 층", "빌드·의존성 층", "런타임 표면(서빙) 층"으로 나눠 보면 한눈에 들어온다.
| 요소 | 역할 |
|---|---|
Mojo (.mojo 3,681개) | 표준 라이브러리(mojo/stdlib, 패키지명 std) + 모든 GPU/CPU 커널(max/kernels) + 예제. 이 플랫폼의 주인공. |
| KGEN (C++, 비공개) | Mojo 컴파일러. 이름은 "kernel generator"의 약자 — "KGEN을 보면 Mojo를 떠올려라"라고 README가 안내. MLIR 기반. |
| AsyncRT (C++, 비공개) | 비동기 런타임. 하드웨어 독립적인 병렬 CPU 연산의 저수준 지원. MLIR·LLD 같은 병렬 컴파일러 인프라도 호스팅. |
| vendored GPU 수학 | _cublas·_cudnn·_cufft·_miopen·_rocblas — NVIDIA/AMD 벤더 수학 라이브러리 바인딩을 동봉. |
| 요소 | 역할 |
|---|---|
| Bazel (bzlmod) | 전체를 Bazel로 빌드(BUILD/.bzl 파일 690개). MODULE.bazel이 커스텀 Mojo 툴체인과 LLVM 소스 빌드를 끌어온다. ./bazelw 래퍼로 실행. |
| Pixi + conda + uv | 실제 환경 관리는 Pixi가 담당(pixi.toml). conda 채널 conda.modular.com/max-nightly에서 mojo·max를 받는다. Bazel 내부 pip 의존성은 uv.lock. |
pyproject.toml | 흥미롭게도 런타임 의존성이 없다 — black(대상에 .mojo 포함)·ruff·mypy 설정만 담는다. requires-python ≥ 3.10. |
| 요소 | 역할 |
|---|---|
| MAX 추론 서버 | max/python/max/serve. OpenAI 호환 HTTP + SSE 스트리밍. 요청→토큰 생성 파이프라인→스케줄러 큐→워커→모델로 흐른다. |
| MAX Graph API | max/python/max/graph. 계산 그래프를 Python으로 조립→컴파일→실행. 여기에 Mojo 커널을 커스텀 연산(custom op)으로 꽂을 수 있다. |
| Pipelines · nn | pipelines/architectures(95개 모델) + nn(고수준 그래프 연산). 새 모델을 그래프로 기술. |
| KV cache · xgrammar | 페이지드 KV 캐시(kv_cache) + 구조화 출력용 xgrammar 동봉. 최신 서빙 기능의 뒷단. |
스택에서 두 가지 취향이 읽힌다. 첫째, "저수준은 Mojo, 조립은 Python" — 성능이 목숨인 커널은 Mojo로 쓰고, 모델을 엮고 서빙하는 상위 로직은 익숙한 Python으로 둔다. 둘째, "컴파일러로 이식성을 산다" — 하드웨어마다 손으로 최적화하는 대신, MLIR 기반 컴파일러(KGEN)가 같은 Mojo 소스를 각 하드웨어용 코드로 낮춘다(lowering). 그래서 CUDA를 직접 쓰지 않고도 여러 GPU를 겨냥할 수 있다.
Modular Platform은 "층층이 쌓인 탑"으로 이해하면 좋다. 맨 아래엔 Mojo 언어와 그 컴파일러(KGEN)가 있고, 그 위에 하드웨어별 커널, 다시 그 위에 계산 그래프(MAX Graph), 모델 파이프라인, 그리고 맨 위에 사용자가 만나는 OpenAI 호환 서버가 있다.
이 그림의 핵심은 "위층은 하드웨어를 모른다"는 점이다. 서빙·그래프·파이프라인은 "무엇을 계산할지"만 기술하고, "그걸 이 GPU에서 어떻게 빠르게 돌릴지"는 아래층(커널 + 컴파일러)이 책임진다. 덕분에 NVIDIA용/AMD용 코드를 따로 짜지 않아도 된다.
Mojo가 여러 하드웨어를 겨냥할 수 있는 비결은 MLIR(Multi-Level Intermediate Representation)이다. MLIR은 LLVM 창시자가 만든 "컴파일러를 위한 레고 블록" 같은 기반으로, 고수준 표현을 여러 단계로 점점 낮춰(lowering) 최종 하드웨어 코드로 만든다. Mojo는 "AI 시대를 위해 처음부터 설계된 언어"를 표방하며, 이 MLIR 위에서 CPU와 여러 벤더 GPU를 같은 소스로부터 생성한다 — 이것이 "N개 언어 문제"를 푸는 방식이다.
MAX의 실전 설계를 가장 잘 보여 주는 패턴이다. 모델을 계산 그래프로 조립할 때, 특정 연산만 직접 만든 Mojo 커널로 대체할 수 있다. 아래는 저장소 예제(max/examples/custom_ops/addition.py)의 뼈대다 — Python으로 그래프를 짜되, custom_extensions로 Mojo 커널 폴더를 가리킨다.
from max.driver import CPU, Accelerator, accelerator_count
from max.engine import InferenceSession
from max.graph import DeviceRef, Graph, TensorType, ops
# 가속기가 있으면 GPU, 없으면 CPU 자동 선택
device = CPU() if accelerator_count() == 0 else Accelerator()
graph = Graph(
"addition",
forward=lambda x: ops.custom( # ← 내가 만든 커널을 연산으로 사용
name="add_one", values=[x],
device=DeviceRef.from_device(device),
out_types=[TensorType(...)],
)[0].tensor,
input_types=[TensorType(...)],
custom_extensions=[mojo_kernels], # ← .mojo 커널이 든 폴더
)
session = InferenceSession(devices=[device])
model = session.load(graph) # 그래프를 컴파일해 로드
이 구조 덕분에 "표준 연산은 MAX가 제공하는 걸 쓰고, 병목이 되는 특정 연산만 내가 Mojo로 최적화해 끼워 넣기"가 가능하다. 연구자가 새 어텐션 변형이나 양자화 커널을 실험할 때 특히 강력하다.
사용자 표면은 철저히 "OpenAI처럼"이다. max serve는 /v1/chat/completions 같은 엔드포인트를 열고, 내부적으로는 요청을 스케줄러 큐에 넣어 여러 요청을 함께 처리(연속 배칭)한다. 긴 문맥을 효율적으로 다루는 페이지드 KV 캐시, 토큰을 미리 여러 개 예측하는 투기적 디코딩, JSON 스키마를 강제하는 구조화 출력이 여기에 얹힌다.
이 저장소의 소스 코드는 Apache License v2.0 with LLVM Exceptions로 열려 있어 읽고 배우고 고치기 좋다. 하지만 MAX 제품의 사용·배포는 별도의 Modular Community License를 따른다. "코드는 오픈소스지만 제품 상업 배포엔 별도 약관"이라는 이중 구조이니, 실제 서비스에 올리기 전 라이선스 조건을 반드시 확인해야 한다. 또한 모델 가중치는 실행 시 Hugging Face에서 내려받으며, 각 모델의 라이선스는 사용자 책임이다.
최상위 폴더가 곧 "무엇이 언어이고 무엇이 플랫폼인가"를 그대로 보여 준다. 크게 Mojo 언어(mojo/), MAX 플랫폼(max/), 그리고 C++로 된 엔진들(KGEN·AsyncRT·Cache·Support 등)로 나뉜다.
이 저장소의 "열림/닫힘"은 폴더 경계로 갈린다 — mojo/stdlib와 max/kernels는 오픈소스이고 기여도 받지만, 컴파일러 KGEN과 런타임 AsyncRT 같은 C++ 엔진은 소스는 보이되 기여는 받지 않는다. 그래서 "Mojo를 공부하고 커널에 기여하고 싶다"면 mojo/와 max/kernels가 놀이터이고, 컴파일러 내부 동작이 궁금하면 KGEN/을 읽되 고치기보다 이해 목적으로 보는 게 맞다.
operators/my_complex.mojo(구조체·트레이트·연산자 오버로딩)와 homepage/homepage_examples.mojo(GPU 커널·Python 연동·컴파일타임 메타프로그래밍을 한 파일에)가 특히 좋다. "언어 전체 문법을 한 장에" 보여 주는 압축판이다.modular/modular는 "현대 AI 시스템 소프트웨어"의 살아 있는 교과서다. 관심 방향에 따라 배울 게 다르다.
Mojo는 Python 문법을 따르지만 시스템 언어의 무기를 얹었다. 저장소 예제(my_complex.mojo)의 구조체는 이렇게 생겼다 — 트레이트를 구현하고 연산자를 오버로딩한다.
from std.math import sqrt
@fieldwise_init
struct Complex(Boolable, Equatable, Writable):
var re: Float64
var im: Float64
def __init__(out self, re: Float64): # out = 초기화되는 결과
self.re = re
self.im = 0.0
def __add__(self, rhs: Self) -> Self:
return Self(self.re + rhs.re, self.im + rhs.im)
def __iadd__(mut self, rhs: Self): # mut = 자신을 변경
self.re += rhs.re
self.im += rhs.im
여기서 배우는 것: var로 값을 선언하고, 소유권/변경 표시(mut=변경 가능, out=결과로 초기화), 트레이트 기반 다형성, 연산자 오버로딩이다. Python 개발자가 "성능을 위해 타입과 소유권을 명시적으로 다루는 법"을 자연스럽게 익힐 수 있다.
Mojo는 GPU를 1급 시민으로 다룬다. DeviceContext로 버퍼를 만들고, global_idx로 스레드 인덱스를 잡고, 커널 함수를 그리드/블록으로 실행한다 — CUDA C의 개념을 그대로, 그러나 Python스러운 문법으로. "GPU 프로그래밍을 배우고 싶지만 CUDA C의 문법 장벽이 부담"이던 사람에게 Mojo의 GPU 예제는 가장 부드러운 입구다. (단, v26.5부터 GPU API가 std.gpu.*에서 max.gpu.*로 옮겨졌다.)
"같은 소스가 어떻게 여러 하드웨어 코드가 되는가"의 실물을 볼 수 있다. KGEN 자체는 닫혀 있지만, MLIR·lowering·컴파일타임 메타프로그래밍(comptime) 개념은 문서와 stdlib에서 배울 수 있다. 컴파일러·언어 설계에 관심 있다면 드문 실전 사례다.
max/python/max/serve는 "프로덕션 LLM 서버를 어떻게 짜는가"의 표본이다 — OpenAI 호환 라우팅, SSE 스트리밍, 스케줄러 큐(연속 배칭), 페이지드 KV 캐시, 투기적 디코딩. vLLM 같은 엔진의 내부가 궁금했다면 읽을 가치가 크다.
bzlmod(MODULE.bazel), 커스텀 언어 툴체인 등록, LLVM을 소스로 빌드하는 방식 등 "언어+플랫폼을 한 저장소에서 재현 가능하게 빌드하는" 기법을 배운다. Pixi로 과학계 파이썬 환경을 재현하는 패턴도 덤이다.
MAX 서버 자체는 GPU 없이 CPU로도 돌지만(가속기가 없으면 자동 폴백), 실전 추론엔 GPU가 사실상 필요하다. OS 지원 범위가 다소 좁은 편이다(현재 Windows 미지원 — WSL/컨테이너 사용).
| 항목 | 요구 / 참고 |
|---|---|
| OS / 플랫폼 | linux-64, linux-aarch64, osx-arm64(Apple 실리콘). macOS는 인텔 맥이 아니라 Apple 실리콘만. |
| Python | ≥ 3.10. |
| NVIDIA GPU | T4 · A10G · L40 · A100 · H100 · RTX 40 시리즈 등. |
| AMD GPU | MI355X · MI325X · Radeon RX 9000 등. |
| Apple GPU | M1 이상(v26.5 기준). M5용 최적화(플래시 어텐션 프리필 등)도 포함. |
| CPU 폴백 | 가속기가 없으면 자동으로 CPU 실행(accelerator_count()==0이면 CPU()). |
| 설치 방법 | Pixi 권장(pixi add max-all) · uv(uv add "max[all]") · pip(pip install modular) · conda 채널 · Docker 컨테이너. |
Pixi에서 pixi add max-all은 nightly(최신), pixi add "max-all==26.5"는 특정 안정판을 고정한다. 처음 공부용이라면 작은 모델(Qwen/Qwen2.5-0.5B-Instruct)로 CPU에서 max serve를 띄워 흐름부터 익힌 뒤, GPU가 있는 환경으로 옮겨 가는 순서를 권한다. pip 설치는 Mojo LSP·디버거가 빠져 있으니, 언어를 본격적으로 만질 거면 Pixi/conda 쪽이 낫다.
Pixi로 max-all을 설치한 뒤 max serve --model Qwen/Qwen2.5-0.5B-Instruct로 서버를 띄운다. 그다음 익숙한 openai Python SDK나 curl로 /v1/chat/completions를 호출해 응답을 받아 본다. 목표: "기존 OpenAI 코드가 그대로 붙는다"를 몸으로 확인하고, 서빙 전체 흐름을 감 잡기.
mojo/examples/operators/my_complex.mojo를 참고해 나만의 작은 구조체(예: 2D 벡터)를 만들고 __add__·__eq__를 구현한 뒤 mojo run으로 돌린다. 배우는 것: var·fn/def·mut/out 소유권 표시·트레이트 구현. Python과 닮았지만 어디가 다른지 직접 부딪혀 익히기.
mojo/examples/homepage/의 GPU 예제를 따라, DeviceContext로 버퍼를 만들고 global_idx로 인덱스를 잡는 벡터 덧셈 커널을 그리드/블록으로 실행한다(가속기 필요). 배우는 것: GPU 프로그래밍의 기본기(스레드·블록·디바이스 버퍼)를 CUDA C 없이. has_accelerator()로 환경 분기하는 법도.
max/examples/custom_ops/addition.py를 그대로 돌려 본 뒤, 딸린 .mojo 커널(add_one)을 조금 바꿔(예: add_two, 혹은 스칼라 곱) 그래프가 다르게 동작하게 만든다. 배우는 것: 계산 그래프 조립 → custom_extensions로 커널 연결 → InferenceSession.load 컴파일의 전체 사이클.
max/examples/custom-models/를 참고해 max serve --custom-architectures ...로 파이프라인에 없는 모델 구조를 직접 정의해 서빙하거나, max benchmark로 처리량·지연을 측정한다. 여유가 되면 --speculative-method mtp(투기적 디코딩)나 --enable-structured-output을 켜 효과를 비교한다. 배우는 것: 파이프라인 아키텍처 정의 방식과 실전 성능 튜닝 감각.
| 주차 | 주제 | 무엇을 · 왜 |
|---|---|---|
| 1주 | Mojo 문법 기초 | fn/def·var·struct·트레이트. Mojo 매뉴얼 + mojo/examples/operators. Python과 닮은 곳/다른 곳부터. |
| 2주 | 소유권 · 값 표현 | mut/out/owned, 값 vs 참조, SIMD·벡터화. "왜 빠른가"를 문법 수준에서 이해. |
| 3주 | GPU 프로그래밍 | DeviceContext·global_idx·그리드/블록, max.gpu.*. CUDA 개념을 Mojo로 재학습. |
| 4주 | MAX Graph API | ops·그래프 조립·custom op·InferenceSession. 추론 엔진이 "그래프를 컴파일한다"는 감각. |
| 5주 | LLM 서빙 | pipelines·페이지드 KV 캐시·양자화(FP8/NVFP4)·투기적 디코딩. 프로덕션 서버의 부품들. |
| 6주 | 컴파일러 · 빌드 | MLIR·lowering 개념 + Bazel(bzlmod)·Pixi. "언어+플랫폼을 재현 가능하게 빌드"의 마무리. |
modular/modular는 저장소가 1만 개 파일이라 처음엔 압도적이다. 하지만 뿌리는 하나 — Mojo라는 언어다. 1~3주에 Mojo 문법과 GPU 기본기를 잡으면, MAX의 커널(max/kernels)도 서빙 코드도 "같은 언어로 쓴 응용"으로 읽힌다. 반대로 서빙부터 파고들면 Python 껍데기만 보고 정작 성능의 핵심인 Mojo 커널을 놓치기 쉽다. 언어가 먼저, 플랫폼이 나중이 이 레포에선 특히 유효하다.
max serve로 OpenAI 호환 엔드포인트를 띄운다. Graph API·pipelines(모델)·kernels(Mojo 커널)로 구성.ops.custom(...) + custom_extensions=[커널폴더]. "표준 연산은 MAX, 병목만 내 커널로"를 가능케 한다.comptime x = ...), 컴파일 시점 분기·반복(comptime if/comptime for)을 한다. 예전 alias·@parameter를 대체한 2026년 문법.mut=호출자의 값을 변경, out=결과로 초기화되는 인자, owned=소유권을 넘겨받음. (예전 inout/let/borrowed를 대체.) 안전성과 성능을 동시에 잡는 장치.vectorize로 반복을 자동 벡터화한다. CPU 성능의 핵심.--speculative-method mtp로 지원.MODULE.bazel). Pixi=conda 기반 환경·패키지 관리자로, 이 프로젝트가 mojo·max를 받고 실행 환경을 재현하는 도구.