Ollama 사용법

Ollama의 CLI 명령어, REST API, 파라미터 설정 등 실전 사용 방법을 상세히 다룹니다.

⚡ 빠른 시작
  1. ollama pull qwen3:8b - 모델 다운로드 (또는 llama3.2, gemma3, deepseek-r1:8b)
  2. ollama run qwen3:8b - 대화형 실행
  3. ollama run deepseek-r1:8b --think - Thinking 모드로 추론 과정 확인
  4. ollama list - 설치된 모델 확인
  5. API로 프로그래밍 방식 접근 (구조화된 출력, 도구 호출 지원)
  6. 파라미터로 출력 품질 조정

CLI 기본 명령어

Ollama CLI는 모델 관리와 실행을 위한 간단하고 직관적인 인터페이스를 제공합니다.

모델 다운로드 (pull)

# 기본 사용법
ollama pull <모델명>

# 예제
ollama pull llama3.2          # 최신 버전 (latest 태그)
ollama pull qwen3:8b          # Qwen 3 8B 모델
ollama pull deepseek-r1:8b    # DeepSeek R1 추론 모델
ollama pull gemma3:12b        # Google Gemma 3
ollama pull llama3.2:7b-instruct-q4_0  # 특정 양자화

# 다운로드 진행 상황
pulling manifest
pulling 8eeb52dfb3bb... 100% ▕████████████████▏ 4.7 GB
pulling 73b313b5552d... 100% ▕████████████████▏  11 KB
pulling 0ba8f0e314b4... 100% ▕████████████████▏  12 KB
pulling 56bb8bd477a5... 100% ▕████████████████▏  96 B
pulling 1a4c3c319823... 100% ▕████████████████▏ 487 B
verifying sha256 digest
writing manifest
success

모델 실행 (run)

run 명령어는 모델을 실행하고 대화형 세션을 시작합니다.

# 대화형 모드
ollama run llama3.2

# 출력 예시
>>> 안녕하세요?
안녕하세요! 무엇을 도와드릴까요?

>>> 파이썬으로 피보나치 수열 함수를 작성해줘
물론입니다. 재귀와 메모이제이션을 사용한 효율적인 구현입니다:

def fibonacci(n, memo={}):
    if n in memo:
        return memo[n]
    if n <= 1:
        return n
    memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo)
    return memo[n]

>>> /bye
# 대화 종료

단일 프롬프트 실행

대화형 모드 없이 즉시 응답을 받고 종료합니다.

# 인라인 프롬프트
ollama run llama3.2 "Explain quantum computing in one sentence"

# 파일에서 프롬프트 읽기
ollama run llama3.2 < prompt.txt

# 출력을 파일로 저장
ollama run llama3.2 "Write a haiku about coding" > haiku.txt

# 파이프라인에서 사용
cat document.txt | ollama run llama3.2 "Summarize this text"

설치된 모델 확인 (list)

# 모든 로컬 모델 나열
ollama list

# 출력 예시
NAME                          ID              SIZE      MODIFIED
qwen3:8b                      f2170b1ea08a    4.9 GB    2 minutes ago
deepseek-r1:8b                28f8fd6cdc67    4.9 GB    1 hour ago
gemma3:12b                    6fd036cdfb18    8.1 GB    3 hours ago
llama3.2:latest               a80c4f17acd5    4.7 GB    2 days ago
mistral:7b-instruct           2ae6f6dd7a3d    4.1 GB    1 week ago

모델 정보 확인 (show)

# 모델 상세 정보
ollama show llama3.2

# 출력 예시
  Model
    architecture        llama
    parameters          7.2B
    context length      131072
    embedding length    4096
    quantization        Q4_0

  Parameters
    stop    "<|start_header_id|>"
    stop    "<|end_header_id|>"
    stop    "<|eot_id|>"

  License
    LLAMA 3.2 COMMUNITY LICENSE AGREEMENT

  System
    You are a helpful assistant.

# Modelfile 출력
ollama show --modelfile llama3.2

FROM /path/to/model/weights
TEMPLATE """{{ .System }}
{{ .Prompt }}"""
PARAMETER stop "<|start_header_id|>"
SYSTEM "You are a helpful assistant."

모델 삭제 (rm)

# 모델 제거
ollama rm llama3.2:7b-instruct-q4_0

# 여러 모델 한 번에 제거
ollama rm model1 model2 model3

# 확인 메시지
deleted 'llama3.2:7b-instruct-q4_0'

실행 중인 모델 확인 (ps)

# 현재 실행 중인 모델
ollama ps

# 출력 예시
NAME              ID              SIZE      PROCESSOR    UNTIL
llama3.2:latest   a80c4f17acd5    7.4 GB    100% GPU     4 minutes from now

# 설명
# - SIZE: 메모리에 로드된 크기
# - PROCESSOR: GPU 또는 CPU 사용률
# - UNTIL: 언로드 예정 시간 (idle timeout)

모델 복사 (cp)

# 모델을 새 이름으로 복사
ollama cp llama3.2:latest my-custom-llama

# 사용 사례: 커스텀 버전 관리
ollama cp llama3.2 llama3.2-backup
# 이후 llama3.2를 커스터마이징하고 원본은 백업으로 유지

커스텀 모델 생성 (create)

# Modelfile을 사용해 새 모델 생성
ollama create my-model -f Modelfile

# Modelfile 예시
FROM llama3.2:7b

# 시스템 프롬프트 커스터마이징
SYSTEM """당신은 한국어 전문 AI 어시스턴트입니다.
항상 정중하고 상세하게 답변합니다."""

# 파라미터 조정
PARAMETER temperature 0.8
PARAMETER top_p 0.9

서버 모드 (serve)

# Ollama API 서버 시작 (보통 자동 시작됨)
ollama serve

# 기본 포트: 11434
# 환경 변수로 포트 변경
OLLAMA_HOST=0.0.0.0:8080 ollama serve

# 로그 확인
time=2024-01-15T10:30:45.123+09:00 level=INFO source=server.go:123 msg="Listening on 127.0.0.1:11434"
💡 CLI 팁
  • 대화 중 /bye 입력으로 종료
  • /set parameter value로 실행 중 파라미터 변경
  • /show로 현재 설정 확인
  • /load <filepath>로 파일 내용을 컨텍스트에 추가
  • Ctrl+D로 대화 종료

일반적인 CLI 워크플로우

1. ollama pull 모델 다운로드 2. ollama list 설치 확인 3. ollama run 실행 4. 대화/작업 프롬프트 입력 만족스럽지 않으면 다른 모델 시도 ollama pull 5. 최적화 파라미터 조정 6. 통합 API로 앱 연동 ollama rm 불필요 모델 삭제

Ollama CLI 워크플로우: 다운로드부터 API 연동까지의 기본 흐름

REST API 사용법

Ollama는 HTTP REST API를 제공하여 프로그래밍 방식으로 모델과 상호작용할 수 있습니다.

주요 API 엔드포인트

엔드포인트 메서드 설명
/api/generate POST 텍스트 생성 (단일 프롬프트)
/api/chat POST 채팅 대화 (멀티턴)
/api/embed POST 텍스트 임베딩 생성
/api/tags GET 로컬 모델 목록
/api/show POST 모델 정보 조회
/api/pull POST 모델 다운로드
/api/push POST 모델 업로드
/api/delete DELETE 모델 삭제

텍스트 생성 API (/api/generate)

기본 사용

# curl 사용
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Why is the sky blue?"
}'

# 응답 (스트리밍)
{"model":"llama3.2","created_at":"2024-01-15T10:30:45Z","response":"The","done":false}
{"model":"llama3.2","created_at":"2024-01-15T10:30:45Z","response":" sky","done":false}
{"model":"llama3.2","created_at":"2024-01-15T10:30:45Z","response":" appears","done":false}
...
{"model":"llama3.2","done":true,"total_duration":2500000000,"prompt_eval_count":10}

스트리밍 비활성화

curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Why is the sky blue?",
  "stream": false
}'

# 응답 (전체 텍스트 한 번에)
{
  "model": "llama3.2",
  "created_at": "2024-01-15T10:30:45Z",
  "response": "The sky appears blue because of a phenomenon...",
  "done": true,
  "total_duration": 2500000000,
  "load_duration": 500000000,
  "prompt_eval_count": 10,
  "prompt_eval_duration": 800000000,
  "eval_count": 50,
  "eval_duration": 1200000000
}

채팅 API (/api/chat)

멀티턴 대화를 위한 API입니다. 대화 히스토리를 유지하려면 이전 메시지를 포함해야 합니다.

curl http://localhost:11434/api/chat -d '{
  "model": "llama3.2",
  "messages": [
    {
      "role": "system",
      "content": "You are a helpful assistant specializing in Python."
    },
    {
      "role": "user",
      "content": "How do I read a CSV file in Python?"
    }
  ]
}'

# 두 번째 메시지 (컨텍스트 유지)
curl http://localhost:11434/api/chat -d '{
  "model": "llama3.2",
  "messages": [
    {
      "role": "system",
      "content": "You are a helpful assistant specializing in Python."
    },
    {
      "role": "user",
      "content": "How do I read a CSV file in Python?"
    },
    {
      "role": "assistant",
      "content": "You can use the csv module or pandas..."
    },
    {
      "role": "user",
      "content": "Can you show me a pandas example?"
    }
  ]
}'

Python API 예제

requests 라이브러리 사용

import requests
import json

def generate_text(prompt, model="llama3.2", stream=True):
    url = "http://localhost:11434/api/generate"
    payload = {
        "model": model,
        "prompt": prompt,
        "stream": stream
    }

    response = requests.post(url, json=payload, stream=stream)

    if stream:
        # 스트리밍 응답 처리
        full_response = ""
        for line in response.iter_lines():
            if line:
                data = json.loads(line)
                if not data.get("done"):
                    chunk = data.get("response", "")
                    full_response += chunk
                    print(chunk, end="", flush=True)
        print()  # 줄바꿈
        return full_response
    else:
        # 비스트리밍 응답
        data = response.json()
        return data.get("response", "")

# 사용 예시
result = generate_text("Explain machine learning in simple terms")
print(result)

채팅 기능 구현

class OllamaChat:
    def __init__(self, model="llama3.2", system_prompt=None):
        self.model = model
        self.messages = []
        self.url = "http://localhost:11434/api/chat"

        if system_prompt:
            self.messages.append({
                "role": "system",
                "content": system_prompt
            })

    def send(self, user_message):
        # 사용자 메시지 추가
        self.messages.append({
            "role": "user",
            "content": user_message
        })

        # API 호출
        payload = {
            "model": self.model,
            "messages": self.messages,
            "stream": False
        }

        response = requests.post(self.url, json=payload)
        data = response.json()

        # 어시스턴트 응답 저장
        assistant_message = data["message"]["content"]
        self.messages.append({
            "role": "assistant",
            "content": assistant_message
        })

        return assistant_message

    def reset(self):
        # 대화 히스토리 초기화
        system_msg = [m for m in self.messages if m["role"] == "system"]
        self.messages = system_msg

# 사용 예시
chat = OllamaChat(
    model="llama3.2",
    system_prompt="You are a helpful coding assistant."
)

print(chat.send("How do I sort a list in Python?"))
print(chat.send("What about in reverse order?"))
print(chat.send("Can I sort by a custom key?"))

JavaScript/Node.js API 예제

// fetch API 사용
async function generateText(prompt, model = 'llama3.2') {
  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model,
      prompt,
      stream: false
    })
  });

  const data = await response.json();
  return data.response;
}

// 스트리밍 처리
async function streamText(prompt, model = 'llama3.2') {
  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ model, prompt, stream: true })
  });

  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    const text = decoder.decode(value);
    const lines = text.split('\n').filter(line => line.trim());

    for (const line of lines) {
      const data = JSON.parse(line);
      if (!data.done) {
        process.stdout.write(data.response);
      }
    }
  }
  console.log();
}

// 사용
await streamText('Write a haiku about programming');

임베딩 API

# 임베딩 생성
curl http://localhost:11434/api/embed -d '{
  "model": "nomic-embed-text",
  "input": "The quick brown fox jumps over the lazy dog"
}'

# 응답
{
  "embeddings": [[0.123, -0.456, 0.789, ...]]  // 768차원
}

# Python 예제
def get_embedding(text, model="nomic-embed-text"):
    response = requests.post(
        "http://localhost:11434/api/embed",
        json={"model": model, "input": text}
    )
    return response.json()["embeddings"][0]

# 코사인 유사도 계산
from numpy import dot
from numpy.linalg import norm

def cosine_similarity(a, b):
    return dot(a, b) / (norm(a) * norm(b))

emb1 = get_embedding("I love programming")
emb2 = get_embedding("I enjoy coding")
emb3 = get_embedding("The weather is nice")

print(cosine_similarity(emb1, emb2))  # 높은 유사도
print(cosine_similarity(emb1, emb3))  # 낮은 유사도

파라미터 설정

Ollama는 API 요청의 options 필드나 Modelfile의 PARAMETER 명령으로 모델의 출력 성향, 응답 길이, 반복 억제, 컨텍스트 길이, 재현성, 성능을 조정할 수 있습니다. 같은 모델이라도 파라미터가 달라지면 코딩용, 채팅용, 요약용, JSON 출력용처럼 전혀 다른 동작을 보입니다.

파라미터를 적용하는 두 가지 위치
  • 요청 단위: /api/generate, /api/chatoptions에 넣습니다. 호출마다 값을 바꿀 수 있어 실험과 서비스 라우팅에 적합합니다.
  • 모델 단위: Modelfile에 PARAMETER temperature 0.2처럼 기록하고 ollama create로 새 모델을 만듭니다. 팀 표준 모델, 역할 고정 모델, 사내 챗봇에 적합합니다.
# API 요청 단위 설정
curl http://localhost:11434/api/chat -d '{
  "model": "qwen3:8b",
  "messages": [{"role": "user", "content": "이 함수의 버그를 찾아줘"}],
  "options": {
    "temperature": 0.2,
    "top_p": 0.9,
    "num_ctx": 8192,
    "num_predict": 1024
  }
}'

# Modelfile 모델 단위 설정
FROM qwen3:8b
PARAMETER temperature 0.2
PARAMETER top_p 0.9
PARAMETER num_ctx 8192
PARAMETER num_predict 1024
PARAMETER repeat_penalty 1.08
SYSTEM """당신은 정확하고 간결한 코드 리뷰어입니다."""

주요 파라미터

아래 표는 공식 Modelfile에서 사용할 수 있는 핵심 PARAMETER와 실무에서 함께 조정하는 주요 옵션을 정리한 것입니다. 기본값은 Ollama와 모델 버전에 따라 달라질 수 있으므로, 실제 모델은 ollama show --modelfile <모델명>ollama ps로 확인하세요.

파라미터 기본값 권장 범위 역할 조정 기준
temperature 0.8 0.0 - 1.2 토큰 선택의 무작위성 낮추면 일관성, 높이면 다양성 증가
top_p 0.9 0.5 - 0.98 누적 확률 기반 후보 제한 낮추면 보수적, 높이면 표현 다양성 증가
top_k 40 10 - 100 확률 상위 k개 토큰만 고려 낮추면 안정적, 높이면 선택 폭 증가
min_p 0.0 0.0 - 0.2 최고 확률 토큰 대비 최소 확률 필터 품질을 유지하면서 다양성을 확보할 때 사용
num_ctx 환경별 차이 4096 - 65536+ 입력과 대화 이력을 담는 컨텍스트 크기 길수록 메모리와 지연 시간 증가
num_predict -1 128 - 4096 최대 출력 토큰 수 짧은 답변은 낮게, 긴 분석은 높게
repeat_penalty 1.1 1.0 - 1.25 반복 토큰 벌점 반복이 많으면 올리고, 문장이 어색하면 낮춤
repeat_last_n 64 64 - 2048 또는 -1 반복 검사 범위 긴 답변에서 반복이 누적되면 증가
seed 0 고정 정수 난수 시드 테스트, 평가, 비교 실험에서 고정
stop [] 문자열 배열 생성 중단 문자열 JSON, 코드 블록, 템플릿 종료 지점 제어
draft_num_predict 모델별 차이 0 - 16 Speculative decoding 초안 토큰 수 초안 모델이나 MTP 지원 모델에서 지연 시간 최적화
num_keep 모델별 차이 0+ 컨텍스트 축약 시 보존할 앞부분 토큰 시스템 프롬프트와 초기 지시를 오래 유지할 때 사용
num_thread 자동 CPU 코어 수 기준 CPU 추론 스레드 수 CPU 사용률과 지연 시간을 보고 조정
num_batch 자동 128 - 2048+ 프롬프트 처리 배치 크기 긴 프롬프트 prefill 속도와 메모리 사용량 균형
num_gpu 자동 0+ GPU에 올릴 레이어 수 VRAM 부족 시 낮추고, 속도 우선이면 높임
main_gpu 0 GPU 인덱스 주 GPU 선택 멀티 GPU 환경에서 주 처리 GPU 지정
use_mmap true true/false 모델 파일 메모리 매핑 일반적으로 기본값 유지
use_mlock false true/false 모델 메모리 스왑 방지 메모리가 충분하고 지연 시간 안정성이 중요할 때 사용
numa false true/false NUMA 최적화 멀티 소켓 서버에서만 검토
호환성 주의

temperature, top_p, top_k, min_p, num_ctx, num_predict, repeat_penalty, repeat_last_n, seed, stop, draft_num_predict는 공식 Modelfile 기준 핵심 파라미터입니다. num_thread, num_batch, num_gpu, main_gpu, use_mmap, use_mlock, numa 등 런타임/성능 옵션은 Ollama 버전, 백엔드, 운영체제, GPU 구성에 따라 지원 여부와 효과가 달라질 수 있습니다.

Temperature (온도)

temperature는 모델이 다음 토큰을 고를 때 확률 분포를 얼마나 평평하게 만들지 결정합니다. 낮은 값은 가장 그럴듯한 토큰에 집중하고, 높은 값은 낮은 확률 후보도 선택하게 만듭니다.

출력 성향 추천 용도
0.0 - 0.2 매우 보수적, 반복 가능성 높음 코드 수정, 테스트 생성, JSON, SQL, 번역 검수
0.3 - 0.5 정확성과 자연스러움의 균형 요약, 문서 작성, RAG 답변, 코드 설명
0.6 - 0.9 자연스러운 대화와 다양한 표현 일반 채팅, 튜터링, 아이디어 정리
1.0 - 1.2 창의적이지만 오류 가능성 증가 브레인스토밍, 카피라이팅, 스토리 초안
# 낮은 temperature (0.1-0.3): 결정론적, 일관적
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Complete the phrase: To be or not to be",
  "options": {
    "temperature": 0.1
  }
}'
# 출력: "that is the question" (매우 일관적)

# 높은 temperature (1.5-2.0): 창의적, 다양함
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Complete the phrase: To be or not to be",
  "options": {
    "temperature": 1.8
  }
}'
# 출력: "a butterfly in the moonlight" (창의적이지만 예측 불가)
0.0 0.8 (기본) 2.0 결정론적 • 코드 생성 • 정확한 답변 • 번역 균형 • 일반 대화 • 질의응답 창의적 • 브레인스토밍 • 스토리 생성 • 시/음악

Temperature 값에 따른 출력 특성 변화

Top-p와 Top-k

top_p, top_k, min_p는 후보 토큰의 범위를 제한합니다. temperature가 확률 분포의 모양을 바꾼다면, 이 값들은 실제 후보 목록을 자르는 필터에 가깝습니다.

파라미터 동작 낮은 값 높은 값 실무 추천
top_p 누적 확률이 p에 도달할 때까지 후보 유지 짧고 보수적 풍부하고 다양함 정확성 0.8-0.9, 일반 대화 0.9, 창작 0.95
top_k 확률 상위 k개 후보만 유지 예측 가능 표현 폭 증가 코딩 20-40, 채팅 40, 창작 50-100
min_p 최고 확률 토큰 대비 너무 낮은 후보 제거 거의 영향 없음 낮은 품질 후보 제거 강화 0.03-0.08부터 실험, 불안정하면 0.0
# Top-p (nucleus sampling)
# 누적 확률이 p에 도달할 때까지의 토큰만 고려
{
  "options": {
    "top_p": 0.9  // 상위 90% 확률 토큰만
  }
}

# Top-k
# 확률 상위 k개 토큰만 고려
{
  "options": {
    "top_k": 40  // 상위 40개 토큰만
  }
}

# 조합 사용 (권장)
{
  "options": {
    "temperature": 0.7,
    "top_p": 0.9,
    "top_k": 40,
    "min_p": 0.05
  }
}

컨텍스트 길이 (num_ctx)

num_ctx는 모델이 한 번에 참고할 수 있는 토큰 수입니다. 입력 프롬프트, 시스템 메시지, 대화 이력, 검색 결과, 출력 중 생성된 토큰이 모두 이 예산을 공유합니다. 긴 컨텍스트는 에이전트와 코드베이스 분석에 유용하지만, VRAM 사용량과 첫 토큰 지연 시간이 증가합니다.

추천 상황 주의점
4096 짧은 채팅, 단일 함수 설명, 간단한 번역 긴 파일이나 긴 대화에는 부족
8192 - 16384 일반 코딩, 문서 요약, RAG 답변 대부분의 로컬 개발 환경에서 현실적인 시작점
32768 - 65536 여러 파일 코드 리뷰, 에이전트, 긴 검색 결과 VRAM과 속도 확인 필요
65536+ 대형 코드베이스, 장문 문서 묶음, 고급 에이전트 충분한 VRAM과 모델의 장문 성능이 필요
# 긴 문서 처리
{
  "model": "llama3.2",
  "prompt": "Summarize this long document: ...",
  "options": {
    "num_ctx": 8192  // 기본 2048보다 큼
  }
}

# 주의: 더 큰 컨텍스트는 더 많은 메모리와 시간 필요
# Llama 3.2는 최대 128K 토큰 지원

출력 길이, 중단, 반복 제어

num_predict, stop, repeat_penalty, repeat_last_n, num_keep는 생성 결과의 길이와 형태를 제어합니다. 서비스에서는 비용과 지연 시간을 줄이기 위해 num_predict를 무제한으로 두지 않는 것이 좋습니다.

파라미터 상세 설명 추천값
num_predict 최대 생성 토큰 수입니다. 너무 낮으면 답변이 잘리고, 너무 높으면 지연 시간과 반복 가능성이 증가합니다. 짧은 QA 256, 채팅 512-1024, 코드/분석 1024-4096
stop 특정 문자열이 나오면 생성을 멈춥니다. 여러 개를 지정할 수 있으며 템플릿 토큰, 코드 블록 종료, JSON 이후 불필요한 설명 차단에 유용합니다. 모델 템플릿 토큰, ```, </json> 등 작업별 지정
repeat_penalty 최근 생성된 토큰이 다시 나올 확률을 낮춥니다. 높이면 반복은 줄지만 문장이 부자연스러워질 수 있습니다. 일반 1.05-1.12, 창작 1.1-1.2, 코드 1.0-1.08
repeat_last_n 반복 벌점을 적용할 과거 토큰 범위입니다. -1은 전체 컨텍스트 기준, 0은 비활성화 의미로 쓰입니다. 짧은 답변 64, 긴 글 256-1024, 반복 심하면 -1 실험
num_keep 컨텍스트가 넘쳐 잘릴 때 앞부분에서 보존할 토큰 수입니다. 시스템 지시와 역할 정의를 유지하는 데 유용합니다. 시스템 프롬프트 길이에 맞춰 128-1024
# JSON만 받고 멈추는 예시
{
  "format": "json",
  "options": {
    "temperature": 0.1,
    "num_predict": 512,
    "repeat_penalty": 1.05,
    "stop": ["\n\n설명:", "</json>"]
  }
}

시드 (재현성)

seed는 샘플링 난수의 시작점을 고정합니다. 같은 모델, 같은 프롬프트, 같은 파라미터, 같은 실행 환경이면 결과가 더 잘 재현됩니다. 다만 GPU 커널, 모델 버전, 병렬 처리, 컨텍스트 차이 때문에 완전한 바이트 단위 동일성을 항상 보장하지는 않습니다.

# 같은 시드 = 같은 출력
{
  "model": "llama3.2",
  "prompt": "Generate a random story",
  "options": {
    "seed": 42,
    "temperature": 0.8
  }
}

# 테스트, 디버깅, 벤치마크에 유용

Mirostat 샘플링

mirostat 계열은 긴 생성에서 놀라움 정도를 목표값 근처로 유지하려는 샘플링 방식입니다. Ollama 버전과 모델에 따라 API 옵션으로 사용할 수 있으며, 공식 Modelfile 표에는 없는 경우도 있으므로 적용 전 실제 동작을 확인하세요.

파라미터 설명 추천값
mirostat 0은 비활성화, 1 또는 2는 Mirostat 활성화입니다. 긴 창작문이나 긴 대화에서 반복과 산만함을 줄이는 데 실험할 수 있습니다. 기본 0, 긴 창작 2 실험
mirostat_tau 목표 perplexity에 해당하는 값입니다. 높을수록 더 다양한 출력을 허용합니다. 일반 5.0, 보수적 3.0-4.0, 창작 6.0-8.0
mirostat_eta 목표값으로 보정하는 학습률입니다. 너무 높으면 출력 성향이 출렁일 수 있습니다. 0.05-0.2
# 긴 창작문에서 Mirostat 실험
{
  "options": {
    "mirostat": 2,
    "mirostat_tau": 6.0,
    "mirostat_eta": 0.1,
    "temperature": 0.8
  }
}

성능 관련 파라미터

성능 파라미터는 출력 품질보다 처리량, 지연 시간, 메모리 사용량에 영향을 줍니다. 일반 사용자는 기본 자동 설정으로 시작하고, ollama ps, GPU 사용량, 응답 지연 시간을 보며 조정하는 편이 안전합니다.

파라미터 효과 추천 운영 방식
num_thread CPU 추론 스레드 수를 정합니다. 물리 코어 수 근처에서 시작하고, 동시 요청이 많으면 낮춰 전체 처리량을 봅니다.
num_batch 프롬프트를 한 번에 처리하는 배치 크기입니다. 긴 입력 prefill이 느리면 올려 보되, 메모리 부족이 나면 낮춥니다.
num_gpu GPU에 올릴 레이어 수입니다. 속도 우선이면 최대, VRAM 부족이면 낮춤 또는 작은 양자화 모델 사용.
main_gpu 여러 GPU 중 주 GPU를 지정합니다. 멀티 GPU 서버에서만 명시적으로 설정합니다.
use_mlock 모델 메모리가 스왑으로 밀려나는 것을 줄입니다. RAM이 충분한 전용 서버에서 지연 시간 안정화 목적으로 사용합니다.
use_mmap 모델 파일을 메모리 매핑으로 읽습니다. 대부분 기본값 유지. 파일 시스템이나 컨테이너 환경 문제가 있을 때만 변경합니다.
numa NUMA 메모리 배치를 고려합니다. 멀티 소켓 CPU 서버에서 벤치마크 후 사용합니다.
draft_num_predict Speculative decoding에서 초안 토큰 수를 정합니다. 지원 모델에서 4부터 시작, 품질 문제나 지연 증가가 있으면 0으로 비활성화.

사용 사례별 파라미터 프리셋

아래 값은 “바로 시작하기 좋은 기준점”입니다. 모델 크기, 양자화 수준, 언어, 프롬프트 품질에 따라 달라지므로 운영 전에는 대표 프롬프트 20-50개로 비교하세요.

사용 목적 temperature top_p top_k num_ctx num_predict 추가 권장값
코딩/버그 수정 0.1 - 0.25 0.85 - 0.95 20 - 40 8192 - 32768 1024 - 4096 repeat_penalty 1.03-1.08, 필요 시 seed 고정
코드 리뷰 0.2 - 0.4 0.9 30 - 40 16384 - 65536 1024 - 2048 결과 형식을 체크리스트로 고정, num_keep로 규칙 보존
일반 채팅 0.6 - 0.8 0.9 40 4096 - 8192 512 - 1024 repeat_penalty 1.08-1.12
정확한 QA 0.0 - 0.2 0.8 - 0.9 20 - 30 4096 - 16384 256 - 1024 모르면 모른다고 답하도록 시스템 프롬프트 지정
RAG/문서 기반 답변 0.1 - 0.3 0.85 - 0.9 20 - 40 16384 - 65536 512 - 2048 출처 인용 형식 고정, 검색 문서가 길면 num_ctx 증가
요약 0.2 - 0.4 0.9 30 - 40 8192 - 32768 256 - 1024 요약 길이를 명시하고 num_predict를 낮게 제한
JSON/구조화 출력 0.0 - 0.15 0.8 - 0.9 10 - 30 4096 - 16384 256 - 1024 format: "json", 스키마, stop 사용
번역/문체 변환 0.2 - 0.4 0.9 30 - 40 4096 - 16384 입력 길이에 맞춤 용어집과 금지어를 시스템 프롬프트에 포함
창작/브레인스토밍 0.9 - 1.2 0.95 - 0.98 50 - 100 8192 - 16384 1024 - 4096 repeat_penalty 1.12-1.2, min_p 0.03-0.08
에이전트/도구 호출 0.0 - 0.2 0.8 - 0.9 20 - 40 32768 - 65536+ 512 - 2048 도구 스키마 엄격화, 관찰 로그가 길면 num_ctx 증가
# 1. 코드 생성/버그 수정 (정확성 우선)
CODE_GENERATION = {
    "temperature": 0.2,
    "top_p": 0.9,
    "top_k": 30,
    "num_ctx": 16384,
    "num_predict": 2048,
    "repeat_penalty": 1.05
}

# 2. 코드 리뷰 (누락 지적과 근거 우선)
CODE_REVIEW = {
    "temperature": 0.3,
    "top_p": 0.9,
    "top_k": 40,
    "num_ctx": 32768,
    "num_predict": 1536,
    "repeat_penalty": 1.08
}

# 3. 일반 채팅
CONVERSATIONAL = {
    "temperature": 0.7,
    "top_p": 0.9,
    "top_k": 40,
    "num_ctx": 8192,
    "num_predict": 1024,
    "repeat_penalty": 1.1
}

# 4. 정확한 답변 (QA)
FACTUAL_QA = {
    "temperature": 0.1,
    "top_p": 0.85,
    "top_k": 25,
    "num_ctx": 8192,
    "num_predict": 512,
    "repeat_penalty": 1.05
}

# 5. RAG/문서 기반 답변
RAG_ANSWER = {
    "temperature": 0.2,
    "top_p": 0.9,
    "top_k": 30,
    "num_ctx": 32768,
    "num_predict": 1024,
    "repeat_penalty": 1.05
}

# 6. JSON/구조화 출력
STRUCTURED_JSON = {
    "temperature": 0.0,
    "top_p": 0.8,
    "top_k": 20,
    "num_predict": 512,
    "repeat_penalty": 1.0,
    "seed": 42
}

# 7. 번역/문체 변환
TRANSLATION = {
    "temperature": 0.3,
    "top_p": 0.9,
    "top_k": 30,
    "repeat_penalty": 1.0
}

# 8. 창의적 글쓰기
CREATIVE_WRITING = {
    "temperature": 1.2,
    "top_p": 0.95,
    "top_k": 80,
    "min_p": 0.05,
    "num_predict": 2048,
    "repeat_penalty": 1.15
}

# 9. 에이전트/도구 호출
AGENT_TOOL_USE = {
    "temperature": 0.1,
    "top_p": 0.85,
    "top_k": 30,
    "num_ctx": 65536,
    "num_predict": 1536,
    "repeat_penalty": 1.05
}
파라미터 주의사항
  • temperature=0은 일관성을 높이지만, 모델과 백엔드에 따라 완전 결정론을 보장하지 않을 수 있습니다.
  • temperature, top_p, top_k, min_p를 모두 강하게 제한하면 답변이 짧고 경직될 수 있습니다.
  • num_ctx를 크게 늘리면 VRAM/RAM 사용량과 첫 토큰 지연 시간이 증가합니다. 긴 컨텍스트가 항상 더 좋은 답변을 의미하지는 않습니다.
  • repeat_penalty가 너무 높으면 코드, JSON, 표처럼 반복 구조가 필요한 출력이 깨질 수 있습니다.
  • 코딩과 도구 호출은 낮은 무작위성, 창작과 브레인스토밍은 높은 다양성, RAG와 QA는 낮은 온도와 충분한 컨텍스트가 기본 전략입니다.

스트리밍 응답 처리

스트리밍은 토큰이 생성되는 즉시 받아볼 수 있어 사용자 경험이 향상됩니다.

Python 스트리밍

import requests
import json

def stream_response(prompt, model="llama3.2"):
    url = "http://localhost:11434/api/generate"
    payload = {
        "model": model,
        "prompt": prompt,
        "stream": True
    }

    with requests.post(url, json=payload, stream=True) as response:
        for line in response.iter_lines():
            if line:
                data = json.loads(line)

                # 생성된 텍스트 출력
                if not data.get("done", False):
                    print(data.get("response", ""), end="", flush=True)
                else:
                    # 완료 정보
                    print("\n\n--- Stats ---")
                    print(f"Total duration: {data.get('total_duration', 0) / 1e9:.2f}s")
                    print(f"Tokens generated: {data.get('eval_count', 0)}")
                    print(f"Speed: {data.get('eval_count', 0) / (data.get('eval_duration', 1) / 1e9):.1f} tokens/s")

# 사용
stream_response("Write a short story about a robot")

JavaScript 스트리밍 (브라우저)

async function streamToDOM(prompt, elementId) {
  const element = document.getElementById(elementId);
  element.textContent = '';

  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3.2',
      prompt,
      stream: true
    })
  });

  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    const text = decoder.decode(value);
    const lines = text.split('\n').filter(l => l.trim());

    for (const line of lines) {
      const data = JSON.parse(line);
      if (!data.done) {
        element.textContent += data.response;
        // 자동 스크롤
        element.scrollIntoView({ behavior: 'smooth', block: 'end' });
      }
    }
  }
}

// 사용
streamToDOM('Explain async/await', 'output');

Server-Sent Events (SSE) 패턴

# Express.js 서버 예제
const express = require('express');
const fetch = require('node-fetch');
const app = express();

app.get('/stream', async (req, res) => {
  const prompt = req.query.prompt;

  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  const ollamaRes = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3.2',
      prompt,
      stream: true
    })
  });

  const reader = ollamaRes.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) {
      res.write('data: [DONE]\n\n');
      res.end();
      break;
    }

    const text = decoder.decode(value);
    const lines = text.split('\n').filter(l => l.trim());

    for (const line of lines) {
      res.write(`data: ${line}\n\n`);
    }
  }
});

app.listen(3000);

멀티모달 (이미지) 처리

Ollama는 LLaVA, Bakllava, Llama 3.2 Vision 등 멀티모달 모델을 지원합니다.

CLI에서 이미지 사용

# 이미지 파일과 함께 프롬프트
ollama run llava "What's in this image?" /path/to/image.jpg

# 여러 이미지
ollama run llava "Compare these images" image1.jpg image2.jpg

# 대화형 모드에서
ollama run llava
>>> 이 이미지를 설명해줘 /path/to/photo.png
이 이미지는 아름다운 해질녘 풍경입니다. 산 너머로 노을이 지고 있습니다...

>>> 이 이미지는 어떤 색상이 있어? /path/to/photo.png
이 이미지의 주요 색상은 주황색, 분홍색, 보라색입니다...

API로 이미지 전송

# Base64 인코딩 필요
import base64
import requests

def analyze_image(image_path, prompt):
    # 이미지를 base64로 인코딩
    with open(image_path, "rb") as img_file:
        image_data = base64.b64encode(img_file.read()).decode('utf-8')

    # API 호출
    response = requests.post(
        "http://localhost:11434/api/generate",
        json={
            "model": "llava",
            "prompt": prompt,
            "images": [image_data],
            "stream": False
        }
    )

    return response.json()["response"]

# 사용 예시
result = analyze_image(
    "screenshot.png",
    "What UI elements are visible in this screenshot?"
)
print(result)

비전 모델 활용 사례

# 1. OCR (텍스트 추출)
analyze_image("document.jpg", "Extract all text from this image")

# 2. 이미지 설명
analyze_image("photo.jpg", "이 이미지를 상세히 설명해줘")

# 3. 객체 감지
analyze_image("scene.jpg", "List all objects you can see")

# 4. 다이어그램 분석
analyze_image("flowchart.png", "Explain this flowchart step by step")

# 5. 코드 스크린샷
analyze_image("code.png", "What does this code do? Find any bugs.")

# 6. UI/UX 분석
analyze_image("website.png", "Critique this web design")

# 7. 차트/그래프 해석
analyze_image("chart.png", "Summarize the trends in this chart")
💡 비전 모델 팁
  • 고해상도 이미지는 자동으로 리사이즈됨
  • 복잡한 이미지는 더 큰 모델(13B+) 사용 권장
  • 명확하고 구체적인 프롬프트 사용
  • OCR은 인쇄된 텍스트에서 가장 잘 작동
  • 여러 각도/버전의 이미지로 테스트

멀티턴 대화 구현

대화 히스토리를 유지하면서 연속적인 대화를 구현하는 방법입니다.

대화 관리 클래스

import requests
from typing import List, Dict

class Conversation:
    def __init__(
        self,
        model: str = "llama3.2",
        system_prompt: str = None,
        api_url: str = "http://localhost:11434/api/chat"
    ):
        self.model = model
        self.api_url = api_url
        self.messages: List[Dict] = []

        if system_prompt:
            self.messages.append({
                "role": "system",
                "content": system_prompt
            })

    def send(self, message: str, stream: bool = False) -> str:
        """메시지 전송 및 응답 받기"""
        self.messages.append({
            "role": "user",
            "content": message
        })

        response = requests.post(
            self.api_url,
            json={
                "model": self.model,
                "messages": self.messages,
                "stream": stream
            },
            stream=stream
        )

        if stream:
            return self._handle_stream(response)
        else:
            data = response.json()
            assistant_msg = data["message"]["content"]
            self.messages.append({
                "role": "assistant",
                "content": assistant_msg
            })
            return assistant_msg

    def _handle_stream(self, response):
        """스트리밍 응답 처리"""
        full_response = ""
        for line in response.iter_lines():
            if line:
                import json
                data = json.loads(line)
                if not data.get("done"):
                    chunk = data.get("message", {}).get("content", "")
                    full_response += chunk
                    print(chunk, end="", flush=True)
        print()
        self.messages.append({
            "role": "assistant",
            "content": full_response
        })
        return full_response

    def get_history(self) -> List[Dict]:
        """대화 히스토리 반환"""
        return self.messages.copy()

    def clear(self):
        """대화 초기화 (시스템 메시지 유지)"""
        system_msgs = [m for m in self.messages if m["role"] == "system"]
        self.messages = system_msgs

    def save(self, filepath: str):
        """대화 저장"""
        import json
        with open(filepath, "w") as f:
            json.dump({
                "model": self.model,
                "messages": self.messages
            }, f, indent=2)

    @classmethod
    def load(cls, filepath: str):
        """저장된 대화 불러오기"""
        import json
        with open(filepath) as f:
            data = json.load(f)
        conv = cls(model=data["model"])
        conv.messages = data["messages"]
        return conv

# 사용 예시
conv = Conversation(
    model="llama3.2",
    system_prompt="You are a helpful Python programming tutor."
)

print(conv.send("How do I create a class in Python?"))
print(conv.send("Can you show me an example?"))
print(conv.send("What about inheritance?"))

# 대화 저장
conv.save("chat_history.json")

# 나중에 불러오기
conv2 = Conversation.load("chat_history.json")
print(conv2.send("Can you explain polymorphism?"))

간단한 REPL 구현

def chat_repl(model="llama3.2"):
    """간단한 대화형 인터페이스"""
    conv = Conversation(model)

    print(f"Chatting with {model}. Type 'exit' to quit, 'clear' to reset.")
    print("=" * 60)

    while True:
        try:
            user_input = input("\n👤 You: ").strip()

            if not user_input:
                continue

            if user_input.lower() == "exit":
                print("Goodbye!")
                break

            if user_input.lower() == "clear":
                conv.clear()
                print("✓ Conversation cleared")
                continue

            print("\n🤖 Assistant: ", end="")
            conv.send(user_input, stream=True)

        except KeyboardInterrupt:
            print("\n\nInterrupted. Goodbye!")
            break
        except Exception as e:
            print(f"\n❌ Error: {e}")

if __name__ == "__main__":
    chat_repl()

고급 CLI 기능

모델 언로드 제어 (keep_alive)

# 기본적으로 5분 후 자동 언로드
# 유지 시간 변경
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Hello",
  "keep_alive": "10m"
}'

# 영구 유지 (서버 재시작 전까지)
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Hello",
  "keep_alive": -1
}'

# 즉시 언로드
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Hello",
  "keep_alive": 0
}'

출력 형식 지정 (format)

# JSON 형식 강제
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "List 3 programming languages with their year of creation",
  "format": "json"
}'

# 출력 예시:
{
  "languages": [
    {"name": "Python", "year": 1991},
    {"name": "JavaScript", "year": 1995},
    {"name": "Rust", "year": 2010}
  ]
}

Raw 모드

# 템플릿 처리 없이 직접 모델에 전달
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "<|start_header_id|>user<|end_header_id|>\n\nHello<|eot_id|>",
  "raw": true
}'
💡 고급 기능 활용
  • keep_alive: 빈번한 요청 시 메모리에 유지하여 속도 향상
  • format: "json": 구조화된 데이터 추출 시 유용
  • raw: true: 특수한 프롬프트 형식 테스트 시 사용

모범 사례

에러 처리

import requests
from requests.exceptions import RequestException, Timeout

def safe_generate(prompt, model="llama3.2", max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.post(
                "http://localhost:11434/api/generate",
                json={"model": model, "prompt": prompt, "stream": False},
                timeout=60  # 60초 타임아웃
            )
            response.raise_for_status()
            return response.json()["response"]

        except Timeout:
            print(f"Timeout on attempt {attempt + 1}")
            if attempt == max_retries - 1:
                raise

        except RequestException as e:
            print(f"Error: {e}")
            if attempt == max_retries - 1:
                raise

        except KeyError:
            print("Invalid response format")
            raise

성능 최적화

  • 배치 처리: 여러 요청을 병렬로 처리
  • 캐싱: 동일 프롬프트 결과 캐시
  • 연결 재사용: requests.Session() 사용
  • 적절한 타임아웃: 긴 응답 예상 시 타임아웃 증가
from concurrent.futures import ThreadPoolExecutor
import requests

# 연결 재사용
session = requests.Session()

def generate_parallel(prompts, model="llama3.2"):
    def _generate(prompt):
        response = session.post(
            "http://localhost:11434/api/generate",
            json={"model": model, "prompt": prompt, "stream": False}
        )
        return response.json()["response"]

    with ThreadPoolExecutor(max_workers=4) as executor:
        results = list(executor.map(_generate, prompts))

    return results

# 사용
prompts = [
    "Summarize quantum computing",
    "Explain blockchain",
    "What is AI?"
]
results = generate_parallel(prompts)

Thinking 모드 (--think)

Ollama는 추론(reasoning) 모델에서 Thinking 모드를 지원합니다. 모델의 내부 사고 과정과 최종 답변을 분리하여 확인할 수 있습니다.

CLI에서 Thinking 모드

# Thinking 모드 활성화
ollama run deepseek-r1:8b --think

# 대화 예시
>>> 9.11과 9.8 중 어느 것이 더 큰가?

<think>
사용자가 9.11과 9.8의 크기를 비교하고 있습니다.
소수점 이하를 비교하면:
9.11의 소수 부분은 0.11
9.8의 소수 부분은 0.80
0.80 > 0.11이므로 9.8이 더 큽니다.
</think>

9.8이 9.11보다 더 큽니다.

# Thinking 모드 비활성화
ollama run deepseek-r1:8b --think=false

API에서 Thinking 모드

# think 필드로 추론 과정 확인
curl http://localhost:11434/api/chat -d '{
  "model": "deepseek-r1:8b",
  "messages": [
    {"role": "user", "content": "How many Rs are in strawberry?"}
  ],
  "think": true,
  "stream": false
}'

# 응답에 thinking 필드가 포함됨
{
  "message": {
    "role": "assistant",
    "content": "There are 3 Rs in 'strawberry'.",
    "thinking": "Let me count the letters... s-t-r-a-w-b-e-r-r-y. R appears at positions 3, 8, 9."
  }
}
Thinking 모드 지원 모델
  • DeepSeek R1 - deepseek-r1:8b, deepseek-r1:14b, deepseek-r1:32b
  • Qwen 3 - qwen3:8b, qwen3:32b 등 (기본 Thinking 모드 활성화)
  • Gemma 4 - gemma4:27b

구조화된 출력 (Structured Output)

Ollama는 JSON Schema를 사용하여 모델의 출력 형식을 정확하게 제어할 수 있습니다. 기존의 "format": "json"보다 훨씬 세밀한 스키마 정의가 가능합니다.

기본 사용법

# JSON Schema로 출력 형식 제어
curl http://localhost:11434/api/generate -d '{
  "model": "qwen3:8b",
  "prompt": "List 3 programming languages",
  "format": {
    "type": "object",
    "properties": {
      "languages": {
        "type": "array",
        "items": {"type": "string"}
      }
    }
  }
}'

# 응답 예시
{
  "languages": ["Python", "JavaScript", "Rust"]
}

복잡한 스키마 예제

# 상세 정보가 포함된 구조화된 출력
curl http://localhost:11434/api/chat -d '{
  "model": "qwen3:8b",
  "messages": [
    {"role": "user", "content": "서울의 날씨와 관광 정보를 알려줘"}
  ],
  "format": {
    "type": "object",
    "properties": {
      "city": {"type": "string"},
      "weather": {
        "type": "object",
        "properties": {
          "temperature": {"type": "number"},
          "condition": {"type": "string"}
        }
      },
      "attractions": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "name": {"type": "string"},
            "category": {"type": "string"}
          }
        }
      }
    }
  },
  "stream": false
}'

Python에서 구조화된 출력

import requests
import json

def structured_generate(prompt, schema, model="qwen3:8b"):
    response = requests.post(
        "http://localhost:11434/api/generate",
        json={
            "model": model,
            "prompt": prompt,
            "format": schema,
            "stream": False
        }
    )
    return json.loads(response.json()["response"])

# 스키마 정의
book_schema = {
    "type": "object",
    "properties": {
        "title": {"type": "string"},
        "author": {"type": "string"},
        "year": {"type": "number"},
        "genres": {
            "type": "array",
            "items": {"type": "string"}
        }
    }
}

result = structured_generate(
    "Tell me about the book '1984'",
    book_schema
)
print(result["title"])    # "1984"
print(result["author"])   # "George Orwell"
print(result["genres"])   # ["Dystopian", "Science Fiction"]
구조화된 출력 팁
  • JSON Schema를 format 파라미터에 직접 전달하면 모델이 해당 스키마를 준수하는 JSON을 생성합니다
  • 기존 "format": "json"도 여전히 지원되지만, 스키마를 사용하면 출력 구조를 보장할 수 있습니다
  • 복잡한 스키마일수록 더 큰 모델(8B+)을 사용하는 것이 정확도가 높습니다

도구 호출 (Tool Calling)

Ollama는 모델이 외부 함수(도구)를 호출할 수 있는 기능을 지원합니다. 모델이 직접 계산하거나 외부 데이터를 가져오는 대신, 정의된 도구를 호출하도록 요청할 수 있습니다.

API에서 도구 호출

# 도구 정의와 함께 채팅 요청
curl http://localhost:11434/api/chat -d '{
  "model": "qwen3:8b",
  "messages": [
    {"role": "user", "content": "서울의 현재 날씨는?"}
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "지정된 도시의 현재 날씨를 가져옵니다",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {
              "type": "string",
              "description": "도시 이름"
            },
            "unit": {
              "type": "string",
              "enum": ["celsius", "fahrenheit"],
              "description": "온도 단위"
            }
          },
          "required": ["city"]
        }
      }
    }
  ],
  "stream": false
}'

# 모델이 도구 호출을 요청하는 응답
{
  "message": {
    "role": "assistant",
    "content": "",
    "tool_calls": [
      {
        "function": {
          "name": "get_weather",
          "arguments": {
            "city": "Seoul",
            "unit": "celsius"
          }
        }
      }
    ]
  }
}

Python에서 도구 호출 처리

import requests
import json

def get_weather(city, unit="celsius"):
    # 실제로는 날씨 API를 호출
    return {"city": city, "temp": 22, "condition": "맑음"}

# 도구 매핑
tools_map = {"get_weather": get_weather}

def chat_with_tools(messages, tools):
    response = requests.post(
        "http://localhost:11434/api/chat",
        json={
            "model": "qwen3:8b",
            "messages": messages,
            "tools": tools,
            "stream": False
        }
    ).json()

    msg = response["message"]

    # 도구 호출이 있는 경우 처리
    if msg.get("tool_calls"):
        messages.append(msg)
        for tool_call in msg["tool_calls"]:
            fn_name = tool_call["function"]["name"]
            fn_args = tool_call["function"]["arguments"]
            result = tools_map[fn_name](**fn_args)
            messages.append({
                "role": "tool",
                "content": json.dumps(result)
            })
        # 도구 결과를 포함하여 다시 요청
        return chat_with_tools(messages, tools)

    return msg["content"]
도구 호출 지원 모델
  • Llama 4 - llama4 시리즈
  • Qwen 3 - qwen3:8b, qwen3:32b
  • Gemma 4 - gemma4:27b
  • Mistral - mistral, mistral-nemo

ollama launch 명령

Ollama v0.15+ (2026년 1월)에 추가된 launch 명령은 코딩 도구를 로컬 또는 클라우드 모델과 바로 연결하는 기능입니다. 환경 변수를 직접 설정할 필요 없이, 한 줄 명령으로 즉시 사용할 수 있습니다.

기본 사용법

# Claude Code를 Ollama 모델과 연결
ollama launch claude-code

# OpenCode를 Ollama 모델과 연결
ollama launch opencode

# Codex를 Ollama 모델과 연결
ollama launch codex

# 특정 모델 지정
ollama launch claude-code --model qwen3:32b

동작 원리

ollama launch는 내부적으로 다음을 자동 처리합니다:

  • 해당 코딩 도구에 필요한 환경 변수 (OLLAMA_HOST, API 키 등)를 자동 설정
  • OpenAI 호환 API 엔드포인트를 코딩 도구에 연결
  • 로컬 모델 또는 클라우드 모델 자동 선택
# 이전 방식 (환경 변수 수동 설정)
export OPENAI_API_BASE=http://localhost:11434/v1
export OPENAI_API_KEY=ollama
claude-code

# 새로운 방식 (한 줄로 해결)
ollama launch claude-code
ollama launch 팁
  • 지원 도구는 지속적으로 추가되고 있습니다 (ollama launch --list로 확인)
  • 클라우드 모델과 함께 사용하려면 먼저 ollama signin이 필요합니다
  • 코딩 도구가 시스템에 설치되어 있어야 합니다

클라우드 모델

Ollama는 로컬 모델 실행 외에도 클라우드 모델을 동일한 인터페이스로 사용할 수 있습니다. 로컬 하드웨어 제약 없이 대형 모델을 활용할 수 있습니다.

계정 연결

# Ollama 계정으로 로그인
ollama signin

# 브라우저가 열리며 인증 진행
# 인증 완료 후 클라우드 모델 사용 가능

클라우드 모델 사용

# 클라우드 모델은 -cloud 접미사로 구분
ollama run qwen3-coder:480b-cloud

# 로컬과 동일한 명령어 사용
ollama run qwen3-coder:480b-cloud "파이썬으로 웹 크롤러를 만들어줘"

# 다른 클라우드 모델 예시
ollama pull deepseek-r1:671b-cloud
ollama run deepseek-r1:671b-cloud --think

API에서 클라우드 모델

# 로컬 모델과 동일한 API 사용
curl http://localhost:11434/api/generate -d '{
  "model": "qwen3-coder:480b-cloud",
  "prompt": "Implement a binary search tree in Python",
  "stream": false
}'
클라우드 모델 주의사항
  • 클라우드 모델 사용 시 데이터가 외부 서버로 전송됩니다
  • 인터넷 연결이 필요하며, 네트워크 지연이 발생할 수 있습니다
  • 사용량에 따라 요금이 발생할 수 있습니다 (계정 플랜 확인)
  • 민감한 데이터는 로컬 모델 사용을 권장합니다

핵심 정리

  • Ollama 사용법의 핵심 개념과 흐름을 정리합니다.
  • CLI 기본 명령어를 단계별로 이해합니다.
  • 실전 적용 시 기준과 주의점을 확인합니다.

실무 팁

  • 입력/출력 예시를 고정해 재현성을 확보하세요.
  • Ollama 사용법 범위를 작게 잡고 단계적으로 확장하세요.
  • CLI 기본 명령어 조건을 문서화해 대응 시간을 줄이세요.