추론 프레임워크
deepseek-ai/DeepInfer · 스타 20,308 · 포크 2,186 · Python · Apache-2.0.
GitHub 메타데이터는 2026-10-23 기준이며, 소스 설명은 커밋 9bd9cf2 기준입니다.
DeepInfer는 DeepSeek 모델을 여러 가속기에 나누어 올리고, 요청·메모리·연산 순서를 조율하는 추론 프레임워크입니다.
README는 DeepSeek의 대규모 운영 서비스에 사용되는 프레임워크라고 소개합니다.
다만 공개된 버전의 사용 흐름은 LLM.generate()에 입력 목록을 주고 결과를 받는 오프라인 추론입니다.
모델 자체의 지식을 학습하는 훈련 코드와는 역할이 다릅니다.
출처: README.
초보자가 이 저장소에서 얻을 수 있는 가장 큰 수확은 거대한 신경망의 수식을 모두 외우는 일이 아닙니다. 모델 한 번을 빠르게 계산하는 문제와, 수많은 요청을 빠짐없이 처리하는 문제를 함께 보는 법을 배울 수 있습니다. 행렬곱이 빨라도 요청을 고르느라 GPU를 기다리게 하거나, 사용 중인 메모리를 일찍 반납하면 시스템 전체는 느려지거나 잘못 동작합니다.
레시피를 잘 아는 요리사만으로 주문 수천 건을 제시간에 내보낼 수는 없습니다.
주문을 묶고, 재료 공간을 배정하고, 어느 조리대가 일을 맡을지 정해야 합니다.
이 저장소에서 Scheduler는 주문 담당자, BlockManager는 재료 보관함 관리자,
Worker는 조리대 작업 담당자에 가깝습니다.
이미 손질한 재료를 다시 손질하지 않는 것이 캐시 재사용입니다. 여러 메뉴를 동시에 준비하되 완성된 접시를 다른 주문과 섞지 않는 것이 배치 처리와 요청별 상태 관리입니다.
deepinfer/entrypoints/llm.py의
LLM.generate()는 단일 문자열을 목록으로 정규화하고, 각 입력을 _add_request()로 등록합니다.
여기서 샘플링 설정은 copy.deepcopy()로 복사하고 토큰 번호는 np.int32 배열로 맞춥니다.
이어 _run_engine()이 반복해서 엔진을 진행시킵니다.
# 소스의 호출 순서를 요약한 개념도입니다. 실행용 코드가 아닙니다.
문자열 또는 토큰 번호 목록
→ LLM.generate()
→ LLM._add_request()
→ LLMEngine.add_request()
→ LLM._run_engine() 안에서 step() 반복
→ 남아 있는 비동기 결과 flush_inflight_reqs()
→ 요청 번호 순으로 정렬하고 필요하면 문자열로 복원
왜 요청을 하나씩 처리하지 않고 묶는지, 왜 GPU가 끝나기 전에 CPU가 다음 일을 시작하는지, 왜 결과를 반환한 뒤에도 메모리 수명을 신경 써야 하는지 설명해 보세요. 이 세 질문에 답하면 복잡한 최적화 코드를 읽을 기준이 생깁니다.
선정 근거는 TrendShift Weekly #3(2026-10-23)입니다. GitHub 메타데이터에 따르면 2026-10-16에 생성된 저장소가 2026-10-23 기준 스타 20,308개, 포크 2,186개를 모았습니다. 약 일주일 된 공개 저장소라는 점은 관심의 크기를 보여 줍니다. 다만 스타·포크 수와 관심도 순위만으로 실제 사용자 수나 성능 우위를 판단할 수는 없습니다.
코드를 읽는 관점에서 주목할 이유는 명확합니다. README에서 소개하는
FlashMLA·DeepGEMM·DeepEP 같은 연산·통신 부품이
실제 요청 처리 루프 안에서 어떻게 이어지는지 볼 수 있습니다.
“빠른 커널 하나”와 “빠른 추론 시스템” 사이를 공부하기 좋은 자료입니다.
README의 지원 모델은 DeepSeek-V4.1-Flash 하나입니다.
실제 ModelRegistry에도
DeepseekV41ForCausalLM 아키텍처 하나가 등록되어 있습니다.
DeepInfer의 학습 가치는 지원 모델의 개수보다, 특정 모델과 하드웨어에 맞춰 시스템 전체를 조율한 코드에 있습니다.
모델 이름을 바꾸기만 하면 모든 Hugging Face 모델이 동작한다고 해석하면 안 됩니다.
| 도구 | 공식 자료에서 확인한 사용 표면 | DeepInfer와 비교하며 배울 점 |
|---|---|---|
| DeepInfer | 특정 DeepSeek 모델의 오프라인 추론. 내부 스케줄러·병렬 실행·커널 연결 공개 | 모델 구조에 맞춘 메모리 배치와 실행 순서의 구체성이 장점. 온라인 서비스 구성은 추가 작업 |
| vLLM | 온라인 서빙과 OpenAI 호환 HTTP 서버 사용법 제공 | API 서비스 표면과 내부 엔진을 구분해 보기. DeepInfer README도 vLLM을 주요 출발점으로 명시 |
| SGLang | Prefill/Decode 분리와 Mooncake·NIXL 등의 전송 설정 문서 제공 | 엔진 사이 KV 전달과 라우터 연결까지 공부할 때 비교할 자료 |
| TensorRT-LLM | 분리 서빙에서 context·generation 서버와 조정 서버를 구성하는 예제 제공 | GPU 실행 최적화가 실제 온라인 요청 경로와 결합하는 방법 비교 |
경쟁 도구의 설명은 각각의 공식 문서 vLLM 온라인 서빙, SGLang 단계 분리, TensorRT-LLM 분리 서빙에 근거합니다. 동일 장비·동일 모델의 직접 성능 비교표가 아니며, 어느 기능을 DeepInfer만 제공한다고 주장하는 표도 아닙니다.
README의 성능 그래프는 prefill에 SM100 GPU 4개, decode에 64개를 사용했고, 각각 하나의 고속 상호 연결 영역 안에서 측정했다고 적습니다. 이 조건을 지우고 개인용 GPU 한 장의 속도로 받아들이면 비교가 무너집니다. 이 글에서는 그래프 이미지를 보고 수치를 추정하거나 자체 측정 결과처럼 재인용하지 않습니다.
examples/README.md는
decode 처리량이 실제 초안 토큰의 채택률과 무관하게 1 + nextn개를 세는
전부 채택된다고 가정한 환산치라고 명시합니다.
프로파일러를 붙인 구간의 시간도 처리 속도를 산출하는 데 쓰지 말라고 설명합니다.
벤치마크를 배울 때는 큰 숫자보다 무엇을 분모·분자로 세었는지가 먼저입니다.
Python은 요청 API와 모델 실행뿐 아니라 TileLang 커널을 기술하는 언어로도 쓰입니다.
따라서 Python 줄 수가 많다고 CPU에서만 계산하는 프로그램은 아닙니다.
반대로 csrc/의 C++는 주로 스케줄링·입력 메타데이터·바인딩을 담당합니다.
대규모 연산 라이브러리의 구현 전체는 외부 의존성에 걸쳐 있습니다.
| 층 | 실제 의존성·버전 | 역할과 확인 파일 |
|---|---|---|
| Python 패키지 | deepinfer 0.1.0, Python >=3.12 | pyproject.toml. 개발 상태는 Beta로 표시 |
| NVIDIA 런타임 | torch==2.13.0+cu132, flash-attn-4==4.0.0b34 | requirements-nvidia.txt. 일반 PyTorch와 CUDA 변형을 혼동하지 않기 |
| Ascend 런타임 | torch==2.13.0+cpu, torch-npu==2.13.0rc1 | requirements-ascend.txt. CPU 표기 PyTorch에 NPU 지원 패키지를 결합 |
| 모델 입출력 | transformers==4.50.0, tokenizers==0.21.4 | 모델 설정·토크나이저를 연결하는 deepinfer/hugging_face/ |
| 가중치 파일 | safetensors==0.8.0, huggingface_hub==0.36.2 | 가중치 읽기와 체크포인트 경로 해석. 다운로드 진입점은 examples/_config.py |
| 수치·자료 배치 | numpy==2.3.5, einops==0.8.2 | CPU 토큰 배열과 다차원 텐서 재배열 |
| 장치 커널 | tilelang==0.1.15, tile-kernels==2.1.0 | deepinfer/model_executor/layers/tilelang_ops/의 인터페이스 및 CUDA·Ascend 구현 |
| 형식 제약 | xgrammar==0.2.2 | JSON Schema·정규식·EBNF로 다음 토큰의 허용 범위를 제한 |
| 프로세스 통신 | pyzmq==27.1.0, posix_ipc==1.3.2 | 프로세스 간 메시지 및 공유 메모리 경로에 사용하는 의존성 |
버전의 1차 근거는
requirements.txt,
requirements-nvidia.txt,
requirements-ascend.txt입니다.
표의 값은 해당 커밋의 의존성 선언입니다. 실제 설치 환경은 플랫폼별 요구사항에 맞춰야 합니다.
현재 커밋에는 웹 UI용 package.json, React·Vue 앱이나 브라우저 화면 코드가 없습니다.
사용자가 만나는 표면은 Python API와 examples/의 명령행 예제입니다.
FastAPI==0.128.0과 uvicorn==0.40.0은
requirements-dev.txt에 있지만, 이것만 보고 대화형 HTTP 추론 서버가 있다고 결론 내리면 안 됩니다.
실제 deepinfer/engine/profile_server.py는
POST /profile로 실행 추적을 수집하는 선택적 프로파일링 서버입니다.
DEEPINFER_PROFILE_HTTP_ENABLE의 기본값은 꺼짐이며,
포트는 기본 6070 + driver_gpu_id입니다. 추론 서비스 API와 관측용 API를 구분하는 좋은 예입니다.
pyproject.toml의
빌드 의존성은 setuptools >= 77.0.3, torch >= 2.7, ninja입니다.
플랫폼별 requirements의 PyTorch 고정 버전과 역할이 다릅니다.
빌드 도구의 최소 버전 선언은 이 저장소가 실제로 맞춰 놓은 실행 환경 전체를 뜻하지 않습니다.
# build.sh와 scripts/build.sh의 주요 처리 순서
build.sh
→ requirements-nvidia.txt 또는 requirements-ascend.txt 선택
→ NVIDIA이면 nvidia-nccl-cu13==2.32.3으로 교체
→ scripts/build_vendor.sh: 서브모듈 초기화와 wheel 빌드
→ scripts/build.sh build: setup.py로 deepinfer._C 빌드
→ deepinfer/_so/{플랫폼}-{아키텍처}/ 아래에 확장 연결
setup.py는
공통 컴파일 옵션 -O2, -std=c++20,
_GLIBCXX_USE_CXX11_ABI=1을 사용합니다. NVIDIA는 CUDAExtension,
Ascend는 NpuExtension을 선택합니다.
scripts/build.sh의 기본 병렬 빌드 수 MAX_JOBS는 16입니다.
단순 Python 패키지 설치와 달리 컴파일러·ABI·가속기 SDK가 함께 맞아야 합니다.
| 외부 서브모듈 | HEAD가 고정한 커밋 앞부분 | 역할 |
|---|---|---|
| DeepEP | f6aa38fe | MoE 전문가 사이의 토큰 통신 |
| DeepGEMM | 1fc9c669 | 행렬곱·MoE 연산 경로 |
| FlashMLA | 2e5429fc | 어텐션 연산 가속 경로 |
| DeepSelect | bfa4507d | 희소 어텐션의 후보 선택 경로 |
| Ascend 변형 | DeepEP 3b25377d, DeepGEMM 3a353262 | 같은 역할을 Ascend용 구현으로 연결 |
.gitmodules의 URL과 git ls-tree HEAD vendor/의 커밋 참조가 외부 의존성을 지정합니다.
외부 구현은 별도 저장소에 있으며 빌드 시 서브모듈 초기화가 필요합니다.
여기서는 DeepInfer 쪽 호출·연결 구조를 다룹니다.
requirements-dev.txt에는 pytest==8.4.2, pytest-xdist==3.8.0,
ruff==0.15.0, clang-format==22.1.3이 있습니다.
pyproject.toml은 Ruff의 줄 길이를 140으로 설정하고, pytest의 기본 검색 경로를 tests로 지정합니다.
import 단계의 무거운 의존성 유입을 줄이기 위한 --import-mode=importlib 설정도 확인됩니다.
커밋 9bd9cf2의 추적 파일에는 Dockerfile, .github/workflows/, GitLab CI 설정이 없습니다.
반면 CONTRIBUTING.md와 pytest 설정에는 ci·ci_npu 마커가 있습니다.
테스트를 분류하는 규칙은 공개되어 있지만, CI 실행 파이프라인까지 공개되어 있다고 볼 근거는 없습니다.
아래는 소스의 책임 경계를 단순화한 시스템 구조도입니다.
Python과 C++가 각각 하나의 서버라는 뜻은 아닙니다. C++ 엔진은 deepinfer._C 확장으로 Python에서 호출됩니다.
Worker는 병렬 구성에 따라 여러 프로세스·장치로 확장되며, 이 그림은 모든 통신 채널을 나열한 배포도가 아닙니다.
LLM이 입력 형식을 맞추면 LLMEngine이 요청 상태와 Worker 호출을 조율합니다.
배치의 실행 대상을 고르는 핵심은
csrc/engine/scheduler.hpp의
Scheduler::_schedule()·_schedule_prefill()·_schedule_decode()입니다.
애플리케이션 코드가 GPU 메모리 블록을 직접 골라야 하는 구조를 피한 셈입니다.
_schedule()은 py::gil_scoped_release로 Python의 GIL을 놓고,
BlockManagerMutexAcquire로 블록 관리자와 상태 관리자를 잠급니다.
Python 스레드를 계속 막아 두지 않는 것과 공유 자원을 안전하게 보호하는 것은 별개의 문제입니다.
“C++로 바꾸면 빨라진다”보다 언제 잠그고 언제 다른 실행을 허용하는지를 읽어야 합니다.
| 엔진 종류 | 소스의 분기 | 교육적으로 볼 지점 |
|---|---|---|
NORMAL | prefill과 decode를 선택 | DP 그룹의 구성원들이 같은 단계로 움직이도록 투표 |
PROMPT | _schedule_prefill() | 입력 처리 전용 엔진을 만들 수 있는 내부 경계 |
COMPLETION | _schedule_decode() | 출력 생성 전용. prefill 경로가 없으므로 선점 시 재계산 정책에도 제약 |
NORMAL은 기본 70 decode 단계마다 모든 rank가 prefill 조건을 충족하는지 확인하고,
기본 100단계마다 한 rank라도 조건을 충족하면 prefill을 시도합니다.
조건은 캐시 사용률 90% 이하이면서 waiting 큐의 맨 앞 요청이 스케줄 가능한 상태인 것입니다.
두 주기가 겹치면 100단계 규칙을 적용하며, prefill 직후 decode 단계 수가 0일 때도 전원 조건을 확인합니다.
설정은 DEEPINFER_PREFILL_ATTEMPT_INTERVAL·DEEPINFER_PREFILL_ANY_ATTEMPT_INTERVAL입니다.
이는 초 단위 타이머가 아닙니다. 여러 rank가 서로 다른 집단 통신을 호출해 멈추지 않도록 단계 종류를 맞춥니다.
첫 투표에서 prefill을 원했어도 슬롯이나 KV 블록 부족으로 실제 배치가 비면,
_schedule()은 두 번째 투표로 전원이 빈손인지 확인하고 decode로 돌아갑니다.
자원은 없는데 빈 prefill만 반복하는 상황을 막는 장치입니다.
분산 시스템에서는 일을 하고 싶다는 상태와 실제 일을 배정했다는 상태를 분리해야 한다는 사례입니다.
자원 부족도 단순한 참·거짓이 아닙니다.
BlockManager::can_allocate_nolock()는
다음처럼 현재 가능·나중에 가능·구조적으로 불가능을 나눕니다. 아래는 해당 함수의 본문입니다.
AllocStatus can_allocate_nolock(int to_allocate_blocks) {
if (to_allocate_blocks >= num_blocks) {
return AllocStatus::NEVER;
}
if (blocks.num_free_blocks() >= to_allocate_blocks) {
return AllocStatus::OK;
}
return AllocStatus::LATER;
}
블록 번호 0은 비어 있음을 뜻하도록 예약됩니다. 그래서 총 블록 수가 8이면 실제 사용 가능한 번호는 1~7입니다.
LATER는 다른 요청이 메모리를 돌려주면 진행할 수 있다는 뜻이고,
NEVER는 기다리기만 해서는 해결되지 않는 크기라는 뜻입니다.
이 구분은 작업 큐·연결 풀·업로드 용량 제한 같은 일반 백엔드에도 적용할 수 있습니다.
Worker.execute_model_step()의
순서는 특히 중요합니다. 현재 단계의 모델 계산을 먼저 내보내고, 이전 단계의 결과를 후처리한 뒤,
현재 단계의 샘플링을 시작합니다. ZOS가 켜진 decode에서는 현재 결과의 후처리를 다음 호출로 미룹니다.
prefill이나 ZOS가 꺼진 경우에는 현재 결과를 그 자리에서 처리합니다.
비동기 최적화의 핵심은 기다림을 뒤로 미루면서도, 아직 쓰는 데이터의 수명을 함께 늘리는 것입니다.
WorkerStepState는 이전 단계의 메타데이터·샘플링 결과·완료 이벤트를 보관합니다.
_post_process_step()은 sample_end_evt.synchronize() 이후에 후처리를 시작합니다.
ZOS라는 이름은 동기화가 완전히 사라진다는 뜻이 아니라, CPU 작업을 장치 계산과 겹치게 하는 설계 의도를 나타냅니다.
deepinfer/engine/llm_engine.py의 DeferredRelease는
메타데이터·출력과 복제 작업의 자원을 모았다가 안전한 지점에서 해제합니다.
더 바깥의 LLM._run_engine()도 반환받은 출력을 RequestOutput.clone(raw_output)으로 복사합니다.
코드에 적힌 이유는 원본 출력이 다음 단계에서 회수될 수 있기 때문입니다.
공용 칠판에 적힌 답을 다른 팀이 곧 지울 예정이라면, 내가 오래 보관할 답은 따로 옮겨 적어야 합니다. 원본 결과를 빌려 쓰는 것과 복사해서 소유하는 것은 다릅니다. 비동기 시스템에서 복사를 없애려면 먼저 “누가 언제까지 지우지 않을 것인가”라는 약속이 필요합니다.
deepinfer/platform.py의
PlatformGPU는 tilelang_ops_backend="cuda"와 distributed_backend="nccl",
PlatformNPU는 "asc"와 "hccl"을 선택합니다.
상위 모델 코드에 장치별 조건문을 계속 늘리는 대신 선택 지점을 모은 구조입니다.
deepinfer/model_executor/layers/tilelang_ops/ops.py는
선택된 백엔드 디렉토리를 읽고 이름이 _tl로 끝나는 공개 커널 팩토리를 내보냅니다.
같은 이름이 충돌하면 assert로 잡고, 없는 커널을 요청하면 KernelUnavailableError를 냅니다.
함수 이름을 맞추는 계약과 누락을 드러내는 실패 경로까지 인터페이스 설계의 일부입니다.
# 실제 norm 관련 파일의 책임을 정리한 경로입니다.
deepinfer/model_executor/layers/tilelang_ops/norm.py
norm(): 텐서 모양·stride·출력 공간과 옵션을 준비
|
v
deepinfer/model_executor/layers/tilelang_ops/ops.py
현재 플랫폼의 norm_tl 선택
|
+→ deepinfer/model_executor/layers/tilelang_ops/cuda/norm.py: @tilelang.jit(target="cuda")
+→ deepinfer/model_executor/layers/tilelang_ops/asc/norm.py: Ascend 백엔드 구현
CUDA의 norm_tl()은 0 < d <= 8192를 검사하고,
기본 128 threads에서 벡터화·패딩·점유율을 고려해 실행 구성을 조절합니다.
공통 norm()은 RMSNorm에 residual 덧셈과 FP8 변환을 함께 처리하는 옵션을 제공합니다.
중간 결과를 장치 메모리에 여러 번 쓰고 읽는 일을 줄이는 연산 융합을 배울 수 있는 진입점입니다.
NPU 경로는 단순히 cuda라는 이름을 바꾸는 것으로 끝나지 않습니다.
PlatformNPU.__init__()에는 transfer_to_npu, TILELANG_DEFAULT_TARGET="ascend",
장치 가시성 변수 검사가 있습니다. 공통 API를 제공하면서도 런타임 초기화 차이는 별도로 다룬다는 점이 핵심입니다.
MoE는 토큰마다 일부 전문가 신경망을 선택합니다. 전문가 수가 같아도 특정 전문가로 토큰이 몰리면
그 전문가를 가진 장치가 병목이 됩니다.
rebalance_experts_global()은
과거 토큰 수 [단계, MoE 층, 논리 전문가]를 받아 인기 전문가에 복제본을 추가하고 물리 배치를 다시 정합니다.
_batch_greedy_indices()는 복제본당 부하를 기준으로 전문가를 정렬한 뒤,
각 후보 rank에 놓았을 때 과거 각 단계의 최대 rank 부하를 더한 값이 작아지도록 탐욕적으로 배치합니다.
평균 부하만 같게 만드는 것보다, 같은 순간에 같이 바빠지는 전문가를 나누는 데 초점이 있습니다.
전역 최적해를 보장하는 수학적 최적화라고 단정해서는 안 됩니다.
deepinfer/model_executor/parallel_utils/parallel_state.py에서 구성됩니다.초안 토큰 검증에도 피드백을 사용합니다.
ConfidenceHead.forward()는
초안 토큰의 채택 가능성을 추정합니다.
csrc/engine/mtp_varlen.hpp의
스케줄링은 그 추정치와 decode 성능 곡선을 이용해 검증할 길이를 정합니다.
CPU에 도착한 추정치가 몇 단계 전 결과인지까지 구분하는 코드가 있어, 비동기 통계의 시차도 관찰할 수 있습니다.
DSpark 초안 생성은 다음 후보를 미리 만들고 주 모델이 검증하게 하는 방식입니다.
DEEPINFER_USE_NEXTN_DECODE의 기본값은 5이고, 신뢰도 기반 가변 길이 검증은
DEEPINFER_ENABLE_MTP_VARLEN=1로 켭니다.
후보를 5개 만든다고 매번 최종 답 5개가 추가로 확정되는 것은 아닙니다.
YoCo의 bounded replay는 지원되는 모델 구조에서 consumer 층에 필요한 끝부분만 다시 처리하도록 줄이는 경로입니다.
deepinfer/model_executor/models/v4_modules/yoco.py의 compact_yoco_boundary()는 hidden·residual과 관련 인덱스를 재배열하고,
기존 query 행 배치에 의존한 후보 캐시를 비웁니다.
앞부분을 줄였는데 예전 인덱스를 그대로 쓰면 안 된다는 점이 일반적인 배열 최적화와도 연결됩니다.
구조화 출력은 또 다른 목적입니다.
deepinfer/structure_output/compiler.py의 dispatch_and_compile()은
json·regex·ebnf를 분기하고, JSON은 strict_mode=True로 컴파일합니다.
SOMatcherBuilder.submit()이 작업을 맡기고 pump()가 준비된 요청을 스케줄러에 넣습니다.
형식 제약을 컴파일하는 CPU 작업이 전체 추론 루프를 막지 않도록 한 구조입니다.
문법에 맞는 JSON이라고 내용까지 참인 것은 아닙니다. 출력의 형식 검사와 답변의 의미 검증을 구분하세요. 이 구분은 API 응답 검증, 데이터 파이프라인, AI 애플리케이션의 결과 처리에서도 그대로 필요합니다.
아래는 실제 SamplingParams 인자 형태를 보여 주는 독해용 예시입니다.
네 자리 숫자라는 문법 제약을 전달합니다. max_tokens는 토큰 수의 상한이므로 글자 수 조건과는 다릅니다.
출력 형식은 정규식으로, 최대 생성 길이는 토큰 수로 각각 제한합니다.
# SamplingParams에 정규식 제약 전달
from deepinfer.sampling_params import SamplingParams
params = SamplingParams(
temperature=0.0,
max_tokens=16,
so_args={"schema_type": "regex", "schema": r"[0-9]{4}"},
)
examples/offline_inference.py에서 입력·출력의 형태를 봅니다. 파일을 실행할 필요는 없습니다.deepinfer/entrypoints/llm.py에서 입력 정규화와 요청 번호, 결과 정렬을 찾습니다.deepinfer/engine/llm_engine.py의 step()에서 스케줄링과 Worker 호출이 만나는 지점을 표시합니다.deepinfer/worker/worker.py에서 현재 단계와 이전 단계의 처리가 섞이는 이유를 읽습니다.csrc/engine/scheduler.hpp, deepinfer/model_executor/eplb/policy.py, deepinfer/model_executor/layers/tilelang_ops/norm.py 중 하나로 내려갑니다.처음부터 deepinfer/model_executor/models/v4_modules/의 모든 수식을 따라가려 하면
데이터가 어디서 와서 어디로 가는지 놓치기 쉽습니다.
처음에는 함수 내부의 수학보다 입력의 모양, 상태를 바꾸는 위치, 결과의 소유자를 먼저 표시하세요.
| 분류 | 파일 수 | 물리 줄 수 |
|---|---|---|
Python .py | 270 | 54,929줄 |
C++ .cpp | 15 | 2,425줄 |
C++ 헤더 .hpp | 18 | 3,484줄 |
타입 선언 .pyi | 4 | 819줄 |
셸 .sh | 10 | 410줄 |
git ls-files -z의 추적 경로 중 일반 파일을 확장자별로 나누고 물리 줄 수를 집계한 값입니다.
빈 줄·주석·테스트·예제를 포함하며, 바이너리 이미지·.git·외부 서브모듈 구현은 제외합니다.
확장자 기준 집계이므로 Python 수치에는 TileLang 커널도 들어갑니다.
Python과 C++ 본문·헤더의 줄 수를 더하면 60,838줄입니다. 이를 전체 시스템의 순수 알고리즘 줄 수로 해석하지 마세요.
rebalance_experts_global을 발견했다면 tests/models/test_eplb_policy.py도 읽으세요.
함수 이름 검색 → 입력 텐서 모양 확인 → 결과 사용처 확인 → 테스트의 기대값 확인 순서가 유용합니다.
한 파일의 설명문만 읽는 것보다 계약을 더 정확히 파악할 수 있습니다.
LLM.generate()는 문자열 하나와 문자열 목록을 모두 받지만 내부에서는 목록으로 다룹니다.
_add_request()는 설정을 복사하고 토큰을 np.int32로 맞춥니다.
이렇게 입구에서 형식을 통일하면 내부의 모든 함수가 여러 입력 변형을 반복해서 처리할 필요가 줄어듭니다.
실습 아이디어: 문자열 한 개·목록·토큰 목록이 들어올 때의 분기표를 종이에 그리세요.
prompts와 prompt_token_ids의 길이가 다를 때 생기는 오류도 찾습니다.
학습 목표는 문법 암기보다 내부 코드가 가정할 수 있는 조건을 입구에서 만들어 주는 일입니다.
BlockManagerMutexAcquire는 생성자에서 잠그고 소멸자에서 풉니다.
C++의 RAII는 이런 자원 처리를 객체 수명에 연결하는 기법입니다.
Scheduler::_schedule()에는 이전 출력이 빌려 쓰던 벡터를 다음 호출에서 비우고 재사용한다는 설명도 있습니다.
Python에서 접근 가능하다고 데이터가 영원히 유효한 것은 아닙니다.
실습 아이디어: clone_states·clone_blocks·zero_states의
생성·소비·초기화 위치를 색깔 세 개로 표시하세요.
빌린 데이터를 오래 보관하고 싶을 때 복사와 수명 연장 중 무엇이 필요한지 설명해 보세요.
deepinfer/model_executor/layers/tilelang_ops/norm.py의 _check_vectorized_strides()는 마지막 축이 연속인지와
나머지 stride가 16의 배수인지 검사합니다. 같은 [B, M, d] 모양이라도
메모리에 놓인 간격이 다르면 커널이 요구하는 읽기 방식과 맞지 않을 수 있습니다.
FP8 변환 결과는 값뿐 아니라 scale factor의 배치도 계약에 포함합니다.
실습 아이디어: 2×3 배열을 행 순서로 적고 전치한 뷰에서 원소가 어떻게 읽히는지 추적하세요.
이어 norm()이 미리 할당한 out을 받을 수 있는 이유를 생각합니다.
출력 공간을 재사용하면 할당 비용을 줄일 수 있지만, 동시에 사용하는 요청과 겹치지 않게 관리해야 합니다.
ModelRunner.execute_main_model()과 execute_sample()에는
forbid_cuda_sync() 범위가 있습니다.
장치의 값을 CPU로 가져오는 .item() 같은 연산은 기다림을 만들 수 있습니다.
비동기 실행 경로에 이런 호출이 무심코 끼어들면 겹쳐 실행하려던 계획이 깨질 수 있습니다.
실습 아이디어:
tests/test_cuda_sync_guards.py를 읽고,
허용 범위와 금지 범위가 여러 스레드에서 겹칠 때 무엇을 보장하는지 적습니다.
이 검사는 모든 동기화를 완벽하게 찾는 장치가 아닙니다. 테스트는 동시 허용 범위가 있을 때 일부 금지 보고를 놓치는 절충도 명시합니다.
EPLB의 핵심은 전문가 개수를 똑같이 나누는 일만이 아닙니다.
같은 시점에 바쁜 전문가들을 같은 GPU에 놓으면 다른 GPU가 기다릴 수 있습니다.
_batch_greedy_indices()가 과거 여러 단계의 부하 벡터를 보존하는 이유를 여기서 찾을 수 있습니다.
실습 아이디어: 토큰이 몰리는 전문가에 복제본을 추가하는 정책과, 이미 만든 복제본을 GPU에 배치하는 정책을 두 장의 표로 분리하세요. “얼마나 복제할까”와 “어디에 둘까”가 다른 결정임을 설명할 수 있으면 성공입니다.
| 소스 속 검증 | 확인하는 계약 | 따라 해 볼 사고 실험 |
|---|---|---|
tests/models/test_eplb_policy.py | 양방향 매핑 일치·복제 수·입력 불변·동점 처리 | 작은 전문가 표를 손으로 재배치하고 역매핑 확인 |
tests/models/test_batch_invariant.py | 같은 토큰 경로의 배치·단독 실행 결과 비교 | 난수 선택과 수치 오차를 분리해 비교하는 방법 정리 |
tests/models/test_sampler.py | PIT·KS 검사를 이용한 샘플러 분포 검증 | 문장이 자연스러운 것만으로 분포가 맞다고 할 수 있는지 토론 |
examples/yoco/ | mask·compact의 메타데이터 및 출력 동등성 | 계산을 생략해도 보존되어야 할 값의 목록 만들기 |
최적화를 공부할 때는 무엇이 빨라졌는지와 함께, 무엇이 같아야 하는지를 먼저 적으세요. 여기서 “같다”는 문자열·토큰·확률·통계적 분포 중 무엇인지에 따라 검증 방법이 달라집니다. 표는 테스트가 검사하는 조건을 정리한 것입니다. 검사 항목의 존재와 실제 실행 결과는 구분해야 합니다.
| 항목 | 저장소에서 확인한 요구사항 | 초보자의 해석 |
|---|---|---|
| 운영체제 | README: Linux | 소스 읽기는 다른 OS에서도 가능. 실제 추론 지원과 혼동하지 않기 |
| Python | README: 3.12, 패키지 선언: >=3.12 | 우선 공식 안내의 3.12 조합을 기준으로 읽기 |
| C++ 컴파일러 | GCC >=13.0, 소스 빌드는 C++20 | Python만 준비하면 끝나는 구조가 아님 |
| NVIDIA | SM100 GPU, README: CUDA 13 | requirements는 cu132 PyTorch를 지정. 임의의 CUDA 조합을 보장하지 않음 |
| Huawei | Ascend 950 NPU, CANN 9.2 | torch-npu와 HCCL, Ascend 커널 경로 필요 |
| 모델 | 기본 deepseek-ai/DeepSeek-V4.1-Flash-1017 | 가중치·설정·토크나이저가 맞는 체크포인트 필요 |
| 장치 수 | 오프라인 예제에 EP8·EP2/DP8·EP2/CP8 등 구성 제시 | 예시의 장치 수가 보편적인 최소 요구량이라는 뜻은 아님 |
| RAM·VRAM·디스크 | 공통 최소 용량을 숫자로 명시한 요구사항은 찾지 못함 | 가중치·문맥 길이·배치·병렬 구성에 따른 별도 산정 필요 |
장치 메모리에는 모델 가중치 외에 KV 캐시, 중간 활성값, 통신 버퍼, 초안 생성 상태,
CUDA Graph 관련 공간 등이 들어갑니다.
EngineArgs.gpu_memory_utilization의 기본값 0.90은 모델이 GPU 메모리의 90% 크기라는 뜻이 아닙니다.
가중치·활성값·KV 캐시를 위해 확보할 메모리 비율이며, 이 값만으로 특정 장비의 수용 가능성을 판단할 수 없습니다.
WorkerBase.profile_num_available_blocks()는
모델 실행을 프로파일링한 뒤, 메모리 활용 한도에서 PyTorch 최대 할당량과 0 이상으로 보정한 PyTorch 외 할당량을 차감합니다.
상태 저장·복사 버퍼 예약분도 빼고 블록 크기로 나눕니다. 이후 전체 프로세스 그룹에서 블록 수를 평균 내고 짝수로 내림합니다.
실행 가능한 배치 크기는 모델 파일 크기뿐 아니라, 실제 실행 경로의 메모리 사용량으로 결정됩니다.
현재 README가 명시한 가속기는 SM100과 Ascend 950입니다. Apple Silicon·CPU 단독·다른 세대 GPU는 README의 지원 대상에 포함되지 않습니다. Linux와 Python을 설치했다는 조건만으로 모델을 실행할 수 있는 것은 아닙니다.
아래 실습은 설치·모델 다운로드·추론 코드 실행 없이 완수하도록 구성했습니다. 실제 성능 재현은 별도의 장비와 검증된 의존성 환경이 준비된 뒤 다룰 주제입니다.
examples/_config.py의 resolve_model_path()는 경로가 로컬 디렉토리가 아니면
huggingface_hub.snapshot_download()로 모델을 받습니다.
로컬 디렉토리는 config.json이 있는지 확인합니다.
DEEPINFER_HF_MODEL_DIR은 기본 모델 이름을 해석할 때 적용되며,
사용자가 따로 전달한 모델 이름까지 무조건 덮어쓰지는 않습니다.
또한 build.sh는 패키지를 설치하고 서브모듈을 가져와 빌드합니다.
모델 이름 해석과 빌드 과정에는 네트워크 접근이 포함될 수 있으므로, 로컬 경로를 읽는 일과 구분해야 합니다.
요구사항 표의 근거는 README와 해당 커밋의 설정·소스입니다.
모든 과제는 DeepInfer/ 저장소의 파일을 읽는 방식으로 진행합니다. 답은 별도의 학습 노트에 적으세요.
아래 명령은 텍스트 검색용이며, 추론 코드나 빌드 스크립트를 실행하는 명령이 아닙니다.
명령을 쓰지 않고 편집기의 검색 기능으로 같은 결과를 찾아도 됩니다.
읽을 파일: README.md, deepinfer/environ.py,
deepinfer/engine/arg_utils.py, examples/_config.py.
할 일: nextn, ZOS, YoCo truncation, batch invariance의 기본값과 변경 지점을 표로 만드세요.
특히 EnvVar의 기본값만 읽었을 때와 EngineArgs.__post_init__()까지 읽었을 때의 차이를 찾습니다.
완료 기준: nextn은 기본 5, YoCo truncation은 off, batch invariance는 꺼짐이고,
ZOS는 엔진 종류에 따라 기본 환경값을 정한다는 사실을 설명합니다.
NORMAL·COMPLETION은 기본 켜짐, PROMPT는 기본 꺼짐입니다.
# 저장소 루트에서 문자열만 검색합니다.
rg -n 'DEEPINFER_USE_NEXTN_DECODE|DEEPINFER_ZERO_OVERHEAD_SCHEDULING' \
deepinfer/environ.py deepinfer/engine/arg_utils.py
rg -n 'default_zero_overhead_scheduling' deepinfer/engine/engine_type.py
추가 질문: 환경변수가 처음 접근할 때 캐시된다면 나중에 os.environ만 바꾸는 것으로 충분할까요?
deepinfer/environ.py의 rearm()·rearm_all()과 tests/conftest.py의 _clean_env()를 찾아 이유를 적어 보세요.
읽을 파일: csrc/engine/block_manager.hpp의
Blocks, can_allocate_nolock(), pin_block(), free().
할 일: 전체 블록이 8개이고 사용 가능한 빈 블록이 현재 3개라고 가정합니다. 2개·4개·8개를 새로 요구하면 각각 어떤 상태인지 판단하세요. 이어 같은 블록을 두 요청이 참조하는 동안 한 요청이 끝나면 바로 재사용해도 되는지 설명합니다.
완료 기준: 답은 순서대로 OK, LATER, NEVER입니다.
참조 수가 2→1이면 아직 사용 중이고, 1→0일 때 빈 블록 목록으로 돌아간다는 과정을 표로 제출합니다.
읽을 파일: deepinfer/entrypoints/llm.py의 _run_engine(),
deepinfer/worker/worker.py의 execute_model_step()·flush_inflight_reqs().
할 일: ZOS decode 세 단계를 시간표로 그립니다.
각 단계의 모델 계산, 이전 단계 후처리, 현재 샘플링, prev_step_state 저장 위치를 표시하세요.
새 요청이 없어졌을 때도 마지막 상태를 회수하는 경로를 찾아 연결합니다.
완료 기준: “이번 호출의 결과가 반드시 이번 단계의 계산 결과인 것은 아니다”를 설명하고,
flush가 필요한 이유와 RequestOutput.clone()이 필요한 이유를 각각 적습니다.
전자는 남아 있는 작업 회수, 후자는 회수될 원본에서 결과를 보존하는 문제입니다.
읽을 파일: deepinfer/model_executor/eplb/policy.py와
tests/models/test_eplb_policy.py의 test_batch_greedy_objective_and_ties().
할 일: 전문가 6개를 GPU 두 곳에 3개씩 놓습니다. 과거 부하가 아래와 같을 때 합계가 큰 전문가부터 배치하되, 후보 점수가 같으면 작은 rank를 선택하세요. 이 과제는 복제본 추가 없이 기존 전문가의 위치만 정하는 단계입니다.
전문가 번호 0 1 2 3 4 5
과거 단계 A 10 0 0 0 0 0
과거 단계 B 0 6 4 0 0 0
목표 점수 = A에서 가장 바쁜 GPU의 부하
+ B에서 가장 바쁜 GPU의 부하
완료 기준: 물리 슬롯 순서 [0, 1, 3, 2, 4, 5]를 얻습니다.
GPU0은 전문가 0·1·3, GPU1은 2·4·5를 갖습니다.
전문가 1을 배치할 때 두 후보 점수가 모두 16이어서 GPU0을 선택하는 이유를 설명하세요.
읽을 파일: examples/README.md, examples/benchmark.py,
examples/yoco/README.md, deepinfer/environ.py.
할 일: 가상의 10개 decode 단계가 2초 걸렸고, 매 단계 요청 64개에 nextn=5라고 가정합니다. 전부 채택 가정의 총 처리량과, 요청마다 초안 2개만 채택되고 기본 토큰 1개가 추가된 경우를 비교하세요. 여기서는 GPU 수·CP 정규화를 생략한 전체 토큰 수만 계산합니다.
완료 기준: 전자는 10 × 64 × 6 ÷ 2 = 1,920토큰/초,
후자는 10 × 64 × 3 ÷ 2 = 960토큰/초입니다.
이는 계산 연습용 수치이며 DeepInfer 실측 성능이 아닙니다.
이어 YoCo에서 KEEP_TOKENS >= window_size + MAX_BACKTRACKING_TOKENS가 필요한 이유를 서술합니다.
README의 기본 V4.1 안내는 compact와 KEEP_TOKENS=140입니다.
검증 예제의 window 128과 기본 nextn 5에 따른 최소 backtracking 6을 넣으면 하한은 134입니다.
140은 이 하한을 충족하는 안내값이지 모든 모델에서 통하는 상수가 아닙니다.
mask·compact 동등성 검증의 L1도 문서상 장치 한 개가 필요하므로, 이 과제에서는 실행하지 않고 검증 항목을 읽습니다.
아래 순서는 장비 구매나 전체 설치를 전제로 하지 않습니다. 매주 소스 두세 개를 읽고 작은 산출물을 남기는 계획입니다. 실행 환경을 갖추기 전에도 데이터 흐름과 보존 조건을 설명하는 능력은 충분히 훈련할 수 있습니다.
| 주차 | 배울 기초와 읽을 소스 | 완료할 산출물 |
|---|---|---|
| 1주차 | Python 함수·목록·자료형·예외. deepinfer/entrypoints/llm.py, deepinfer/sampling_params.py | 입력 정규화 분기표와 잘못된 인자 세 가지. 문자열·토큰·요청 번호의 차이 설명 |
| 2주차 | 토큰 생성·KV 캐시·배치의 목적. deepinfer/sequence.py, deepinfer/worker/cache_engine.py | 요청별 상태와 공유 가능한 상태의 구분표. 가중치와 KV의 차이 설명 |
| 3주차 | C++ enum·vector·RAII·pybind11. csrc/engine/block_manager.hpp, csrc/engine/scheduler.hpp | 할당 상태 전이도. 빈 블록·예약 블록·참조 수를 손으로 추적한 표 |
| 4주차 | 비동기 실행·이벤트·메모리 수명. deepinfer/worker/worker.py, deepinfer/worker/zos_status.py, DeferredRelease | 세 단계의 시간표와 종료 flush 경로. 결과 복사를 없애려면 필요한 계약 정리 |
| 5주차 | 분산 그룹·MoE·탐욕 알고리즘. deepinfer/model_executor/parallel_utils/parallel_state.py, deepinfer/model_executor/eplb/policy.py | DP·CP·EP 비교표와 전문가 배치 예제. 동점 처리의 재현성 설명 |
| 6주차 | 커널 융합·수치 형식·검증. deepinfer/model_executor/layers/tilelang_ops/norm.py, deepinfer/model_executor/layers/tilelang_ops/cuda/norm.py, 모델 테스트 | 출력 동등성·배치 불변성·샘플링 분포·성능의 검증 기준을 나눈 한 장짜리 보고서 |
기초가 약하다면 2주차와 3주차 사이에 배열·참조·동시성 개념을 더 공부하세요. 이미 백엔드를 해 본 독자라면 4주차의 이벤트·풀 수명 관리가 기존 경험과 연결되기 쉽습니다. GPU 경험이 있다면 6주차에서 stride와 scale factor 배치, 커널 실행 구성을 더 깊게 추적할 수 있습니다.
도시 전체 지도를 외우기보다 집에서 학교까지 길 하나를 먼저 익히는 방식입니다. “요청 등록 → 배치 선택 → 계산 → 결과 회수”라는 길이 잡히면, 문법 제약·이미지 입력·초안 검증은 그 길에 새 정거장을 추가하며 이해할 수 있습니다.
이후 실제 장비를 확보했다면 같은 모델·커밋·입력·문맥 길이·병렬 구성·정밀도를 고정한 검증 계획부터 세우세요. 먼저 출력 보존 조건을 확인하고 그다음 측정 구간과 워밍업을 정하는 순서가 좋습니다. 이 문서의 범위는 그 계획을 작성할 만큼 코드를 이해하는 데까지입니다.
| 용어 | 쉬운 설명 |
|---|---|
| 추론 | 이미 배운 모델로 새 입력의 답을 계산하는 일. 이 저장소의 중심 과제 |
| 토큰 | 모델이 읽고 쓰는 번호 단위. 자연어 단어나 글자 수와 꼭 일치하지 않음 |
| Prefill | 입력 토큰을 읽고 이후 생성에 쓸 내부 상태를 준비하는 단계 |
| Decode | 이전 상태를 참조하며 출력 토큰을 이어 만드는 단계 |
| 배치 | 여러 요청의 계산을 한 묶음으로 처리하는 것. 처리량과 대기 시간 사이에 절충이 생김 |
| KV 캐시 | 어텐션 연산에서 다시 쓸 Key·Value 상태. 모델 가중치나 완성된 답변 문자열의 캐시와 다름 |
| 블록 테이블 | 한 요청이 사용하는 실제 KV 블록 번호의 목록. 논리적 문맥과 물리 저장 공간을 연결 |
| MoE | 여러 전문가 신경망 중 일부를 토큰별로 골라 계산하는 모델 구조 |
| 논리·물리 전문가 | 모델이 정의한 전문가는 논리 전문가, 장치에 배치한 그 전문가의 복제본은 물리 전문가 |
| DP · CP · EP | 요청·문맥·전문가처럼 서로 다른 단위를 나누는 병렬화 방식 |
| EPLB | 전문가별 부하에 맞춰 복제본 수와 배치를 조정하는 정책 |
| Rank | 분산 실행에 참여하는 프로세스의 번호. 그룹 안에서 자신의 역할을 식별 |
| All-reduce | 여러 참여자의 값을 합·최솟값 같은 규칙으로 모으고 결과를 함께 받는 집단 통신 |
| ZOS | CPU의 배치·후처리 작업을 장치 실행과 겹치는 비동기 스케줄링 방식 |
| 이벤트 | 장치 작업의 특정 지점까지 끝났는지 확인하거나 실행 시간을 재는 표식 |
| 객체 풀 | 반복 사용할 객체를 모아 두고 빌려주고 돌려받는 구조. 반납 뒤 원본을 계속 참조하면 위험 |
| CUDA Graph | 반복되는 장치 작업 흐름을 기록해 재사용하는 방식. 입력 버퍼·메모리 수명 관리가 중요 |
| 커널 융합 | 여러 작은 연산을 함께 실행해 중간 메모리 접근과 호출 비용을 줄이는 최적화 |
| BF16 · FP8 · FP4 | 서로 다른 비트 폭의 수치 형식. 저장·연산 효율과 표현 정확도를 함께 고려해야 함 |
| Scale factor | 낮은 비트 폭으로 저장한 수치의 크기 범위를 해석하는 데 필요한 배율 정보 |
| 초안 검증 | 미리 제안한 여러 토큰을 주 모델이 확인하는 생성 방식. 제안 수와 최종 채택 수는 다름 |
| SWA | 가까운 토큰 범위만 참조하는 슬라이딩 윈도 어텐션(sliding window attention) |
| YoCo | 이 저장소에서는 KV 공유 구조와 consumer 층의 제한된 재처리 경로를 이해할 때 만나는 이름 |
| 배치 불변성 | 함께 처리되는 다른 요청이 달라져도 같은 입력의 모델 계산 결과를 유지하려는 성질 |
| 결정적 샘플링 | 고정된 조건과 난수 시드로 같은 출력 선택을 재현하는 것. 배치 불변성과 별도 조건 |
| 구조화 출력 | 생성 토큰의 허용 범위를 문법으로 제한해 JSON·정규식·EBNF 형식을 따르게 하는 것 |
| ABI | 컴파일된 부품들이 서로 호출하고 데이터를 주고받는 약속. 확장 모듈의 호환성에 영향 |
| NUMA | CPU와 메모리의 접근 거리가 균일하지 않은 시스템 구조. 장치와 가까운 CPU 배치가 중요 |
| PPL | 정해진 토큰 경로에 모델이 부여한 확률로 계산하는 예측 불확실성 지표. 이 저장소의 회귀 검사에도 사용 |
재현 가능한 출력을 원할 때 README는 NVIDIA에서 DEEPINFER_BATCH_INVARIANT=1,
DEEPINFER_ENABLE_MTP_VARLEN=0, 고정된 SamplingParams.seq_seed를 함께 안내합니다.
시드를 고정하는 일 하나가 배치 구성·수치 연산·가변 검증 길이의 모든 차이를 해결한다고 생각하지 마세요.
| 항목 | 확인 내용과 근거 |
|---|---|
| 스타 / 포크 | 20,308 / 2,186 — 2026-10-23 GitHub 기준 |
| 생성일 | 2026-10-16 — 2026-10-23 GitHub 기준 |
| 최근 push | 2026-10-21 — 2026-10-23 GitHub 기준 |
| 최근 커밋 | 9bd9cf2, 2026-10-21. DeepEP 갱신과 SSH→HTTPS URL 치환 규칙 제거, PR #157 |
| 최신 릴리스 | 없음 (2026-10-23 GitHub 기준). 패키지 선언 버전 0.1.0과 GitHub 릴리스는 별개 |
| 주 언어 | Python — 2026-10-23 GitHub 기준. 실제로 Python·C++·TileLang 연산 경로가 함께 존재 |
| 코드 규모 | Python 270파일·54,929줄, C++ 33파일·5,909줄. 커밋 9bd9cf2 기준, 빈 줄·주석 포함, 서브모듈 구현 제외 |
| 타입·빌드 코드 | .pyi 819줄, 셸 410줄. 주요 언어 집계와 별도 |
| 패키지 상태 | pyproject.toml: 버전 0.1.0, 개발 상태 Beta, Python >=3.12 |
| 라이선스 | Apache-2.0 — 2026-10-23 GitHub 기준 및 저장소 LICENSE |
| 공개 사용 범위 | README 기준 오프라인 추론. 완성된 온라인 서비스에 필요한 KV 시스템·단계 분리·복제본 부하 분산은 별도 |
| 소스 기준 | 커밋 9bd9cf2의 추적 파일·의존성 선언·핵심 구현·테스트 명세. 성능 조건은 README와 예제 문서 기준 |
README는 완전한 서비스에 별도의 KV 캐시 시스템, VE/Prefill/Decode 분리, prefill·decode 복제본 부하 분산이 필요하다고 명시합니다.
공개 코드에 CacheEngine과 블록 관리자가 존재하는 것은 이 설명과 모순되지 않습니다.
장치 내부의 실행용 캐시를 관리하는 일과, 요청·엔진 사이에서 캐시를 장기간 저장·전달하는 서비스는 범위가 다릅니다.
운영 설계 문답의 장기 캐시 보관·대규모 클러스터 운영 설명은 배경 자료입니다. 서비스 전체를 구성하려면 README에 명시된 외부 계층을 함께 준비해야 합니다. README 성능 주장, 문서의 벤치마크 환산치, 이 글의 가상 계산 예시는 각각 구분해서 읽어야 합니다.
이 커밋의 지원 모델·장비는 한정되어 있으며 외부 연산 구현은 별도 서브모듈로 관리됩니다. 설치 가능성은 패키지 배포 상태와 플랫폼 환경에, 성능과 정확성은 모델·장비·설정과 검증 조건에 따라 달라집니다.