Ollama API 호출 방법: curl부터 OpenAI SDK 호환 인터페이스까지

터미널에서 실행한 curl 명령의 JSON 응답에 단어가 절반만 들어 있었습니다. 두 시간이나 씨름한 뒤에야 스트리밍 응답 때문이라는 사실을 알았습니다. Ollama는 기본적으로 물이 흐르듯 내용을 조금씩 내보내며, 각 JSON 객체에는 몇 글자만 담깁니다.
로컬 LLM 배포에서 Ollama는 진입 장벽을 크게 낮췄습니다. 다운로드, 설치, 실행이면 세 단계로 끝납니다. 하지만 API 호출에서는 헷갈리기 쉽습니다. 네이티브 REST API와 OpenAI SDK 호환 인터페이스는 무엇이 다를까요? 스트리밍 응답은 어떻게 처리해야 할까요?
이 글에서는 직접 겪은 문제를 바탕으로 curl 명령부터 OpenAI SDK의 코드 변경 없는 마이그레이션, 문서에서 명확히 설명하지 않은 세부 사항까지 정리합니다.
Ollama API의 두 가지 인터페이스
이 부분은 한동안 정말 헷갈렸습니다. Ollama는 실제로 완전히 다른 두 종류의 API 인터페이스를 제공합니다.
네이티브 REST API: http://localhost:11434/api/*
- 엔드포인트:
/api/generate(텍스트 생성),/api/chat(대화),/api/tags(모델 목록) - 기본적으로 스트리밍 응답 사용(새벽 3시에 겪었던 문제의 원인입니다)
- 별도 SDK 없이 직접 HTTP로 호출
OpenAI 호환 인터페이스: http://localhost:11434/v1/*
- 엔드포인트:
/v1/chat/completions,/v1/completions,/v1/models - OpenAI SDK와 완전히 호환(Python과 JavaScript에서 바로 사용 가능)
- 기존 OpenAI 도구 생태계 지원
왜 두 종류가 필요한지 궁금할 수 있습니다. 각각 쓰임새가 다릅니다. 네이티브 API는 더 가볍고 직접적이어서 직접 HTTP 클라이언트를 작성할 때 적합합니다. OpenAI 호환 인터페이스는 기존 OpenAI SDK 코드를 그대로 사용할 수 있게 해 줍니다. base_url만 바꾸면 됩니다.
솔직히 꽤 영리한 설계입니다. 간단한 호출을 원하는 개발자와 이미 OpenAI 생태계용 코드를 보유한 팀을 모두 고려했습니다.
네이티브 REST API: curl로 시작하기
먼저 네이티브 API를 살펴보겠습니다. 표준 REST 인터페이스라서 사용법은 비교적 단순합니다.
기본 curl 호출
가장 간단한 텍스트 생성 예제입니다.
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "Why is the sky blue?",
"stream": false
}'
여기서 stream: false에 주의해야 합니다. Ollama는 기본적으로 콘텐츠를 스트리밍 방식으로 반환합니다. 완전한 JSON 응답을 원한다면 스트리밍을 명시적으로 비활성화해야 합니다. 그렇지 않으면 다음과 같은 출력이 이어집니다.
{"model":"llama3.2","response":"That","done":false}
{"model":"llama3.2","response":"'","done":false}
{"model":"llama3.2","response":"s","done":false}
{"model":"llama3.2","response":" a","done":false}
...
{"model":"llama3.2","response":"!","done":true}
각 JSON 객체에는 몇 글자만 들어 있고 token 단위로 출력됩니다. 이것이 NDJSON(Newline-Delimited JSON) 형식입니다. 한 줄마다 JSON 객체 하나가 들어갑니다. 새벽 3시에 문제를 겪었을 때는 이 점을 놓치고 일반 JSON처럼 파싱해서 첫 번째 객체의 “That”만 받았습니다.
대화 모드가 더 실용적입니다
일회성 생성은 간단한 작업에 적합하지만, 실제로는 대화 모드를 더 자주 사용합니다.
curl http://localhost:11434/api/chat -d '{
"model": "llama3.2",
"messages": [
{ "role": "user", "content": "Hello!" }
],
"stream": false
}'
messages 배열을 유지하면서 이전 대화를 함께 전달하면 모델이 문맥을 기억할 수 있습니다. 채팅 애플리케이션을 구축할 때 특히 중요합니다.
설치된 모델 확인
로컬에 어떤 모델이 있는지 확인하고 싶을 때는 다음 명령을 사용합니다.
curl http://localhost:11434/api/tags
반환된 JSON에는 다운로드한 모든 모델과 각 모델의 크기, 수정 시각, 양자화 수준 등이 표시됩니다. 꽤 편리합니다.
스트리밍 응답 처리
이 부분은 따로 짚고 넘어갈 필요가 있습니다. Ollama의 스트리밍 응답은 전체 콘텐츠를 한 번에 반환하지 않고 token 단위로 출력합니다.
Python에서 스트리밍 처리
Python의 requests 라이브러리로 스트리밍 응답을 처리하는 예제입니다.
import requests
import json
url = "http://localhost:11434/api/chat"
payload = {
"model": "llama3.2",
"messages": [{"role": "user", "content": "Write a short poem"}],
"stream": True
}
response = requests.post(url, json=payload, stream=True)
for line in response.iter_lines():
if line:
chunk = json.loads(line)
print(chunk.get("message", {}).get("content", ""), end="", flush=True)
핵심은 response.iter_lines()입니다. 이 메서드를 사용하면 NDJSON 스트림을 한 줄씩 읽을 수 있습니다. 각 chunk에는 몇 글자만 들어 있을 수 있으므로 내용을 누적해야 완전한 응답을 얻을 수 있습니다.
JavaScript에서 스트리밍 처리
프론트엔드에서 fetch API를 사용할 때도 방식은 비슷합니다.
const response = await fetch('http://localhost:11434/api/chat', {
method: 'POST',
body: JSON.stringify({
model: 'llama3.2',
messages: [{ role: 'user', content: 'Hello!' }],
stream: true
})
});
const reader = response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = new TextDecoder().decode(value);
// 각 chunk 처리...
}
스트리밍 처리는 비스트리밍 방식보다 조금 번거롭지만 사용자 경험은 훨씬 좋습니다. 한참 기다린 뒤 긴 텍스트가 갑자기 나타나는 대신, 모델이 “생각”하고 출력하는 과정을 실시간으로 볼 수 있습니다.
OpenAI SDK 호환 인터페이스: 코드 변경 없이 마이그레이션
가장 마음에 드는 부분입니다. Ollama는 완전한 OpenAI API 호환 인터페이스를 제공하므로 기존 코드를 거의 그대로 마이그레이션할 수 있습니다.
Python OpenAI SDK 예제
OpenAI 공식 SDK를 그대로 사용합니다.
from openai import OpenAI
client = OpenAI(
base_url='http://localhost:11434/v1/',
api_key='ollama' # 로컬에서는 검증하지 않으므로 아무 값이나 입력 가능
)
response = client.chat.completions.create(
model="llama3.2",
messages=[{"role": "user", "content": "Hello!"}]
)
print(response.choices[0].message.content)
보이는 것처럼 달라지는 부분은 base_url 설정과 임의의 api_key 입력뿐입니다. 나머지 코드는 완전히 동일합니다.
개발 환경과 프로덕션 환경 전환
이 기능은 특히 유용합니다. 개발 환경에서는 로컬 Ollama를 사용하고 프로덕션 환경에서는 OpenAI를 사용할 수 있습니다.
# 개발 환경 .env
OPENAI_API_KEY=anyrandomtext
LLM_ENDPOINT="http://localhost:11434/v1"
MODEL=llama3.2
# 프로덕션 환경 .env
OPENAI_API_KEY=sk-XXXXXXXXXXXXXXXXXXXXXXXX
LLM_ENDPOINT="https://api.openai.com/v1"
MODEL=gpt-3.5-turbo
코드에서는 환경 변수에서 값을 읽기만 하면 됩니다.
import os
from openai import OpenAI
client = OpenAI(
base_url=os.getenv('LLM_ENDPOINT'),
api_key=os.getenv('OPENAI_API_KEY')
)
이렇게 하면 개발 중에는 OpenAI API 호출 비용 없이 로컬에서 충분히 테스트할 수 있습니다. 배포할 때는 환경 변수만 바꾸면 실제 OpenAI로 전환됩니다.
지원하는 엔드포인트
Ollama의 OpenAI 호환 인터페이스는 다음 엔드포인트를 지원합니다.
| 엔드포인트 | 기능 | 지원 수준 |
|---|---|---|
/v1/chat/completions | 대화 생성 | 완전 지원 |
/v1/completions | 텍스트 완성 | 완전 지원 |
/v1/models | 모델 목록 | 완전 지원 |
/v1/embeddings | 텍스트 임베딩 | 완전 지원 |
/v1/responses | 새로운 응답 API | 완전 지원 |
실험적인 /v1/images/generations 엔드포인트도 있지만 아직 안정성이 충분하지 않습니다.
모델 별칭
작은 팁이 하나 있습니다. 모델에 별칭을 지정할 수 있습니다. 예를 들어 코드상으로 GPT-3.5를 호출하는 것처럼 보이게 하려면 다음 명령을 사용합니다.
ollama cp llama3.2 gpt-3.5-turbo
이제 코드에 model="gpt-3.5-turbo"라고 작성해도 실제로는 로컬 llama3.2를 사용합니다. 코드를 마이그레이션할 때 유용합니다.
두 방식 중 무엇을 선택해야 할까요?
여기까지 읽으면 어떤 방식을 사용해야 할지 고민될 수 있습니다.
네이티브 REST API가 적합한 경우
다음과 같은 상황에 적합합니다.
- 가장 가벼운 호출 방식을 원하는 경우
- OpenAI SDK 생태계가 필요하지 않은 경우
- 직접 HTTP 클라이언트를 작성하는 경우(임베디드 장치나 특수 환경 등)
- 스트리밍 응답의 세부 사항을 정밀하게 제어해야 하는 경우
네이티브 API는 더 직접적이고 저수준에 가깝습니다. HTTP 프로토콜에 익숙하다면 편하게 사용할 수 있습니다.
OpenAI SDK 호환 인터페이스가 적합한 경우
다음과 같은 상황에 적합합니다.
- 이미 OpenAI SDK 기반 코드가 있는 경우
- 로컬 배포로 빠르게 마이그레이션해야 하는 경우
- OpenAI 도구 체인(LangChain, LlamaIndex 등)을 사용하는 경우
- 개발 환경과 프로덕션 환경 사이를 전환해야 하는 경우
간단히 말해 기존 도구를 그대로 활용하면서 코드를 바꾸고 싶지 않다면 OpenAI 호환 인터페이스를 선택하면 됩니다.
제안
솔직히 개발할 때는 OpenAI SDK 호환 인터페이스를 더 선호합니다. 코드 변경이 적고 도구 체인을 사용할 수 있으며 디버깅도 편합니다. 하지만 아주 단순한 CLI 도구를 만들거나 OpenAI SDK를 지원하지 않는 환경에서 호출해야 할 때는 네이티브 API가 더 적합합니다.
실전 코드 조각
마지막으로 자주 사용하는 코드 조각 몇 가지를 공유합니다.
Python 스트리밍 채팅(OpenAI SDK)
from openai import OpenAI
client = OpenAI(
base_url='http://localhost:11434/v1/',
api_key='ollama'
)
stream = client.chat.completions.create(
model="llama3.2",
messages=[{"role": "user", "content": "Write a poem"}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
JavaScript 전체 대화(네이티브 API)
async function chat(messages) {
const response = await fetch('http://localhost:11434/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'llama3.2',
messages: messages,
stream: false
})
});
return await response.json();
}
// 대화 기록 유지
let conversation = [
{ role: 'user', content: 'Hello!' }
];
const result = await chat(conversation);
conversation.push({
role: 'assistant',
content: result.message.content
});
console.log(result.message.content);
도구 호출 예제
Ollama는 Function Calling(도구 호출)도 지원합니다.
from openai import OpenAI
client = OpenAI(base_url='http://localhost:11434/v1/', api_key='ollama')
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"]
}
}
}
]
response = client.chat.completions.create(
model="llama3.2",
messages=[{"role": "user", "content": "What's the weather in Tokyo?"}],
tools=tools
)
if response.choices[0].message.tool_calls:
print("Model wants to call:", response.choices[0].message.tool_calls[0].function.name)
마무리
Ollama의 API 설계는 꽤 균형이 잘 잡혀 있습니다. 네이티브 REST API의 직접성과 가벼움, OpenAI SDK의 편리함과 생태계 호환성을 모두 제공합니다. 두 방식은 각각 맞는 상황이 있으므로 요구 사항에 따라 선택하면 됩니다.
Ollama를 처음 사용한다면 OpenAI SDK 호환 인터페이스부터 시도해 보기를 권합니다. 시작하기 쉽고 코드 변경도 적습니다. 익숙해진 뒤 구체적인 요구에 따라 네이티브 API 사용 여부를 결정하면 됩니다.
그리고 스트리밍 응답 처리는 정말 놓치기 쉬운 부분입니다. 기본값이 스트리밍이라는 점을 기억하세요. 스트리밍이 필요하지 않다면 stream: false를 명시적으로 설정해야 합니다. 그렇지 않으면 저처럼 새벽 3시에 단어 절반을 바라보며 고민하게 될 수 있습니다.
참고 자료
- Ollama API Introduction
- Ollama OpenAI Compatibility
- Ollama Streaming Guide
- KodeKloud OpenAI Compatibility Guide
Ollama API를 호출하는 두 가지 방법
curl 기반 네이티브 API부터 OpenAI SDK 호환 인터페이스까지 전체 호출 과정
⏱️ Estimated time: 10 min
- 1
Step 1: Ollama 설치 및 실행 상태 확인
먼저 Ollama가 정상적으로 실행 중인지 확인합니다.
• 터미널에서 ollama list 실행(다운로드한 모델 확인)
• 또는 http://localhost:11434 접속(Ollama is running이 표시되어야 함)
• 기본 포트: 11434 - 2
Step 2: 호출 방식 선택
상황에 맞게 선택합니다.
• 네이티브 REST API: 가벼운 호출이나 사용자 지정 클라이언트에 적합
• OpenAI SDK 호환: 기존 OpenAI 코드나 빠른 마이그레이션에 적합 - 3
Step 3: 네이티브 REST API 사용(curl 방식)
가장 기본적인 curl 호출입니다.
• 텍스트 생성: curl http://localhost:11434/api/generate -d '{"model": "llama3.2", "prompt": "...", "stream": false}'
• 대화 모드: curl http://localhost:11434/api/chat -d '{"model": "llama3.2", "messages": [...], "stream": false}'
• 주의: 기본값은 스트리밍 응답이므로 비활성화하려면 stream: false를 설정해야 합니다. - 4
Step 4: OpenAI SDK 호환 인터페이스 사용
Python OpenAI SDK 호출 방법입니다.
• base_url='http://localhost:11434/v1/' 설정
• api_key는 아무 값이나 입력 가능(로컬에서 검증하지 않음)
• 나머지 코드는 OpenAI와 완전히 동일
• 환경 전환: base_url만 변경(개발 환경은 로컬, 프로덕션 환경은 OpenAI) - 5
Step 5: 스트리밍 응답 처리
스트리밍 응답 처리의 핵심입니다.
• Python: response.iter_lines()로 NDJSON을 한 줄씩 읽기
• JavaScript: response.body.getReader()로 스트림 읽기
• 각 chunk에는 몇 글자만 들어 있으므로 전체 응답을 누적해야 함
• 비스트리밍: stream: false를 설정해 완전한 JSON 받기
FAQ
Ollama의 네이티브 API와 OpenAI SDK 호환 인터페이스는 무엇이 다른가요?
Ollama API를 호출했는데 왜 단어의 절반만 반환되나요?
• stream: false를 설정해 스트리밍을 끄고 완전한 JSON 받기
• 또는 NDJSON 스트림을 올바르게 처리해 한 줄씩 읽고 내용을 누적하기
개발 환경에서는 로컬 Ollama를, 프로덕션 환경에서는 OpenAI를 사용하려면 어떻게 하나요?
Ollama는 어떤 OpenAI 엔드포인트를 지원하나요?
Ollama 모델에 별칭을 지정할 수 있나요?
Ollama는 도구 호출(Function Calling)을 지원하나요?
3분 읽기 · 게시일: 2026년 4월 3일 · 수정일: 2026년 9월 4일
Ollama 로컬 LLM 가이드
검색으로 들어왔다면 같은 시리즈의 이전 글이나 다음 글로 이동하는 것이 가장 빠릅니다.
이전
Ollama + Open WebUI로 로컬 ChatGPT 인터페이스 구축하기(완전 가이드)
Ollama와 Open WebUI를 사용해 로컬에 ChatGPT 스타일의 AI 채팅 인터페이스를 구축하는 방법을 단계별로 설명합니다. 설치와 배포, 모델 선택, RAG 지식 베이스, API 연동, 성능 최적화까지 30분 안에 로컬 AI 어시스턴트를 완성할 수 있습니다.
14편 중 7편
다음
Ollama API 실전: Python과 Node.js 클라이언트 개발 가이드
Ollama API 호출 방법을 자세히 설명하며 Python 및 Node.js SDK 네이티브 호출, 스트리밍 응답 처리, 도구 호출 Agent Loop, thinking 모드와 OpenAI 호환 방식 비교를 다룹니다.
14편 중 9편



댓글
GitHub로 로그인하여 댓글을 남기세요