Ollama API 실전: Python과 Node.js 클라이언트 개발 가이드

터미널에 ollama run gemma3를 입력하자 화면에 첫 번째 답변이 나타납니다. 로컬 모델이 실행된 것입니다.
다음으로 이런 생각이 듭니다. 이걸 내 프로젝트에 연결할 수 있을까? API Key도 필요 없고 비용도 들지 않으며 로컬에서 실행되니 꽤 매력적입니다.
문서를 찾아보니 공식 Python 및 JavaScript SDK가 제공되고, OpenAI SDK도 코드 두 줄만 바꾸면 연결할 수 있었습니다. 생각보다 훨씬 간단했습니다.
그렇다고 함정이 없는 것은 아닙니다. 스트리밍 응답은 어떻게 누적할까요? 도구 호출을 위한 Agent Loop는 어떻게 작성할까요? thinking 모드에서는 추론과 답변을 어떻게 나눌까요? 모두 직접 부딪혀 본 문제입니다.
이 글에서는 이런 문제를 하나씩 해결합니다. Python과 Node.js를 비교하고 네이티브 SDK와 OpenAI 호환 방식까지 모두 설명해 완전한 클라이언트 개발 가이드를 제공합니다.
아직 Ollama를 설치하지 않았다면 먼저 이 시리즈의 첫 글인 LangChain + Ollama 통합 실전을 참고해 로컬 모델부터 실행해 보세요.
1장: Ollama API 기초
먼저 API가 어떻게 동작하는지 알아보겠습니다.
Ollama는 기본적으로 로컬에서 http://localhost:11434/api 주소로 REST API 서비스를 시작합니다. 브라우저에서 이 주소를 열었을 때 간단한 “Ollama is running” 문구가 보이면 서비스가 정상적으로 작동하는 것입니다.
주요 엔드포인트
두 가지 핵심 엔드포인트를 기억해야 합니다.
| 엔드포인트 | 용도 | 특징 |
|---|---|---|
/api/chat | 멀티턴 대화 | messages 배열을 지원하며 컨텍스트를 전달할 수 있음 |
/api/generate | 싱글턴 생성 | 단순하고 직접적이며 일회성 작업에 적합 |
/v1/chat/completions라는 엔드포인트도 있습니다. OpenAI 호환 엔드포인트이므로 기존 OpenAI 프로젝트가 있다면 base_url만 바꾸면 사용할 수 있습니다. 뒤에서 자세히 살펴보겠습니다.
curl로 테스트하기
먼저 가장 기본적인 방식으로 API를 테스트해 봅니다.
curl http://localhost:11434/api/chat -d '{
"model": "gemma3",
"messages": [
{ "role": "user", "content": "天空为什么是蓝色的?" }
]
}'
터미널에 여러 JSON이 출력됩니다. 핵심은 message.content 필드이며, 여기에 모델의 답변이 들어 있습니다.
응답 구조는 대략 다음과 같습니다.
{
"model": "gemma3",
"created_at": "2026-04-18T01:23:45.678Z",
"message": {
"role": "assistant",
"content": "天空呈现蓝色主要是因为..."
},
"done": true
}
done 필드는 매우 중요합니다. 스트리밍 응답에서는 각 chunk의 done이 모두 false이고 마지막 chunk만 true입니다. 뒤에서 스트리밍 응답을 처리할 때 이 값을 사용합니다.
스트리밍 응답
기본적으로 API는 모델이 생성을 마칠 때까지 기다린 뒤 결과를 한 번에 반환합니다. 사용자에게 ‘타이핑 효과’를 보여 주려면 stream: true를 추가해야 합니다.
curl http://localhost:11434/api/chat -d '{
"model": "gemma3",
"messages": [{ "role": "user", "content": "天空为什么是蓝色的?" }],
"stream": true
}'
이번에는 터미널에 JSON이 한 줄씩 나타납니다. 각 줄은 작은 chunk이며, 이를 모아야 완전한 답변이 됩니다.
이 chunk들을 직접 처리하기는 확실히 번거롭습니다. 그래서 공식 SDK가 이런 세부 사항을 대신 처리해 줍니다.
2장: Python SDK 완전 실전
Python SDK는 공식적으로 유지 관리되며 설치도 매우 간단합니다.
pip install ollama
설치 후 바로 사용할 수 있습니다. Python 3.8 이상을 지원한다는 점도 반갑습니다.
기본 호출
가장 간단한 호출 방식은 코드 몇 줄이면 충분합니다.
from ollama import chat
response = chat(
model='gemma3',
messages=[{'role': 'user', 'content': '天空为什么是蓝色的?'}]
)
print(response.message.content)
이게 전부입니다. chat() 함수는 SDK가 제공하는 단축 함수로, 내부에서 로컬 Ollama 서비스에 연결하는 기본 Client를 자동 생성합니다.
Ollama가 다른 컴퓨터에서 실행되는 경우처럼 연결 매개변수를 직접 설정하려면 Client를 생성하면 됩니다.
from ollama import Client
client = Client(host='http://192.168.1.100:11434')
response = client.chat(model='gemma3', messages=[...])
스트리밍 응답
스트리밍 응답은 핵심 기능입니다. 사용자가 한참 기다린 뒤 전체 답변을 한꺼번에 받는 대신 글자가 조금씩 나타나는 모습을 볼 수 있어야 합니다.
from ollama import chat
stream = chat(
model='gemma3',
messages=[{'role': 'user', 'content': '天空为什么是蓝色的?'}],
stream=True,
)
for chunk in stream:
print(chunk['message']['content'], end='', flush=True)
여기에는 한 가지 주의점이 있습니다. chunk는 객체가 아니라 딕셔너리로 반환됩니다. 따라서 chunk.message.content가 아니라 chunk['message']['content']로 접근해야 합니다. 처음에는 이 부분을 놓쳐 한동안 오류 원인을 찾지 못했습니다.
비동기 클라이언트
FastAPI나 aiohttp처럼 비동기 아키텍처를 사용하는 애플리케이션에서는 비동기 클라이언트를 사용해야 합니다.
import asyncio
from ollama import AsyncClient
async def main():
client = AsyncClient()
# 非流式
response = await client.chat(
model='gemma3',
messages=[{'role': 'user', 'content': '你好'}]
)
print(response.message.content)
# 流式
stream = await client.chat(
model='gemma3',
messages=[{'role': 'user', 'content': '天空为什么是蓝色的?'}],
stream=True,
)
async for chunk in stream:
print(chunk['message']['content'], end='', flush=True)
asyncio.run(main())
비동기 스트리밍은 async generator를 반환하므로 async for로 순회합니다. 동기 버전과 논리는 같고 await와 async가 추가될 뿐입니다.
Cloud Models
흥미롭게도 Ollama SDK는 클라우드 모델도 지원합니다. 120B 규모의 gpt-oss처럼 로컬에서 실행하기 어려운 대형 모델도 클라우드에서는 사용할 수 있습니다.
from ollama import chat
response = chat(
model='gpt-oss:120b-cloud',
messages=[{'role': 'user', 'content': '你好'}]
)
모델 이름에 -cloud 접미사가 붙으면 클라우드 API를 사용합니다. 물론 Ollama 클라우드 계정과 API Key가 필요하며 구성 방식도 로컬과는 조금 다릅니다. 자세한 내용은 공식 문서를 참고하세요.
솔직히 이 기능은 꽤 실용적입니다. 소형 모델은 로컬에서 실행해 비용을 아끼고, 대형 모델은 클라우드에서 실행해 하드웨어 부담을 줄일 수 있습니다. 괜찮은 하이브리드 방식입니다.
3장: Node.js SDK 완전 실전
Node.js SDK도 마찬가지로 간단합니다.
npm i ollama
이 패키지는 Node.js와 브라우저 환경을 모두 지원합니다. 브라우저 버전은 별도로 가져와야 합니다.
// Node.js
import ollama from 'ollama'
// 浏览器
import ollama from 'ollama/browser'
기본 호출
Node.js에서는 기본적으로 비동기 방식이므로 자연스럽게 작성할 수 있습니다.
import ollama from 'ollama'
const response = await ollama.chat({
model: 'gemma3',
messages: [{ role: 'user', content: '天空为什么是蓝色的?' }],
})
console.log(response.message.content)
Python 버전과 비교하면 Python은 딕셔너리로 messages를 전달하고 Node.js는 객체를 사용합니다. 매개변수 이름은 거의 같으므로 언어를 바꿔도 개념을 다시 배울 필요가 없습니다.
스트리밍 응답
Node.js의 스트리밍 처리는 기본적으로 비동기 generator입니다.
import ollama from 'ollama'
const stream = await ollama.chat({
model: 'gemma3',
messages: [{ role: 'user', content: '天空为什么是蓝色的?' }],
stream: true,
})
for await (const chunk of stream) {
process.stdout.write(chunk.message.content)
}
여기서는 console.log 대신 process.stdout.write를 사용합니다. console.log는 자동으로 줄바꿈하므로 글자가 하나씩 나올 때마다 줄이 바뀌는 결과를 원하지는 않을 것입니다.
사용자 지정 구성
SDK는 사용자 지정 host와 headers를 지원합니다.
import ollama from 'ollama'
// 自定义 host
const client = new ollama.Ollama({ host: 'http://192.168.1.100:11434' })
// 或者用全局配置
ollama.setDefaultHost('http://192.168.1.100:11434')
// 添加 headers(比如认证)
const stream = await ollama.chat({
model: 'gemma3',
messages: [{ role: 'user', content: '你好' }],
headers: { Authorization: 'Bearer xxx' },
})
headers 매개변수는 매우 유용합니다. Ollama 서비스 앞단에 인증 프록시를 추가했다면 여기에서 token을 전달할 수 있습니다.
스트리밍 생성 취소하기
진행 중인 스트리밍 생성을 취소할 수 있는 abort() 메서드가 있습니다.
import ollama from 'ollama'
const stream = await ollama.chat({
model: 'gemma3',
messages: [{ role: 'user', content: '写一篇长文...' }],
stream: true,
})
// 用户点击了停止按钮
ollama.abort()
for await (const chunk of stream) {
// abort 后循环会提前结束
process.stdout.write(chunk.message.content)
}
이 기능은 채팅 인터페이스를 만들 때 꼭 필요합니다. 사용자가 모델의 긴 답변이 끝날 때까지 기다리고 싶지 않다면 버튼을 눌러 중단할 수 있습니다.
브라우저 버전
브라우저에서도 사용법은 비슷하지만 몇 가지 차이가 있습니다.
import ollama from 'ollama/browser'
// 浏览器里只能用流式,因为原生 API 不支持非流式跨域请求
const stream = await ollama.chat({
model: 'gemma3',
messages: [{ role: 'user', content: '你好' }],
stream: true,
})
for await (const chunk of stream) {
document.getElementById('output').textContent += chunk.message.content
}
브라우저 버전에는 한 가지 제한이 있습니다. 스트리밍 모드를 사용해야 합니다. Ollama API의 비스트리밍 요청은 큰 JSON을 한 번에 반환하기 때문에 교차 출처 요청이 시간 초과되거나 차단되기 쉽습니다. 스트리밍 요청은 여러 chunk로 나뉘므로 문제가 훨씬 적습니다.
합리적인 설계입니다. 브라우저에서 채팅 UI를 만든다면 원래부터 스트리밍 표시가 필요하기 때문입니다.
4장: 도구 호출 실전
도구 호출은 Agent를 구축하는 기초입니다. Ollama는 모델이 개발자가 정의한 함수를 호출하고, 함수 반환 결과에 따라 답변 생성을 계속하도록 지원합니다.
Python SDK에는 편리한 기능이 있습니다. Python 함수를 도구로 직접 전달하면 SDK가 함수의 docstring과 매개변수 타입을 자동으로 해석합니다.
Python 함수 자동 해석
def get_weather(city: str) -> str:
"""获取指定城市的天气信息
Args:
city: 城市名称,如"北京"、"上海"
Returns:
天气描述字符串
"""
# 模拟数据
weather_data = {
'北京': '晴,温度 18°C',
'上海': '多云,温度 22°C',
'广州': '雨,温度 26°C',
}
return weather_data.get(city, f'未找到 {city} 的天气数据')
from ollama import chat
response = chat(
model='qwen3',
messages=[{'role': 'user', 'content': '北京今天天气怎么样?'}],
tools=[get_weather],
)
print(response.message.content)
SDK는 함수를 도구 정의 형식으로 자동 변환합니다. 함수명에서 이름을, docstring에서 설명을, 타입 힌트에서 매개변수를 가져옵니다. JSON Schema를 직접 작성할 필요가 없습니다.
Agent Loop 패턴
하지만 이것만으로 끝나지는 않습니다. 모델이 여러 도구를 호출하거나, 도구를 호출한 뒤 또 다른 도구를 호출하려 할 수 있습니다. 이를 처리하려면 반복문이 필요합니다.
이것이 Agent Loop입니다.
from ollama import chat
def add(a: int, b: int) -> int:
"""加法运算"""
return a + b
def multiply(a: int, b: int) -> int:
"""乘法运算"""
return a * b
tools = [add, multiply]
tool_map = {'add': add, 'multiply': multiply}
messages = [{'role': 'user', 'content': '计算 (3 + 5) * 2'}]
while True:
response = chat(model='qwen3', messages=messages, tools=tools)
if response.message.tool_calls:
# 模型想调用工具
for call in response.message.tool_calls:
func_name = call.function.name
func_args = call.function.arguments
result = tool_map[func_name](**func_args)
# 把工具调用结果加进消息历史
messages.append({
'role': 'tool',
'content': str(result),
'tool_name': func_name,
})
else:
# 模型没调用工具,说明结束了
print(response.message.content)
break
동작 방식은 다음과 같습니다.
- 도구 정의와 함께 모델에 메시지를 전송합니다.
- 모델이
tool_calls를 반환하면 해당 함수를 실행합니다. - 함수 결과를 메시지 기록에 넣고 다시 모델에 전송합니다.
- 모델이 더 이상 도구를 호출하지 않을 때까지 반복합니다.
Agent를 만들 때 반드시 필요한 패턴입니다. 여러 도구 함수를 정의해 두면 모델이 호출 시점, 호출할 도구, 호출 순서를 스스로 결정합니다.
thinking 모드
qwen3 같은 일부 모델은 thinking 모드를 지원합니다. 모델이 먼저 ‘생각’한 뒤 답변을 제공합니다.
from ollama import chat
stream = chat(
model='qwen3',
messages=[{'role': 'user', 'content': '为什么天空是蓝色的?'}],
stream=True,
think=True,
)
thinking = ''
content = ''
for chunk in stream:
if chunk.message.thinking:
thinking += chunk.message.thinking
elif chunk.message.content:
content += chunk.message.content
print('=== 思考过程 ===')
print(thinking)
print('=== 最终回答 ===')
print(content)
thinking 모드에서는 chunk에 thinking 필드가 하나 더 생깁니다. 사고 내용과 최종 답변을 각각 누적해야 합니다.
이 기능은 상당히 흥미롭습니다. 모델이 어떤 과정을 거쳐 단계별로 답을 도출하는지 볼 수 있습니다. 교육용 애플리케이션이나 Prompt 디버깅에 유용합니다.
5장: 네이티브 SDK vs OpenAI 호환 API
이제 두 가지 선택지가 있습니다.
- 앞에서 설명한 Ollama 네이티브 SDK 사용
- OpenAI SDK의 주소를 바꿔 Ollama에 연결
어떤 방식이 더 좋을까요? 상황에 따라 다릅니다.
OpenAI 호환 방식
기존 OpenAI 프로젝트가 있다면 가장 적은 비용으로 이전하는 방법은 base_url을 바꾸는 것입니다.
from openai import OpenAI
client = OpenAI(
base_url='http://localhost:11434/v1',
api_key='ollama', # 必填,但会被忽略
)
response = client.chat.completions.create(
model='gemma3',
messages=[{'role': 'user', 'content': '天空为什么是蓝色的?'}],
)
print(response.choices[0].message.content)
이게 전부입니다. OpenAI SDK는 뒤에서 Ollama가 실행되고 있다는 사실을 전혀 모릅니다. 자신이 ‘OpenAI API’와 통신한다고만 인식합니다.
Node.js 버전도 같습니다.
import OpenAI from 'openai'
const client = new OpenAI({
baseURL: 'http://localhost:11434/v1',
apiKey: 'ollama',
})
const completion = await client.chat.completions.create({
model: 'gemma3',
messages: [{ role: 'user', content: '天空为什么是蓝色的?' }],
})
console.log(completion.choices[0].message.content)
두 방식 비교
| 항목 | 네이티브 SDK | OpenAI 호환 |
|---|---|---|
| 설치 | pip install ollama | 기존 OpenAI SDK 사용 가능 |
| 도구 호출 | 함수 docstring 자동 해석 | JSON Schema 직접 작성 |
| 스트리밍 응답 | 딕셔너리 형식 chunk | 표준 OpenAI 형식 |
| Cloud Models | 지원 | 지원하지 않음 |
| 이전 비용 | 새 프로젝트에서는 비용 없음 | 기존 프로젝트에서는 매우 낮음 |
선택 가이드
새 프로젝트: 네이티브 SDK를 사용하세요.
이유는 다음과 같습니다.
- 도구 호출이 더 편리하며 Python 함수를 도구로 바로 전달할 수 있습니다.
- Cloud Models와 thinking 모드 등 더 많은 기능을 지원합니다.
- 문서와 예제가 공식 자료이므로 문제가 생겼을 때 찾아보기 쉽습니다.
기존 OpenAI 프로젝트 이전: OpenAI 호환 방식을 사용하세요.
이유는 다음과 같습니다.
- 코드 두 줄만 바꾸면 실행됩니다.
- 기존 로직을 다시 작성할 필요가 없습니다.
- 나중에 OpenAI로 다시 전환하기도 쉽습니다.
한 문장으로 요약하면 네이티브 SDK는 기능이 더 풍부하고 OpenAI 호환 방식은 이전이 더 빠릅니다. 필요에 맞게 선택하세요.
솔직히 두 방식 모두 사용해 봤습니다. 네이티브 SDK의 도구 호출은 확실히 훨씬 편합니다. JSON Schema 정의를 직접 작성할 필요 없이 함수 docstring만 명확히 작성하면 됩니다. 하지만 프로젝트가 이미 OpenAI에서 실행 중이라면 Ollama를 사용하기 위해 전체를 리팩터링할 필요는 없습니다.
마무리
지금까지의 핵심을 정리해 보겠습니다.
기본 호출: Python과 Node.js SDK 모두 잘 추상화되어 있어 코드 몇 줄이면 실행할 수 있습니다. 스트리밍 응답은 stream=True로 활성화하세요.
도구 호출: Agent Loop가 핵심 패턴입니다. 모델이 더 이상 호출하지 않을 때까지 tool_calls를 반복 처리합니다. Python SDK는 함수를 도구로 바로 전달할 수 있어 JSON Schema를 작성하는 수고를 줄여 줍니다.
thinking 모드: qwen3 등의 모델이 지원하며 모델의 사고 과정을 확인할 수 있습니다. chunk의 thinking과 content 필드를 따로 처리해야 합니다.
방식 선택: 새 프로젝트에는 기능이 더 풍부한 네이티브 SDK를, 기존 OpenAI 프로젝트에는 주소만 바꾸면 되는 호환 방식을 사용하세요.
다음 단계를 권합니다.
- 아직 Ollama를 설치하지 않았다면 시리즈의 첫 글을 참고해 로컬 모델부터 실행하세요.
- 프로젝트에 맞는 방식(네이티브 또는 OpenAI 호환)을 선택해 직접 테스트해 보세요.
- 공식 문서는 계속 업데이트되고 새로운 기능도 추가되므로 시간 날 때 살펴보세요.
로컬에서 LLM을 실행하는 진입 장벽은 점점 낮아지고 있습니다. Ollama는 복잡한 요소를 간단한 API 뒤에 숨겨 줍니다. 호출 방법만 알면 나머지는 Ollama에 맡길 수 있습니다.
이 글은 이 시리즈의 두 번째 글입니다. 다음 글에서는 Modelfile 사용자 지정, 즉 원하는 방식으로 모델을 조정하는 방법을 다룹니다.
Ollama API 클라이언트 개발
Python 또는 Node.js SDK로 Ollama 로컬 모델 API를 호출하는 전체 가이드
⏱️ Estimated time: 45 min
- 1
Step 1: SDK를 설치하고 기본 호출 테스트하기
Python 사용자는 `pip install ollama`를, Node.js 사용자는 `npm i ollama`를 실행합니다.
설치가 끝나면 가장 간단한 코드로 연결을 테스트합니다.
```python
from ollama import chat
response = chat(model='gemma3', messages=[{'role': 'user', 'content': '你好'}])
print(response.message.content)
```
Ollama 서비스가 시작되어 있고(기본 포트 11434) 해당 모델을 미리 내려받았는지 확인하세요. - 2
Step 2: 스트리밍 응답 구현하기
스트리밍 모드를 활성화해 사용자에게 글자가 차례로 출력되는 모습을 보여 줍니다.
```python
from ollama import chat
stream = chat(model='gemma3', messages=[...], stream=True)
for chunk in stream:
print(chunk['message']['content'], end='', flush=True)
```
chunk는 딕셔너리로 반환되므로 `chunk['message']['content']`로 접근해야 합니다. - 3
Step 3: 도구 호출 구성하기(선택 사항)
Python 함수를 도구로 정의하면 SDK가 docstring과 타입 힌트를 자동으로 해석합니다.
```python
def get_weather(city: str) -> str:
"""获取城市天气信息"""
return f'{city}: 晴'
response = chat(model='qwen3', messages=[...], tools=[get_weather])
```
모델이 최종 답변을 반환할 때까지 여러 차례의 도구 호출을 반복 처리하는 Agent Loop를 구현합니다. - 4
Step 4: 네이티브 방식과 OpenAI 호환 방식 중 선택하기
새 프로젝트에는 기능이 더 풍부한 네이티브 SDK(Cloud Models, thinking 모드)를 권장합니다.
기존 OpenAI 프로젝트는 두 줄만 바꾸면 됩니다.
```python
client = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')
```
이전 비용이 매우 낮고 언제든 OpenAI로 다시 전환할 수 있습니다.
FAQ
Ollama API의 기본 포트와 주소는 무엇인가요?
Python SDK의 스트리밍 응답은 어떤 타입으로 반환되나요?
Node.js SDK를 브라우저 환경에서 사용할 때 어떤 제한이 있나요?
Agent Loop 패턴이란 무엇인가요?
thinking 모드에서 사고 과정과 최종 답변을 각각 어떻게 가져오나요?
네이티브 SDK와 OpenAI 호환 방식 중 무엇을 선택해야 하나요?
5분 읽기 · 게시일: 2026년 4월 18일 · 수정일: 2026년 9월 4일
Ollama 로컬 LLM 가이드
검색으로 들어왔다면 같은 시리즈의 이전 글이나 다음 글로 이동하는 것이 가장 빠릅니다.
이전
Ollama API 호출 방법: curl부터 OpenAI SDK 호환 인터페이스까지
Ollama API를 호출하는 두 가지 방법을 설명합니다. curl 기반 네이티브 REST API와 OpenAI SDK 호환 인터페이스, 스트리밍 응답 처리와 실전 코드를 함께 살펴봅니다.
14편 중 8편
다음
LangChain + Ollama 통합 실전: 로컬 LLM 애플리케이션 개발 완벽 가이드
LangChain과 Ollama를 통합하는 전체 과정을 Chat, RAG, Agent 세 가지 실전 코드 예제와 함께 설명하고, OpenAI와 Ollama 전환 전략까지 비교해 로컬 모델로 엔터프라이즈급 LLM 애플리케이션을 만드는 방법을 안내합니다.
14편 중 10편



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