Ollama + Hermes로 로컬 LLM 인프라 구축하기 — API 비용 0원, 데이터 외부 유출 없음
매달 OpenAI 청구서를 보면서 "이게 맞나?" 싶었던 순간이 한 번쯤은 있으실 겁니다. 저도 사이드 프로젝트에 GPT-4 API를 붙여뒀다가 한 달 만에 몇 만 원이 빠져나간 걸 보고 멈칫했거든요. 더 찜찜했던 건, 테스트 데이터에 회사 내부 텍스트가 섞여 있었다는 점이었습니다. 민감한 정보가 외부 서버로 날아가는 게 맞는 건지 확인하기도 어려운 상황이었죠.
그 고민 끝에 Ollama와 NousResearch의 Hermes 모델 조합으로 옮겨왔습니다. 이 두 가지를 연결하면 외부 클라우드 없이 내 컴퓨터에서만 돌아가는 AI 에이전트 파이프라인을 구성할 수 있습니다. 어떻게 가능한지, 기존 OpenAI 코드를 건드리지 않고도 전환하는 방법이 있는지, 그 과정에서 맞닥뜨렸던 함정들을 여기서 같이 살펴보겠습니다.
핵심 개념
Ollama: AI 모델계의 Docker
Docker를 처음 썼을 때를 떠올려보세요. 환경 설정 걱정 없이 docker run 하나로 어떤 서비스든 띄울 수 있다는 게 신선했던 그 느낌 말이에요. Ollama가 딱 그 포지션입니다.
LLM을 로컬에서 직접 실행하려면 원래 양자화 설정, VRAM 할당, CUDA/Metal 가속 세팅까지 꽤 복잡한 준비가 필요합니다. Ollama는 이 모든 걸 추상화해줍니다. 명령어 하나로 모델을 내려받고, 자동으로 GPU를 감지해 가속을 적용하며, 포트 11434에서 OpenAI 호환 REST API를 띄워줍니다.
# Ollama 설치
curl -fsSL https://ollama.com/install.sh | sh
# 모델 실행 (최초 실행 시 자동 다운로드)
ollama run llama3.1:8b
# OpenAI SDK와 동일한 방식으로 호출 가능
curl http://localhost:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "llama3.1:8b",
"messages": [{"role": "user", "content": "안녕하세요!"}]
}'OpenAI 호환 API: Ollama는
/v1/chat/completions엔드포인트를 OpenAI와 동일한 스펙으로 구현합니다. 기존 OpenAI SDK 코드에서base_url만http://localhost:11434/v1으로 바꾸면 나머지 코드를 건드리지 않고도 로컬 모델로 전환됩니다.
양자화(Quantization): 모델 가중치를 32비트 부동소수점에서 4비트·8비트 정수로 압축하는 기법입니다. 모델 크기와 메모리 요구량이 크게 줄어들되 정확도는 약간 손실됩니다. Ollama에서는
llama3.1:8b-q4_0같은 형식으로 양자화 수준을 선택할 수 있습니다.
하드웨어 환경별로 어떤 모델을 선택하면 좋을지 아래 표로 정리했습니다.
| 모델 | 크기 | 권장 RAM | 용도 |
|---|---|---|---|
llama3.2:3b |
~2GB | 8GB | 입문·저사양 |
llama3.1:8b |
~5GB | 16GB | 범용 추천 |
qwen2.5-coder:7b |
~5GB | 16GB | 코딩 특화 |
nous-hermes |
~5GB | 16GB | 함수 호출·에이전트 태스크 최적화 |
mistral:7b |
~4GB | 16GB | 빠른 응답·고품질 균형 |
Hermes: 에이전트 작업에 최적화된 NousResearch의 파인튜닝 모델
Hermes는 NousResearch가 개발한 파인튜닝 LLM 모델 시리즈입니다. Hermes 2, Hermes 3를 거쳐 현재까지 이어지고 있으며, Ollama 라이브러리에서 nous-hermes 이름으로 바로 받아 쓸 수 있습니다.
일반 베이스 모델과 비교했을 때 Hermes가 두드러지는 부분은 함수 호출(Function Calling)과 구조화된 출력입니다. LangChain이나 자체 에이전트 파이프라인에서 도구를 호출하거나 JSON 스키마에 맞는 응답을 생성해야 할 때 일반 모델보다 훨씬 안정적으로 동작합니다. 저도 처음엔 llama3.1:8b로 에이전트를 구성했다가 도구 호출 파싱이 자꾸 실패해서 nous-hermes로 바꿨더니 바로 해결됐던 경험이 있습니다.
NousResearch는 별도로 Hermes Agent라는 에이전트 프레임워크도 개발 중입니다. 자기 개선(self-improving) 루프와 세션 간 메모리 유지를 특징으로 내세우는 제품인데, 이 포스팅에서는 검증 가능한 nous-hermes 모델 활용에 집중하겠습니다. Hermes Agent 프레임워크에 관심이 있다면 NousResearch 공식 GitHub에서 최신 릴리즈 상태를 직접 확인하는 것을 권장합니다.
Ollama + Hermes: 계층 분리의 아름다움
두 도구를 연결하면 관심사가 명확하게 분리됩니다.
┌─────────────────────────────────┐
│ 에이전트 오케스트레이션 │ ← LangChain / 자체 파이프라인
│ (메모리 · 도구 · 워크플로우 관리) │ 함수 호출, RAG, 멀티스텝 태스크
└──────────────┬──────────────────┘
│ OpenAI 호환 API
│ http://localhost:11434/v1
┌──────────────▼──────────────────┐
│ Ollama │ ← 모델 서빙 레이어
│ (양자화 · GPU 가속 · API 서버) │ nous-hermes, llama3.1 등
└─────────────────────────────────┘에이전트 오케스트레이션: 에이전트가 어떤 도구를 어떤 순서로 쓸지 결정하고, 중간 상태와 메모리를 관리하는 역할입니다. LangChain이 대표적인 오케스트레이션 레이어이고, 그 아래에서 실제 모델 추론을 담당하는 것이 Ollama입니다.
오케스트레이션 레이어를 LangChain에서 다른 프레임워크로 교체해도 Ollama는 그대로 쓸 수 있고, 반대로 Ollama를 vLLM 같은 다른 서빙 레이어로 바꿔도 위 코드는 영향을 받지 않습니다.
실전 적용
예시 1: Ollama 설치 및 nous-hermes 모델 실행
바로 시작해볼 수 있는 가장 빠른 진입점입니다. Ollama와 nous-hermes 모델만 있으면 됩니다.
# 1. Ollama 설치
curl -fsSL https://ollama.com/install.sh | sh
# 2. nous-hermes 모델 다운로드
ollama pull nous-hermes # 함수 호출·에이전트 태스크 최적화
ollama pull llama3.1:8b # 범용 백업 모델
# 3. 설치 확인
ollama list # 다운로드된 모델 목록 확인# API 동작 확인
curl http://localhost:11434/v1/models
# nous-hermes로 함수 호출 테스트
curl http://localhost:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "nous-hermes",
"messages": [
{"role": "user", "content": "현재 날씨 조회가 필요하면 JSON 형식으로 도구 호출을 응답해줘."}
]
}'| 단계 | 실행 명령 | 확인 방법 |
|---|---|---|
| Ollama 기동 확인 | ollama list |
다운로드된 모델 목록 출력 |
| API 동작 확인 | curl http://localhost:11434/v1/models |
모델 JSON 응답 |
| 모델 직접 대화 | ollama run nous-hermes |
터미널 대화 인터페이스 진입 |
예시 2: 기존 OpenAI 코드를 로컬로 전환
이미 OpenAI SDK로 작성된 코드가 있다면 가장 먼저 적용해볼 수 있는 패턴입니다.
실무에서 가장 많이 쓰이는 패턴입니다. 코드 전체를 고칠 필요 없이 단 두 줄만 바꾸면 됩니다.
from openai import OpenAI
# 변경 전
client = OpenAI(api_key="sk-...")
# 변경 후 — 이게 전부입니다
client = OpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama", # 로컬이라 실제 키 불필요, 빈 문자열 아닌 임의 문자열 필요
)
response = client.chat.completions.create(
model="nous-hermes",
messages=[
{"role": "system", "content": "당신은 친절한 코드 리뷰어입니다."},
{"role": "user", "content": "이 함수에서 개선할 점을 알려주세요."}
]
)
print(response.choices[0].message.content)api_key 주의: Ollama 로컬 환경에서는 인증이 필요 없지만, OpenAI SDK는
api_key가 빈 문자열이면 예외를 발생시킵니다."ollama"처럼 임의의 문자열을 넣어주면 됩니다. 저도 처음에 이걸 몰라서AuthenticationError가 왜 나는지 한참 헤맸습니다.
예시 3: Docker로 팀 환경 구성
혼자 쓰는 게 아니라 팀 전체가 공유할 수 있는 내부 AI 채팅 환경이 필요할 때 적합한 패턴입니다.
# docker-compose.yml
services:
ollama:
image: ollama/ollama:latest
ports:
- "11434:11434"
volumes:
- ollama_data:/root/.ollama
# GPU 환경에서만 아래 블록 활성화 (CPU-only 환경에서는 이 섹션 전체 제거)
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
open-webui:
image: ghcr.io/open-webui/open-webui:main
ports:
- "3000:8080"
environment:
- OLLAMA_BASE_URL=http://ollama:11434
depends_on:
- ollama
volumes:
ollama_data:# 실행
docker compose up -d
# 모델 초기 다운로드 (최초 1회)
docker compose exec ollama ollama pull llama3.1:8b
docker compose exec ollama ollama pull nous-hermes
# Open WebUI는 http://localhost:3000 에서 접근 가능CPU-only 환경 주의: MacBook이나 GPU가 없는 서버라면
deploy.resources.reservations.devices블록 전체를 제거하면 됩니다. GPU 없이도 동작하지만 응답 속도가 크게 느려집니다. GPU를 갖추지 못한 팀 서버라면llama3.2:3b처럼 더 가벼운 모델부터 시작하는 것을 권장합니다.
이렇게 구성하면 팀원들이 http://서버IP:3000으로 접속해 ChatGPT처럼 쓸 수 있는 내부 AI 채팅 환경이 만들어집니다. 팀에 이 구성을 처음 올렸을 때 "진짜 ChatGPT랑 뭐가 달라요?"라는 질문이 제일 많았는데, 가장 큰 차이는 데이터가 팀 서버 밖으로 나가지 않는다는 점입니다.
예시 4: LangChain과 연동한 RAG 파이프라인
사내 문서를 AI로 검색하거나 특정 도메인 지식 기반 QA 시스템이 필요할 때 적합한 패턴입니다.
Ollama를 LangChain과 연결해 사내 문서 기반 QA 시스템을 구성하는 것도 자주 쓰이는 패턴입니다.
from langchain_ollama import OllamaLLM, OllamaEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain_community.document_loaders import DirectoryLoader
# 로컬 모델 초기화
llm = OllamaLLM(model="nous-hermes", base_url="http://localhost:11434")
embeddings = OllamaEmbeddings(model="nomic-embed-text")
# 문서 로드 및 벡터 스토어 생성
loader = DirectoryLoader("./docs", glob="**/*.md")
docs = loader.load()
vectorstore = Chroma.from_documents(
documents=docs,
embedding=embeddings,
persist_directory="./chroma_db"
)
# RAG 체인 구성
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vectorstore.as_retriever(search_kwargs={"k": 3})
)
# 사내 문서 기반으로 질의
result = qa_chain.invoke({"query": "배포 프로세스가 어떻게 되나요?"})
print(result["result"])임베딩과 추론이 모두 완전 로컬에서 이루어집니다. 회사 내부 위키나 기술 문서를 이렇게 연결하면 민감한 내용이 외부로 유출될 걱정 없이 AI 검색 시스템을 운영할 수 있습니다.
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| 완전한 프라이버시 | 데이터가 머신 밖으로 전송되지 않음. 로그·텔레메트리 없음 |
| 비용 구조 | 초기 하드웨어 투자 후 운영 비용 $0. 연간 클라우드 대비 최대 수백만 원 절감 가능 |
| 예측 가능한 레이턴시 | 네트워크 의존 없이 일정한 응답 속도 (Apple Silicon M 시리즈 기준 7B 모델 약 50~80 tokens/sec) |
| 오프라인 동작 | 인터넷 연결 없이 완전 동작. IoT·원격 현장 환경에 적합 |
| OpenAI 호환 API | 기존 코드 변경 최소화로 로컬 전환 가능 |
| 함수 호출 품질 | nous-hermes는 도구 호출·JSON 출력에서 동급 크기 일반 모델 대비 안정적 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| 하드웨어 요구사항 | GPU VRAM 8~16GB+ 권장. 에이전트 용도라면 64K 토큰 컨텍스트 이상 모델 필요 | Apple Silicon Mac(통합 메모리)은 비교적 저렴하게 시작 가능 |
| 모델 성능 격차 | GPT-4.5·Claude Opus 같은 클라우드 최신 모델 대비 복잡한 추론 능력이 낮음 | 단순 작업은 로컬, 복잡한 추론만 클라우드로 에스컬레이션하는 하이브리드 전략 |
| 초기 하드웨어 비용 | GPU 서버 또는 고사양 워크스테이션 구매 비용 발생 | 기존 보유 장비(MacBook M 시리즈 등)에서 소규모로 검증 후 확장 |
| 모델 관리 부담 | 업데이트·버전 관리를 직접 수행해야 함 | ollama pull 스크립트를 cron으로 자동화 |
| 컨텍스트 윈도우 제약 | 소규모 모델은 멀티스텝 에이전트 작업에 충분한 컨텍스트 유지가 어려움 | 8B 이상 모델 사용, 또는 RAG로 컨텍스트 길이 문제 보완 |
실무에서 가장 흔한 실수
팀에서 이 스택을 처음 도입할 때 가장 많이 받았던 질문들이기도 합니다.
-
너무 작은 모델로 에이전트를 구성하는 경우 — 3B 모델로 에이전트 파이프라인을 연결하면 도구 호출 파싱이나 멀티스텝 추론에서 자주 실패합니다. 에이전트 용도라면 최소 8B, 가급적
nous-hermes계열 모델을 사용하는 것을 권장합니다. -
api_key를 빈 문자열로 설정하는 경우 — OpenAI SDK는api_key=""이면 예외를 발생시킵니다. 로컬 환경에서는"ollama"같은 임의 문자열을 넣어주면 됩니다. -
첫 모델 로드 시간을 응답 레이턴시로 착각하는 경우 — 모델이 메모리에 올라가기 전 첫 요청은 수십 초가 걸릴 수 있습니다.
ollama run nous-hermes명령으로 미리 모델을 로드해두거나, 서비스 시작 시에 warm-up 요청을 한 번 보내두는 방식으로 해결할 수 있습니다.
마치며
처음 로컬 AI 파이프라인을 구성할 때는 "설정이 이렇게 많은데 진짜 쓸 만할까?" 싶었습니다. 그런데 Ollama에 nous-hermes를 올리고 기존 OpenAI 코드를 base_url 하나만 바꿔서 연결했더니, 첫 번째 완전 로컬 응답을 받는 순간 "이게 되네" 싶은 감각이 왔습니다. 그 이후로는 클라우드 청구서 걱정 없이 마음껏 실험할 수 있게 됐고요.
Ollama + nous-hermes 조합은 프라이버시 보호와 비용 절감이라는 두 가지 문제를 동시에 해결하면서, 기존 OpenAI 코드를 거의 그대로 재사용할 수 있는 현실적인 로컬 AI 인프라 선택지입니다.
지금 바로 시작해볼 수 있는 3단계:
-
Ollama 설치 후 llama3.1:8b 실행해보기 —
curl -fsSL https://ollama.com/install.sh | sh && ollama run llama3.1:8b명령 하나로 시작할 수 있습니다. RAM이 16GB 미만이라면ollama run llama3.2:3b로 먼저 시도해볼 수 있습니다. -
기존 OpenAI 코드의
base_url만 바꿔보기 —OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")로 수정하면 같은 코드로 로컬 모델을 호출할 수 있습니다. 응답 품질과 속도를 직접 체감해보시면 좋습니다. -
nous-hermes로 에이전트 파이프라인 연결해보기 —ollama pull nous-hermes이후 LangChain 에이전트에 연결해 도구 호출 태스크를 맡겨보시면 됩니다. 일반 모델과의 함수 호출 안정성 차이를 바로 느끼실 수 있습니다.
참고 자료
- Ollama OpenAI 호환성 공식 블로그 | ollama.com
- Ollama 공식 라이브러리 — nous-hermes 모델 | ollama.com
- NousResearch/Hermes-Function-Calling | GitHub
- LangChain + Ollama 통합 | LangChain Docs
- Open WebUI | GitHub
- Local LLM Hosting: Complete 2025 Guide | DEV Community
- Local LLMs vs Cloud LLMs 비교 (2026) | freeacademy.ai
- Ollama 고급 통합 — Open WebUI, LiteLLM, LangChain | cohorte.co