Ollama에는 공식 ollama Python 라이브러리가 있지만, 'pip를 설치하고 싶지 않다'거나 '단발성 스크립트에 의존성을 늘리고 싶지 않은' 상황에서는 표준 라이브러리인 urllib만으로도 충분히 채팅이 가능합니다. 이 글에서는 표준 라이브러리만을 사용하여 스트리밍(생성되면서 순차적으로 표시)하는 채팅 CLI를 작성하고 실행해 봅니다.
- Windows 11 / Python 3.11 (표준 라이브러리만 사용, 추가 설치 없음)
- Ollama 0.40.4 (
http://127.0.0.1:11434)
- 모델:
qwen2.5:0.5b
chat_stream.py
:
import json
import sys
import urllib.request
...
python chat_stream.py qwen2.5:0.5b "Count from 1 to 5, separated by spaces, nothing else."
실행 결과:
문자가 순차적으로 출력됩니다 (파이프에 리다이렉트하는 경우 한 번에 표시되지만, 터미널 상에서는 생성되는 과정을 볼 수 있습니다).
/api/chat 에 stream: true (기본값)로 요청하면 응답은 NDJSON(1줄당 1개의 JSON) 형식으로 도착합니다. 각 줄은 다음과 같은 구조를 가집니다.
{"model":"...","message":{"role":"assistant","content":"1"},"done":false}
{"model":"...","message":{"role":"assistant","content":" "},"done":false}
...
...
따라서, for line in res: 로 한 줄씩 읽고, message.content 를 추출하여 print(..., end="", flush=True) 만 사용하면 스트리밍 표시가 가능합니다. 마지막에는 done: true 인 청크가 오기 때문에 이를 신호로 루프를 빠져나옵니다. 통계 정보(토큰 수 등)도 이 최종 청크에 포함됩니다.
처음 실행할 때는 모델 로딩으로 인해 대기 시간이 발생합니다. urllib의 기본 설정은 타임아웃이 무제한이라 문제가 되기 어렵지만, 자체적으로 타임아웃을 지정하는 경우에는 길게 설정해야 합니다 (실측 결과 0.5B 모델의 첫 요청에 약 30초가 소요되었습니다).
.res 를 반복하면 줄 단위로 읽을 수 있는 urllib의 응답은 바이너리 줄을 반환하므로, 일반적인 JSON 파싱 전에 UTF-8 처리에 막히지 않도록 json.loads 는 bytes 상태 그대로 전달해도 무방합니다 (Python 3.6 이상에서는 UTF-8을 자동 판별합니다).
- 대화 기록 관리나 토큰 통계 포맷팅까지 직접 처리하는 것이 번거롭다면, 공식 라이브러리 사용도 고려해 볼 수 있습니다. 이 글의 목적은 '의존성 제로로 구동하는 것'입니다.
ollama 라이브러리는 필요 없지만 있어도 좋습니다.
urllib + json 만으로 Ollama 스트리밍 채팅이 구현할 수 있습니다. 핵심은 /api/chat 의 stream: true 가 반환하는 NDJSON을 한 줄씩 처리하는 것입니다.
done: true 를 종료 조건으로 삼으면 통계 정보도 놓치지 않을 수 있습니다.
스트리밍의 연장선으로, 매일 아침 다이제스트 자동 생성까지를 한 권에 정리했습니다. 제1장과 제2장은 무료로 읽을 수 있습니다.