Python용 Ollama API 및 호스팅 대안
Python의 Ollama API는 약 10줄이 필요하며, 동일한 코드 구조는 호스팅 엔드포인트에서도 작동합니다. 이 기사에서는 둘 다 보여주고 언제 어떤 것을 선택해야 하는지 설명합니다.
업데이트
주요 포인트
- Ollama는 포트 11434에서 대기하며 기본 API와 OpenAI 스타일 /v1 엔드포인트를 제공합니다.
- ollama 패키지, 일반 requests 및 OpenAI SDK 모두 작동하며, OpenAI SDK가 가장 이식성이 뛰어납니다.
- 호스팅 API로 이동하려면 기본 URL, 키 및 모델 이름을 변경해야 합니다.
- 로컬은 오프라인 작업과 고정 하드웨어에 가장 적합하며, 호스팅은 GPU가 없을 때 더 간단합니다.

간단 요약
ollama api python을 검색할 때 일반적으로 다음 세 가지 중 하나를 원합니다: 로컬 머신에서 실행 중인 모델 호출, 해당 모델에서 토큰 스트리밍, 또는 동일한 스크립트를 다른 환경에서도 작동하게 만들기. Ollama는 이 세 가지를 모두 제공합니다. 기본적으로 http://localhost:11434에서 로컬 서버를 실행하며, ollama Python 패키지, 일반 HTTP 또는 /v1 경로를 가리키는 OpenAI 클라이언트를 통해 통신할 수 있습니다.
문제는 모델이 귀하의 하드웨어에서 실행되어야 한다는 것입니다. 적절한 GPU가 없는 노트북은 더 큰 모델에서 느릴 수 있으며, GPU가 없는 서버는 적합하지 않습니다. 이러한 경우 호스팅된 OpenAI 호환 API가 더 쉬운 경로이며, 요청 형식이 동일하므로 전환하는 데 구성 3줄이 필요합니다. 아래에는 붙여넣을 수 있는 코드가 포함된 두 경로가 모두 다뤄집니다.
ollama 패키지를 사용하여 로컬 모델 호출
Ollama를 설치하고 모델을 가져온 후 서버가 실행 중인지 확인하십시오. 그런 다음 Python 클라이언트를 설치합니다:
pip install ollama
ollama pull llama3.2
기본 채팅 호출은 다음과 같습니다. 모델 이름은 pull한 모델에 따라 다릅니다. llama3.2는 예시에 불과합니다.
import ollama
response = ollama.chat(
model="llama3.2",
messages=[{"role": "user", "content": "Explain DNS in two sentences."}],
)
print(response["message"]["content"])
스트리밍
stream=True를 전달하면 하나의 응답 대신 청크의 반복기를 얻습니다. 각 청크는 message.content에 답변의 일부를 포함합니다.
import ollama
stream = ollama.chat(
model="llama3.2",
messages=[{"role": "user", "content": "Write a haiku about servers."}],
stream=True,
)
for chunk in stream:
print(chunk["message"]["content"], end="", flush=True)
print()
클라이언트를 다른 머신의 엔드포인트로 지정
Ollama가 다른 호스트에서 실행되는 경우 명시적 주소로 클라이언트를 생성합니다. 예를 들어 ollama.Client(host="http://192.168.1.20:11434")와 같습니다. 기본적으로 서버는 로컬 머신에서만 수신하므로 원격 액세스는 서버 측에서 의도적으로 설정해야 합니다. 프록시와 인증이 앞에 위치하지 않으면 공개 인터넷에 노출하지 마십시오. 네이티브 API에는 자체 키 검사가 없기 때문입니다.
requests를 사용한 일반 HTTP
패키지가 전혀 필요하지 않습니다. 네이티브 채팅 엔드포인트는 POST /api/chat입니다. 여기서는 스트리밍이 기본값이며, 스트림은 SSE가 아닌 줄바꿈으로 구분된 JSON 형식입니다. 단일 객체를 받으려면 "stream": false를 설정하십시오.
import requests
r = requests.post(
"http://localhost:11434/api/chat",
json={
"model": "llama3.2",
"messages": [{"role": "user", "content": "Name three HTTP status codes."}],
"stream": False,
},
timeout=120,
)
r.raise_for_status()
print(r.json()["message"]["content"])
관대한 시간 제한을 설정하십시오. 가져오기 후 첫 번째 요청은 모델을 메모리에 로드해야 하므로 나중에 요청하는 것보다 훨씬 오래 걸릴 수 있습니다.
스트림을 직접 읽는 것은 몇 줄 더 추가하는 작업에 불과합니다. requests.post(..., stream=True)를 호출하고, r.iter_lines()를 반복하며, 빈 줄을 건너뛰고 각 줄에 json.loads를 실행하세요. 각 객체는 응답의 작은 조각을 포함하며, 마지막 객체에는 "done": true가 포함됩니다. 이는 다른 패키지를 설치하기보다 선호하는 최소한의 컨테이너 환경에서 유용하며, 라이브러리가 수행하는 작업을 명확히 보여줍니다. 호스팅 API는 data:로 시작하는 SSE 줄 형식으로 다르게 스트리밍하므로, 이식 가능한 코드에서 OpenAI SDK가 스트림을 구문 분석하도록 위임하는 것이 좋습니다.
Ollama와 함께 OpenAI SDK 사용
Ollama는 또한 /v1 아래에 OpenAI 스타일 엔드포인트를 노출합니다. 이는 공식 openai 패키지가 작동한다는 의미이며, 사용자 정의 기본 URL을 설정할 수 있는 대부분의 소프트웨어도 작동합니다. 키는 SDK에서 필요하지만 로컬 Ollama에서는 무시되므로 임의의 문자열이면 됩니다.
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
resp = client.chat.completions.create(
model="llama3.2",
messages=[{"role": "user", "content": "Give me a one-line summary of TCP."}],
)
print(resp.choices[0].message.content)
이것은 가장 유용한 형태입니다. 코드를 서버와 분리하기 때문입니다. 동일한 함수는 오늘 로컬 모델과 대화하고 내일 다른 것과 대화할 수 있습니다. 이는 다음 섹션입니다.
호스팅 API에 대한 동일한 코드
여기서의 호스팅 옵션은 단일 모델 uncensored을 사용하는 OpenAI 호환 API로, 독립적인 제공업체가 실행하며 합법적인 성인 사용에 대한 콘텐츠 거부 없이 답변하도록 조정되었습니다. 텍스트 전용입니다. 기본 URL은 https://api.ollamaapi.cc/v1이며, API 키 페이지에서 Bearer 키로 인증합니다.
여기서 환경 변수에서 대상을 읽는 버전이 있습니다. 호스팅 값이 기본값입니다. 로컬 서버로 돌아가려면 두 변수를 내보내고 다른 것은 변경하지 마십시오.
import os
from openai import OpenAI
client = OpenAI(
base_url=os.getenv("LLM_BASE_URL", "https://api.ollamaapi.cc/v1"),
api_key=os.getenv("LLM_API_KEY", "YOUR_API_KEY"),
)
MODEL = os.getenv("LLM_MODEL", "uncensored")
resp = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "List four uses of a message queue."},
],
temperature=0.7,
)
print(resp.choices[0].message.content)
로컬 실행의 경우 LLM_BASE_URL=http://localhost:11434/v1, LLM_API_KEY=ollama 및 LLM_MODEL=llama3.2를 설정하십시오. 빠른 시작에는 curl 및 Node와 동일한 설정이 있습니다.
호스팅 측의 스트리밍, JSON 모드 및 도구
호스팅 엔드포인트는 SSE를 통한 스트리밍, JSON 모드, 도구 호출 및 일반적인 샘플링 매개변수(temperature, top_p, stop, seed 및 페널티)를 지원합니다. SDK를 사용한 스트리밍은 모든 OpenAI 스타일 서버에 대해 작성할 반복기와 동일합니다:
stream = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "Tell a two-paragraph story about a lighthouse."}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
구조화된 출력을 위해 response_format={"type": "json_object"}를 설정하고 프롬프트에서 JSON을 원한다고 명시하십시오. 모델이 예상치 못한 것을 반환할 수 있으므로 어쨌든 try 블록 내에서 구문 분석하십시오.
로컬 사용과 코드에서 중요한 차이점 중 하나는 제한 사항입니다. 전체 키는 8개의 동시 요청과 분당 300개의 요청을 허용하며, 스트리밍된 요청은 스트림이 끝날 때까지 슬롯을 유지합니다. 스레드를 사용하여 병렬로 요청을 분산하는 경우, 풀 크기를 8로 제한하고 HTTP 429 응답 시 Retry-After 헤더가 있는 경우 해당 헤더를 사용하여 재시도하십시오.
대화 유지하기
로컬 및 호스팅 채팅 엔드포인트 모두 호출 간에 상태를 기억하지 않습니다. 서버는 귀하가 보내는 메시지만 보므로, 채팅봇은 귀하가 메시지를 추가하고 다시 전송하는 목록입니다. 이 패턴은 두 대상 모두에 동일하므로 OpenAI 스타일 클라이언트를 기본값으로 유지하는 것이 좋습니다.
history = [{"role": "system", "content": "You are a helpful assistant."}]
def ask(text):
history.append({"role": "user", "content": text})
resp = client.chat.completions.create(model=MODEL, messages=history)
answer = resp.choices[0].message.content
history.append({"role": "assistant", "content": answer})
return answer
print(ask("Pick a name for a hiking app."))
print(ask("Give me a tagline for it."))
두 가지 실용적인 참고 사항. 첫째, 로컬 모델은 설정하고 메모리가 보유해야 하는 컨텍스트 길이를 가집니다. 기록이 이를 초과하면 설정에 따라 이전 턴이 잘리거나 호출이 실패합니다. 호스팅 모델은 완료 포함 100,000개의 토큰 창을 허용하며, 이는 대부분의 채팅에 필요한 것보다 훨씬 많지만 긴 기록은 여전히 모든 턴에서 입력 토큰 비용이 발생합니다. 둘째, 기록이 길어지면 모든 것을 다시 보내는 대신 가장 오래된 턴을 하나의 짧은 메시지로 요약하십시오. 이렇게 하면 두 백엔드 모두에서 지연 시간과 비용이 일정하게 유지됩니다.
정중하게 재시도
호스팅 API에서 일시적인 과부하 발생 시 HTTP 429 응답과 함께 Retry-After: 5 헤더가 반환됩니다. 간단한 래퍼 함수로 이를 처리할 수 있습니다:
import time
from openai import RateLimitError
def chat_with_retry(messages, tries=4):
for attempt in range(tries):
try:
return client.chat.completions.create(model=MODEL, messages=messages)
except RateLimitError:
time.sleep(5 * (attempt + 1))
raise RuntimeError("still rate limited")
로컬 Ollama는 속도 제한을 적용하지 않지만, 모델이 바쁠 때 요청을 대기열에 넣습니다. 따라서 동일한 래퍼 함수를 사용해도 문제가 없습니다.
로컬 또는 호스팅: 결정 방법
일반적으로 어느 쪽이 더 낫지는 않습니다. 아래 체크리스트를 사용하십시오.
- 로컬 Ollama를 선택하세요 오프라인으로 작업해야 하거나, 데이터가 머신에서 절대 벗어나서는 안 되거나, 이미 적절한 성능의 GPU를 보유하고 있거나, 여러 오픈 모델을 빠르게 시도하려는 경우입니다.
- 호스팅된 API 선택: GPU가 없거나 작은 VPS 또는 CI에서 실행 중이거나, 여러 사람이나 서비스가 하나의 백엔드를 공유하거나, 메모리 크기를 직접 조정하지 않고 긴 컨텍스트 창을 원하는 경우. 호스팅된 모델은 프롬프트와 생성을 합쳐 최대 100,000개의 토큰을 허용합니다.
- 개발 중 둘 다 혼합하십시오: 로컬에서 반복한 후 환경 변수를 통해 프로덕션을 호스팅 URL로 향하게 합니다.
호스팅 사용은 선불 크레딧에서 토큰당 청구됩니다. 입력 토큰 100만 개당 $0.15, 출력 토큰 100만 개당 $0.50입니다. 가격 페이지에는 충전 금액이 나열되어 있으며, 새 계정은 카드 없이 한 번의 클릭으로 $0.50 무료 체험 크레딧을 받을 수 있습니다. 프롬프트는 학습에 사용되지 않습니다.
직면할 오류
| 증상 | 잠재적 원인 | 해결 방법 |
|---|---|---|
| 포트 11434에서 연결 거부 | Ollama 서버가 실행 중이 아님 | 앱을 시작하거나 ollama serve를 실행하십시오 |
| 모델을 찾을 수 없음 | 모델이 pull되지 않았거나, 이름에 오타가 있습니다. | ollama list를 실행한 후, 사용하는 모델 이름을 ollama pull로 pull하세요. |
| 첫 번째 호출 시간 초과 | 모델이 여전히 로딩 중임 | 타임아웃을 늘리거나 워밍업 요청을 보내십시오. |
| 호스팅 API의 인증 오류 | 누락되거나 잘못된 Bearer 키 | LLM_API_KEY와 기본 URL을 확인하세요. |
코드 concurrency HTTP 429 | 동시에 처리 중인 요청이 8개 이상 (시험 키의 경우 2개) | 워커 수를 줄이세요 |
코드 rate_limited HTTP 429 | 분당 요청 수 제한 초과 | 잠시 후 재시도하세요. |
호스팅 제공자 측의 실패하거나 거부된 요청은 요금이 부과되지 않으므로, 재시도 로직이 실패한 시도에도 비용을 청구하지 않습니다.
더 많은 가이드
질문과 답변
기본 Ollama API 주소는 무엇입니까?
로컬 Ollama 서버는 http://localhost:11434에서 대기합니다. 네이티브 엔드포인트는 /api 아래에 위치하며, 예를 들어 /api/chat이 있고, OpenAI 스타일 엔드포인트는 /v1 아래에 위치합니다.
Ollama와 함께 OpenAI Python SDK를 사용할 수 있습니까?
예. base_url을 http://localhost:11434/v1로 설정하고 API 키로 아무 문자열이나 입력하세요. SDK는 로컬 모델로 표준 채팅 응답 생성 요청을 보냅니다.
Ollama에서 호스팅 API로 전환하는 방법은 무엇입니까?
베이스 URL, 키 및 모델 이름을 변경하세요. 코드가 환경 변수에서 이를 읽는다면 코드 변경이 필요하지 않습니다.
제 쪽에서 GPU 없이 호스팅된 API가 작동합니까?
예. 모델은 제공업체에서 실행되므로 스크립트에는 인터넷 연결과 Bearer 키만 필요합니다. 선불 크레딧에서 토큰당 요금을 지불합니다.