개요
Ollama는 로컬에서 대규모 언어 모델(LLM)을 실행할 수 있는 도구이다. Python의 requests 라이브러리를 사용하여 Ollama API를 호출할 수 있다.
사전 준비
1. Ollama 설치
# Ollama 공식 사이트에서 설치: https://ollama.ai
# 모델 다운로드
ollama pull llama3.2:latest
2. Python 라이브러리 설치
pip install requests
기본 사용법
API 엔드포인트
Ollama는 기본적으로 http://localhost:11434에서 실행된다.
import requests
import json
OLLAMA_URL = "http://localhost:11434/api/chat"
MODEL = "llama3.2:latest"
def call_ollama(user_input: str) -> str:
payload = {
"model": MODEL,
"messages": [
{"role": "user", "content": user_input}
],
"stream": False
}
response = requests.post(OLLAMA_URL, json=payload, timeout=30)
response.raise_for_status()
return response.json()["message"]["content"]
# 사용 예시
result = call_ollama("안녕하세요")
print(result)
Payload 옵션
messages와 role 옵션
messages는 대화를 구성하는 메시지 배열이며, 각 메시지는 role과 content로 구성된다.
role의 종류
Ollama API에서 사용할 수 있는 role은 세 가지가 있다:
system: 시스템 프롬프트 - LLM의 역할과 동작 방식을 정의user: 사용자 입력 - 사용자가 입력한 메시지assistant: LLM 응답 - 모델이 생성한 응답
role: "system" - 시스템 프롬프트
시스템 프롬프트는 LLM의 역할, 성격, 응답 방식을 정의한다. 대화의 맥락을 설정하고 모델의 행동을 제어한다.
사용 방법
messages = [
{
"role": "system",
"content": "당신은 친절한 AI 어시스턴트입니다. 항상 존댓말을 사용하고 도움이 되는 답변을 제공하세요."
}
]
예시 1: 역할 정의
SYSTEM_PROMPT = """당신은 프로그래밍 전문가입니다.
코드 예시를 제공하고, 버그를 찾아주며, 최적화 방법을 제안합니다.
답변은 항상 한국어로 작성하세요."""
payload = {
"model": MODEL,
"messages": [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": "Python에서 리스트를 정렬하는 방법을 알려주세요."}
],
"stream": False
}
예시 2: 응답 형식 지정
SYSTEM_PROMPT = """사용자의 질문을 분석하여 JSON 형식으로 응답하세요.
형식: {"category": "카테고리", "answer": "답변"}
카테고리는 다음 중 하나: "기술", "일반", "기타"
"""
payload = {
"model": MODEL,
"messages": [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": "Python이란 무엇인가요?"}
],
"stream": False,
"format": "json"
}
예시 3: 성격 설정
SYSTEM_PROMPT = """당신은 75세의 불교 스님입니다.
인자하고 차분한 존댓말을 사용하며, 상대의 마음을 존중하며 공감하는 표현을 사용합니다.
판단하거나 단정하지 않고, 부드럽게 질문으로 이끌어갑니다."""
payload = {
"model": MODEL,
"messages": [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": "요즘 스트레스를 많이 받고 있어요."}
],
"stream": False
}
role: "user" - 사용자 입력
사용자가 입력한 메시지를 나타낸다. LLM이 응답해야 할 질문이나 요청을 포함한다.
사용 방법
messages = [
{"role": "user", "content": "오늘 날씨가 어때요?"}
]
예시 1: 단순 질문
payload = {
"model": MODEL,
"messages": [
{"role": "user", "content": "파이썬에서 딕셔너리를 만드는 방법은?"}
],
"stream": False
}
예시 2: 복잡한 요청
payload = {
"model": MODEL,
"messages": [
{
"role": "system",
"content": "당신은 코드 리뷰 전문가입니다."
},
{
"role": "user",
"content": """다음 코드를 리뷰해주세요:
def calculate_sum(numbers):
total = 0
for num in numbers:
total += num
return total"""
}
],
"stream": False
}
role: "assistant" - LLM 응답
모델이 생성한 응답을 나타낸다. 대화 기록을 유지하거나 Few-shot Learning을 구현할 때 사용한다.
사용 방법
messages = [
{"role": "assistant", "content": "안녕하세요! 무엇을 도와드릴까요?"}
]
예시 1: 대화 기록 유지
conversation_history = []
def chat_with_history(user_input: str) -> str:
messages = [
{"role": "system", "content": "당신은 친절한 AI 어시스턴트입니다."}
]
# 이전 대화 기록 추가
messages.extend(conversation_history)
# 현재 사용자 입력 추가
messages.append({"role": "user", "content": user_input})
payload = {
"model": MODEL,
"messages": messages,
"stream": False
}
response = requests.post(OLLAMA_URL, json=payload, timeout=30)
result = response.json()["message"]["content"]
# 대화 기록 업데이트
conversation_history.append({"role": "user", "content": user_input})
conversation_history.append({"role": "assistant", "content": result})
return result
# 사용 예시
print(chat_with_history("내 이름은 철수야"))
print(chat_with_history("내 이름이 뭐였지?")) # 이전 대화를 기억함
예시 2: Few-shot Learning
Few-shot Learning은 몇 가지 예시를 제공하여 모델이 원하는 패턴을 학습하도록 하는 기법이다.
messages = [
{
"role": "system",
"content": "사용자의 문장을 감정으로 분류하세요."
},
{
"role": "user",
"content": "오늘 정말 기분이 좋아요!"
},
{
"role": "assistant",
"content": "긍정"
},
{
"role": "user",
"content": "비가 와서 우울해요."
},
{
"role": "assistant",
"content": "부정"
},
{
"role": "user",
"content": "이 영화는 최고였어요!" # 이 문장의 감정을 분류
}
]
payload = {
"model": MODEL,
"messages": messages,
"stream": False
}
예시 3: 대화 맥락 유지
def multi_turn_conversation():
messages = [
{"role": "system", "content": "당신은 도서관 사서입니다."}
]
# 첫 번째 대화
messages.append({"role": "user", "content": "추천 도서를 알려주세요"})
response1 = requests.post(OLLAMA_URL, json={"model": MODEL, "messages": messages}, timeout=30)
assistant_reply1 = response1.json()["message"]["content"]
messages.append({"role": "assistant", "content": assistant_reply1})
# 두 번째 대화 (이전 맥락 유지)
messages.append({"role": "user", "content": "그 중에서도 과학 소설을 좋아해요"})
response2 = requests.post(OLLAMA_URL, json={"model": MODEL, "messages": messages}, timeout=30)
assistant_reply2 = response2.json()["message"]["content"]
return assistant_reply2
완전한 예시
대화형 챗봇 구현
import requests
import json
OLLAMA_URL = "http://localhost:11434/api/chat"
MODEL = "llama3.2:latest"
SYSTEM_PROMPT = """당신은 친절한 AI 어시스턴트입니다.
항상 존댓말을 사용하고, 도움이 되는 답변을 제공하세요."""
def chat_bot():
conversation_history = []
print("챗봇을 시작합니다. 'quit'를 입력하면 종료됩니다.\n")
while True:
user_input = input("사용자> ").strip()
if user_input.lower() in ("quit", "exit", "종료"):
print("챗봇을 종료합니다.")
break
# 메시지 구성
messages = [
{"role": "system", "content": SYSTEM_PROMPT}
]
# 대화 기록 추가
messages.extend(conversation_history)
# 현재 사용자 입력 추가
messages.append({"role": "user", "content": user_input})
# API 호출
payload = {
"model": MODEL,
"messages": messages,
"stream": False
}
try:
response = requests.post(OLLAMA_URL, json=payload, timeout=30)
response.raise_for_status()
assistant_reply = response.json()["message"]["content"]
# 대화 기록 업데이트
conversation_history.append({"role": "user", "content": user_input})
conversation_history.append({"role": "assistant", "content": assistant_reply})
# 최근 20개 대화만 유지
if len(conversation_history) > 20:
conversation_history = conversation_history[-20:]
print(f"봇> {assistant_reply}\n")
except requests.exceptions.RequestException as e:
print(f"오류 발생: {e}\n")
if __name__ == "__main__":
chat_bot()
기타 Payload 옵션
stream 옵션
payload = {
"model": MODEL,
"messages": messages,
"stream": False # False: 전체 응답을 한 번에 받음, True: 실시간 스트리밍
}
format 옵션
payload = {
"model": MODEL,
"messages": messages,
"format": "json" # JSON 형식으로 응답 받기
}
options 옵션
payload = {
"model": MODEL,
"messages": messages,
"options": {
"temperature": 0.7, # 창의성 조절 (0.0~1.0)
"top_p": 0.9, # 토큰 선택 범위
"top_k": 40 # 상위 K개 토큰만 고려
}
}
temperature
- 용도: 응답의 창의성과 무작위성을 조절
- 범위: 0.0 ~ 1.0 (또는 그 이상)
- 낮은 값 (0.0~0.3): 일관되고 결정적인 답변, 사실 기반 응답에 적합
- 높은 값 (0.7~1.0): 창의적이고 다양한 답변, 창작이나 아이디어 생성에 적합
- 예시:
temperature: 0.0: 정확한 정보 요청 (날짜, 사실 등)temperature: 0.7: 일반적인 대화temperature: 1.0: 창의적 글쓰기, 시나리오 작성
top_p (Nucleus Sampling)
- 용도: 확률 분포에서 상위 토큰들을 선택하는 범위를 제한
- 범위: 0.0 ~ 1.0
- 작동 방식: 누적 확률이 top_p 값에 도달할 때까지의 토큰만 고려
- 낮은 값 (0.1~0.5): 더 집중적이고 일관된 답변, 상위 확률 토큰만 선택
- 높은 값 (0.9~1.0): 더 다양한 답변, 넓은 범위의 토큰 고려
- 장점:
- 낮은 확률의 이상한 토큰을 제외하여 품질 향상
- temperature와 함께 사용하면 더 나은 제어 가능
- 예시:
top_p: 0.1: 매우 집중적인 답변 (기술 문서, 코드 등)top_p: 0.9: 균형잡힌 답변 (일반 대화)top_p: 1.0: 모든 토큰 고려 (최대 다양성)
top_k
- 용도: 다음 토큰 선택 시 고려할 상위 K개 토큰만 제한
- 범위: 1 이상의 정수
- 작동 방식: 확률이 높은 상위 K개 토큰만 후보로 고려
- 낮은 값 (1~10): 매우 집중적이고 예측 가능한 답변
- 높은 값 (40~100): 더 다양한 답변 가능
- 장점:
- 계산 비용 절감 (고려할 토큰 수 제한)
- 낮은 확률의 이상한 토큰 제외
- 예시:
top_k: 1: 항상 가장 확률 높은 토큰만 선택 (매우 결정적)top_k: 40: 상위 40개 토큰 중에서 선택 (균형잡힌 다양성)top_k: 100: 상위 100개 토큰 고려 (높은 다양성)
옵션 조합 예시
# 정확한 정보 요청 (날짜, 사실 등)
options = {
"temperature": 0.0,
"top_p": 0.1,
"top_k": 10
}
# 일반적인 대화
options = {
"temperature": 0.7,
"top_p": 0.9,
"top_k": 40
}
# 창의적 글쓰기
options = {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 100
}
# 코드 생성 (일관성 중시)
options = {
"temperature": 0.2,
"top_p": 0.5,
"top_k": 20
}
top_p vs top_k
- top_p: 확률 기반 선택 (누적 확률 기준)
- top_k: 개수 기반 선택 (상위 K개만 고려)
- 함께 사용: 두 옵션을 함께 사용하면 더 정밀한 제어 가능
- 예:
top_k: 40과top_p: 0.9를 함께 사용하면 상위 40개 중에서 누적 확률 0.9에 해당하는 토큰만 선택
- 예:
주의사항
- role 순서: 일반적으로
system→user→assistant→user→ ... 순서로 구성 - 대화 기록 관리: 대화가 길어지면 메모리 사용량이 증가하므로 최근 N개만 유지
- 에러 처리: 네트워크 오류나 타임아웃에 대한 예외 처리 필요
- 시스템 프롬프트: 명확하고 구체적인 시스템 프롬프트가 더 나은 결과를 만든다