Aiden Kwak Pages
03 · Project

로컬에서 코딩 에이전트 돌리기

맥북 M4 Max 36GB에서 Qwen3.6 돌려본 후기

2026-07-05 ·

LLM 모델 사용 제한과 가격인상. 언젠가 이런 날이 올 것이라고 어렴풋이 생각했고, 막연하게나마 준비해야 한다는 생각도 하고 있었습니다. 그런데 최근 Anthropic과 OpenAI의 정책 변화를 보면서, 그 시점이 생각보다 훨씬 빨리 올 수 있겠다는 위기감을 느꼈습니다.

지금까지는 SOTA 모델들을 비교적 저렴하게 이용해왔지만, 이런 환경이 오래 지속되지는 않을 것 같다는 생각이 계속 듭니다. GLM-5나 Qwen3.6 같은 오픈웨이트 모델들의 성능에 대한 이야기는 꾸준히 들려오고 있지만, 벤치마크 성능과 실제 사용 경험 사이에는 분명한 괴리가 있습니다. 그래서 직접 써보기로 했습니다.

목표는 명확했습니다. 제가 현재 보유한 맥북 M4 Max, 36GB RAM 환경에서 코딩 에이전트를 실사용 수준으로 돌릴 수 있는지 확인하는 것이었습니다. 단순한 코드 조각 생성이 아니라, 게임 하나를 처음부터 끝까지 만들게 하고, 실제로 사람이 플레이할 수 있는 결과물이 나오는지까지 보는 것이 목표였습니다.

모델은 몇 가지를 옮겨가며 테스트하다가 최종적으로 Qwen3.6-35B-A3B-4Q에 정착했습니다. 모델을 고르는 과정에서 특히 흥미로웠던 것은 생성 속도였습니다.

아무리 모델 지능이 높아도, 저는 속도가 중요한 기준 중 하나라고 생각합니다. 그래서 처음에는 Qwen3.5-9B-4Q를 선택했습니다. AC 전원에 연결하고 맥북을 고성능 모드로 설정한 기준으로 초당 45-52토큰 정도가 나왔습니다. 클라우드 API 환경에서 Claude Code가 대략 초당 90토큰 정도 나오는 것을 감안하면, 이 정도면 충분히 만족스러운 속도였습니다.

그런데 더 흥미로웠던 것은 Qwen3.6-35B-A3B-4Q의 속도였습니다. 이 모델은 MoE 구조라 전체 파라미터는 35B이고 가중치 크기는 약 19GB지만, 토큰당 활성화되는 파라미터는 3B 수준입니다. 덕분에 생성 속도가 dense 9B 모델보다 오히려 빨랐습니다. 실제 측정 결과 초당 84토큰 정도가 나왔고, 체감상 클라우드 스트리밍과 큰 차이가 없었습니다. 에이전트와 상호작용하는 과정에서도 속도 병목을 거의 느끼지 못했습니다.

테스트를 위한 최종 구성은 아래와 같습니다.

  • 하드웨어: MacBook M4 Max, 36GB RAM
  • 로컬 추론 서버: mlx-lm
  • 에이전트 하네스: Claude Code
  • 라우팅: claude-code-router
  • 모델: Qwen3.5-9B-4Q, Qwen3.5-35B-A3B-4Q, Qwen3.6-35B-A3B-4Q

테스트1: 테트리스

가장 먼저 시킨 것은 테트리스였습니다. 게임 규칙이 명확하고, 구현 범위가 적당하며, 사람이 바로 플레이하면서 검증할 수 있기 때문입니다. 로컬 코딩 에이전트의 첫 테스트로는 꽤 좋은 과제였습니다.

처음에는 9B 모델로 시작했습니다. 전체 구현에는 약 1시간 반이 걸렸고, 결과물은 생각보다 그럴듯했습니다. 블록이 떨어지고, 회전하고, 줄이 사라지고, 점수가 올라가는 기본 흐름은 구현됐습니다. 이 정도면 "로컬 모델도 간단한 게임은 만들 수 있다"고 말할 수 있는 수준이었습니다.

하지만 직접 플레이해보니 몇 가지 런타임 버그가 보였습니다. 특히 회전 처리와 경계 조건에서 문제가 발생했습니다. 흥미로웠던 점은, 버그를 자연어로 설명하면 모델이 원인을 대체로 이해했고, 한두 번의 수정 턴 안에 고치는 경우가 많았다는 것입니다. 즉, 간단한 웹앱이나 작은 게임 수준에서는 9B 모델도 꽤 실용적인 모습을 보여줬습니다.

테트리스 결과물 - 9B 모델이 생성한 플레이 가능한 테트리스


두 번째 테스트: 마인크래프트 스타일 3D 데모

다음 목표는 3D 개발이었습니다. 단순한 2D 게임을 넘어서, 모델이 three.js를 이해하고 3D 씬을 구성할 수 있는지 확인하고 싶었습니다. 과제는 마인크래프트 스타일의 채굴 데모였습니다.

요구사항은 일부러 꽤 구체적으로 줬습니다. 12x12 크기의 블록 월드, 6개 높이의 레이어, 흙, 돌, 나무, 석탄, 철, 다이아몬드 블록, 블록별 강도, 곡괭이 티어, 채굴 진행도, 인벤토리, 제작 버튼, 모바일 세로 화면 대응까지 포함했습니다.

9B 모델은 여기서 막혔습니다. three.js 관련 오류를 해결하지 못했고, 10턴 이상 같은 부근에서 헤매는 모습을 보였습니다. 오류 메시지를 읽고 수정하려고는 했지만, 실제 원인을 좁히지 못하고 비슷한 수정을 반복했습니다. 이때 9B 모델의 한계가 비교적 명확하게 보였습니다. 작은 2D 앱은 가능하지만, 라이브러리 API와 렌더링 구조가 얽히는 순간 안정성이 크게 떨어졌습니다.

같은 요청을 Qwen3.5-35B-A3B에 다시 줬습니다. 우리가 상상하는 형태의 그럴듯한 3D 오브젝트를 만드는 데는 실패했습니다. 나무나 지형의 조형미를 구현하지 못했습니다. 하지만 로지컬한 부분들은 성공했습니다. three.js 씬을 구성했고, 블록 강도와 채굴 로직을 제대로 반영해 오류없이 빌드를 하는데 성공했습니다.

아래 결과물을 얻는데 2시간 반이 소요되었습니다.

마인크래프트 스타일 3D 채굴 데모 - 35B 모델이 three.js로 구성한 복셀 월드


로컬에서의 모델 운용 문제

제일 먼저 겪게되는건 메모리 문제입니다. 조금만 큰 프롬프트를 보내면 Metal OOM으로 시스템이 죽습니다. 루프를 몇번 돌리면 컨텍스트가 불어나 이때도 OOM이 나버립니다. 이 문제를 개선하기위해 아래 과정들을 거쳤습니다.

첫째, macOS의 GPU 메모리 상한입니다. 맥의 통합 메모리는 CPU와 GPU가 RAM을 공유하는 구조인데, GPU가 점유할 수 있는 상한인 iogpu.wired_limit_mb의 기본값이 낮았습니다. 19GB짜리 모델을 올리고 나면 실제로 사용할 수 있는 여유가 얼마 남지 않았습니다. 이 상한을 올리자 45k 토큰짜리 프롬프트도 안정적으로 처리됐습니다.

둘째, 동시 요청 문제입니다. OOM은 평균 사용량이 아니라 prefill 순간의 스파이크에서 발생합니다. 코딩 에이전트는 생각보다 여러 요청을 동시에 날립니다. 두 prefill이 겹치면 메모리 스파이크도 같이 겹칩니다. "병렬 요청을 하지 말라"고 지시해도 모델과 도구 체인은 그 지시를 항상 지키지 않았습니다. 저는 파이썬 프록시를 따로 만들어 generation 요청을 물리적으로 한 번에 하나씩만 통과시켰습니다. 그 뒤로 이 유형의 OOM은 사라졌습니다.

셋째, KV 캐시 입니다. 처음 제 사고과정은 이랬습니다. 35B-A3B는 MoE 모델이니까 3B만 활성화 시키겠구나, 프롬프트 캐시도 작을거니까 9B 모델때 설정 그대로 해도되겠지, 라는게 제 생각이었으나 그렇지 않습니다. Attention은 MoE가 아닙니다. 35B 크기에 대한 캐시 메모리가 들어가므로 KV Cache는 생각보다 훨씬 커지게 됩니다. 9B모델 설정 당시 저는 프롬프트 캐시를 8개 보관하도록 설정했습니다. 하지만 35B 모델에서는 KV 캐시 하나만해도 1.5에서 2GB를 넘어갑니다. 가중치 19GB위에 캐시만 10GB 넘게 얹히니 36GB 초과하면서 OOM이 나는겁니다. 35B 모델에서는 프롬프트 캐시 1개, 바이트 총량 상한 2.5GB를 주어 해결했습니다.

넷째, Skill의 활용입니다. 귀찮은 일을 줄이려면 턴당 컨텍스트의 양을 최대한으로 줄여야합니다. 기본 요청 외에는 최대한 Skill로 빼내서 prefill 되는 컨텍스트를 줄였습니다.

다섯째, 제 작업과정은 이런 모습이었습니다. OOM이 나기전에 파이썬 훅이 에이전트 동작을 중단합니다. 한 세션에 컨텍스트가 많이 불어나 OOM이 우려되면 PROGRESS.md에 작업 사항과 다음 작업할 내용을 기록하고 세션이 중단됩니다. 이후에는 수동으로 새로운 세션을 열고 "OOO작업폴더/PROGRESS.md를 읽고 작업 재개" 명령을 주어 작업을 이어갑니다. 이게 효과적으로 이루어질 수 있으려면 한 세션에서 너무 많은 작업이 이루어져서는 안됩니다. 첫 요청시 작업은 최대 12단계로 나누어지고, 각 세션에서 한단계씩을 작업합니다. PROGRESS.md가 명확하게 작성될 수 있을수록 작업물의 퀄리티가 좋아집니다.


세 번째 테스트: 장기

마지막 테스트는 장기였습니다. 테트리스는 작은 게임 루프를 검증하기 좋았고, 마인크래프트 스타일 데모는 3D와 상태 관리를 검증하기 좋았습니다. 장기는 다른 성격의 과제였습니다. 규칙이 복잡하고, 예외가 많고, 테스트 없이는 사람이 바로 신뢰하기 어렵습니다.

가장 처음 드러난 약점은 렌더링이었습니다. 장기의 첫 시도는 Qwen3.5-35B-A3B로 했는데, 이 모델은 규칙뿐 아니라 화면 구성에서도 흔들렸습니다. 아래는 3.5가 만든 결과물인데, 장기판 격자와 말의 위치가 서로 맞지 않습니다. 말이 교차점이 아니라 칸 사이에 떠 있거나, 붉은 병과 포가 엉뚱한 줄에 배치돼 있습니다. 좌표 계산과 렌더링처럼 "보이는 것을 정확히 맞추는" 작업에서 3.5는 확연히 약했습니다. 작업시간은 2시간 반이 소요되었습니다.

Qwen3.5로 만든 장기 - 장기판 격자와 말 위치가 어긋나 있다

이후 모델을 Qwen3.6-35B-A3B로 올리고 나서야 보드와 말이 제자리를 찾았습니다. 다음 문제는 게임의 규칙에 대한 것이었는데, 장기는 유명한 게임이니 모델의 도메인 지식을 이용해도 충분할 것이라고 생각을 했었습니다. 그래서 먼저 장기규칙과 장기말들의 움직임을 정의한 RULES.md를 생성하고 이후에 이것을 SSOT로 하여 개발을 진행하도록 요구하였습니다. 이후 테스트 코드까지 전부 통과하여 확인을 해보았는데 생각과 다르게 동작하는 말들이 있어 확인을 해보니 모델이 정의한 룰이 잘못된 것을 발견하였습니다. 도메인 지식은 신뢰를 하지 말아야한다는 교훈을 얻었고, 전부 수정하고 나니 정상 작동하는 것을 확인했습니다. 흥미로웠던 점은 작업 시간이 30분 정도에 불과했다는 점, Qwen3.5 모델과 달리 배터리 소모 속도보다 충전속도가 더 빨랐다는 점입니다.

장기 구현 결과물 - 규칙 엔진과 보드 UI


구조가 중요하다

로컬 모델은 클라우드 SOTA 모델보다 분명히 약합니다. 그런데 그 약함은 단순히 "코드를 못 짠다"는 형태로 나타나지 않았습니다. 오히려 더 자주 보인 것은 "지시를 끝까지 지키지 못한다"는 문제였습니다.

예를 들어 "실패하면 같은 시도를 반복하지 말라"고 말해도 반복합니다. "파일을 수정하기 전에 현재 내용을 다시 읽어라"고 말해도 생략합니다. "컨텍스트가 커지면 멈춰라"고 말해도 계속 진행합니다. 지시문은 압박 상황에서 쉽게 무시됩니다.

하지만 훅이나 프록시로 물리적으로 막으면 이야기가 달라집니다. 병렬 요청을 하지 말라고 지시하는 대신 프록시에서 직렬화하면 100% 지켜집니다. 특정 도구 호출이 무한루프를 만들면 훅으로 차단하면 됩니다. 세션이 길어져 위험해지면 프록시가 요청 크기를 보고 거부하거나 새 세션으로 넘기게 만들 수 있습니다.

컨텍스트 관리도 마찬가지입니다. Skill을 통해 AI가 잘 활용할 수 있는 도서관을 구축해주면 컨텍스트 양에 대한 압박없이 전달되는 컨텍스트의 퀄리티를 최대한으로 끌어올릴 수 있습니다.

이 과정에서 느낀 것은, 로컬 LLM을 실사용하려면 하네스 엔지니어링이 더 중요하다는 점입니다. 모델을 설득하려 하지 말고, 실패할 수 없는 구조를 만들어야 합니다.

결론

로컬기기에서의 이번 LLM 사용후기는 굉장히 성공적이었다고 생각합니다. 아직 멀었다는 후기를 굉장히 많이 봤던 터라 35B로는 어림도 없을거라고 생각했던 작업들이 작동하는 것을 보면서 많이 놀랐습니다.

정리해보면 이렇습니다. 간단한 2D 게임 구현, three.js 기반 3D 데모, 복잡한 규칙을 가진 게임 엔진 작성, 컴파일 에러를 읽고 스스로 수정하는 루프는 충분히 가능했습니다. 초당 80토큰대의 생성 속도도 실사용에서 답답하지 않았습니다. 무엇보다 API 비용이 들지 않고, 코드가 기기 밖으로 나가지 않는다는 장점이 큽니다.

아직 안 되는 것도 분명합니다. 지시문 준수율이 낮습니다. 컨텍스트 관리에 대한 부담이 큽니다. 하네스 없이 그냥 돌리면 무한루프, OOM, 환각으로 쉽게 무너집니다.

하지만 이번 실험에서 가장 중요한 발견은, 이 문제들 상당수가 모델 교체 없이 구조로 완화된다는 점이었습니다. GPU 메모리 상한을 조정하고, 요청을 직렬화하고, KV 캐시에 상한을 걸고, 규칙 문서를 단일 출처로 만들고, 빌드와 테스트와 훅을 게이트로 세우면 로컬 모델도 꽤 안정적으로 일합니다.

SOTA API가 지금보다 더 비싸지거나 닫히는 날이 오더라도, 준비가 완전히 불가능한 것은 아니라는 생각이 들었습니다. 오픈웨이트 모델의 성능은 이미 개인이 실험해볼 만한 수준까지 올라왔습니다. 적어도 코딩 에이전트 영역에서는, 맥북 한 대로도 꽤 많은 것을 할 수 있는 시점에 와 있습니다.

Back toProject 목록