로컬 LLM이 멍청해 보일 때, 진짜 원인은 모델이 아니다
로컬 LLM이 멍청해 보일 때, 진짜 원인은 모델이 아니다
같은 오픈웨이트 모델인데 내 PC에서 돌리면 클라우드판보다 눈에 띄게 답이 나빠진다. 이것은 모델이 원래 그 정도라서인가, 아니면 우리가 그것을 잘못 돌리고 있어서인가?
도입
오픈웨이트 LLM을 직접 내려받아 돌려 본 사람이라면 한 번쯤 겪는 실망이 있다. 벤치마크 순위표에서는 상위권이고, 클라우드 API로 같은 모델을 부르면 멀쩡히 대답하는데, 막상 로컬 GPU에 올려 놓으면 답이 어딘가 어긋난다. 포맷을 무시하고, 추론을 도중에 끊고, 같은 문장을 반복하고, 도구 호출(tool call)을 엉뚱하게 닫는다. 그래서 “역시 로컬은 아직 멀었다”는 결론으로 넘어가기 쉽다.
Level1Techs 포럼에 올라온 「Why your local LLM feels dumber than it is」라는 글은 바로 그 결론을 정면으로 반박한다. 글쓴이의 주장은 단순하다. 로컬 모델이 나빠 보이는 것은 대개 모델 가중치의 근본 성능 문제가 아니라, 그 가중치를 실제로 실행하는 추론 스택(inference stack)의 구성 문제라는 것이다. 하드웨어가 다르고, 커널이 다르고, 양자화 방식이 다르고, 샘플링 설정이 다르면 같은 가중치도 다른 토큰을 뱉는다. 이 글은 그 “다름”을 감상이 아니라 로짓(logit) 단위로 측정해 보인다. 로컬 LLM 생태계가 “원래 그 정도”라는 통념이 얼마나 실행 환경에 오염되어 있는지를 따져 볼 때가 됐다.
증상: 같은 가중치, 다른 답
먼저 현상부터 보자. 사용자가 체감하는 “멍청함”은 대개 몇 가지 정형화된 증상으로 나타난다. 지시한 출력 포맷을 지키지 않고, 생각을 짧게 끊거나 반대로 사고(thinking) 블록에서 빠져나오지 못한 채 무한히 맴돌며, 같은 구절을 반복하고, 도구 호출의 인자나 종료 토큰을 망가뜨린다. 겉으로는 전부 “모델이 덜떨어져서” 그런 것처럼 보인다.
포럼 글쓴이는 이 증상들을 실제 업무 워크로드에서 로짓 단위로 추적했다. 그가 쓴 방법은 두 가지다. 하나는 top-1 불일치(top-1 disagreement) 추적으로, 서로 다른 구현이 그리디(greedy argmax)로 골라내는 토큰이 얼마나 갈리는지를 센다. 다른 하나는 KL 발산(KL divergence) 분석인데, 그는 여기에 분명한 단서를 단다. 기준이 되는 체크포인트와 실행 환경을 통째로 공개하지 않으면 그 수치는 해석 자체가 불가능하다는 것이다. 결정적 구간에서는 통계 추정 대신 로짓을 100% 캡처해, 분기가 시작된 지점부터 실제 출력이 어떻게 갈라지는지를 그대로 따라갔다.
그렇게 추적한 실패는 추상적인 확률 이야기가 아니라 구체적인 손상으로 나타났다. 글쓴이가 든 예를 보면, 어떤 어텐션 커널에서는 시스코 네트워크 명령의 인터페이스 이름 GigabitEthernet0/0/1.201이 GigabitEthernet0/1/4로 뒤바뀌었고, PostgreSQL 포트 번호 5432가 543ql로 깨졌으며, 호스트명 tenant가 그냥 - 한 글자로 치환됐다. 자동화 파이프라인에서 이런 토큰 하나의 뒤틀림은 곧바로 잘못된 장비에 명령을 던지는 사고로 이어진다. 흥미로운 점은 이런 뒤틀림이 매끄럽게 조금씩 늘지 않고 “덩어리”로 뭉쳐서 나타났으며, 무작위가 아니라 프롬프트 내용에 따라 달라졌다는 관찰이다.
특히 인상적인 것은 양자화 등급 사이의 격차다. 글쓴이는 BF16 기준본, FP8, INT8 W8A16, NVFP4, AWQ W4A16 등 여러 가중치 양자화를 도구 사용 정확도로 비교했는데, 하필 NVIDIA가 내놓은 “공식” NVFP4 배포본이 꼴찌를 기록해 88k 컨텍스트 지점에서 토큰 플립률이 약 50%에 이르렀다고 보고했다. 반대로 커뮤니티가 만든 INT8 양자화가 전 등급을 압도했다. “공식이니 믿을 만하다”거나 “숫자가 크니 정밀하다”는 직관이 여기서 무너진다. 어떤 등급의 양자화가 내 워크로드에서 잘 도는지는 라벨이 아니라 실측으로만 알 수 있다는 이야기다.
같은 계측은 가중치를 손댄 파인튜닝 변형에도 적용된다. 글쓴이는 안전 필터를 제거한 이른바 “abliterated” 계열의 인기 변형들을 원본 모델과 나란히 비교했다. 그 결과 어떤 변형(Heretic-ARA, Huihui 계열)은 top-1 플립률을 1.5% 미만으로 유지하며 원본이 강하게 선호하던 토큰을 하나도 뒤집지 않은 반면, 또 다른 변형(AEON 계열)은 구조적으로 무효한 출력을 수십 건 만들어 냈고, 원본이 확신하던 선택을 여러 차례 뒤집었다. 같은 베이스 모델에서 갈라져 나온 변형들 사이에서도 품질은 이렇게까지 벌어진다. 사용자가 이름만 보고 “이건 검열 없는 버전이니 더 낫다”고 고르는 순간, 자기도 모르게 크게 열화된 가중치를 쥐고 있을 수 있다는 뜻이다. 그리고 이 차이 역시 감(感)이 아니라 플립률이라는 숫자로 드러난다는 점이 이 글의 일관된 태도다.
원인: 추론 스택의 어디서 품질이 새는가
그렇다면 왜 이런 일이 벌어지는가. 원인은 하나가 아니라 추론 경로 곳곳에 흩어져 있고, 각각이 품질과 VRAM·속도 사이의 트레이드오프를 안고 있다.
첫째, 가중치 양자화 손실이다. 로컬에서 큰 모델을 좁은 VRAM에 밀어 넣으려면 가중치를 4비트나 8비트로 압축하는데, 이 과정에서 표현력이 깎인다. HN 토론에서는 Ollama 같은 도구를 쓰는 사람들이 자기가 Q4 양자화본을 돌리고 있다는 사실조차 모른 채, 그 결과가 BF16 원본과 상당히 다르다는 점을 간과한다는 지적이 나왔다. 압축률을 높이면 메모리와 속도는 벌지만 품질이 샌다는 것이 핵심 트레이드오프다.
둘째, 더 치명적인 것은 KV 캐시 양자화다. 포럼 글쓴이는 KV 캐시를 int4로 양자화하자 도구 호출 오류가 재현 가능하게(reproducibly) 터졌고, int8로 올리자 회복됐다고 적었다. HN 토론에서도 모델이 그 방식으로 학습된 게 아니라면 KV 캐시 양자화는 피하고, 속도를 희생하더라도 가능한 한 큰 파일 크기(예: Q8 GGUF)를 쓰라는 권고가 나왔다. 어텐션이 매 스텝 참조하는 캐시를 거칠게 압축하면 긴 문맥일수록 오차가 누적된다는 이야기다.
셋째, chat·prompt 템플릿과 파서의 문제다. HN 토론에서는 어떤 추론 엔진의 파서가 사고 블록을 처리하면서 줄바꿈 문자(\n) 하나를 여분으로 잡아먹은 탓에, 여러 턴이 이어지는 긴 세션에서 자기 교정이 연쇄적으로 일어나 출력이 서서히 무너졌다는 사례가 공유됐다. 한 패턴이 문맥에 많이 등장할수록 다음 턴에도 그 패턴이 더 잘 나타나는 자기강화 루프가 생겨, 단발 프롬프트에서는 보이지 않던 열화가 대화형에서만 드러난다는 것이다. 채팅 템플릿이 조금만 어긋나도 모델이 학습 때 본 형식과 달라져 지시를 무시하는 것처럼 보인다.
넷째, 컨텍스트 윈도우와 truncation이다. HN 토론에서는 Ollama의 기본 컨텍스트 창이 2,000~4,000 토큰 수준이라, 사용자가 손대지 않으면 긴 입력이 조용히 잘려 나가 모델이 무능해 보인다는 지적이 반복됐다. 나아가 잘 갖춘 하드웨어에서도 컨텍스트가 대략 80K를 넘어서면 응답이 불안정하고 느려지더라는 관찰도 나왔다. 광고된 최대 컨텍스트가 곧 실사용 품질을 보장하지는 않는다는 뜻이다.
다섯째, 샘플링 파라미터 오설정이다. 포럼 글쓴이는 temperature를 너무 낮게 잡는 것이야말로 “Qwen이 THINK 출력에서 빠져나오지 못하고 맴도는” 원인이라고 짚으며, HuggingFace 모델 카드가 대개 그 모델에 맞는 샘플러 설정(예: temperature 1.0, top-p 0.95 등, 모델마다 다름)을 명시해 두니 그대로 따르라고 했다. temperature·top-p·repeat penalty를 임의로 만지면 반복 억제와 다양성 사이의 균형이 깨져, 루프에 빠지거나 지나치게 산만해진다. 추론 강도(reasoning effort) 설정도 마찬가지다. HN 토론에서는 어떤 Qwen 계열 모델이 기본값으로 잡힌 과도한 추론 강도 탓에 한없이 생각만 하며 멈춘 듯 보였는데, 이를 중간 수준으로 낮추자 무한정 맴돌지 않더라는 사례가 나왔다. 다만 강도를 낮추면 복잡한 문제의 미묘함을 놓칠 수 있다는 반대 방향의 트레이드오프가 함께 지적됐다. 여기에 시스템 프롬프트 누락이 겹치면 모델은 자기가 어떤 역할과 형식으로 답해야 하는지 모르는 채 기본값으로 흘러간다.
여섯째, 더 깊은 층에는 커널과 병렬화 자체의 비결정성이 있다. 포럼 글쓴이에 따르면 FlashAttention 2, FlashInfer, Triton 같은 서로 다른 어텐션 백엔드는 프리필(prefill) 단계에서 비트 단위로 다른 로짓을 만들어 토큰 선택을 갈라놓는다. 텐서 병렬화 설정을 TP1·TP2·TP4로 바꾸기만 해도 도구 호출 결과가 달라졌는데, 이는 GPU 간 통신(NCCL)의 차이에서 온다. 그가 쓴 vLLM 스택 하나에만 734개(그중 파이썬 패키지 252개)의 의존성이 얽혀 있었다는 사실은, 어디선가 조용히 수치가 어긋날 여지가 그만큼 많다는 뜻이다. HN 토론에서는 추론 엔진의 단위 테스트 허용 오차(예: rtol=5e-03)가 너무 느슨해, 행 단위 어텐션 오차가 있어도 테스트는 통과해 버리는 침묵의 열화가 있다는 지적도 나왔다.
시사점: ‘로컬은 원래 나쁘다’는 오해의 비용
이 진단을 실무로 옮기면 체크리스트가 나온다. 모델을 올리기 전에 (1) 지금 돌리는 양자화 등급이 무엇인지 명시적으로 확인하고, 필요하면 더 큰 등급으로 올린다. (2) KV 캐시 양자화는 그 모델이 그렇게 학습되지 않았다면 끈다. (3) 채팅 템플릿과 시스템 프롬프트가 모델 카드의 형식과 일치하는지 대조한다. (4) 컨텍스트 창을 기본값에 맡기지 말고 워크로드에 맞춰 명시적으로 늘린다. (5) 샘플러 값은 임의로 만지지 말고 모델 카드가 권한 값부터 시작한다. (6) 무엇보다, 벤치마크 순위나 모델 카드의 약속을 신뢰의 최종 근거로 삼지 말고, 자기 워크로드로 재현 가능한 사설 벤치마크를 만들어 실측한다.
포럼 글쓴이의 결론도 여기에 있다. “그들의 하드웨어는 당신 것과 다르고, 그들의 소프트웨어는 당신 것과 매우 다르다.” HN 토론에서도 모델들이 보도자료에서 언급한 벤치마크에 맞춰 최적화되는 경향이 있으니, 공개 수치를 믿기보다 자기만의 비공개 벤치마크를 만들라는 권고가 나왔다. 도구 선택도 시사점이 있다. HN 토론에서는 llama.cpp가 가장 신뢰할 만하고, vLLM과 SGLang이 기능 면에서 Ollama보다 앞서며, 애플 하드웨어에서는 MLX가 빠르다는 평이 모였다. Ollama는 쓰기는 쉽지만 기본값이 문제라는 것이다.
낙관적으로 보면 이 문제들은 대부분 설정으로 고칠 수 있는, 즉 원리적으로 해결 가능한 결함이다. 비관적으로 보면 이 미세한 함정들이 오픈웨이트 생태계 전체의 평판을 갉아먹는다. 제대로 세팅하면 클라우드판에 근접하는 모델이 잘못된 기본값 탓에 “역시 로컬은 안 된다”는 인상을 남기고, 그 인상은 다시 오픈웨이트 대신 폐쇄형 API로 사람들을 밀어 넣는다. 현실 시나리오는 그 사이 어딘가일 것이다. 도구들의 기본값이 점점 나아지고 모델 카드의 샘플러 명세가 표준화되면서, 오늘의 함정 중 상당수는 내일의 상식으로 흡수될 것이다.
결론
그래서 로컬 LLM은 정말 멍청한가. 이 글의 답은 “대체로 아니다”에 가깝다. 우리가 본 것은 모델의 무능이 아니라 배포의 무질서였다. 양자화 등급, KV 캐시 정밀도, 채팅 템플릿, 컨텍스트 창, 샘플러 값, 그리고 커널과 병렬화의 비결정성 — 이 여섯 층 어디서든 품질은 샐 수 있고, 대개 여러 곳에서 동시에 샌다. 그리고 이 모든 누수는 감상이 아니라 로짓 단위로 측정 가능하다.
실무자에게 남는 행동은 분명하다. 모델을 탓하기 전에 자기 스택을 먼저 계측하라. 자기 워크로드로 된 작은 벤치마크 하나를 만들어, 양자화 등급을 바꾸거나 샘플러를 만질 때마다 그 결과를 눈으로 확인하라. “로컬은 원래 나쁘다”는 문장은, 정확히 말하면 “나는 아직 내 로컬을 제대로 계측하지 않았다”의 다른 표현일 때가 많다. 당신의 모델이 마지막으로 멍청해 보였을 때, 그것은 정말 모델이었을까, 아니면 기본값이었을까?
출처: