한 줄 요약부터. 부팅과 KV 캐시, CUDA graph까지는 이번에 싹 정복했습니다. 그런데 정작 제일 중요한 1M 단일 prefill, 즉 실제로 977K짜리 문서 하나를 통째로 넣는 그 순간은 여전히 벽입니다. 레시피가 좋아져도 day-0 빌드의 한계는 그대로였어요. 결국 남은 건 '거의 다 됐는데, 딱 하나가 안 되는' 그 답답함이었습니다.
레시피가 나왔습니다
아시다시피 지난 편에서 저는 977K에서 막혀서 "뭐, 별 수 있겠어" 하고 접었습니다. 완전한 1M 컨텍스트는 day-0 빌드의 한계이고, SGLang이 Qwen4Exp의 1M을 안정화하면 그때 다시 도전하자고요.
그런데 그 약속을 지킬 필요가 없어졌습니다. 며칠 뒤 MiaAI-Lab이 Qwen3.8-Flash-Next 전용 듀얼-Spark 레시피를 공개했는데, 공개 이틀 만에 별 171개를 받았습니다. 그러니까, 저희가 못 뚫던 그 977K 멈춤의 원인을 어떤 커뮤니티 누군가가 이름까지 붙여서 문서로 정리해놓은 겁니다. 이걸 보고 나서는 다시 안 뚫어볼 수가 없더라고요.
원인은 두 가지로 정리되어 있었어요.
하나는 SM121 문제입니다. FlashInfer의 TRT-LLM sparse-decode 경로가 장문 디코드를 조용히 손상시킵니다. 120k, 190k, 210k 같은 긴 입력에서 토큰 id 0으로 떨어져요. 비유하자면, 대화하다가 상대방이 중요한 얘기하는 중간에 갑자기 "..." 같은 응답만 반복하는 느낌이랄까요. packed FA4 CuTe는 GB10에서 컴파일조차 안 되고요.
여기서 가장 재밌는 부분이 나옵니다. 이게 저희 전편 패치와 정반대였거든요. 저희는 is_sm120_supported()로 그 경로를 강제로 켰는데, 실제로는 SM121에서 그 경로를 꺼버리고 Triton packed-varlen fallback을 쓰는 것이었습니다. 인생에서 방향을 반대로 잡았던 걸 나중에 알게 된 그 느낌, 아시죠?

다른 하나가 977K 멈춤의 진짜 원인입니다. QSA indexer의 prefill workspace가 fp32 [chunk × history] 로짓 행렬을 레이어마다 통째로 만들어냅니다. chunk 4096에 history 300k만 해도 임시 메모리가 8~10GB나 돼요. 그게 레이어마다 쌓이니까, 마치 서랍 하나에 옷가지 전부를 우겨넣는 것처럼, 어느 순간 박스가 통째로 웨징되는 식이었습니다. 해결책은 CHUNKED_PREFILL_SIZE=1024 하나였다고 합니다. 이렇게 간단한 걸 몰랐다니, 좀 씁쓸하네요.
NVFP4 KV 캐시도 이 레시피의 축입니다. 아키텍처 고유 기능인데, 1M YaRN 기준으로 KV 풀이 2,851,328 토큰까지 들어갑니다. bf16의 925K와 비교하면 2.72배니까, 냉장고 하나 살 자리에 김치냉장고까지 들여놓은 격이죠. 메모리 비율은 0.82에 mamba ratio 0.3으로 잡혀 있고, 전편에서 0.90으로 밀어붙였던 것보다는 한결 여유가 있었습니다.
재도전
진행은 재미있게 풀렸습니다. start.sh를 받아서 .env만 저희 클러스터로 바꿨어요. 200G RoCE, MTU 9000 구성인데, doctor가 전부 통과했고 YaRN 1M과 NVFP4 KV 설정도 자동으로 잡혀 버립니다. 이렇게까지 알아서 되면 오히려 불안한 법이지만요.
이번에는 캐시를 다시 받지 않았습니다. 기존 126GB짜리 HF 캐시를 그대로 쓸 수 있었고, 419개 파일 135.25GB 검증에 재다운로드는 0바이트였어요. worker 쪽도 이미 동기화되어 있어서 받을 게 아무것도 없었습니다. SM121 Triton fallback과 NVFP4 KV 패치를 넣은 이미지를 양 노드에 빌드하고 부팅을 걸었습니다.
부팅은 성공했습니다.
context length 1048576 (YaRN factor 4.0)
kv cache dtype nvfp4 (KV pool 3,110,400, float4_e2m1fn_x2)
CHUNKED_PREFILL_SIZE 1024
mem fraction 0.82 · mamba ratio 0.3
load time 441.84s
KV 풀이 전편의 1,632,448에서 거의 두 배로 늘었어요. CUDA graph 캡처 전부 OK, 모델 로딩 441.84초. 이 시점에서 저는 기분이 꽤 좋았습니다. 될 것 같았거든요. 운동화 끈 조이고 코트 입고 나서는, 이제 진짜 달리기만 하면 되는 그런 기분이었죠.
977K, 여전히 벽입니다
그리고 977K 단일 needle prefill. 전편에서 쓰던 그 976,837 토큰 문서를 그대로 다시 쐈습니다.
스케줄러가 GPU 0%, CPU 90%로 8분을 돌다가 죽었습니다. Subprocess scheduler_0 crashed with exit code -15 (SIGTERM). 그러니까 하드웨어는 거의 안 쓰면서 CPU만 열심히 돈다는 건데, 사람으로 치면 화면은 안 보면서 키보드만 두드리고 있는 격이죠. 8분 뒤엔 통째로 종료되고 500이 떨어졌습니다.

형태가 달라진 것만은 분명했습니다. 전편은 chunk 4096에서 500과 coredump였고, 이번에는 chunk 1024에서 CPU-bound SIGTERM이었어요. 여러 가지를 바꿔도 1M 단일 prefill만은 그대로 벽입니다.
좋아진 것은 부팅과 KV, 그래프까지였어요. 근데 그게 다예요. day-0 SGLang 빌드에서 1M 단일 prefill은 아직 안정화되지 않았습니다. 전편의 day-0 한계 결론을, 이번엔 손에 쥔 MiaAI 레시피까지 들고 실측으로 다시 확인한 꼴입니다. 소름이 돋을 정도로 깔끔하게요.

곁다리로 본 GLM
재도전이 막힌 동안, GLM-5.3-Flash도 한번 들여다봤습니다. 2대의 Spark에서 1M을 굴릴 수 있는지가 궁금했거든요. 결론부터 말씀드리면, 안 됩니다.
퀀타이즈는 있었어요. LibertAIDAI의 NVFP4 버전이 598.5GiB를 181GiB로 줄여줍니다. tool-eval 실측이 FP8의 90점에서 85점으로 빠지긴 했지만, 그 정도 손해는 감당할 만합니다. 다이어트를 하긴 했는데 근육만 빠진 게 아니라 지방도 좀 같이 빠진, 그래도 옷은 입을 만한 그런 상태요.
문제는 퀀타이즈가 아니라 아키텍처였습니다. 34개 KDA 선형어텐션 레이어가 요청마다 재귀 상태, 상태캐시를 요구합니다. 컨텍스트와 동시성이 직접 경쟁하는 구조예요. 2대에서 max-req 8에 131K를 주면 상태캐시가 넘칩니다. 안정적인 조합은 65K~131K 사이이고, 1M은 4대에서만 가능하며 그때도 30~43 tok/s입니다. 여관방 두 개에 단체 손님 100명을 재우려는 셈이라, 어떻게 도배를 새로 해도 구조적으로 안 되는 겁니다.

그래서, 하나 더 남았네요
정리하면 이렇습니다. Flash-Next의 1M은 부팅, KV, CUDA graph까지 정복했습니다. 그런데 단일 1M prefill이 day-0 한계에 그대로 남아 있고, GLM의 1M은 2대로 구조적인 불가능입니다. 실전 1M으로 검증된 DS4-0731 유지가 여전히 맞는 선택입니다. 1M 미만의 인터랙티브와 에이전트만 Flash-Next 262K가 후보고요.
그리고 남은 관문은 이제 딱 하나입니다. SGLang이 Qwen4Exp의 1M을 안정화해서 릴리스하는 일, sglang#36497이 그 이슈입니다. 그것이 나오면 다시 도전합니다. 그때까지는 지금 조합으로 버틸 예정이에요. 저는 이제 그 발표를 손꼽아 기다립니다. 이번에는 정말 됐으면 좋겠네요.
'공부 > 인공지능' 카테고리의 다른 글
| thinking 기본값 xhigh의 세금 — 17배 태우고 같은 오답을 냈다 (GB10 듀얼 실측) (0) | 2026.09.03 |
|---|---|
| LLM 에이전트 메모리가 꽉 찼다 — 4계층 구조로 풀기까지 (0) | 2026.09.01 |
| H3를 직접 돌려봤다. Wan 2.2와 스프라이트 7모션 비교 (레고 로봇) (0) | 2026.08.29 |
| 게임 스프라이트를 로컬 Wan 2.2로 뽑아봤다. (핑크팬더 5모션) (0) | 2026.08.28 |
| DGX Spark 2대, 1M 컨텍스트 도전기. (Qwen3.8-Flash-Next day-0) (0) | 2026.08.28 |