맥 스튜디오에서 대규모 AI 모델 구동을 위한 3가지 버그 수정
M3 맥 스튜디오 얼트라 환경에서 5만 토큰 이상의 긴 대화 컨텍스트를 처리할 때 첫 토큰 생성까지 수 분이 걸리던 치명적인 지연 문제를 해결한 사례입니다. 저자는 DS4 Flash 모델에서 지연 시간이 더 짧은 Qwen 3.5 122B로 교체하고, 하이브리드 어텐션 구조로 인한 캐시 메모리 누수 등 서빙 스택의 버그 3가지를 직접 수정하여 로컬 환경에서도 실사용이 가능한 에이전트 코딩 환경을 구축했습니다. 로컬 LLM 최적화 및 Mac 하드웨어 활용에 관심 있는 개발자들에게 매우 유용한 기술적 인사이트를 제공합니다.
목차
5만 토큰짜리 대화에서 후속 질문을 던지면 첫 번째 토큰이 나타나기까지 3~5분이 걸렸다. 전체 답변이 아니라 첫 토큰이다. 이건 챗봇이 아니라 배치 작업(batch job)이며, AI가 생각하는 동안 커피나 한 잔 하러 가야 하는 수준이다. 맥 스튜디오 성능을 극대화하는 데 광팬인 열두 명의 다른 긱(geek)들에게 좋은 소식을 가져왔다. 좋은 소식이라 함은, 여러분이 고생하지 않도록 내가 3주 동안 캐시 누수(cache leak)를 디버깅했다는 뜻이다.
이 모든 것은 소비자용 하드웨어에서 대규모 모델을 구동하는 훌륭한 실험인 antirez/ds4에서 시작되었다. 두 달 전, 나는 충동적으로 M3 맥 스튜디오 얼트라를 샀다. RAM 가격이 오르면 곧 96GB 구성을 구하기 어려워질 것 같았기 때문이다(스포일러: 실제로 그렇게 되었다). 그리고 육아 휴직 중에 로컬 추론 스택을 깊이 파고들고 싶었다.
목표는 단순했다. 단일 머신에서 최첨단 모델을 구동하고, 계속 준비된 상태(warm)로 유지하며, 문맥을 실제로 이해하는 대화형 AI를 갖는 것이었다. 하지만 생각보다 더 복잡했다. 모델은 통합 메모리(unified memory)에 들어맞았고 제대로 된 답변을 내놓았다. 하지만 매일 사용해 본 몇 주 후, 나는 방향을 완전히 틀었다: DS4 Flash를 버리고 Qwen 3.5 122B로 전환한 것이다.
이후 두 가지 별개의 일이 일어났는데, 이 둘을 구분해서 보는 것이 중요하다. 모델 교체는 속도와 적합성에 대한 결정이었다. 새 모델을 실제로 사용 가능하게 만든 것은 내 서빙 스택에서 발견된 세 가지 버그를 수정한 일이었으며, 이는 내가 어떤 모델을 구동하느냐와는 전혀 상관이 없었다.
모델을 교체한 이유 # DS4 Flash는 정말 훌륭한 모델이며 antirez의 스택은 걸작이다. 다만 내가 하는 작업에는 맞지 않는 모델이었을 뿐이다. 이는 결함에 대한 이야기가 아니라 적합성에 대한 이야기다.
나의 사용 사례는 긴 문맥의 에이전트 코딩이다. 모델이 수천 토큰에 달하는 대화, 코드, 도구 호출 결과를 유지하고, 내가 흐름을 유지할 수 있도록 거의 즉각적인 응답이 필요한 페어 프로그래밍이다. 이 특정 워크플로우에서는 사전 채우기(prefill) 지연 시간이 결정적인 걸림돌이었다. 5만 토큰을 넘기면 간단한 후속 질문에 첫 토큰이 나오기까지 3~5분이 걸렸고, 차 한 잔을 기다리게 만드는 모델과는 페어 프로그래밍을 할 수 없다. 모델이 답을 낼 때쯤이면 나는 이미 다음 문제로 넘어가 있었다.
이것은 DS4가 절대적인 의미에서 느리다는 뜻이 아니라, 내 하드웨어에서 해당 설정이 긴 문맥의 사전 채우기를 처리하는 방식과 내 워크플로우의 요구 사이에 불일치가 있었다는 뜻이다.
Qwen 3.5 122B는 내가 신경 쓰는 모든 면에서 M3 얼트라에 더 잘 맞아 보였다:
최첨단에 가까운 완전한 로컬 구동. API 호출 없음, 속도 제한 없음, 데이터 유출 없음. 독점 시스템에 필적하는 122B 모델이 완전히 오프라인으로 구동됨. 얼트라의 대역폭에 가장 적합한 활성 파라미터 크기. M3 얼트라의 메모리 대역폭은 매우 크다. 약 10B의 활성 파라미터를 가진 122B MoE 모델은 GPU가 컴퓨팅 유닛에 데이터를 끊김 없이 공급할 수 있는 최적의 조건(sweet spot)에 위치한다. 도구 호출과 추론의 좋은 균형. 복잡한 코드 로직을 처리할 만큼 충분한 추론 깊이, 신뢰할 수 있는 함수 호출과 에이전트 오케스트레이션을 위한 견고함. 통합 KV 캐시에 딱 맞는 크기. 96GB의 통합 메모리를 사용하면 저비트(low bit-width)로 양자화된 122B 모델은 SSD 기반의 깊은 KV 캐시를 위한 충분한 여유 공간을 남긴다. 이는 스와핑 없이 긴 문맥을 유지하기 위한 핵심이다. 내가 찾을 수 있었던 가장 근접한 서빙 스택은 rapid-mlx였다. 하지만 이것은 하이브리드 어텐션(hybrid attention)에서 다른 방향을 취하고 있었다. 이러한 차이를 고려하여, 나는 이를 포크(fork)했다. 그 결과가 바로 GitHub에 공개된 qMLX이다. 이 포크는 하이브리드 어텐션에 특화되어 있다(이에 대해서는 글 마지막에 더 자세히 다룬다).
진짜 작업: 세 가지 버그 죽이기 # 모델은 메모리에 잘 들어맞았지만, 모델 자체와는 무관한 이유들로 인해 바로 사용할 수 없었다. 바로 모든 후속 메시지가 전체 대화를 처음부터 다시 처리한다는 것이었다. 13만 토큰짜리 문맥에서는 모델이 단 한 단어를 내뱉기까지 몇 분을 기다려야 한다.
원인은 GatedDeltaNet (SSM) 레이어와 밀집 어텐션(dense attention)이 혼합된 하이브리드 어텐션 아키텍처에 있었다. SSM 레이어의 순환 상태(recurrent state)는 이전 위치로 되감기거나 다듬을 수 없으므로, 메모리 누수를 피하기 위해 인메모리 캐시는 해당 레이어를 포함하는 모든 항목을 버리게 된다. 이를 위해...