macOS에서 로컬 코딩 에이전트 구축하기
인터넷 연결 문제에 대비하고자 macOS 환경에서 완전히 로컬로 구동되는 코딩 에이전트 환경을 구축한 후기를 공유합니다. Apple Silicon(M1 Max) 환경에서 llama.cpp와 Gemma 4 모델, 그리고 다중 토큰 예측(MTP) 기술을 활용해 실사용 가능한 수준의 높은 추론 속도를 달성했습니다. 특히 Apple 전용 프레임워크인 MLX보다 llama.cpp와 MTP 조합이 더 빠른 속도를 보여준다는 흥미로운 벤치마크 결과를 포함하고 있습니다.
최근 인터넷이 몇 번 끊기면서 코딩 에이전트를 사용할 수 없는 난감한 상황을 겪었습니다. 그래서 Gemma 4의 다중 토큰 예측(MTP, Multi-Token Prediction) 업데이트로 인해 속도가 2배 빨라졌다는 소식을 접하고, 직접 로컬 환경에서 구동해보기로 결심했습니다.
제가 원했던 로컬 코딩 에이전트 환경의 조건은 다음과 같았습니다. 첫째, Mac에서 실제로 사용할 수 있을 만큼 빨라야 합니다. 둘째, OpenAI 호환 API를 통해 작동해야 합니다(이를 통해 다른 개발 도구에서도 사용 가능). 셋째, 가급적 스크린샷이나 이미지를 처리할 수 있어야 하므로, 에이전트가 자신이 만든 결과물의 스크린샷을 입력받아 피드백할 수 있어야 합니다.
그리고 결국 성공했습니다! 첨부된 영상은 실시간 속도를 보여주며, 에이전트가 완벽하게 실용적인 수준의 속도로 응답하는 것을 확인할 수 있습니다. 약간의 테스트를 거친 후, 제가 최종적으로 구축한 환경은 다음과 같습니다:
- macOS에서 Metal 가속을 활용하도록 빌드된 llama.cpp
- GGUF 형식의 Gemma 4 26B-A4B 모델
- 추측 디코딩(Speculative decoding)을 위한 Q8 MTP 드래프트 모델
- Gemma 4 멀티모달 프로젝터(Multimodal projector)
- 터미널 코딩 에이전트인 Pi
이 설정은 macOS 15.7.7이 실행 중인 64GB 통합 메모리를 갖춘 Apple M1 Max에서 테스트되었습니다.
모델
사용된 메인 모델은 gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf입니다. (Huggingface 링크: models/unsloth-gemma-4-26B-A4B-it-GGUF/gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf) 이 파일의 크기는 약 16GB입니다. MTP 드래프트 헤드와 멀티모달 프로젝터를 포함하면 모델 폴더의 크기는 약 17GB입니다.
벤치마크에 사용된 프롬프트는 다음과 같았습니다: "통합 diff(unified diff)를 파싱하여 변경된 파일 경로를 반환하는 간결한 Python 함수를 작성하세요. 그리고 두 가지 예외 상황(Edge cases)을 설명하세요." 각 벤치마크 테스트는 약 128개의 토큰을 생성했습니다.
기준선(Baseline): llama.cpp + Metal
우선 Metal 가속이 적용된 llama.cpp를 통해 메인 모델을 직접 실행해 보았습니다:
repos/llama.cpp/build/bin/llama-cli \
-m models/unsloth-gemma-4-26B-A4B-it-GGUF/gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf \
-ngl 999 \
-fa on \
-c 4096 \
-n 128
결과:
- 설정: Gemma 4 26B-A4B Q4, llama.cpp Metal
- 프롬프트 처리 속도(Prompt tok/s): 298.0
- 토큰 생성 속도(Generation tok/s): 58.2
초당 58토큰은 빠른 편은 아니지만 사용할 만합니다. 하지만 코딩 에이전트 작업, 특히 에이전트가 수많은 도구 호출(tool calls)을 수행해야 할 때는 속도가 가능한 한 빨라야 합니다.
MTP 드래프트 모델 추가
이제 Gemma 4에 사용할 수 있는 MTP 드래프트 모델이 공개되었습니다: MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf
이 모델은 추측 드래프트 모델(Speculative draft model)로서 llama.cpp에 로드할 수 있습니다:
repos/llama.cpp/build/bin/llama-cli \
-m models/unsloth-gemma-4-26B-A4B-it-GGUF/gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf \
--model-draft models/unsloth-gemma-4-26B-A4B-it-GGUF/MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf \
--spec-type draft-mtp \
--spec-draft-n-max 3 \
-ngl 999 \
-fa on \
-c 4096 \
-n 128
4개의 드래프트 토큰을 사용한 MTP 첫 실행 결과는 초당 69.2토큰이었습니다. Unsloth의 'MTP 모델 실행 방법' 가이드에는 다음과 같은 참고 사항이 있습니다: "--spec-draft-n-max 2가 가장 좋은 출발점이라는 것을 발견했습니다. 하지만 성능은 하드웨어에 따라 다르므로 2가 최적의 값이라고 가정하지 마십시오. 1부터 6까지의 값을 시도해보고 시스템에서 가장 빠른 값을 사용하세요."
--spec-draft-n-max 값을 조정해 본 결과, 3개의 드래프트 토큰을 사용했을 때 초당 72.2토큰으로 가장 좋은 결과를 얻었습니다.
- 메인 모델만 사용 시: 프롬프트 298.0 / 생성 58.2 / 속도 향상비 1.00x
- 메인 모델 + Q8 MTP 드래프트: 프롬프트 295.6 / 생성 72.2 / 속도 향상비 1.24x
여기서 주목할 만한 점은 프롬프트 처리 속도는 기본적으로 비슷하게 유지되면서, 생성 속도는 약 24% 향상되었다는 것입니다.
MTP 튜닝
--spec-draft-n-max 값을 1부터 6까지 테스트해 보았습니다.
- 1: 프롬프트 295.5 / 생성 68.4
- 2: 프롬프트 299.1 / 생성 72.0
- 3: 프롬프트 295.6 / 생성 72.2
- 4: 프롬프트 297.3 / 생성 70.7
- 5: 프롬프트 297.9 / 생성 63.7
- 6: 프롬프트 296.3 / 생성 61.2
제 M1 Max 머신에서는 3이 가장 빨랐으며, 2도 비슷한 성능을 보여 둘 중 어느 것을 사용해도 괜찮았습니다. 그 이상의 값은 오히려 속도가 느려졌습니다.
MLX 비교
Mac에서 모델을 실행하는 더 빠른 방법이 무엇인지 알아보기 위해 mlx-lm을 통한 MLX 모델도 테스트했습니다.
- llama.cpp Metal + MTP (Unsloth GGUF Q4 + Q8 MTP): 72.2 tok/s
- llama.cpp Metal (Unsloth GGUF Q4): 58.2 tok/s
- MLX-LM (Unsloth UD MLX 4-bit): 45.8 tok/s
- MLX-LM (mlx-community 4-bit): 43.9 tok/s
- MLX-LM (mlx-community OptiQ 4-bit): 38.1 tok/s
제 생각에는 Mac에 최적화된 MLX가 가장 빠를 것이라고 예상했습니다. 하지만 이 특정 설정에서는 llama.cpp가 MLX보다 빨랐고, MTP가 결합된 llama.cpp가 확실히 최고의 선택이었습니다. 아마도 오랜 시간에 걸쳐 llama.cpp에 쏟아부은 모든 노력과 최적화 덕분에 현실적인 환경에서도 상당히 잘 최적화된 것이 아닐까 싶습니다.