모델 가중치를 공개하는 일은 이제 흔합니다. 하지만 같은 모델을 실제 서비스 규모로 돌리는 추론 엔진을 공개하는 일은 드뭅니다. DeepSeek가 10월 20일 DeepInfer를 Apache-2.0으로 공개했습니다. 저장소를 열어 보면 첫인상은 "vLLM을 주 기반으로 삼아 DeepSeek 모델에 맞춘 고성능 엔진"에 가깝습니다.
그런데 README 끝부분에는 중요한 단서가 붙어 있습니다.
A KV cache system, VE/Prefill/Decode disaggregation (most required engine functionality is already implemented), and load balancing across data-parallel replicas for both prefill and decode are required for a complete inference service and are not included in this release.
한마디로, 공개된 것은 완성된 서비스가 아니라 서비스의 핵심 부품과 설계도입니다. 이 구분을 놓치면 "오픈소스로 공개됐다는데 왜 바로 서비스에 못 붙이지"라는 질문에서 막힙니다. 이 글은 공식 README, 저장소 안의 배포 Q&A, 예제 코드를 기준으로 DeepInfer가 실제로 무엇을 열었고, 무엇을 남겼는지 정리합니다.
공개된 것과 빠진 것
먼저 범위를 표로 나눠 보겠습니다. 이 표만 봐도 도입 가능 여부의 절반은 판단할 수 있습니다.
| 구분 | 내용 | 실무 의미 |
|---|---|---|
| 코드 라이선스 | Apache-2.0 | 상용 사용과 수정이 가능하지만 고지 의무는 지켜야 함 |
| 모델 라이선스 | DeepSeek-V4.1-Flash-1017, MIT | 코드 라이선스와 별개이므로 모델 카드도 확인해야 함 |
| 지원 모델 | DeepSeek-V4.1-Flash-1017 하나 | 다른 모델은 모델 구현과 커널을 직접 붙여야 함 |
| 지원 하드웨어 | NVIDIA SM100, Huawei Ascend 950 | H100·A100·소비자용 GPU는 공식 지원 목록에 없음 |
| 포함 | 최적화 커널, EP/CP 병렬화, DSpark, SWA bounded replay, 비동기 스케줄링, 배치 불변 추론, 결정적 샘플링, 구조화 출력 | 엔진 내부 최적화를 읽고 재사용할 수 있음 |
| 미포함 | KV 캐시 시스템, 완성된 E/P/D 분리 구성, 데이터 병렬 복제본 간 로드밸런싱 | 완성된 서비스로 바로 배포하기 어려움 |
여기서 "E/P/D 분리는 대부분 구현됐지만 릴리스에는 완성된 형태로 포함되지 않았다"는 문장을 눈여겨볼 필요가 있습니다. 코드가 전혀 없다는 뜻이 아니라, 서비스로 조립할 때 필요한 마지막 부품과 운영 구성이 빠져 있다는 뜻입니다. DeepSeek도 배포 Q&A에서 KV 캐시 관리와 로드밸런싱이 내부 인프라와 강하게 결합돼 있어 아직 전체 공개가 어렵다고 설명합니다.
[공개된 부품]
모델 로딩 -> 최적화 커널 -> EP/CP 병렬화 -> 스케줄러
-> DSpark 검증 -> SWA 재생 -> 샘플러 -> 구조화 출력
[서비스로 만들기 위해 직접 붙여야 하는 것]
요청 라우터 / KV 캐시 저장소 / Prefill-Decode 전송
/ 데이터 병렬 복제본 로드밸런서 / 오토스케일링 / 장애 복구 / 관측성
이 구조는 DeepInfer를 "vLLM 대체품"으로만 보면 놓치는 지점을 보여줍니다. DeepInfer는 모델 실행 코어에 가깝고, 주변의 운영 계층은 사용자가 채워야 합니다.
왜 추론 엔진이 모델만큼 어려운가
추론은 크게 두 단계로 나뉩니다.
요청
-> 토크나이즈
-> prefill: 프롬프트 전체를 한 번에 계산
-> decode: 출력 토큰을 하나씩 생성
-> detokenize
prefill: 계산량이 많아 GPU 연산이 병목
decode: 매 토큰마다 KV 캐시를 읽어 메모리 대역폭이 병목
prefill은 첫 토큰까지 걸리는 시간(TTFT)을 좌우하고, decode는 토큰 사이 간격(ITL)과 전체 생성 시간을 좌우합니다. 같은 모델이라도 이 두 단계를 어떻게 나누고, 배치를 어떻게 묶고, KV 캐시를 얼마나 재사용하는지에 따라 비용과 지연이 크게 달라집니다.
DeepSeek-V4.1-Flash는 MoE 모델입니다. 전문가를 여러 GPU에 나눠 두고 토큰을 라우팅합니다. Expert Parallelism(EP)을 키우면 전문가당 메모리 트래픽이 줄어 decode 효율이 좋아질 수 있지만, 통신 비용과 전문가별 부하 불균형이라는 대가가 따릅니다. DeepInfer의 EP/CP 병렬화, EPLB, 비동기 스케줄링은 바로 이 줄다리기를 다루는 장치입니다.
DeepInfer의 여섯 가지 장치
README가 내세우는 기능을 "무엇을 푸는가"와 "어떤 조건이 붙는가"로 다시 정리하면 다음과 같습니다.
| 장치 | 푸는 문제 | 문서상 조건과 주의 |
|---|---|---|
| 비동기 스케줄링 | CPU의 배치 스케줄링과 GPU 실행을 겹쳐 유휴 시간을 줄임 | 기본 활성화. 디버깅과 추적이 복잡해짐 |
| 배치 불변 추론 | 배치 구성이 달라도 같은 결과를 유지 | DEEPINFER_BATCH_INVARIANT=1, NVIDIA 전용 |
| 결정적 샘플링 | 같은 입력·파라미터·시드에 같은 출력 | 배치 불변 + MTP 가변 길이 비활성 + 고정 seq_seed, NVIDIA 전용 |
| 구조화 출력 | JSON 스키마·정규식·EBNF로 출력 형식을 강제 | so_args로 전달. 문법 컴파일 비용과 표현 범위를 확인해야 함 |
| DSpark | draft 토큰과 신뢰도 기반 검증으로 decode 가속 | 기본 draft 길이 5. 동시성이 낮으면 이득이 없을 수 있음 |
| SWA bounded replay | 긴 문맥에서 KV 캐시 재계산 범위를 줄임 | 정확한 재계산이 아닌 근사. 품질 회귀를 별도로 확인해야 함 |
비동기 스케줄링: GPU가 기다리지 않게
decode 한 스텝은 대략 schedule -> forward -> sample -> post-process로 진행됩니다. 스케줄링과 후처리는 CPU 일이고, forward와 sample은 GPU 일입니다. 순서대로 실행하면 CPU가 일하는 동안 GPU가 놀고, GPU가 일하는 동안 CPU가 놀 수 있습니다.
DeepInfer는 다음 스텝의 스케줄링을 현재 스텝의 GPU 실행과 겹칩니다. 배포 Q&A는 SGLang과 NanoFlow의 기존 구현을 참고했다고 밝힙니다. 효과는 CPU 오버헤드가 큰 워크로드에서 커지지만, 모든 워크로드에서 같은 폭으로 좋아진다고 가정하면 안 됩니다. 비동기 파이프라인은 버그가 났을 때 원인 추적도 어렵게 만듭니다.
배치 불변과 결정적 샘플링: 재현성은 플래그 하나로 끝나지 않는다
LLM 출력은 같은 프롬프트라도 배치 크기, 배치 구성, 커널 버전, speculative decoding 설정에 따라 달라질 수 있습니다. 배치 불변 추론은 배치 구성이 바뀌어도 결과를 같게 유지하는 기능입니다. 평가나 회귀 테스트를 운영하는 팀에는 매력적입니다.
하지만 README가 말하는 "결정적 샘플링"은 조건이 꽤 구체적입니다.
DEEPINFER_BATCH_INVARIANT=1
DEEPINFER_ENABLE_MTP_VARLEN=0
SamplingParams(seq_seed=고정값)
세 조건을 모두 만족해야 하고, NVIDIA에서만 동작합니다. 여기에 더해 모델 버전, 커널 버전, 하드웨어가 바뀌면 같은 출력이 보장된다고 가정해서는 안 됩니다. "deterministic"이라는 단어를 보고 평가 파이프라인 전체가 재현된다고 결론 내리기보다, 내 환경에서 같은 입력을 여러 번 돌려 해시가 같은지 확인해야 합니다. 공식 문서에는 이 기능의 성능 비용 수치가 없으므로, 처리량과의 trade-off도 직접 재야 합니다.
구조화 출력: 형식은 보장하지만 내용은 보장하지 않는다
구조화 출력은 JSON 스키마, 정규식, EBNF 문법을 받아 매 decode 스텝에서 허용된 토큰만 남깁니다. 공식 예제는 SamplingParams의 so_args에 schema_type과 schema를 넘기는 방식입니다. 배포 Q&A에 따르면 문법 컴파일은 추론과 분리해 비동기로 처리하고, 요청이 엔진에 들어가기 전에 컴파일 결과를 가져옵니다.
Tool call이나 API 응답을 안정적인 JSON으로 받고 싶을 때 유용합니다. 다만 구조화 출력은 "형식이 맞는 출력"을 보장할 뿐, "사실이 맞는 출력"이나 "안전한 출력"을 보장하지 않습니다. 문법에 맞는 거짓말은 얼마든지 만들 수 있습니다. 보안 경계로 쓰면 안 됩니다.
DSpark: 동시성이 낮으면 이득이 사라질 수 있다
DSpark는 draft 모델이 여러 토큰을 먼저 제안하고, confidence head가 토큰별 수용 가능성을 추정해 검증할 길이를 고릅니다. 고정 길이로 검증하면 수용 가능성이 낮은 토큰에 연산을 낭비할 수 있는데, 이를 줄이려는 설계입니다.
DeepSeek가 배포 Q&A에 공개한 EP64/DP64 측정을 보면, 이 최적화가 공짜가 아니라는 점이 드러납니다.
| 동시성(seqs/rank) | 고정 5 검증 길이 | 동적 검증 길이 | 고정 5 수용 길이 | 동적 수용 길이 | 고정 5 tok/s/rank | 동적 tok/s/rank | 차이 |
|---|---|---|---|---|---|---|---|
| 16 | 5 | 4.44 | 3.32 | 3.24 | 4,891 | 4,816 | -1.5% |
| 32 | 5 | 3.65 | 3.25 | 3.17 | 8,964 | 9,111 | +1.6% |
| 60 | 5 | 3.58 | 3.30 | 3.21 | 13,730 | 14,466 | +5.4% |
| 96 | 5 | 3.24 | 3.29 | 3.12 | 16,817 | 18,660 | +11.0% |
읽을 점은 세 가지입니다.
첫째, 검증 길이는 5.00에서 3.2~4.4로 줄지만 수용 길이는 거의 그대로입니다. 검증 연산을 줄이면서 실제로 채택되는 토큰 수는 크게 잃지 않는다는 뜻입니다.
둘째, 이득은 동시성에 따라 뒤집힙니다. 동시성이 16일 때는 -1.5%로 오히려 손해이고, 60에서 +5.4%, 96에서 +11.0%입니다. 동시성이 낮은 서비스라면 DSpark를 켰을 때 이득이 없다고 가정해야 합니다.
셋째, 이 표는 DeepSeek의 운영 지점(약 60 seqs/rank)을 포함하지만, 내 워크로드의 최적점은 다를 수 있습니다. DSpark를 켜고 끈 A/B 테스트 없이 "동적 검증이 더 빠르다"고 일반화하면 안 됩니다.
SWA bounded replay: 근사라는 점을 기억해야 한다
긴 문맥에서는 prefill 비용이 커집니다. DeepInfer는 SWA(슬라이딩 윈도우 어텐션) 캐시를 복원할 때 전체 문맥을 다시 계산하지 않고, 마지막 128토큰만 재생하는 방식을 씁니다. README는 기본 설정으로 DEEPINFER_YOCO_PREFILL_TRUNCATION_MODE=compact와 DEEPINFER_YOCO_PREFILL_KEEP_TOKENS=140을 안내합니다. 유지하는 suffix가 SWA 윈도우와 최대 백트래킹 길이를 덮어야 한다는 조건도 붙습니다.
중요한 것은 배포 Q&A가 이 결과를 "approximate SWA KV cache"라고 부른다는 점입니다. 정확한 KV 캐시를 복원하는 것이 아니라 근사합니다. DeepSeek는 PPL 기준선으로 회귀를 감시하지만, 품질에 민감한 작업이라면 자체 평가셋으로 별도 확인해야 합니다.
실행 조건: 한 대의 GPU로는 시작하기 어렵다
DeepInfer를 "내 노트북에서 돌려 보자"는 마음으로 접근하면 바로 벽을 만납니다. 공식 문서의 전제 조건을 표로 정리하면 이렇습니다.
| 항목 | 조건 |
|---|---|
| 운영체제 | Linux |
| 빌드 도구 | GCC 13 이상 |
| Python | 3.12 |
| NVIDIA | CUDA 13, SM100 GPU |
| Ascend | CANN 9.2, Ascend 950 NPU |
| 지원 모델 | DeepSeek-V4.1-Flash-1017 |
| README 벤치마크 | prefill 4 SM100, decode 64 SM100 |
| Q&A의 최소 효율 배포 | prefill 64 GPU + decode 64 GPU |
| Q&A의 권장 병렬화 | prefill EP2~8/DP2~8, decode EP64~128/DP64~128 |
특히 "H100에서 돌릴 수 있나"라는 질문에는 README 기준으로 아니오라고 답해야 합니다. 지원 목록에 H100이나 A100이 없습니다. 코드가 다른 하드웨어에서 컴파일될 가능성과 공식 지원은 다른 문제입니다. SM100은 데이터센터용 GPU이고, Ascend 950은 화웨이 NPU입니다. 개인 워크스테이션용 엔진이 아닙니다.
배포 Q&A는 1P+1D 구성도 배포 자체는 가능하다고 하지만, 권장 decode 구성이 EP64 이상이라 가장 작은 효율적 단위를 64P+64D로 봅니다. 즉 "GPU 8대짜리 한 노드"로 시작하는 튜토리얼이 아니라, 클러스터 운영을 전제로 한 코드입니다.
코드로 확인하는 두 가지: 오프라인 추론과 구조화 출력
공식 README의 오프라인 추론 예제는 다음 명령으로 시작합니다.
export DEEPINFER_ACCELERATOR=nvidia
./build.sh
python examples/offline_inference.py --ep 8
이 글에서는 이 명령을 실행하지 않았습니다. SM100 환경이 없기 때문입니다. 명령 자체는 공식 README와 examples/README.md에서 확인한 내용입니다.
구조화 출력은 공식 examples/_structured_output.py를 축약하면 이런 모양입니다.
from deepinfer.sampling_params import SamplingParams
params = SamplingParams(
temperature=0,
max_tokens=64,
so_args={
"schema_type": "json",
"schema": (
'{"type":"object",'
'"properties":{"answer":{"type":"string"}},'
'"required":["answer"]}'
),
},
)
이 snippet은 공식 예제를 읽고 옮긴 미실행 예시입니다. 실제 호출은 llm.generate(prompts=..., sampling_params=[params])처럼 prompt와 함께 넘깁니다. so_args에는 JSON 외에도 정규식(regex)과 EBNF(ebnf)를 지정할 수 있고, 특정 토큰이 나온 뒤에만 문법을 적용하는 trigger 설정도 있습니다.
결정적 샘플링을 원한다면 환경 변수와 시드를 함께 고정해야 합니다.
DEEPINFER_BATCH_INVARIANT=1
DEEPINFER_ENABLE_MTP_VARLEN=0
SamplingParams(seq_seed=42)
README는 이 조합이 NVIDIA에서만 동작한다고 명시합니다. "시드만 고정하면 같은 출력이 나온다"는 기대는 버려야 합니다.
도입 판단: 누구에게 유용하고, 누구에게 이른가
DeepInfer가 유용한 팀과 그렇지 않은 팀을 나누면 이렇습니다.
| 상황 | 판단 |
|---|---|
| V4.1-Flash-1017을 64+ GPU 규모로 서빙하고, KV 캐시와 로드밸런서를 직접 붙일 수 있다 | 검토할 가치가 큼 |
| 범용 OpenAI 호환 추론 서버가 필요하다 | vLLM·SGLang·TensorRT-LLM을 먼저 비교 |
| 단일 GPU나 로컬 워크스테이션에서 돌리고 싶다 | 공식 지원 밖 |
| 평가 재현성이 중요하다 | 배치 불변·결정적 샘플링이 유용하지만, 내 환경에서 검증 필요 |
| tool call용 JSON 출력이 필요하다 | 구조화 출력이 편리하지만, 문법 컴파일 비용 확인 |
| DeepSeek의 서빙 최적화를 공부하고 싶다 | 코드와 Q&A의 학습 가치가 큼 |
도입 전에 최소한 다음 질문에는 답할 수 있어야 합니다.
[ ] 내 모델이 DeepSeek-V4.1-Flash-1017인가?
[ ] SM100 또는 Ascend 950을 확보했는가?
[ ] KV 캐시 저장소와 E/P/D 전송, 로드밸런서를 직접 운영할 수 있는가?
[ ] 64P+64D 규모의 클러스터와 3FS 같은 스토리지를 감당할 수 있는가?
[ ] 결정적 출력이나 구조화 출력이 실제 요구인가?
[ ] DSpark를 켜고 끈 A/B 테스트를 할 수 있는가?
이 중 하나라도 "아니오"라면 DeepInfer는 지금 당장의 서빙 솔루션이 아니라 연구·벤치마크 대상입니다.
결론: 공개된 것은 부품이지 서비스가 아니다
DeepInfer의 진짜 가치는 "DeepSeek의 프로덕션 스택을 무료로 가져다 쓰는 것"이 아닙니다. DeepSeek가 어떤 병목을 어떤 순서로 풀었는지, 특히 prefill과 decode를 나누고, MoE 전문가를 병렬화하고, speculative decoding의 검증 길이를 동적으로 조절하고, 배치 구성에 흔들리지 않는 샘플링을 만드는 방식을 코드로 볼 수 있다는 점입니다.
반대로 완성된 서비스가 필요한 팀에게는 아직 이릅니다. KV 캐시, E/P/D 분리, 로드밸런싱, 오토스케일링, 장애 복구를 직접 붙여야 하고, 지원 모델과 하드웨어도 매우 좁습니다. 도입 결정은 "Apache-2.0이니 무료"가 아니라 "빠진 부품을 우리가 얼마에 만들 수 있는가"로 내려야 합니다.
함께 읽으면 좋은 글
- DeepSeek V4.1 Flash 1017: 코딩 에이전트 점수는 왜, 얼마나 올랐나
- NVIDIA AIPerf: 평균이 아니라 p95와 동시성으로 서빙을 재는 법
- GLM-5.3 Fast는 새 모델이 아니다: inference lane으로 보는 법
- WhatsApp 도움말에 숨은 AI 지시문: 프롬프트 인젝션보다 먼저 볼 것
참고 자료
- DeepInfer 공식 GitHub 저장소 (Apache-2.0)
- DeepInfer README: 지원 기능·하드웨어·미포함 구성
- DeepSeek V4.1 Flash Inference Deployment Q&A
- DeepInfer examples: 오프라인 추론·벤치마크·구조화 출력
- DeepInfer eval: AIME 2026·HLE·GPQA Diamond 기준 결과
- DeepSeek-V4.1-Flash-1017 모델 카드 (MIT)
- DeepSeek의 DeepInfer 공개 발표 (X, 2026-10-20)
- TNW: DeepSeek open-sources DeepInfer (2026-10-20)
이 주제를 직접 따라가며 배우고 싶다면
추론 엔진의 배치·캐시·검증 루프는 결국 에이전트가 모델을 호출하는 하네스와 맞닿아 있습니다. 모델 호출을 포함한 실행 루프를 직접 설계해 보면, 처리량과 지연이 어디서 갈리는지 감이 잡힙니다.