본문으로 건너뛰기
5분 AI.
GITHUB TRENDING RUST WEEKLY #6 딥다이브 · 2026-10-23 분석

uzu 딥다이브
— AI의 다음 한 토큰이 나오기까지

추론 라이브러리

빠른 판단

무엇
모델 가중치를 Metal로 실행하고 대화·분류 API와 언어별 바인딩을 제공하는 Rust 로컬 추론 엔진
이럴 때
Apple 앱 안에 모델 실행과 응답 스트리밍을 내장하거나 Rust·GPU 메모리 계층을 직접 조정할 때
입력
지원 모델 가중치와 대화·분류 입력
결과
앱에서 소비할 생성 토큰 스트림·분류 결과
짧은 대화 API 뒤에는 모델 파일 로딩, 토큰 변환, GPU 명령, 메모리 관리, 취소 처리가 숨어 있습니다. uzu는 이 과정을 Rust와 Metal로 구현하고 Python·Swift·TypeScript 앱에 연결하는 추론 엔진입니다. Rust 약 10.5만 줄을 모두 읽을 필요는 없습니다. 공개 API에서 연산 커널까지 이어지는 길을 따라가며, 로컬 AI를 만드는 시스템 설계를 배워 봅니다. (trymirai/uzu · ⭐2,546 · 포크 146 · MIT · 2026-10-23 GitHub 기준)
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

AI 모델과 앱 사이에 놓이는 실행 장치

uzu는 이미 학습된 AI 모델을 기기에서 실행하고, 그 결과를 앱이 쓰기 좋은 대화·분류 API로 바꾸는 Rust 라이브러리입니다. 모델을 처음부터 훈련하는 프로젝트와는 목적이 다릅니다. 모델의 가중치를 읽고, 입력에 맞는 계산을 수행하고, 다음 토큰을 선택하는 일이 중심입니다.

이 저장소에서 배울 핵심은, 한 줄의 대화 요청을 실제 하드웨어 연산으로 바꾸는 여러 계층의 연결 방식입니다. 사용자 인터페이스를 만들 사람도, Rust를 배울 사람도, GPU에 관심 있는 사람도 각자 시작할 입구가 있습니다.

용어부터
추론과 토큰
추론은 학습을 마친 모델에 입력을 주고 출력을 계산하는 과정입니다. 토큰은 모델이 처리하는 텍스트 조각입니다. 한 글자나 한 단어와 항상 일치하지 않으며, 모델은 토큰의 정수 번호를 받아 다음 번호의 점수를 계산합니다.
전체를 잡는 비유

모델이 악보라면, uzu는 악보를 읽어 실제 소리를 내는 연주 장치입니다

악보만 내려받아서는 소리가 나지 않습니다. 악보를 읽는 사람, 악기, 박자 관리가 필요합니다. 모델 파일도 마찬가지입니다. 가중치를 읽는 로더, 계산하는 CPU·GPU, 결과를 순서대로 전달하는 스트림이 함께 있어야 앱이 답변을 보여줄 수 있습니다.

Python·Swift·TypeScript 바인딩은 같은 연주 장치에 붙인 서로 다른 조작 패널입니다. 핵심 계산을 언어마다 다시 만드는 대신 Rust 구현을 함께 사용합니다.

사용자 관점의 흐름은 다섯 단계입니다

  1. Engine::new로 설정·저장소·모델 목록·백엔드를 준비합니다.
  2. engine.model로 모델을 찾고 engine.download로 필요한 파일을 받습니다.
  3. engine.chat으로 대화 세션을 만듭니다.
  4. session.reply 또는 스트리밍 API에 메시지를 전달합니다.
  5. 토큰 출력을 대화 메시지로 해석해 앱에 돌려줍니다.
// README의 Rust Quick Start와 같은 대화 호출 흐름
// model은 조회·다운로드를 마친 값이라고 가정합니다.
let session = engine.chat(model, ChatConfig::default()).await?;
let messages = vec![
    ChatMessage::user().with_text("추론 엔진을 쉽게 설명해 줘".to_string()),
];
let replies = session.reply(messages, ChatReplyConfig::default()).await?;
if let Some(reply) = replies.last() {
    println!("{}", reply.message.text().unwrap_or_default());
}

위 코드는 흐름을 보여주는 부분 예시입니다. 가져오기 선언과 초기화까지 포함한 예시는 README의 Quick Start에 있습니다. 실제 앱에서는 다운로드 실패, 모델 부재, 사용자의 취소도 처리해야 합니다.

읽기의 출발점
동일한 Engine 이름이 두 계층에 있습니다

uzu::engine::Engine은 모델 관리와 세션을 담당하는 공개 창구입니다. uzu_engine::engine::Engine<B>은 선택한 백엔드의 계산 문맥을 소유합니다. 이름이 같아도 책임은 다르므로, 파일의 경로와 타입 인수를 함께 보세요.

2왜 주목받는가

순위보다 중요한 것은 이 설계가 풀려는 문제

uzu는 2026-10-23 분석 대상인 GitHub Trending Rust Weekly #6입니다. 다만 이 순위만으로 특정 기능이 유행을 만들었다고 단정할 수는 없습니다. 여기서는 코드와 배포 구성이 보여주는 관심을 끌 만한 지점을 해석합니다.

2-1. 로컬 추론을 앱 기능으로 묶습니다

GPU 계산 라이브러리만 있어도 제품을 만들기는 어렵습니다. 모델 목록, 다운로드 진행률, 대화 상태, 토큰 스트림이 추가로 필요합니다. crates/legacy/uzu/src/engine/mod.rs의 Engine::new는 이 기능들을 묶습니다. apps/mirai-gui의 데스크톱 앱과 apps/uzu-pi-extension의 코딩 에이전트 확장은 같은 엔진을 사용하는 응용 사례입니다.

앱 제작자에게는 이 결합이 장점입니다. 연산 커널의 속도뿐 아니라, 다운로드부터 취소까지 이어지는 사용 경험을 하나의 엔진 위에서 만들 수 있습니다. 다만 모델 형식과 하드웨어 지원 범위를 먼저 맞춰야 그 장점이 성립합니다.

2-2. Apple 메모리 구조를 실제 버퍼 설계에 반영합니다

MetalDenseBuffer::new는 MTLResourceOptions::STORAGE_MODE_SHARED로 버퍼를 만듭니다. CPU와 GPU가 공유할 수 있는 자원을 사용하고, residency set에 등록해 GPU 접근을 관리합니다. “통합 메모리를 활용한다”는 설명이 실제 코드의 자원 생성 방식으로 이어지는 지점입니다.

공유 메모리가 계산이나 동기화 비용을 없애 주지는 않습니다. 특히 긴 대화는 KV 캐시를 키우므로, 가중치 파일이 메모리에 들어간다고 해서 모든 길이의 대화를 처리할 수 있는 것은 아닙니다.

2-3. 경쟁 도구와 비교하면 학습 목적이 선명해집니다

대상주된 초점uzu를 선택할 이유 / 확인할 점
uzuRust 추론 코어와 앱용 API·바인딩앱 통합 경로와 GPU 내부를 함께 공부하기 좋음. 자체 모델 형식과 플랫폼 제약 확인 필요
llama.cppC/C++ 기반 추론, GGUF, 여러 하드웨어 백엔드uzu는 Rust 타입 설계와 공개 세션 API를 함께 읽을 수 있음. 범용 하드웨어 폭은 별도로 비교해야 함
MLX / MLX LMApple 기기의 배열 연산·학습·텍스트 생성uzu는 모델 관리와 대화 제품의 경계를 한 저장소에서 따라가기 좋음
vLLM추론 서빙, PagedAttention, 연속 배칭uzu는 기기 내 앱 통합을 공부하는 입구. 다중 요청 처리량은 같은 조건으로 측정해야 함

비교 근거는 각 프로젝트의 공식 설명인 llama.cpp 저장소, MLX 소개, vLLM 소개입니다. 위 표는 용도 비교이며 속도 순위가 아닙니다. 같은 모델·양자화·문맥 길이·기기에서 측정한 공통 수치는 제시하지 않습니다.

README 표현을 정확히 읽기
지연 0·완전한 프라이버시·비용 0은 조건을 붙여야 합니다

README는 이런 장점을 내세우지만, 로컬 계산에도 모델 로딩과 토큰 생성 시간이 듭니다. 전력·메모리·저장 공간 비용도 남습니다. 공개 엔진에는 원격 서비스 연결 경로가 있으므로, 모든 설정에서 데이터가 기기 안에만 머문다고 일반화할 수 없습니다.

반면 GUI의 apps/mirai-gui/desktop/src/engine.rs는 클라우드 키와 Ollama·LM Studio 탐색을 명시적으로 끕니다. “라이브러리에 가능한 동작”과 “특정 앱이 선택한 정책”을 구분해야 합니다.

3기술 스택 전체 지도

의존성 이름을 기능의 위치와 함께 기억하기

아래 버전은 커밋 637cf10의 의존성 선언 기준입니다. Cargo의 "1.53.3", npm의 ^18.3.1, Python 패키지의 >=2.10.0은 각각 허용 범위를 나타냅니다. 설치 결과를 재현할 때는 해당 잠금 파일도 함께 봐야 합니다.

3-1. 백엔드: Rust가 관리하고 CPU·Metal이 계산합니다

기술·선언 버전담당하는 일확인 파일
Rust edition 2024워크스페이스 공통 언어 설정. rust-version = "1.98"Cargo.toml
Tokio 1.53.3공개 엔진의 비동기 초기화·채널·세션 작업Cargo.toml, crates/legacy/uzu/Cargo.toml
tokenizers 0.22.2텍스트와 토큰 번호 사이 변환. 기본 기능을 끄고 fancy-regex 사용Cargo.toml
serde 1.0.229
serde_json 1.0.154
모델 설정·메타데이터·요청 데이터 읽기Cargo.toml
mtl-rs 0.3.0metal이라는 의존성 이름으로 Apple GPU API 연결Cargo.toml
half 2.7.1
bytemuck 1.25.2
반정밀도 수와 버퍼의 바이트 표현 다루기Cargo.toml
xgrammar-rs 0.2.8문법에 맞는 다음 토큰만 고르는 구조화 출력Cargo.toml, crates/uzu-engine/Cargo.toml
Rocket 0.5.1CLI의 HTTP 서버와 스트리밍 응답Cargo.toml, crates/legacy/cli/Cargo.toml
# crates/uzu-engine/Cargo.toml의 기본 기능
[features]
default = ["cpu", "metal", "grammar"]
cpu = []
# metal과 grammar에는 선택적 의존성 묶음이 연결됩니다.

# crates/legacy/uzu/Cargo.toml의 공개 기능 이름
default = ["backend-cpu", "backend-metal", "capability-grammar"]
backend-cpu = ["uzu-engine/cpu"]
backend-metal = ["uzu-engine/metal"]
capability-grammar = ["uzu-engine/grammar"]

공개 패키지와 코어의 기능 이름이 다릅니다. backend-metal은 내부의 metal을 켜는 연결선입니다. 또한 기능을 켜는 것과 해당 운영체제에서 실제 백엔드가 생성되는 것은 별개입니다. 그 최종 분기를 crates/uzu-engine/build/main.rs가 처리합니다.

3-2. 언어 바인딩: Rust 타입을 다른 언어에 노출합니다

창구실제 선언배울 것
PythonPyO3 0.29.3, abi3-py312·experimental-async; maturin >=1.8,<2.0Rust 라이브러리를 Python 확장 모듈로 포장하는 방식
SwiftUniFFI 0.31.2, tokio 기능; Package.swift의 tools-version 5.9생성한 Swift 인터페이스와 배포용 바이너리의 결합
TypeScriptnapi 3.14.2, napi-derive 3.6.12; 패키지 @trymirai/uzu 0.6.13타입 선언과 실제 네이티브 모듈의 역할 차이
WebAssemblywasm-bindgen 0.2.129, wasm-bindgen-futures 0.4.79대상별 조건부 컴파일. 브라우저에서 모든 기능이 된다는 뜻은 아님

선언 출처는 루트 Cargo.toml, Python pyproject.toml, TypeScript package.json입니다. Python 패키지는 Python 3.12 이상을 요구합니다.

3-3. 프론트엔드: 엔진 위의 데스크톱 제품

apps/mirai-gui/package.json은 React ^18.3.1, Zustand ^4.5.7, TanStack React Router ^1.170.41, Vite ^5.4.21, TypeScript ^5.9.3, Tailwind CSS ^4.3.3을 선언합니다. Rust 데스크톱 셸은 Tauri 2.12.4입니다. 추론 코어 자체가 React에 의존하는 구조는 아닙니다.

화면의 apps/mirai-gui/client/src/platform/services/models/tauri.ts는 명령 호출과 이벤트 구독으로 데스크톱에 연결됩니다. 같은 위치의 apps/mirai-gui/client/src/platform/services/models/web.ts는 모델 목록을 빈 배열로 돌려주고 다운로드를 거부합니다. 따라서 브라우저 화면이 열린다는 것만으로 웹 추론까지 구현됐다고 판단하면 안 됩니다.

3-4. 인프라·빌드: 연산 코드도 빌드 파이프라인의 일부입니다

설정확인한 값·행동의미
Rust 도구 체인rust-toolchain.toml: channel = "nightly"날짜로 고정한 nightly는 아님. 재현 시점에 주의
Metal 컴파일MetalStd::Metal4_0, 최소 OS 26.4오래된 Metal 환경을 그대로 가정할 수 없음
Nixflake.nix: Apple SDK 26, Metal toolchain build 27A266a시스템별 개발 도구 구성. HEAD 변경도 이 도구 체인 갱신
Node·pnpmGUI package: Node >=22.19, pnpm 12.14.0; CI는 Node 26패키지 최소 선언과 문서 권장 환경을 구분
GitHub Actionsfmt·clippy·잠금 파일·cargo-deny·바인딩·GUI 검사여러 언어로 노출하는 API의 일관성도 검증 대상
Python 개발 도구torch >=2.10.0, transformers >=5.5.0, pytest >=9.0.2tools/pyproject.toml의 내보내기·분석 도구. Rust 추론 코어의 필수 Python 런타임은 아님

의존성 목록은 외울 대상이 아니라, 어느 계층에서 어떤 책임을 맡는지 찾는 지도입니다. 먼저 코어, 공개 API, 바인딩, 앱, 개발 도구의 다섯 칸으로 나누면 긴 설정 파일도 읽기 쉬워집니다.

4아키텍처 심화 분석

요청 하나를 아래로 따라가고, 상태 하나를 옆으로 추적하기

4-1. 전체 시스템 구조

다음은 모든 모듈을 나열한 그림이 아니라, 로컬 언어 모델의 대화 경로를 중심으로 정리한 구조입니다. 원격 모델을 선택하면 같은 공개 엔진에서 별도의 backend-remote 경로로 연결됩니다.

사용자 앱 / CLI / Mirai GUI / Pi 확장 | Rust · Python · Swift · TypeScript API | crates/legacy/uzu :: engine::Engine [설정] [레지스트리] [다운로드·저장소] [백엔드 등록] | nagare의 ChatSession · ChatInstance [메시지·세션] [토큰 처리] [응답 스트림] | uzu :: engine::bridge :: UzuLlmBackend | select_backend / BackendSelection +-------+--------+ | | CPU 선택 Metal 선택 | | +-------+--------+ | uzu_engine :: Engine<B> | load_language_model(모델 디렉터리) config.json + tokenizer.json + model.safetensors | LanguageModel<B> + LanguageModelState<B> | LanguageModelStream :: generate() [prefill] [decoder] [sampling] [선택적 speculator] | Decoder -> Transformer -> 연산 블록 -> 커널 | Backend::Context / CommandBuffer / Buffer +-------+--------+ | | CPU 커널 Metal 커널·GPU 명령 | | +-------+--------+ | 토큰 번호 -> 메시지 해석 -> 앱에 표시

모델 목록과 파일 다운로드는 계산 코어 바깥에 있습니다. 코어의 load_language_model은 이미 존재하는 모델 디렉터리를 받습니다. 이 경계 덕분에 파일을 얻는 정책과 파일을 계산하는 구현을 따로 읽을 수 있습니다.

4-2. 설계 패턴 ①: 백엔드 추상화와 경계에서의 선택

crates/uzu-engine/src/backends/common/backend.rs의 Backend 트레이트는 계산 문맥, 명령 버퍼, 여러 버퍼 타입, 커널 묶음을 연관 타입으로 지정합니다. LanguageModel<B>는 이 약속을 통해 CPU와 Metal의 구체 타입을 바꾸어 사용합니다.

// Backend의 선언 중 일부만 발췌
pub trait Backend: Clone + Send + Sync + 'static {
    type Context: Context<Backend = Self>;
    type CommandBuffer: CommandBuffer<Backend = Self>;
    type GlobalBuffer: GlobalBuffer<Backend = Self>;
    type Kernels: Kernels<Backend = Self>;
    // 나머지 연관 타입과 상수 생략
}
Rust를 읽기 위한 용어
트레이트·제네릭·연관 타입
트레이트는 구현이 지켜야 할 약속이고, <B>는 구체 타입을 나중에 지정하는 자리입니다. B::Context 같은 연관 타입은 “이 백엔드와 한 세트인 문맥 타입”을 뜻합니다. 서로 맞지 않는 백엔드와 버퍼를 연결하는 실수를 타입으로 줄일 수 있습니다.

crates/uzu-engine/src/backends/mod.rs의 select_backend는 컴파일된 백엔드 중 하나를 고릅니다. 기본은 Metal 백엔드가 컴파일되어 있으면 Metal, 그렇지 않으면 CPU입니다. UZU_BACKEND 환경변수로 선택을 바꿀 수 있지만, 컴파일하지 않은 백엔드를 새로 만들어 주지는 않습니다. 알 수 없는 값이나 컴파일되지 않은 백엔드를 지정하면 호출자가 넘긴 오류를 반환합니다.

공개 계층의 ChatTokenInstanceSelection::select<B>는 구체 타입의 인스턴스를 만든 뒤 Box<dyn ChatTokenInstance>로 감쌉니다. 하드웨어별 구현은 제네릭으로 구체화하고, 상위 API의 접점에서는 공통 인터페이스로 다루는 방식입니다.

읽을 파일: 백엔드 선택, 공개 엔진과 코어 사이 브리지.

4-3. 설계 패턴 ②: 모델과 대화 상태를 분리합니다

LanguageModel<B>에는 디코더, 토크나이저, 기본 생성 설정, 선택적 추측기가 있습니다. LanguageModelState<B>에는 누적 토큰, 난수 상태, Transformer 상태, 마지막 출력 토큰이 있습니다. 공유할 계산 재료와 요청 흐름에 따라 달라지는 기록을 구분한 것입니다.

// 실제 API 시그니처: 하나의 스트림이 가변 상태를 빌립니다.
pub fn stream<'a>(
    &'a self,
    input: &[u64],
    state: &'a mut LanguageModelState<B>,
    options: LanguageModelStreamOptions,
) -> Result<LanguageModelStream<'a, B>, LanguageModelStreamError<B>>

&self는 모델을 읽기용으로 빌리고, &mut state는 해당 상태를 독점해서 변경하겠다는 뜻입니다. 이 함수의 사용 범위에서는 동일한 상태를 두 스트림이 동시에 가변으로 빌릴 수 없습니다. 다만 이것만으로 요청 스케줄링이나 모든 GPU 동시성 문제가 해결되지는 않습니다.

모델과 상태를 나누는 이유

같은 교과서를 여러 학생이 읽을 수 있어도, 각자의 풀이 노트는 따로 있어야 합니다. 모델은 교과서이고, 누적 토큰과 KV 캐시는 풀이 노트입니다. 노트가 섞이면 앞사람의 대화가 뒷사람의 계산에 들어갈 수 있습니다.

모델 로딩은 파일 세 개를 여는 데서 끝나지 않습니다

  1. Engine::load_language_model이 config.json을 LanguageModelConfig로 읽습니다.
  2. ParameterLoader::new가 model.safetensors의 헤더 길이와 JSON 헤더를 읽습니다.
  3. Tokenizer::from_file이 tokenizer.json을 읽고, Decoder::new가 필요한 가중치를 요청합니다.
  4. 이 로딩 경로의 기본 계산 자료형은 DataType::BF16입니다. 저장된 모든 가중치가 비양자화 BF16이라는 뜻은 아닙니다.
  5. assert_all_tensors_read가 읽지 않은 텐서가 남았는지 확인합니다.

ParameterTree::tensor는 이름뿐 아니라 예상 모양과 자료형도 비교합니다. 바이트 구간의 길이가 예상 크기와 맞는지도 검사합니다. 파일이 열렸다는 사실과 모델에 맞는 파일이라는 사실을 나눠 검증하는 사례입니다.

읽을 파일: 모델 로딩, 대화 상태, 가중치 검증.

KV 캐시도 독립된 저장 전략을 갖습니다

crates/uzu-engine/src/encodable_block/mixer/attention/kv_storage.rs의 KVStorage는 BF16과 Int8 저장 방식을 구분합니다. Int8에는 코드 버퍼 외에 스케일 버퍼가 따로 있습니다. create_kv_buffer는 기기가 SPARSE_BUFFERS를 지원하면 희소 버퍼를, 아니면 일반 버퍼를 만듭니다.

KVStorage::prepare는 희소 버퍼의 필요한 앞부분을 매핑합니다. 최대 공간을 표현하는 것과 그 공간에 물리 메모리를 모두 붙이는 것을 분리하는 방식입니다. 이 기능이 있다고 사용 중인 대화의 메모리 비용이 사라지는 것은 아닙니다.

4-4. 설계 패턴 ③: 스트리밍을 상태 머신으로 만듭니다

LanguageModelStream은 단순히 반복문에서 문자열을 내보내는 객체가 아닙니다. DecodingState로 다음 연산의 진행 상태를 표현하고, generate를 호출할 때 상태를 전이합니다. GPU 작업이 제출됐지만 아직 끝나지 않은 경우도 타입의 한 상태로 다룹니다.

스트림 상태의 주요 분기 new(): 새 입력 있음 -- prefill 제출 --> ForwardPassPending 새 입력 없음 -----------------> Seeded (기존 출력 토큰 사용) generate(): Seeded ---------------------------+ | ForwardPassPending -- full_accept -+-- 다음 계산 제출 --> ForwardPassPending | | + 토큰 반환 | 후보 트리 검증 | v | Accepting -- 마지막 토큰 ----+ | +-- 남은 수락 토큰 반환 --> Accepting 다음 계산 전에 문맥 한도에 도달하면 --> Halted Halted / Closed의 generate()는 None 반환 각 진행 상태 -- close() -------------> Closed Invalid: 상태를 꺼내 교체하는 중의 내부 표지

LanguageModelStream::new는 상태와 입력이 모두 비어 있으면 NoSeedToken, 합친 길이가 제한을 넘으면 ContextOverflow를 반환합니다. 입력이 있으면 먼저 prefill을 수행하며, 이 구현은 입력을 최대 1024토큰 단위로 나눕니다. 이 값은 현재 attention 구현의 제약과 연결되어 있다는 주석도 있습니다.

추론의 두 구간
prefill과 decode
prefill은 새로 들어온 입력 토큰을 읽고 계산 기록을 채우는 구간입니다. decode는 그 기록을 바탕으로 출력을 이어 가는 구간입니다. 긴 질문을 읽는 시간과 답변이 이어지는 속도는 서로 다른 병목을 가질 수 있습니다.

공개 브리지의 UzuChatTokenBackendInstance::stream은 취소 토큰과 생성 한도를 검사합니다. 취소, 한도 도달, 정상 종료, 오류의 경로마다 내부 스트림의 close().await를 호출하는 처리가 있습니다. 생성 루프뿐 아니라 정리 경로도 API의 일부입니다.

Drop for LanguageModelStream은 아직 닫히지 않은 스트림을 block_on(self.close())로 정리합니다. 자원 회수를 보조하지만, 소멸 과정에서도 대기가 발생할 수 있다는 뜻입니다. 비동기 자원을 설계할 때 명시적 종료 메서드가 왜 필요한지 보여 줍니다.

선택적 최적화: 여러 후보 토큰을 제안하고 확인합니다

모델 디렉터리에 speculator가 있으면 먼저 디코더의 추측 디코딩 지원 여부를 단언문으로 검사한 뒤 DFlashTfmSpeculator 로더를 호출합니다. 지원하지 않으면 단언문 실패로 패닉이 발생합니다. propose_tree는 후보 토큰 트리를 만들고, 생성 루프는 후보를 검사해 수락한 토큰과 상태를 반영합니다. 트리 예산과 최대 깊이도 별도 설정입니다.

이는 “한 번에 무조건 여러 토큰을 출력한다”는 약속이 아닙니다. 후보가 얼마나 채택되는지, 제안 비용이 얼마나 드는지에 따라 효과가 달라집니다. 모든 모델에 추측기가 들어 있는 것도 아닙니다.

구조화 출력: 문자열을 다 만든 뒤 검사하는 것보다 앞에서 개입합니다

crates/uzu-engine/src/engine/language_model/grammar/grammar.rs의 Grammar::new는 JSON Schema·정규식·기본 JSON 문법을 컴파일합니다. next_bitmask는 다음에 허용할 토큰을 비트마스크로 만들고, accept_token은 선택한 토큰에 따라 문법 상태를 갱신합니다.

문법에 맞는 JSON을 얻는 것과 내용이 사실에 맞는 것은 별개입니다. 예를 들어 숫자 필드를 보장해도 그 숫자가 정확한지는 앱이 검증해야 합니다. 또한 빌드 설정상 wasm32에서는 이 grammar 기능이 활성화되지 않습니다.

읽을 파일: 생성 상태 머신, 취소·한도·정리, 후보 트리, 문법 제약.

4-5. 설계 패턴 ④: 빌드 시 코드 생성으로 연산 경계를 연결합니다

crates/uzu-engine/build/main.rs의 main은 공통 GPU 타입을 수집한 뒤 CPU·Metal 컴파일러를 구성하고, 커널을 빌드한 결과로 traitgen_all을 호출합니다. Rust 타입과 커널 인자를 연결하는 반복 작업을 빌드 단계에서 처리하는 구조입니다.

Metal 컴파일러의 build와 compile은 타입·래퍼·바인딩 생성에 참여합니다. crates/uzu-engine/build/metal/toolchain.rs에서는 metal4.0 표준을 사용합니다. 커널 파일만 읽어서는 완성된 인터페이스의 출처를 모두 찾을 수 없는 이유입니다.

공통 GPU 타입 + 백엔드별 커널 코드 | build/main.rs :: main | CpuCompiler / MetalCompiler | 타입·래퍼·바인딩·커널 산출물 | traitgen_all | Rust 코어에서 호출할 공통 인터페이스

실행 중에도 모든 행렬에 같은 GPU 구현을 적용하지는 않습니다. GemmProblem::select_plan은 Trellis 형식 여부, MXU 지원 여부, 행렬 모양과 GPU 계열을 바탕으로 계획을 고릅니다. 빌드할 수 있는 후보를 준비하는 단계와 현재 입력에 맞는 후보를 고르는 단계가 함께 있습니다.

읽을 파일: 빌드 진입점, Metal 컴파일러, GEMM 실행 계획 선택.

서버 코드에서 추가로 배우기
같은 API 모양과 같은 서버 처리 능력은 다릅니다

crates/legacy/cli/src/server/runner.rs의 run_server는 세션을 Arc<Mutex<ChatSession>>로 공유하고 루트와 /v1에 경로를 등록합니다. 생성 처리도 세션 잠금을 얻습니다. 이 구조만 보고 다수 사용자를 연속 배칭하는 서버와 같은 처리량을 기대할 수는 없습니다.

성능 코드를 읽을 때는 계산식뿐 아니라, 상태의 소유자와 작업 완료를 기다리는 위치를 함께 찾아야 합니다. uzu의 큰 그림은 이 두 질문으로 다시 정리할 수 있습니다.

5디렉토리 구조 해부

폴더 이름을 외우기보다 진입점의 역할을 기억하기
uzu/ |-- Cargo.toml / Cargo.lock Rust 워크스페이스·의존성 |-- rust-toolchain.toml Rust 도구 체인·대상 목록 |-- flake.nix / flake.lock 개발 환경·도구 체인 구성 |-- Package.swift Swift 패키지·바이너리 연결 |-- crates/ | |-- uzu-engine/ | | |-- build/ 커널 컴파일·코드 생성 | | |-- src/ | | | |-- engine/ 모델 로딩·상태·생성 스트림 | | | |-- backends/ 공통 약속 + CPU + Metal | | | |-- encodable_block/ 디코더·attention·샘플링 | | | |-- config/ 모델·레이어·토큰 설정 | | | |-- speculators/ 후보 토큰 트리 제안 | | | `-- safetensors.rs 가중치 헤더·텐서 검증 | | `-- unit/ 테스트·마이크로벤치마크 | |-- uzu-engine-macros/ 코어의 절차적 매크로 | `-- legacy/ | |-- uzu/ 공개 Engine·저장소·바인딩 | |-- nagare/ 대화·분류 등 세션 구성 | |-- shoji/ 공통 타입·백엔드 계약 | |-- backend-remote/ 원격 모델 연결 | |-- download-manager/ 다운로드 처리 | |-- bindings/ 언어 노출용 매크로 | |-- cli/ 터미널 앱·HTTP 서버 | `-- cli-tools/ cargo tools 개발 명령 |-- apps/ | |-- mirai-gui/ Tauri·React 데스크톱 앱 | |-- playground/ Swift 예제 앱 | `-- uzu-pi-extension/ Pi 코딩 에이전트 연결 |-- tools/ Python 내보내기·분석 도구 |-- scripts/ 빌드 보조·벤치마크 도구 |-- docs/ 문서 원본·예제 조각 `-- .github/ CI·릴리스 워크플로

5-1. legacy는 읽지 않아도 되는 폴더일까요?

아닙니다. 루트 Cargo.toml은 이 구역에 to be rewritten이라는 주석을 붙이지만, 현재 워크스페이스 구성원으로 포함합니다. GUI도 이 안의 공개 uzu 패키지를 사용합니다. 폴더 이름은 개편 방향을 알려줄 뿐, 현재 실행 경로에서 제외됐다는 증거가 아닙니다.

5-2. 확장자별 코드 규모

커밋 637cf10 기준 확장자별 파일 수와 물리적 줄 수입니다. 빈 줄·주석·테스트·생성된 바인딩을 포함하고, .git은 제외했습니다. 실행 코드만 센 수치나 GitHub 언어 비율과는 다릅니다.

분류파일 수물리적 줄 수
Rust · .rs1,046104,738
Swift · .swift4817,917
TypeScript · .ts20414,394
React · .tsx14713,530
Python · .py769,245
Metal · .metal527,096
C/C++ 헤더 · .h/.hpp856,606
C++ · .cpp6945
C · .c5484
JavaScript · .js/.mjs71,033

Rust 안에서는 crates/uzu-engine이 43,041줄, crates/legacy가 54,210줄, 나머지가 7,487줄입니다. “작은 코어에 얇은 포장만 붙은 프로젝트”라고 보기에는 앱 통합 계층도 상당한 비중을 차지합니다.

처음 읽는 순서

네 파일을 먼저 펼치세요

README.md에서 사용 흐름을 보고, crates/legacy/uzu/src/engine/bridge/backend.rs에서 연결을 찾고, crates/uzu-engine/src/engine/language_model/mod.rs에서 모델 로딩을 읽으세요. 마지막으로 crates/uzu-engine/src/engine/language_model/stream/stream.rs의 상태 이름을 표시하면 다음에 볼 폴더가 정해집니다.

6학습 포인트 (기술별)

파일을 읽은 뒤, 내 말로 설명할 수 있어야 하는 것
기술이 저장소에서 배울 것작은 실습 아이디어
Rust 타입 설계Backend의 연관 타입, Engine<B>, 상위 계층의 dyn 경계프린터 두 종류를 같은 인터페이스로 다루는 장난감 예제로 옮기기
소유권·수명모델은 공유하고 상태는 가변으로 빌리는 stream 시그니처동일 상태의 두 번째 가변 대여가 왜 안 되는지 그림으로 설명하기
비동기 처리GPU 작업의 Pending 상태와 상위 스트림의 취소·종료가짜 계산 작업에 취소를 넣고 정리가 한 번만 일어나게 설계하기
메모리 관리공유 버퍼, 희소 버퍼, KV 저장 형식과 메모리 추정문맥 길이를 두 배로 늘린 경우를 표로 계산하기
GPU 계산Decoder::encode에서 커널 호출까지 내려가는 경로작은 행렬곱을 손으로 계산하고 GPU 타일링이 나누는 영역 표시하기
언어 바인딩PyO3·UniFFI·N-API의 역할, 기능 전파와 생성 코드세 언어의 Quick Start에서 같은 개념의 이름을 대응시키기
프론트엔드 경계GUI의 PlatformClient와 Tauri·웹 서비스 구현엔진 없이 모델 목록을 흉내 내는 구현의 계약 작성하기
정확성 검증CPU 기준 결과, 오차 허용, 무작위 입력 테스트양자화로 오차가 생겨도 통과할 수 있는 판정 기준 토론하기

6-1. 첫 GPU 학습은 attention보다 작은 커널에서 시작하세요

crates/uzu-engine/unit/backends/common/kernel/tensor_add_scale_test.rs를 먼저 읽어 보세요. 입력과 편향 버퍼를 만들고, 명령을 인코딩하고, 제출·완료 대기를 한 뒤 결과를 읽습니다. 작은 연산으로도 GPU 프로그램의 전체 생애를 볼 수 있습니다.

// 테스트에서 사용하는 명령 버퍼 처리 흐름
// 앞에서 커널 인코딩과 출력 버퍼 준비를 마친 부분 예시입니다.
block_on(command_buffer.end_encoding().submit().wait_until_completed()).unwrap();

// 결과를 읽는 시점은 완료 대기 뒤입니다.
buffer_to_vec::<B, T>(&output_buffer)

crates/uzu-engine/unit/common/assert.rs의 assert_eq_float는 배열 길이를 확인하고 각 원소의 절대 오차를 eps와 비교합니다. 모든 부동소수점 연산을 무조건 정확히 같은 비트로 비교하지 않는 이유를 생각해 보세요. 어떤 커널에는 절대 오차만으로 충분하지 않을 수도 있습니다.

6-2. 테스트는 구현이 지키려는 약속을 보여 줍니다

crates/uzu-engine/unit/encodable_block/sampling_test.rs는 난수 입력과 시드를 만들고, 여러 백엔드의 샘플링 결과를 CPU 기준 결과와 비교하는 구조를 갖습니다. ComparableTestResults::compare에서 결과를 어떻게 판정하는지 먼저 보면 복잡한 입력 생성 코드의 목적이 보입니다.

crates/uzu-engine/unit/encodable_block/kv_cache_state_test.rs의 ring_accept_over_capacity_keeps_last는 용량을 넘긴 링 캐시에 최근 항목이 남는 상황을 검사합니다. 이름만 읽고 끝내지 말고, source와 destination 숫자를 칸 그림으로 옮겨 보세요.

테스트를 읽는 요령

복잡한 기계의 설명서를 처음부터 읽기 어렵다면 검사표를 먼저 보는 것과 같습니다. 무엇이 잘못되면 실패하는지 알면, 구현의 여러 분기가 왜 필요한지도 이해하기 쉬워집니다.

6-3. 프론트엔드 개발자도 배울 경계가 있습니다

apps/mirai-gui/client/src/platform/platform-singleton.ts의 initPlatform은 중복 초기화를 거부하고, getPlatform은 초기화 전 접근을 거부합니다. 전역 객체를 아무 때나 쓰기보다 초기화 순서를 계약으로 만든 예입니다. 웹 구현의 “이용 불가” 응답도 그 계약 안에 들어갑니다.

연산 엔진을 몰라도 “화면은 어떤 능력을 요청하고, 플랫폼은 무엇을 보장하는가”를 읽을 수 있습니다. 이 원리는 브라우저·데스크톱·모바일을 함께 지원하는 일반 앱에도 적용됩니다.

좋은 학습의 단위는 파일 하나를 다 읽는 것이 아니라, 입력·출력·불변 조건 하나를 끝까지 설명하는 것입니다.

7하드웨어 / 시스템 요구사항

문서의 대상 목록, 배포 조건, 실제 기능 범위를 나눠 보기
사용 경로확인 가능한 요구사항해석할 때 주의할 점
소스 읽기·설계 실습텍스트 편집기, 파일 검색 도구GPU·모델 다운로드 없이 대부분의 읽기 과제 가능
Mirai GUIREADME: Apple silicon, macOS 26.4 이상, Xcode 26 및 Metal 도구 체인빌드 명령의 대상은 aarch64-apple-darwin
Metal 코어빌드 코드: metal4.0, 최소 OS 26.4; Metal 4 명령 큐 사용CPU로 컴파일 가능한 환경과 GPU 기능 지원 환경은 다름
Swift 패키지Package.swift: iOS·macOS·Mac Catalyst 26.4, Swift tools 5.9tools-version은 지원 OS 버전과 별개
Python 바인딩Python 3.12 이상Python 버전만 맞아도 모든 OS에서 같은 바이너리를 쓸 수 있다는 뜻은 아님
TypeScript 패키지os = darwin, cpu = arm64/x64명시된 패키지 대상과 실제 기기의 Metal 기능을 함께 확인
Pi 확장Darwin·arm64, Node 22.19.0 이상GUI와 별개의 패키지 제약
Linux·Windows·WASMREADME의 여러 대상이 in progress; CPU 구현과 일부 CI 경로 존재앱·바인딩·모델 형식별로 지원 범위를 따로 확인

근거: GUI 요구사항, Swift 플랫폼 설정, Metal 도구 체인. GUI README는 Node 26 이상을 요구하지만 package.json의 최소 선언은 22.19입니다. 실제 개발 환경을 맞출 때는 이 차이도 확인해야 합니다.

7-1. “CPU가 있다”는 말의 범위를 제한해서 읽으세요

crates/uzu-engine/src/backends/cpu/kernel/matmul/reference.rs의 WeightData::from_b는 MatmulB::Trellis를 UnsupportedLayout 오류로 반환합니다. CPU 코드가 존재해도 모든 양자화 형식과 모델 경로를 지원하는 것은 아닙니다. 하드웨어 이름뿐 아니라 모델의 가중치 표현도 호환성 조건입니다.

문서 원본 docs/index.mdx의 FAQ는 현재 지원 기기를 Apple silicon의 iOS·macOS로 더 좁게 안내합니다. README의 대상 목록, npm의 x64 선언, 문서의 제품 지원 범위가 같은 수준의 약속은 아닙니다.

CI에는 Linux CLI 빌드와 WASI 스레드 대상의 커널 테스트가 있습니다. 이 검증 범위와 Windows를 포함한 모든 대상의 제품 수준 지원을 같은 것으로 읽으면 안 됩니다. rust-toolchain.toml의 target 목록은 필요한 도구를 설치할 목록이기도 합니다.

7-2. 메모리는 가중치 + 캐시 + 임시 공간으로 계산하세요

고정된 “최소 RAM 몇 GB”를 모든 모델에 적용할 수는 없습니다. 출발점으로 다음 근삿값을 계산할 수 있습니다. 아래는 특정 uzu 모델의 실측값이 아닌 일반적인 크기 계산 예입니다.

# 이상적인 가중치 데이터 크기
파라미터 수 × 파라미터당 비트 수 ÷ 8

0.8B × 4비트 ÷ 8 = 약 0.4 GB
4B   × 4비트 ÷ 8 = 약 2.0 GB
7B   × 4비트 ÷ 8 = 약 3.5 GB

# BF16 KV 캐시의 단순 추정: 전체 attention 층에 같은 구조를 가정
2 × 레이어 수 × KV 헤드 수 × 헤드 차원 × 토큰 수 × 2바이트

2 × 24 × 8 × 128 × 4096 × 2 = 384 MiB

가중치 예시의 GB는 10억 바이트, 캐시 예시의 MiB는 2의 20제곱 바이트입니다. 실제 양자화 파일에는 스케일·보조 정보가 붙고, 실행 시에는 활성값·임시 버퍼·토크나이저·운영체제 메모리도 필요합니다. 서로 다른 attention·mixer를 섞는 모델에는 위 캐시 공식을 그대로 적용할 수 없습니다.

혼동하기 쉬운 두 압축
가중치 양자화와 KV 캐시 양자화
가중치는 모델 자체의 수치이고, KV 캐시는 대화를 처리하면서 쌓이는 수치입니다. 가중치를 4비트로 저장했다고 KV 캐시까지 4비트가 되는 것은 아닙니다. uzu의 KVStorage는 BF16과 Int8 경로를 별도로 갖습니다.

7-3. 권장 문맥 길이도 정밀한 메모리 모델은 아닙니다

LanguageModel::recommended_context_length는 희소 버퍼 지원 시 모델의 최대 문맥 길이를 반환합니다. 지원하지 않고 최대 길이가 유한하면 iOS에서는 8192, 그 외에는 16384와 모델 한도 중 작은 값을 고릅니다.

소스 주석도 이를 정식 메모리 모델이 아닌 단순한 접근이라고 설명합니다. 이 값이 모든 기기에서 메모리 부족을 막아 주는 보장은 아닙니다. iOS에 대해서는 README가 Increased Memory Capability와 여러 모델을 동시에 유지하지 않는 사용 방식을 권합니다.

모델 파일이 들어가는지와 대화를 끝까지 생성할 수 있는지는 서로 다른 메모리 질문입니다.

8직접 해볼 수 있는 실습 과제

작은 산출물과 완료 기준이 있는 다섯 과제

다음 과제는 모델 설치 없이 시작할 수 있습니다. 처음부터 대규모 엔진을 수정하려 하기보다, 호출 경로·오류 조건·작은 시뮬레이터를 통해 이해를 확인하세요.

과제 1 · 입문

대화 요청의 여행 지도 만들기 30~45분

목표: 공개 API와 계산 코어가 만나는 지점을 찾습니다.

읽을 곳: README Quick Start → crates/legacy/uzu/src/engine/mod.rs → crates/legacy/uzu/src/engine/bridge/backend.rs → crates/uzu-engine/src/engine/language_model/mod.rs.

할 일: 각 단계의 입력·출력·실패 원인 한 가지를 표로 적습니다. 공개 Engine과 제네릭 Engine을 별도 칸에 놓고, 둘 사이를 잇는 타입을 표시합니다.

완료 기준: “모델 조회가 성공해도 로딩은 왜 실패할 수 있는가?”에 파일 형식·자료형·백엔드 중 두 가지 근거를 들어 답할 수 있습니다.

# 저장소 루트에서 실행하는 읽기 전용 검색 예시
rg -n 'pub async fn chat|pub async fn chat_instance' crates/legacy/uzu/src/engine/mod.rs
rg -n 'select_backend|impl BackendSelection' crates/legacy/uzu/src/engine/bridge/backend.rs
rg -n 'load_language_model|assert_all_tensors_read' crates/uzu-engine/src/engine/language_model/mod.rs
과제 2 · 입문

버전과 지원 범위의 차이 찾기 30분

목표: 설정 파일을 근거로 읽는 연습입니다.

읽을 곳: rust-toolchain.toml, 루트 Cargo.toml, apps/mirai-gui/package.json, 같은 앱의 README, Package.swift.

할 일: 최소 버전, 권장 버전, 패키지 버전, 도구 체인 채널을 분류합니다. Node 최소 선언과 README 요구사항, nightly 채널과 날짜 고정의 차이를 설명합니다.

완료 기준: 서로 다른 의미의 버전 값 여섯 개를 출처와 함께 적고, “버전 숫자가 크다”만으로 호환성을 판단하지 않을 수 있습니다.

과제 3 · 중급

두 칸짜리 KV 링 캐시를 손으로 시뮬레이션하기 60분

목표: 제한된 캐시에 최근 토큰만 남기는 상태 전이를 이해합니다.

읽을 곳: crates/uzu-engine/unit/encodable_block/kv_cache_state_test.rs의 ring_accepts_append_then_wrap, ring_accept_over_capacity_keeps_last.

할 일: 두 칸을 그리고 각 호출 뒤의 prefix 길이·ring offset·복사 원본과 목적지를 기록합니다. 테스트의 입력 인덱스와 실제 토큰 ID를 구분합니다.

완료 기준: 용량보다 많은 후보를 수락할 때 어떤 복사가 불필요해지는지 설명하고, 직접 만든 배열 시뮬레이터에서 같은 표를 얻습니다.

과제 4 · 중급

취소 가능한 가짜 토큰 스트림 설계하기 60~90분

목표: 정상 출력보다 종료 경로를 먼저 설계합니다.

읽을 곳: crates/legacy/uzu/src/engine/bridge/chat_token_backend.rs의 스트림 생성 부분과 코어의 LanguageModelStream::close.

할 일: 정수 세 개를 차례로 내보내는 가짜 생성기를 만듭니다. 시작 전 취소, 두 번째 출력 뒤 취소, 한도 도달, 생성 오류를 표로 정리하고 각 경우의 반환·정리 횟수를 정합니다.

완료 기준: 한도 도달과 사용자 취소를 서로 다른 결과로 처리하고, 반복 종료 요청에도 같은 자원을 두 번 정리하지 않는 설계를 제시합니다.

# 과제 4의 언어 독립적인 의사코드
반복:
    취소되었으면:
        정리하고 종료
    생성 개수가 한도에 도달했으면:
        정리하고 한도 도달 알림
    다음 항목을 요청
    오류 또는 정상 끝이면:
        정리하고 종료
    항목 전달 후 생성 개수 증가
과제 5 · 고급

“더 빠르다”를 판정할 벤치마크 설계서 작성하기 90~120분

목표: 성능 주장을 재현 가능한 질문으로 바꿉니다.

읽을 곳: crates/uzu-engine/unit/common/metrics.rs, crates/uzu-engine/unit/common/perf.rs, tools/model_compare/comparison.py, README의 Benchmarks 절.

할 일: 모델·가중치 형식·기기·입력 길이·출력 한도·샘플링·추측기 유무를 고정하는 표를 만듭니다. 다운로드, 최초 로딩, prefill, decode를 서로 다른 구간으로 정의합니다.

완료 기준: 첫 토큰 시간, decode 처리 속도, 최대 메모리, 출력 유효성의 네 지표와 반복·예열·온도 조건을 적습니다. 값은 측정 전까지 빈칸으로 둡니다.

스스로 확인할 질문
그림을 지우고 설명해 보세요

어떤 자료는 공유되고 어떤 자료는 세션마다 달라지는지, 취소 뒤 어떤 작업을 기다려야 하는지, CPU에서 거부되는 가중치 형식은 무엇인지 답할 수 있다면 주요 구조를 이해한 것입니다.

9관련 기술 심화 학습 로드맵

6주 동안, 추론 엔진을 읽기 위한 기초부터 쌓기

주당 3~5시간을 가정한 학습 순서입니다. 익숙한 주제는 건너뛰어도 되지만, 매주 작은 설명 자료 하나는 남기세요. 모델 수학 전체를 먼저 공부하지 않아도 작은 연산·상태·인터페이스부터 이해를 넓힐 수 있습니다.

주차배울 개념uzu에서 읽을 곳주간 산출물
1주소유권, 참조, Result, 구조체·열거형crates/uzu-engine/src/engine/language_model/state.rs, 로딩 오류 열거형모델·상태·스트림의 소유 관계 그림
2주트레이트, 제네릭, 연관 타입, 동적 디스패치crates/uzu-engine/src/backends/common/backend.rs, 브리지의 선택 구현CPU·Metal 선택 경로와 장난감 백엔드 설계
3주async/await, 스트림, 취소, 잠금crates/uzu-engine/src/engine/language_model/stream/stream.rs, 공개 브리지취소·한도·오류별 상태 전이 표
4주행렬곱, 임베딩, logits, 토큰 샘플링crates/uzu-engine/src/encodable_block/decoder.rs, 작은 커널 테스트입력 모양에서 출력 모양까지의 계산 표
5주Metal 버퍼, 명령 제출, KV 캐시, 양자화crates/uzu-engine/src/backends/metal/buffer/dense.rs, KV 저장 코드문맥 길이에 따른 가중치·캐시 메모리 추정 표
6주FFI, 코드 생성, CI, 성능 측정 설계crates/uzu-engine/build/main.rs, 바인딩 설정, .github/workflows/tests.yml기능 하나를 여러 언어에 노출할 변경 목록

시간이 더 있다면 두 갈래로 확장하세요

시스템 구현에 관심 있다면

연산 한 개의 CPU·Metal 구현과 테스트를 묶어 읽기

버퍼 크기, 자료형, 메모리 접근, 결과 오차를 기록하세요. 그다음 GEMM 계획 선택, attention, 추측 디코딩으로 넓히면 됩니다. 빠른 커널을 이해하려면 먼저 비교 기준이 되는 느리고 단순한 구현을 읽을 수 있어야 합니다.

앱 개발에 관심 있다면

모델 준비부터 답변 취소까지 하나의 기능으로 보기

GUI의 모델 목록·다운로드 이벤트·세션·저장 경계를 따라가세요. 사용자가 창을 닫거나 다운로드를 취소할 때 누가 상태를 소유하는지 적어 보면, 추론 코어를 모두 이해하기 전에도 제품 설계를 배울 수 있습니다.

학습의 목표는 코드를 전부 기억하는 것이 아니라, 새 기능을 넣을 때 바꿀 계층과 지켜야 할 계약을 찾는 능력입니다.

10핵심 키워드 사전

처음 나오는 말을 다시 찾기 위한 짧은 해설
용어쉬운 설명
추론학습한 모델로 입력에 대한 출력을 계산하는 과정입니다.
가중치학습으로 정한 모델의 수치입니다. 실행할 때 읽는 큰 데이터의 중심입니다.
텐서수치를 여러 축으로 배열한 자료입니다. 모양과 자료형을 함께 알아야 해석할 수 있습니다.
토크나이저텍스트를 모델의 토큰 번호로 바꾸고 번호를 텍스트로 되돌리는 도구입니다.
임베딩토큰 번호를 계산에 사용할 수치 벡터로 바꾸는 단계입니다.
logits모델이 계산한 다음 토큰 후보의 점수입니다. 곧바로 확률을 뜻하지는 않습니다.
샘플링점수와 선택 규칙을 이용해 실제 다음 토큰을 고르는 과정입니다.
greedy가장 높은 점수의 토큰을 고르는 선택 방식입니다.
temperature토큰 선택 분포의 집중도를 조절하는 값입니다. 값의 효과는 샘플링 구현과 함께 봐야 합니다.
top-k / top-p상위 k개 또는 누적 확률 기준으로 후보를 줄이는 선택 규칙입니다.
문맥 길이모델이 계산 상태에 반영하는 토큰 범위입니다. 사용자 문장의 글자 수와 다릅니다.
prefill / decode입력을 읽어 상태를 채우는 구간과 출력을 이어 생성하는 구간입니다.
attention토큰 사이의 관련도를 바탕으로 정보를 섞는 연산입니다.
KV 캐시attention에서 이전 토큰의 Key·Value 계산을 재사용하기 위한 기록입니다.
BF16 / Int816비트 부동소수점 표현과 8비트 정수 표현입니다. 정밀도·범위·보조 정보가 다릅니다.
양자화수치를 더 적은 비트 등으로 표현해 저장·전송·연산 비용을 줄이는 기법입니다.
통합 메모리CPU와 GPU가 같은 메모리 풀에 접근하는 구조입니다. 동기화까지 자동으로 없어지지는 않습니다.
희소 버퍼큰 논리적 공간 중 필요한 구간에 물리 메모리를 연결해 쓰는 버퍼입니다.
커널 / GEMM커널은 장치에서 수행하는 계산 단위이고, GEMM은 일반 행렬곱 연산을 가리킵니다.
명령 버퍼장치에 수행할 작업을 기록해 제출하는 묶음입니다. 기록·제출·완료 시점이 다릅니다.
트레이트 / 연관 타입구현이 지킬 약속과, 그 구현에 연결되는 타입을 표현하는 Rust 기능입니다.
Arc / Mutex여러 곳에서 소유권을 공유하거나, 공유 자료의 접근을 조정하는 도구입니다.
상태 머신가능한 상태와 상태 사이의 이동을 정해 복잡한 진행을 관리하는 설계입니다.
추측 디코딩후보 토큰을 먼저 제안하고 본 모델의 확인을 거쳐 생성하는 최적화 방식입니다.
문법 제약허용할 다음 토큰을 제한해 출력의 구조를 유도합니다. 사실성 보장과는 다릅니다.
FFI / 바인딩서로 다른 언어가 연결되는 경계와, 그 경계를 쓰기 편하게 만든 인터페이스입니다.
절차적 매크로Rust 코드의 구조를 읽어 추가 코드를 생성하는 기능입니다.
Safetensors텐서의 모양·자료형·바이트 구간을 기록하는 저장 형식입니다. 확장자가 같아도 모델 내부 구조는 맞아야 합니다.
첫 토큰 시간요청 후 첫 출력 토큰을 얻을 때까지의 시간입니다. 모델 로딩을 포함하는지 정의해야 합니다.
OpenAI 호환 API기존 클라이언트가 쓰는 요청·응답 형태에 맞춘 API입니다. 전체 기능·처리 능력이 동일하다는 뜻은 아닙니다.

11참고 링크

입문 자료와 소스 근거를 함께 찾아보기

공식 저장소와 제품 문서

핵심 코드를 다시 찾는 링크

관련 기술의 공식 학습 자료

현재 상태 (2026-10-23 확인)

항목확인 내용
선정GitHub Trending Rust Weekly #6
스타 / 포크2,546 / 146 · 2026-10-23 GitHub 기준
주 언어Rust
생성일2025-06-23
최신 릴리스0.6.13 · 2026-10-22
최근 push2026-10-23
최근 커밋637cf10 · 2026-10-23 · “Update nix metal toolchain (#1011)”
코드 규모Rust 104,738줄, TS·TSX 합계 27,924줄, Swift 17,917줄, Python 9,245줄, Metal 7,096줄
집계 범위확장자별 물리적 줄 수. 테스트·주석·생성 코드 포함, Git 이력 제외
핵심 백엔드CPU·Metal. 운영체제·가중치 형식별 지원 범위는 별도 확인
모델 형식자체 설정·가중치 구조. 언어 모델 로더는 config.json·tokenizer.json·model.safetensors 사용
라이선스MIT · LICENSE의 저작권 표기는 2025 Mirai Tech Inc. 모델·종속 자원은 각 조건 별도 확인
사용하기 전에 알아둘 한계
코드로 확인한 구조와 실행 환경의 보장은 다릅니다

이 글의 구현 설명은 커밋 637cf10 기준입니다. 이후 API·플랫폼·모델 지원이 바뀔 수 있으며, 현재 문서와 과거 커밋의 코드가 서로 다를 수 있습니다. 물리적 줄 수는 기능 수나 품질 점수가 아닙니다.

하드웨어 호환성, 속도 우위, 최대 문맥 길이를 실제 기기에서 보장하는 자료는 아닙니다. 메모리 계산은 단순 예시이고, README의 성능·비용·프라이버시 문구에는 로컬 모델 선택과 실행 설정이라는 조건이 붙습니다.

Safetensors 파일만 있다고 바로 호환되지는 않습니다. 설정·텐서 이름·자료형·양자화 형식까지 맞아야 합니다. 학습 순서는 작은 테스트와 CPU 기준 구현에서 시작하고, 제품 적용 전에는 사용할 버전과 기기의 조건을 다시 확인하세요.