1P by GN⁺ | ★ favorite | 댓글 1개
  • 로컬 코딩 에이전트 구성은 인터넷 장애 때도 macOS에서 OpenAI 호환 API로 모델을 실행하고 Pi에서 텍스트와 이미지 입력을 처리하도록 만드는 설정임
  • Apple M1 Max 64GB, macOS 15.7.7에서 llama.cpp Metal과 Gemma 4 26B-A4B GGUF 모델을 사용했으며, 기본 생성 속도는 58.2 tok/s였음
  • MTP draft model을 추가하고 --spec-draft-n-max 3으로 조정한 뒤 생성 속도가 72.2 tok/s로 올라가 약 24% 개선됨
  • mmproj-BF16.gguf--mmproj로 로드하고 Pi 모델 입력을 ["text", "image"]로 설정해야 스크린샷 같은 이미지 입력이 전달됨
  • 최종 구성은 llama.cpp 서버를 127.0.0.1:8080/v1에서 실행하고 Pi가 이를 로컬 제공자로 쓰는 방식이며, Qwen3.6 35B-A3B는 더 나은 코딩 에이전트 벤치마크를 보였지만 이 테스트에서는 55 tok/s로 더 느렸음

로컬 코딩 에이전트 구성 목표

  • 인터넷 장애가 몇 번 발생해 코딩 에이전트를 사용할 수 없었던 상황이 로컬 실행 구성을 시도한 계기가 됨
  • 원하는 구성은 Mac에서 실제로 쓸 만큼 빠르고, OpenAI 호환 API를 통해 다른 도구에서도 사용할 수 있어야 했음
  • 필요할 때 스크린샷이나 이미지를 처리해 에이전트가 만든 결과물을 다시 입력으로 줄 수 있는 구성이 목표였음
  • 최종 구성은 llama.cpp, Gemma 4 26B-A4B GGUF, Q8 MTP draft model, Gemma 4 multimodal projector, Pi 터미널 코딩 에이전트로 이뤄짐
  • 테스트 환경은 Apple M1 Max, 64GB 통합 메모리, macOS 15.7.7이었음

모델

  • 메인 모델은 gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf였으며, Hugging Face의 unsloth-gemma-4-26B-A4B-it-GGUF 저장소에 있음
  • 해당 파일 크기는 약 16GB이며, MTP draft head와 multimodal projector를 함께 두면 모델 폴더는 약 17GB가 됨
  • 벤치마크 프롬프트는 Write a compact Python function that parses a unified diff and returns the changed file paths. Then explain two edge cases.였음
  • 각 벤치마크는 약 128개 토큰을 생성함

기본 실행: llama.cpp + Metal

  • 메인 모델을 llama.cppMetal 가속으로 직접 실행했음
  • 실행 명령은 llama-cli에 모델 경로, -ngl 999, -fa on, -c 4096, -n 128을 지정하는 방식이었음
  • 기본 구성의 프롬프트 처리 속도는 298.0 tok/s, 생성 속도는 58.2 tok/s였음
  • 58 tok/s는 빠르지는 않지만 사용할 수 있는 수준이며, 코딩 에이전트 작업에서는 많은 도구 호출 때문에 가능한 한 빠른 속도가 필요함

MTP draft model 추가

  • Gemma 4에는 MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf 형태의 MTP draft model이 제공됨
  • llama.cpp에서는 이를 --model-draft, --spec-type draft-mtp, --spec-draft-n-max로 투기적 디코딩(speculative decoding)에 로드함
  • MTP 첫 실행은 draft token 4개에서 69.2 tok/s를 기록함
  • Unsloth 문서는 --spec-draft-n-max 2를 시작점으로 권장하지만, 1부터 6까지 하드웨어별로 테스트해 가장 빠른 값을 쓰라고 함
  • --spec-draft-n-max를 조정한 결과, draft token 3개에서 72.2 tok/s가 가장 빨랐음
  • 메인 모델 단독은 58.2 tok/s였고, Q8 MTP draft model을 더한 구성은 72.2 tok/s였음
  • 프롬프트 처리 속도는 거의 유지됐고, 생성 속도는 약 24% 개선됨

MTP 튜닝 결과

  • --spec-draft-n-max 값 1부터 6까지 테스트했음
  • 값 1은 프롬프트 295.5 tok/s, 생성 68.4 tok/s였음
  • 값 2는 프롬프트 299.1 tok/s, 생성 72.0 tok/s였음
  • 값 3은 프롬프트 295.6 tok/s, 생성 72.2 tok/s로 가장 빨랐음
  • 값 4는 생성 70.7 tok/s, 값 5는 63.7 tok/s, 값 6은 61.2 tok/s로 느려졌음
  • 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-LMmlx-community 4-bit에서 43.9 tok/s, mlx-community OptiQ 4-bit에서 38.1 tok/s를 기록함
  • 이 특정 구성에서는 llama.cpp가 MLX보다 빨랐고, MTP를 적용한 llama.cpp가 가장 좋은 선택이었음
  • gemma-4-swift-mlx로 Gemma 4 MTP도 시도했지만, 테스트한 26B 4-bit MLX 체크포인트가 로더의 예상 weight key와 맞지 않아 새 모델을 다시 내려받아 조정하지 않고 중단함

이미지 지원 추가

  • Pi에서 스크린샷을 첨부하려면 모델 입력이 텍스트 전용이면 안 됨
  • 원래 로컬 모델 항목은 "input": ["text"]로 설정되어 있었고, 이 경우 Pi가 이미지 도구 출력을 모델에 제대로 보내지 못함
  • llama.cpp 서버도 멀티모달 기능을 위해 Gemma 4 multimodal projectormmproj-BF16.gguf가 필요함
  • --mmproj로 projector를 로드하면 llama.cpp가 멀티모달 지원을 알리고 Pi가 이미지를 보낼 수 있음
  • projector 없이 llama.cpp Metal + MTP를 실행한 테스트는 프롬프트 120.3 tok/s, 생성 71.4 tok/s였음
  • mmproj-BF16.gguf를 로드한 최종 실행은 프롬프트 297.4 tok/s, 생성 72.2 tok/s였음
  • projector를 로드한 최종 실행에서 텍스트 생성 속도 저하는 나타나지 않았음

llama.cpp 설치

  • 의존성은 Homebrew로 cmake, git, tmux, python@3.11을 설치함
  • ~/Developer/ML-Models/Gemma4/repos 경로를 만들고 ggml-org/llama.cpp 저장소를 repos/llama.cpp로 클론함
  • 빌드는 cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_METAL=ON -DGGML_ACCELERATE=ON으로 구성함
  • 이후 cmake --build build --config Release -j로 릴리스 빌드를 수행함
  • 테스트한 빌드는 GGML_METAL=ON, GGML_ACCELERATE=ON, GGML_BLAS=ON, GGML_BLAS_VENDOR=Apple 설정을 가짐

모델 파일 다운로드

  • Python 3.11 가상환경을 만들고 huggingface_hubhf_xet를 설치함
  • huggingface-cli download로 Gemma 4 메인 모델, mmproj-BF16.gguf, MTP draft model을 내려받음
  • 다운로드 대상 파일은 gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf, mmproj-BF16.gguf, MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf
  • 최종 모델 폴더는 models/unsloth-gemma-4-26B-A4B-it-GGUF/ 아래에 세 파일을 포함함

로컬 서버 시작

  • 최종 서버는 llama-server로 실행하며, 메인 모델과 MTP draft model, multimodal projector를 모두 지정함
  • 주요 옵션은 --spec-type draft-mtp, --spec-draft-n-max 3, -ngl 999, -fa on, -c 65536, --parallel 1
  • 서버는 --host 127.0.0.1 --port 8080으로 실행함
  • OpenAI 호환 엔드포인트는 http://127.0.0.1:8080/v1
  • start_server.sh 래퍼는 tmux 세션에서 서버를 실행하고 로그를 logs/llama-server-mtp.log에 남김
  • chmod +x start_server.sh./start_server.sh로 서버를 시작함
  • 서버 동작 여부는 curl http://127.0.0.1:8080/v1/models로 확인함

Pi 설정

  • Pi는 모델 제공자 설정을 ~/.pi/agent/models.json에서 읽음
  • 로컬 제공자 gemma4-localbaseUrlhttp://127.0.0.1:8080/v1을 가리킴
  • apiopenai-completions이고, 로컬 서버이므로 authHeaderfalse로 둠
  • 모델 ID는 gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf이고, 이름은 Gemma 4 26B-A4B Q4 + MTP로 설정함
  • input["text", "image"]여야 하며, 그렇지 않으면 Pi가 모델을 텍스트 전용으로 취급함
  • 컨텍스트 윈도는 65536, 최대 토큰은 8192로 설정함
  • 필요하면 ~/.pi/agent/settings.json에서 defaultProvidergemma4-local, defaultModel을 해당 GGUF 파일명으로 지정함
  • pi --offline --list-models gemma 실행 시 이미지 지원이 yes로 표시되는 결과를 기대함
  • 로컬 모델 실행은 pi --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf로 수행함
  • 비대화형 실행은 pi -p --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf "Explain what this repository does" 형태로 수행함
  • 스크린샷 입력은 pi -p @"/path/to/screenshot.png" "Describe this image and point out anything relevant to the UI" 형태로 수행함

최종 구성

  • 최종 추론 런타임은 llama.cpp
  • macOS 가속은 Metal + Accelerate 조합임
  • 메인 모델은 gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf
  • draft model은 gemma-4-26B-A4B-it-Q8_0-MTP.gguf
  • MTP 설정은 --spec-draft-n-max 3
  • multimodal projector는 mmproj-BF16.gguf
  • 서버는 127.0.0.1:8080llama-server
  • API는 OpenAI 호환 /v1
  • 코딩 에이전트는 Pi이며, Pi 모델 입력은 ["text", "image"]
  • MTP draft model은 이 환경에서 Gemma 4 생성 속도를 58.2 tok/s에서 72.2 tok/s로 올렸고, 로컬 OpenAI 호환 서버로 실행할 만큼 구성이 단순함

Qwen3.6 35B-A3B 대안

  • 일부는 Gemma 4 26B-A4B 대신 Qwen3.6 35B-A3B 사용을 제안함
  • 확인 가능한 벤치마크 기준으로 Qwen은 Gemma 4보다 훨씬 더 나은 코딩 에이전트라고 평가됨
  • 하지만 Qwen 구성은 더 느렸으며, Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf, unsloth-Qwen3.6-35B-A3B-MTP-GGUF, mmproj-BF16.gguf 조합에서 55 tok/s를 기록함
  • 72 tok/s 대신 55 tok/s는 사용자가 기다리는 상황에서 상당한 차이로 작용함
  • Qwen 모델 다운로드는 unsloth/Qwen3.6-35B-A3B-MTP-GGUF에서 Qwen3.6-35B-A3B-UD-Q4_K_XL.ggufmmproj-BF16.gguf를 받는 방식임
  • Qwen 서버는 같은 llama-server를 쓰되 --port 8081로 실행함
  • Pi 설정의 Qwen 제공자 이름은 qwen36-local, baseUrlhttp://127.0.0.1:8081/v1
  • Qwen 모델 설정은 reasoning: true, input: ["text", "image"], contextWindow: 65536, maxTokens: 8192를 사용함

댓글과 토론

Hacker News 의견들
  • 벤치마크 프롬프트가 “unified diff를 파싱해 변경된 파일 경로를 반환하는 간결한 Python 함수를 작성하고, 엣지 케이스 두 가지를 설명하라”였고, 각 벤치마크가 약 128토큰을 생성했다면 좋은 결과를 얻기엔 128토큰이 너무 적어 보임
    MTP 가속은 예측 토큰이 얼마나 자주 채택되는지에 달려 있는데, 경험상 출력 초반부는 채택률이 더 높아서 짧은 테스트가 거짓 양성 가속을 만들 수 있음
    llama.cpp에는 서버를 재시작하고 프롬프트를 보낼 필요 없이 인자를 훑어주는 벤치마크 전용 도구가 있음: https://github.com/ggml-org/llama.cpp/blob/master/tools/llam...
    모델 다운로드 섹션도 llama.cpp의 -hf 인자가 모델을 대신 내려받아 준다는 점을 언급했어야 함. 작성자가 경험을 공유한 건 고맙지만, 초보자에게는 최선의 가이드가 아닐 수 있음

    • 제대로 된 개발자 가이드로 쓴 글은 아니었음. 화면 녹화가 즐겨찾기를 많이 받고 설정 방법을 묻는 메시지가 오기 시작해서, 이 테스트를 어떻게 구성했는지 빠르게 정리한 것임
      Unclothe의 “속도 2배” 발표를 보고 “이 정도면 실제로 쓸 만큼 빨라질까?” 싶어서 직접 설정해 봤음
      작년에도 Devstral 같은 걸로 테스트했지만 너무 느리고 멍청해서 계속 써 볼 마음이 안 들었고, 이번에는 드디어 속도와 지능 모두에서 쓸 만하다는 느낌에 도달함
    • 현실적으로는 임의의 사용자 프롬프트에 더해 충분한 시스템 프롬프트까지 넣고 실험해야 함. 최소 1000토큰 이상, 실제로는 3000토큰 정도가 좋아 보임
      llama.cpp에는 이를 위한 도구가 있고, 제대로 측정하려면 토큰 생성 전에 프리필(prefill) 을 넣어야 함. 점점 32k나 64k 같은 긴 문맥에서의 토큰 생성 속도 측정도 중요해지고 있음
    • 128토큰이면 오페라가 아니라 서곡만 벤치마크하는 셈임
    • 실제 문제를 살피지 않고 “내 컴퓨터에서는 돌아감”이라고 말하는 것과 비슷함. 128토큰은 정말 아무것도 아니고, 짧은 인사 응답보다 조금 긴 수준임
  • 예전에 ollama와 opencode를 써서 비슷한 글을 쓴 적이 있음: https://blog.kulman.sk/running-local-llm-coding-server/

    • Ollama는 좋은 선택이 아님: https://sleepingrobots.com/dreams/stop-using-ollama/
      opencode는 시스템 프롬프트가 문맥을 너무 많이 먹지 않나? 로컬 모델은 문맥 제약이 큰데, 기억으로 opencode는 그중 10k 정도 또는 그에 가까운 양을 사용함
    • 실제로 유용하고, ollama GUI를 쓰면 아마 더 단순화할 수도 있음
  • llama.cpp만 쓴다면 무언가를 다운로드하려고 huggingface-cli가 꼭 필요하진 않아 보임. -hf ...를 넘기면 모델을 내려받아 줌
    다운로드 위치를 바꾸려면 LLAMA_CACHE를 설정하면 됨:
    LLAMA_CACHE="models" ./llama-server \
    -hf unsloth/gemma-4-31B-it-GGUF:UD-Q4_K_XL \
    ...

    • 드래프트 모델에는 -hfd를 쓰면 됨
  • 통합 메모리 RAM은 크지만 테라플롭스와 대역폭 GB/s가 중간 이하라면 보통 MoE가 가장 희망적임. 내 환경인 M2 Max 96GB에서 (지능, tok/s, 문맥 깊이) 기준 현재 1위는 DeepSeek-V4-Flash REAP25 <65gb gguf + ds4-server + pi agent임
    물론 클라우드 API보다 낫진 않지만, 필요하다면 감수하고 쓸 만큼은 됨. 인터넷 없는 4시간 비행에서도 로컬 LLM이 60W를 먹는데 배터리가 충분히 버텼음
    REAP을 지원하는 ds4 브랜치는 여기 있음: https://github.com/ljubomirj/ds4/tree/reap-compact-support
    DS4F가 784K 문맥에서야 10 tok/s 미만의 사용 불가 수준으로 떨어지는 점이 큰 차이를 만듦

  • 이런 로컬 모델이 특정 프로그래밍 언어에 전문가가 아닌 사용자에게도 정말 문제를 해결해 줄 수 있을지 궁금함
    인라인 자동완성이나 단위 구현을 넘어서, 실제로 작동하는 기술 명세를 설계하고 조합할 수 있는지 확신이 안 듦

  • llama.cpp/server를 써서 로컬 LLM을 띄우고 Claude Code나 Codex-CLI와 함께 쓰는 건 비교적 간단함
    필요한 llama server 설정이 여기저기 흩어져 있는 경우가 많아서, 인기 있는 오픈 LLM 몇 가지에 대한 지침을 여기 관리하고 있음: https://pchalasani.github.io/claude-code-tools/integrations/...

    • 그걸 일상용으로 쓰고 있나? Claude Code의 프롬프트가 엄청 커서 로컬 모델에서는 프롬프트 처리에 아주 오래 걸리고, 얼마 지나지 않아 문맥도 다 써버리게 됨
  • omlx.ai로 내 하드웨어에 맞는 여러 MLX 모델을 다운로드하고, 그 모델로 오픈소스와 폐쇄형 하네스(Claude Code, Codex)를 자동 실행하는 데 꽤 성공적으로 썼음
    웹 또는 데스크톱 UI에서 모두 가능해서, 개인적으로는 omlx를 쓰면 블로그 글을 따라 할 필요가 없음

    • 64GB M1 Max에서 oMLX나 MLX가 llama.cpp의 GGUF보다 특별히 유리한 점은 못 봤음
      지금까지 찾은 Gemma 4 MLX 빌드는 같은 양자화에서 더 느렸고, MTP에서는 훨씬 느렸음
      모델을 고른 뒤에는 llama.cpp의 내장 웹 UI가 꽤 좋고, 이것저것 만져볼 때는 LM Studio도 괜찮음
      Gemma-4와 Qwen 3.6은 일반적인 opencode 시스템 프롬프트의 큰 덩어리가 전혀 필요 없으며, 빼는 편이 더 나음
    • oMLX와 Pi에 붙일 샌드박스를 찾는다면 이게 있음: https://github.com/Dotnaught/pi-sandbox
    • Mac에서 로컬 추론을 위한 최첨단이라고 봄. 회귀가 생겨도 개발자들이 엄청 빠르게 대응하고, 최근 본 오픈소스 프로젝트 중 가장 인상적임
  • antirez의 ds4로 돌리는 DeepSeek v4 Flash가 꽤 인상적이었음
    “저장된 지식” 측면에서는 GPT-4급 모델처럼 느껴지지만, 긴 흐름의 도구 호출은 GPT-4급 모델들보다 더 잘함
    128GB MBP M4 Max에서 생성은 약 24 t/s, 프리필은 약 200 t/s가 나옴. 느릴 줄 알았고 코드 생성 같은 작업에서는 실제로 느리지만, 간단한 작업을 위한 머신 오케스트레이터로는 놀랄 만큼 유용함
    에이전트형이 아닌 용도에서는 대화하기에 충분히 괜찮은 모델이고, 완전히 자체 구동·비공개라는 장점도 있음
    [0]https://github.com/antirez/ds4

  • 매우 게으르게 하고 싶다면 터미널에서 Claude Code를 열고, 이 글을 가리킨 다음 그냥 “해줘”라고 시키면 됨

    • 이제 Google 검색을 거의 안 하게 됨. 10번 중 9번은 정보 품질이 형편없고, 주변의 스팸 속에서 필요한 내용을 가려내기 어렵기 때문임
      반면 Claude는 한 번에 처리하거나 아주 조금만 다듬으면 바로 해줌
      지식과 실행으로 가는 관문은 이제 LLM이고, Google Search는 공룡처럼 느껴짐
      스마트폰보다도 더 멋질 정도로, 한 세기쯤 미래에 와 있는 느낌임