주력 모델 기준은 처음부터 고정이었다. 1M 토큰, 그리고 어느 정도의 멀티유즈. 하드웨어는 DGX Spark 2대. GB10 에 128GB 통합 메모리를 품은 기기를 200Gbps RoCE 로 엮은 것.
결론부터 말한다. 262K 서빙은 성공했고, 300K needle 도 통과했다. 완전 1M 은 아직 아니다. prefill 을 약 365K 처리하는 지점에서 멈췄다. 부분 성공, 한계는 명확하게 잡힌 상태다. 이 글은 그 지점까지의 막힌 기록이다.
day-0 스택
Flash-Next 는 125B MoE, 토큰당 실제로 움직이는 것은 6B. 옆에 51B 크기의 n-gram 임베딩 테이블이 붙어 있다. 어텐션은 4 레이어. 히스토리를 고정 크기 상태로 압축하는 GDN 이 3개, Qwen Sparse Attention 이 1개. Qwen4 아키텍처의 프리뷰이고, 멀티모달이며, 네이티브 컨텍스트는 262K. 무엇보다 thinking 모델이다. 기본적으로 생각하고, per-request 로 껏다 켰다 할 수 있다.
첫 시도는 vLLM 이었고, n-gram 테이블에 걸렸다. PLE CPU offload 는 2노드를 지원하지 않아서 에러가 바로 떴다. --ple-offload-embedding 으로 멀티노드를 지원한다는 SGLang 로 갈아탔다. 그런데 day-0 이미지는 H200, B200, GB300 용이다. Spark 의 GB10, SM121 은 대상 밖. 직접 패치해서 빌드할 수밖에 없었다.
패치는 2종. QSA 가드에 SM121 을 붙이고, mrope 부분 한 곳을 고쳤다. 그리고 제 발등을 찍었다. 가드 패치는 넣었는데 is_sm120_supported 의 import 를 빼먹은 것이다. warmup 에서만 드러났다. NameError, 크래시. 재시작 정책이 unless-stopped 이었던 탓에, 크래시하면 6분 동안 모델을 다시 올리고 또 크래시. 루프의 탄생이다.
패치가 잘못됐나 하고 한참을 헤맸다. 드디어 크래시 로그를 다시 보니 import 1줄이 빠진 것이었다. 한 줄을 넣고 부팅 성공. 2노드 TP2, NCCL over RoCE, PLE offload, MTP 추측 디코딩을 켰다. 모델 로딩에 5.8분이 걸린다.
thinking 예산의 함정
첫 벤치는 무효였다. 한 쪽은 thinking OFF, 다른 쪽은 ON, 조건이 달랐다. 그리고 더 깊은 함정이 있었다. thinking 모델에 max_tokens 300 을 주면, thinking 이 예산을 전부 쓴다. 결과는 finish=length, content 0. 처음 벤치에서 content 가 안 나온 것도 이 원인이었다. 모델의 문제가 아니었다.
코딩 질문이면 thinking 만이 800~1,700+ 토큰을 쓰고, 자유문은 37 토큰. 프롬프트에 따라 hugely 변동한다. 둘 다 thinking ON, 예산 4096 통일로 재설계하고 다시 잰다.
262K, 나온 수치
262K 서빙은 KV 풀 668,672 토큰으로 올라왔다. thinking ON 이면 간단 질문에 TTFT 0.23~0.35초, 생각 43 토큰 뒤에 답이 온다. thinking OFF 디코드는 30~45 tok/s. 동시 4요청을 쏘면 60 tok/s 집합, thinking ON 이면 28.1 tok/s. 짧은 요청을 많이 보내는 에이전트에게는 0.23초라는 첫 토큰 대기시간이 전부다.
커뮤니티에서 걱정하는 할루 시험도 해 봤다. 존재하지 않는 행성 NGC-7742b, 존재하지 않는 교수의 경력을 물었다. 둘 다 전제가 거짓인 질문이고, 둘 다 전제 자체를 거부했다. "NGC 번호는 행성에 부여되지 않는다", "재직하지 않는다". 2건에 불과하고 보증은 아니다. 하지만 적어도 경보는 실측으로 확인되지 않았다.
1M 레시피
1M 확장 레시피는 Qwen 의 Hugging Face 모델카드에 적혀 있다. config.json 을 직접 고치는 것은 막다른 길이다. draft 모델 config 가 엮여 들어와서 부팅에서 AttributeError 로 크래시한다. 공식 경로는 --json-model-override-args 인자, YaRN factor 4.0.
SGLANG_ALLOW_OVERWRITE_LONGER_CONTEXT_LEN=1 sglang serve \
--json-model-override-args '{"text_config": {"rope_parameters": {
"mrope_interleaved": true, "mrope_section": [11, 11, 10],
"rope_type": "yarn", "rope_theta": 10000000,
"partial_rotary_factor": 0.25, "factor": 4.0,
"original_max_position_embeddings": 262144}}}' \
--context-length 1000000
SGLANG_ALLOW_OVERWRITE_LONGER_CONTEXT_LEN=1 환경변수가 없으면 262K 에 그대로 남는다. KV 공간을 확보하려고 mamba 캐시 슬롯을 97에서 24로 줄였다. KV 풀이 1,632,448 토큰이 됐다. 1M 요청 하나에 여유까지.
300K 통과, 977K 멈춤
needle 테스트의 첫 넘어지는 것은 토크나이저였다. chars/token 으로 추정한 1M 문서가 30% 빗나와서 1.31M 요청이 됐다. 엔진 크래시 2회. 실제 토크나이저로 실측하니 para 하나당 74~75 토큰.
그다음은 됐다. 300,382 토큰 문서, 네이티브 262K 를 38K 토큰 넘은 크기. 40% 지점에 숨긴 코드가 돌아왔다. wall 179초. YaRN 확장이 실존한다는 증거다. 262K 를 실제로 넘어서까지.
976,837 토큰 문서, 1M 경계 이하로 정확히 생성한 것은 멈췄다. prefill 중, 약 364K 처리 지점에서. hang 이었다. 다시 쏘니 정확히 같은 지점, pending 612,345. 결정론적이지, 랜덤이 아니다. watchdog 300초, CUDA coredump, 자동 재기동 4회. 여기서 관두었다.

닿은 곳은 여기까지다. 262K 와 멀티유즈, Flash-Next 는 실사용 가능한 수준이다. TTFT 0.23초, 동시 4요청 60 tok/s, 할루 시험도 이상 없음. 완전 1M 은 레시피 확보, 365K 까지 검증, 그 이상은 day-0 빌드의 한계. 27B 모델은 단 1개 Spark 에서 1M 이 정상이라, 하드웨어의 탓은 아니다.
배분은 명확하다. 1M 실전 작업은 지금 쓰는 모델이 그대로 간다. 1M 미만의 인터랙티브와 에이전트는 Flash-Next 가 후보다. SGLang 이 Qwen4Exp 의 1M 을 안정화하는 업데이트가 나오면 다시 도전한다. 뭐 별 수 있겠어.
'공부 > 인공지능' 카테고리의 다른 글
| 게임 스프라이트를 로컬 Wan 2.2로 뽑아봤다. (핑크팬더 5모션) (0) | 2026.08.28 |
|---|---|
| [세컨드브레인 개발기] 16. 122B와 27B — 커도, 빠른 것도 다 이긴 건 아니었다 (0) | 2026.08.27 |
| [세컨드브레인 개발기] 15. 주력 모델이 3번 바뀌었다. 사유도 각각 달랐다. (0) | 2026.08.18 |
| [세컨드브레인 개발기] 14. GB10 에서 배운 것 — 속도는 대역폭을 활성 파라미터로 나눈 값이다 (0) | 2026.08.16 |
| [세컨드브레인 개발기] 13. Hermes 에게 자율성을 얼마나 줄 수 있나 — 실측 (0) | 2026.08.12 |