M4 MacBook Pro에서 로컬 Qwen 3.8 27B 모델로 9가지 코딩 하네스 벤치마킹
TL;DR
단일 M4 MacBook Pro에서 로컬로 서빙되는 Qwen 3.8 27B 모델로 9가지 인기 코딩 에이전트 하네스를 실행한 결과, 세 가지 뚜렷한 성능 그룹이 드러났습니다: (1) 가벼우면서 안정적인 하네스 (pi, mini-swe-agent, chad)는 약 8토큰/초의 속도와 1초 미만의 턴 지연 시간을 제공합니다; (2) 무겁지만 규율 있는 하네스 (dsh, cline, codex, goose)는 6–8토큰/초를 달성하지만 첫 토큰 대기 시간이 더 깁니다; (3) 시작이 무거운 하네스 (crush, opencode)는 출력 전에 3–4분을 소비하며 약 5–6토큰/초로 떨어집니다. 차이는 주로 시스템 프롬프트 크기, 도구 스키마 수, 캐시 재사용 효율성에서 비롯됩니다.
실험 설정
- 하드웨어: Apple M4 MacBook Pro, 24GB RAM, macOS 26.6.2.
- 모델: Qwen 3.8 27B,
unsloth/Qwen3.8-27B-GGUF를 통해 3비트 양자화,llama.cpp(빌드 10470)로 서빙. - 서버: 모든 하네스가 공유하는 단일
llama-server인스턴스; 프록시가 균일한 샘플링 방식을 강제했습니다 (temperature = 1.0, top_k = 20, top_p = 0.95, min_p = 0.05). - 캐시: 32,768토큰 통합 프리픽스 캐시, 4개 슬롯으로 분할.
- 벤치마크: 8개의 Exercism Python 연습문제, 각각 자동 승인 모드에서 동일한 한 문장 프롬프트로 실행. 메트릭은 서버 자체 회계에서 수집되었습니다 (두 개의 chad 행은 내부 추적을 사용한 경우 제외).
메트릭 정의
| 메트릭 | 의미 |
|---|---|
| 첫 토큰 전 대기 | 시스템 프롬프트, 도구 스키마, 첫 사용자 요청을 프리필하는 시간. |
| 이후 턴 대기 | 첫 턴 이후의 중앙값 및 90번째 백분위수 일시 중지 (사이드 요청 제외). |
| 캐시 재사용 | 후속 턴에서 프리픽스 캐시에서 제공된 토큰의 백분율. |
| 체감 토큰/초 | 총 생성 토큰을 벽시계 시간으로 나눈 값 (프리필 및 도구 오버헤드 포함). |
| 통과 (게이트) | 1,200초 제한 시간 내에 완료된 Exercism 작업 수. |
로컬 추론이 클라우드보다 어려운 이유
- 대용량 시스템 프롬프트 및 도구 스키마 – 약 90토큰/초를 읽고 약 10토큰/초를 쓰는 노트북에서 2,000토큰 프롬프트는 생성 전에 약 22초가 소요됩니다; 18,000토큰 프롬프트 (Opencode에서 사용)는 약 226초가 소요됩니다. 클라우드 GPU는 >10k토큰/초로 프리필하여 이러한 지연을 1초 미만으로 줄입니다.
- 축소된 컨텍스트 창 – 시스템 프롬프트를 소비한 후, 남은 컨텍스트는 종종 <32k토큰입니다. Opencode의 18k토큰 프롬프트는 실제 작업에 창의 약 44%만 남기지만, 가벼운 pi 하네스는 약 94%를 유지합니다.
- 사이드 요청 오버헤드 – 보조 요청 (예: 코드 요약)을 반복적으로 발행하는 하네스는 로컬 모델이 대기열에 추가되거나 다시 프리필되도록 하여 GPU가 벽시계 시간의 >100% 동안 "바쁘게" 만듭니다.
벤치마크 결과
| 하네스 | 버전 | 도구 | 프롬프트 (토큰) | 첫 토큰 대기 | 이후 턴 대기 (중앙값·p90) | 캐시 재사용 | 토큰/초 | 통과 (24개 중) |
|---|---|---|---|---|---|---|---|---|
| mini-swe-agent | 2.4.6 | 1 | 1,171 | 12.2초 | 3.6초·21초 | 96% | 8.0 | 11 (14시간 초과) |
| pi | 0.80.3 | 4 | 2,008 | 21.6초 | 1.3초·22초 | 99% | 8.1 | 19 (7시간 초과) |
| cline | 3.0.60–61 | 26 | 5,876 | 64.1초 | 9.9초·52초 | 94% | 7.3 | 17 |
| codex | 0.151.0 | 10 | 7,804 | 87.8초 | 9.6초·28초 | 94% | 6.9 | 19 (5시간 초과) |
| dsh | 0.1.1-rc.2 | 25 | 8,052 | 94.4초 | 2.2초·34초 | 99% | 7.2 | 18 |
| goose | 1.50.0 | 18 | 9,617 | 110.3초 | 1.0초·22초 | 100% | 8.0 | 22 (3시간 초과) |
| crush | 0.92.0 | 26 | 16,263 | 199.8초 | 1.8초·40초 | 100% | 5.8 | 18 (8시간 초과) |
| opencode | 1.17.12 | 10 | 18,046 | 225.7초 | 4.6초·44초 | 99% | 5.7 | 15 (13시간 초과) |
| chad (llama.cpp) | 2.0.3 | 5 | 2,563 | 25.6초 | 0.8초·19초 | 99% | 7.9 | 24 |
| chad (MLX, 직렬) * | 2.0.3 | 5 | 2,566 | 4.7초 | 1.0초·19초 | 99% | 12.4 | 21 (3시간 초과) |
| chad (MLX, dflash2) * | 2.0.3 | 5 | 2,562 | 4.6초 | 0.9초·36초 | 99% | 17.4 | 22 (3시간 초과) |
숫자 해석
- 가벼운 하네스 (pi, mini-swe-agent, chad)는 시스템 프롬프트를 약 2k토큰 미만으로 유지하고, >99% 캐시 재사용을 달성하며, 약 8토큰/초를 유지합니다. chad의 MLX 변형은 캐시를 프로세스 내에서 소유하여 처리량을 두 배로 늘립니다 (최대 17.4토큰/초).
- 무겁지만 규율 있는 하네스는 첫 토큰 대기 시간이 더 길지만 (최대 약 110초) 높은 캐시 재사용을 유지하므로 정상 상태 처리량은 여전히 괜찮습니다 (약 7토큰/초).
- 시작이 무거운 하네스 (crush, opencode)는 출력 전에 3분 이상을 소비하고 ≤6토큰/초로 떨어져 노트북에서 실용적이지 않습니다.
- 통과율은 지연 시간과 상관관계가 있습니다: chad (두 변형 모두)만 24개 작업을 모두 해결했습니다; 다음으로 좋은 것은 goose (22/24)였습니다. mini-swe-agent의 낮은 통과 횟수는 괜찮은 토큰 속도에도 불구하고 빈번한 시간 초과에서 비롯됩니다.
로컬 모델 하네스를 위한 설계 교훈
- 시스템 프롬프트를 다듬으세요 – 추가 토큰마다 노트북에서 약 0.01초의 프리필 지연이 추가됩니다. 2k토큰 미만을 목표로 하세요.
- 도구 스키마를 제한하세요 – 추가 도구마다 프롬프트 크기가 커지고 사용 가능한 컨텍스트 창이 줄어듭니다.
- 프리픽스 캐시를 유지하세요 – 턴 간에 캐시된 프리필을 재사용하면 (≥95% 재사용) 반복 작업이 제거되고 체감 처리량이 크게 향상됩니다.
- 에이전트 루프와 모델을 함께 배치하세요 – chad의 프로세스 내 MLX 구현은 캐시를 소유하면 네트워크 왕복이 제거되어 2배-3배 속도 향상을 제공함을 보여줍니다.
- 드래프터를 제공하세요 – DFlash2 드래프터는 chad의 토큰 속도를 12.4 → 17.4토큰/초로 높여 초기 토큰 생성을 위한 경량 드래프트 모델의 가치를 입증합니다.
커뮤니티 피드백 하이라이트
"리소스가 제한된 환경을 위한 코딩 에이전트가 필요하다면 hax를 확인해 보세요 – 0.7MB 네이티브 바이너리로 미니멀한 프롬프트와 도구 세트를 갖추고 있습니다." – OleksandrC
"이런 벤치마크는 빠르게 변합니다; 재현 가능한 저장소가 있으면 누구나 자신의 하드웨어에서 턴당 토큰 수, 첫 토큰 지연 시간, 통과율을 비교할 수 있을 것입니다." – humbleferret
"jcode는 작은 Rust 바이너리로 RAM 사용량에서 모든 것을 능가하지만 연구에 포함되지 않았습니다." – lrvick
"Reasonix는 프리픽스 캐시 재사용에 크게 초점을 맞추기 때문에 흥미로운 비교가 될 수 있습니다." – swiftcoder
이러한 의견은 가벼운 프롬프트, 오픈 소스 재현성, 원래 매트릭스에 포함되지 않은 대체 초경량 에이전트의 존재의 중요성을 강조합니다.
벤치마크 재현
전체 실험은 chad 저장소에 스크립트로 작성되어 있습니다:
# 저장소 클론
git clone https://github.com/nathansutton/chad.git
cd chad
# 종속성 설치 (uv 권장)
uv run python benchmarks/matrix/run.py setup # 모델 설치, llama.cpp 빌드
uv run python benchmarks/matrix/run.py smoke # 정상 작동 확인
uv run python benchmarks/matrix/run.py llama # llama.cpp 서버를 통해 모든 하네스 실행
uv run python benchmarks/matrix/run.py mlx # MLX 백엔드로 chad 실행
uv run python benchmarks/matrix/run.py table # 위의 마크다운 테이블 생성
모든 원시 데이터 (grid.json, turns.jsonl)는 벤치마크 코드와 함께 커밋되어 단일 행에서 집계된 숫자까지 완전한 추적성을 보장합니다.
결론
노트북에서 클라우드 LLM을 로컬 모델로 교체할 때 지배적인 요소는 프롬프트 크기로 인한 프리필 지연 시간입니다. 사실상 무료인 클라우드 프리필을 위해 설계된 하네스 (대용량 시스템 프롬프트, 많은 도구 스키마)는 로컬에서 사용할 수 없게 됩니다. 규율 있는 최소 프롬프트와 지속적인 프리픽스 캐싱, 가능하다면 프로세스 내 모델 루프를 결합하면 소비자 하드웨어에서 클라우드에 가까운 처리량을 제공할 수 있습니다.
Sources
관련
- Dispatch
- Dispatch
- Dispatch
- Dispatch
- Dispatch