본문 바로가기
AI 활용기

맥미니로 24시간 도는 AI 에이전트 만들기 (2) — 모델 운용기

by Bookman 2026. 6. 23.

1편에서 Hermes Agent를 맥미니에 설치하고 헤드리스·원격·Discord 연동까지 마쳤습니다. 이제 본질적인 질문이 남습니다 — 이 두뇌를 무엇으로 생각하게 할 것인가. 즉 어떤 모델로 추론을 돌릴 것인가입니다.

이번 편은 로컬 모델과 클라우드 API를 섞는 하이브리드 구성, 그리고 24GB 통합 메모리라는 벽과 씨름한 기록입니다. 결론부터 말하면, "용도에 따라 모델을 바꿔 쓰는" 라우팅이 정답이었습니다.

왜 하이브리드인가

먼저 오해를 하나 풀고 가겠습니다. "로컬 모델을 쓰면 API 비용이 안 든다"는 점이 이 시스템의 핵심 동기는 아닙니다. 어차피 빠르고 좋은 결과가 필요할 때는 클라우드 API를 써야 하고, 거기엔 비용이 듭니다. 로컬 모델은 비용을 0으로 만드는 마법이 아니라, 선택지를 하나 더 갖는 것입니다.

그 선택지가 의미 있는 두 가지 축은 이렇습니다.

  • 로컬 (Ollama): 데이터가 외부로 나가지 않아야 하는 작업, 그리고 비용을 신경 쓰지 않고 마음껏 돌리고 싶은 정기 작업. 느리지만 토큰 비용이 0이고, 24시간 켜둔 맥미니의 유휴 시간을 활용할 수 있습니다.
  • 클라우드 (Gemini API): 빠른 응답과 높은 품질이 필요한 작업. 비용이 들지만 소액이고, 결과물의 깊이가 다릅니다.

이 분리가 시스템 전체의 운영 원칙이 됐습니다. 빠르고 깊게 원하면 클라우드, 데이터를 가두거나 마음껏 돌리고 싶으면 로컬.

로컬 모델 — Ollama와 24GB의 벽

로컬은 Ollama를 백엔드로 썼습니다. macOS에서는 Ollama 공식 앱을 받아 실행하면 백그라운드에서 서버가 돌고, 터미널에서 ollama 명령을 쓸 수 있게 됩니다. 모델을 받는 것도 한 줄입니다.

ollama pull qwen3:14b

받은 모델 목록은 다음으로 확인합니다.

ollama list

여기서 첫 번째 벽에 부딪혔습니다. Hermes는 최소 64K 컨텍스트를 요구합니다. 그냥 모델을 받아 붙이면 기본 컨텍스트가 작아서 거부당합니다. 실제로 처음에는 이런 에러를 만났습니다.

Model 'qwen3:14b' has a context window of 40,960 tokens, which is below the minimum 64,000 required by Hermes Agent.

Ollama 모델은 두 가지 설정을 모두 64K로 올려야 했습니다.

hermes config set model.ollama_num_ctx 65536
hermes config set model.context_length 65536

context_length는 Hermes에게 알려주는 표시값이고, ollama_num_ctx는 Ollama가 실제로 모델을 메모리에 올릴 때 쓰는 런타임 값입니다. 둘은 다릅니다. 처음엔 context_length만 바꿨다가, "런타임 컨텍스트가 여전히 40,960"이라는 에러를 다시 만나고서야 둘 다 설정해야 한다는 걸 알았습니다.

막혔던 지점: 30B 모델은 24GB에서 안 됩니다

욕심을 내서 30B급 모델을 띄우려다 이런 에러를 만났습니다.

Provider returned an empty stream with no finish_reason

이건 Ollama가 모델을 메모리에 올리려다 실패하거나 스왑에 걸려 멈춘 것입니다. 계산해보면 당연합니다. 30B는 4bit 양자화해도 약 18GB, 거기에 64K 컨텍스트의 KV 캐시까지 더하면 24GB를 넘깁니다. OS가 6~8GB를 먼저 쓰니 실제 가용 메모리는 15~17GB뿐입니다.

24GB의 현실적인 로컬 모델 한계는 이랬습니다.

  • 9B (~5GB) — 64K 컨텍스트에도 여유. 안정적.
  • 14B (~9GB) — 적당. 64K와 함께면 빠듯하지만 작동.
  • 30B 이상 — 메모리 초과로 불가.

결국 14B(qwen3:14b)로 정착했습니다. 컨텍스트를 제대로 64K로 잡아주자 한국어로 끝까지 자연스럽게 답하기 시작했습니다. 그 전에 작은 컨텍스트로 돌 때는 답이 안녕하세요ItI처럼 토막나서 한참 헤맸는데, 원인이 바로 컨텍스트 설정이었습니다.

클라우드 모델 — Gemini와 가성비

클라우드는 Google AI Studio에서 발급한 Gemini API 키를 썼습니다. AI Studio는 API 키만 발급하는 곳이고, 어떤 모델을 쓸지는 거기서 정하는 게 아니라 Hermes 쪽에서 지정합니다(키 하나로 여러 Gemini 모델에 접근 가능). 연결은 hermes model 마법사로 Gemini provider를 선택하고 키를 붙여넣으면 됩니다.

가성비 관점에서 모델을 골랐습니다 (100만 토큰당 입력/출력 기준).

  • Gemini 3.1 Flash-Lite ($0.10 / $0.40) — 가장 저렴. 일상·간단 작업의 기본 드라이버.
  • Gemini 2.5 Flash ($0.15 / $0.60) — 조금 비싸지만 더 길고 충실한 출력.

개인 사용량(하루 작업 몇 건)이면 종량제로 월 몇 달러도 안 나옵니다. 한 가지 짚어둘 점은, ChatGPT Plus나 Claude Pro 같은 정액 구독으로는 이런 외부 프로그램에서 API를 쓸 수 없다는 것입니다. 구독은 그 회사의 채팅 앱·웹사이트를 쓰는 권리이고, Hermes 같은 외부 도구는 별도의 종량제 API가 필요합니다. 다행히 사용량이 적으면 종량제가 정액보다 오히려 쌉니다.

막혔던 지점: 모델 설정을 직접 건드리지 마세요

가장 크게 데인 부분입니다. 기본 모델을 바꾸려고 터미널에서 직접 쳤습니다.

hermes config set model gemini-2.5-flash   # 이렇게 하면 안 됩니다

이렇게 하자 모델 설정이 provider·api_key·base_url을 포함한 전체 묶음에서 모델명 문자열 하나만 남고 나머지가 다 날아갔습니다. 그 결과 Hermes가 "이게 어느 provider 모델이지?" 하고 엉뚱하게 OpenRouter 카탈로그에서 찾다가 404 에러를 냈습니다.

HTTP 404: Model 'gemini-3.1-flash-lite' not found. The requested model does not exist in our configuration or OpenRouter catalog.

복구는 정상 상태를 보여주는 hermes config show로 확인하는 데서 시작했습니다. 정상일 때 모델 항목은 {'api_key': ..., 'base_url': ..., 'provider': 'gemini', 'default': 'gemini-3.1-flash-lite'}처럼 전체 묶음으로 떠야 하는데, 깨졌을 때는 모델명만 덩그러니 남아 있었습니다.

교훈: 모델 변경은 항상 /model(Discord) 또는 hermes model(마법사)로 합니다. 이 방식은 provider 정보를 통째로 정확히 매칭해줍니다. 손으로 ID를 치면 묶음이 깨집니다.

또 하나: 세션 단위 vs 영구

/model로 모델을 바꾸면 "session only"라는 안내가 뜹니다. 즉 게이트웨이를 재시작하면 풀립니다. 영구 고정하려면 --global 옵션을 붙여야 합니다.

/model qwen3:14b --global

이걸 모르고 한참을 "왜 자꾸 기본 모델로 돌아가지?" 하며 매번 다시 설정했습니다. 모델을 바꿨는데 자꾸 초기화된다면 십중팔구 --global을 안 붙인 것입니다.

출력 길이 — 모델 체급의 차이

같은 작업을 시켰을 때 모델별로 출력 깊이가 확연히 달랐습니다. Flash-Lite는 답을 짧게 압축하는 경향이 강했고, 2.5 Flash는 훨씬 길고 충실했습니다. 프롬프트에 "각 단계를 충분히 길게 써라"를 명시해도 Flash-Lite는 잘 따르지 않았습니다 — 경량 모델의 본질적 특성입니다.

출력이 잘리는 또 다른 원인은 출력 토큰 한도였습니다. 기본값이 config에 명시돼 있지 않아 작게 동작하고 있었는데, 명시적으로 올려주니 개선됐습니다.

hermes config set model.max_tokens 8192

다만 한도를 늘려도 근본적으로 출력 품질과 깊이는 모델 체급에 달렸습니다. 그래서 "가벼운 건 Flash-Lite, 깊은 분석은 2.5 Flash"로 작업에 따라 바꿔 쓰는 게 합리적이었습니다.

정착한 라우팅 구성

일상 대화·간단 질문    → Gemini 3.1 Flash-Lite  (싸고 빠름)
깊은 분석·긴 리포트    → Gemini 2.5 Flash       (충실)
데이터 격리·정기 배치  → 로컬 qwen3:14b          (외부 유출 0, 토큰 0)

Discord 채널을 용도별로 나누고, 각 채널에 맞는 모델을 /model로 지정해두면 "채널만 옮기면 모델이 자동으로 맞는" 구조가 됩니다. 단 session only라 재시작 후엔 재설정이 필요한 점은 감안해야 합니다.

2편 정리

핵심 교훈을 정리하면 다음과 같습니다.

  • 하이브리드가 답이다. 빠르고 깊게=클라우드, 가두거나 마음껏=로컬. 하나로 다 하려 들지 말 것.
  • 24GB에선 14B가 현실적 상한. 30B는 안 된다.
  • Ollama 컨텍스트는 ollama_num_ctx와 context_length 둘 다 64K로.
  • 모델 변경은 config set model로 직접 하지 말고 /model이나 hermes model 마법사로. provider 묶음이 깨진다.
  • 영구 고정은 --global.
  • 출력 깊이는 모델 체급에 달렸다. 정액 구독으로는 외부 도구에서 API를 쓸 수 없으니 종량제가 필요하고, 소량이면 오히려 싸다.

여기서 다시 강조하고 싶은 것은, 로컬 모델의 진짜 의미입니다. 로컬은 "공짜 클라우드 대체재"가 아니라 24시간 켜둔 기기에서 비용 걱정 없이 마음껏 돌릴 수 있는 두뇌입니다. 낮에 빠른 답이 필요하면 클라우드를 쓰고, 밤새 천천히 돌려도 되는 작업은 로컬에 맡기는 식이죠. 이 분업이 다음 3편의 자동화로 이어집니다.

다음 3편에서는 이 모델들 위에 실제 활용을 얹습니다 — 여러 역할이 협업하는 커스텀 멀티에이전트 스킬을 직접 만들고, 과거 분석을 기억하는 메모리 기능과 자동화(병렬 처리·cron·외부 연동)까지 다루겠습니다.